util/src/gui/text/qfontengine_ft.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qdir.h"
       
    43 #include "qmetatype.h"
       
    44 #include "qtextstream.h"
       
    45 #include "qvariant.h"
       
    46 #include "qfontengine_ft_p.h"
       
    47 
       
    48 #ifndef QT_NO_FREETYPE
       
    49 
       
    50 #include "qfile.h"
       
    51 #include "qabstractfileengine.h"
       
    52 #include "qthreadstorage.h"
       
    53 #include <qmath.h>
       
    54 #include <private/qpdf_p.h>
       
    55 #include <private/qharfbuzz_p.h>
       
    56 
       
    57 #include "qfontengine_ft_p.h"
       
    58 #include <ft2build.h>
       
    59 #include FT_FREETYPE_H
       
    60 #include FT_OUTLINE_H
       
    61 #include FT_TRUETYPE_TABLES_H
       
    62 #include FT_TYPE1_TABLES_H
       
    63 #include FT_GLYPH_H
       
    64 
       
    65 #if defined(FT_LCD_FILTER_H)
       
    66 #include FT_LCD_FILTER_H
       
    67 #endif
       
    68 
       
    69 #if defined(FT_CONFIG_OPTIONS_H)
       
    70 #include FT_CONFIG_OPTIONS_H
       
    71 #endif
       
    72 
       
    73 #if defined(FT_LCD_FILTER_H) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING)
       
    74 #define QT_USE_FREETYPE_LCDFILTER
       
    75 #endif
       
    76 
       
    77 #ifdef QT_LINUXBASE
       
    78 #include FT_ERRORS_H
       
    79 #endif
       
    80 
       
    81 QT_BEGIN_NAMESPACE
       
    82 
       
    83 /*
       
    84  * Freetype 2.1.7 and earlier used width/height
       
    85  * for matching sizes in the BDF and PCF loaders.
       
    86  * This has been fixed for 2.1.8.
       
    87  */
       
    88 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
       
    89 #define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
       
    90 #define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
       
    91 #else
       
    92 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
       
    93 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
       
    94 #endif
       
    95 
       
    96 #define FLOOR(x)    ((x) & -64)
       
    97 #define CEIL(x)	    (((x)+63) & -64)
       
    98 #define TRUNC(x)    ((x) >> 6)
       
    99 #define ROUND(x)    (((x)+32) & -64)
       
   100 
       
   101 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
       
   102 {
       
   103 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
       
   104     FT_Face face = (FT_Face)font;
       
   105     FT_ULong ftlen = *length;
       
   106     FT_Error error = 0;
       
   107 
       
   108     if ( !FT_IS_SFNT(face) )
       
   109         return HB_Err_Invalid_Argument;
       
   110 
       
   111     error = FT_Load_Sfnt_Table(face, tableTag, 0, buffer, &ftlen);
       
   112     *length = ftlen;
       
   113     return (HB_Error)error;
       
   114 #else
       
   115     return HB_Err_Invalid_Argument;
       
   116 #endif
       
   117 }
       
   118 
       
   119 // -------------------------- Freetype support ------------------------------
       
   120 
       
   121 class QtFreetypeData
       
   122 {
       
   123 public:
       
   124     QtFreetypeData()
       
   125         : library(0)
       
   126     { }
       
   127 
       
   128     FT_Library library;
       
   129     QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
       
   130 };
       
   131 
       
   132 #ifdef QT_NO_THREAD
       
   133 Q_GLOBAL_STATIC(QtFreetypeData, theFreetypeData)
       
   134 
       
   135 QtFreetypeData *qt_getFreetypeData()
       
   136 {
       
   137     return theFreetypeData();
       
   138 }
       
   139 #else
       
   140 Q_GLOBAL_STATIC(QThreadStorage<QtFreetypeData *>, theFreetypeData)
       
   141 
       
   142 QtFreetypeData *qt_getFreetypeData()
       
   143 {
       
   144     QtFreetypeData *&freetypeData = theFreetypeData()->localData();
       
   145     if (!freetypeData)
       
   146         freetypeData = new QtFreetypeData;
       
   147     return freetypeData;
       
   148 }
       
   149 #endif
       
   150 
       
   151 FT_Library qt_getFreetype()
       
   152 {
       
   153     QtFreetypeData *freetypeData = qt_getFreetypeData();
       
   154     if (!freetypeData->library)
       
   155         FT_Init_FreeType(&freetypeData->library);
       
   156     return freetypeData->library;
       
   157 }
       
   158 
       
   159 int QFreetypeFace::fsType() const
       
   160 {
       
   161     int fsType = 0;
       
   162     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
       
   163     if (os2)
       
   164         fsType = os2->fsType;
       
   165     return fsType;
       
   166 }
       
   167 
       
   168 HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
       
   169 {
       
   170     int load_flags = (flags & HB_ShaperFlag_UseDesignMetrics) ? FT_LOAD_NO_HINTING : FT_LOAD_DEFAULT;
       
   171 
       
   172     if (HB_Error error = (HB_Error)FT_Load_Glyph(face, glyph, load_flags))
       
   173         return error;
       
   174 
       
   175     if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
       
   176         return HB_Err_Invalid_SubTable;
       
   177 
       
   178     *nPoints = face->glyph->outline.n_points;
       
   179     if (!(*nPoints))
       
   180         return HB_Err_Ok;
       
   181 
       
   182     if (point > *nPoints)
       
   183         return HB_Err_Invalid_SubTable;
       
   184 
       
   185     *xpos = face->glyph->outline.points[point].x;
       
   186     *ypos = face->glyph->outline.points[point].y;
       
   187 
       
   188     return HB_Err_Ok;
       
   189 }
       
   190 
       
   191 /*
       
   192  * One font file can contain more than one font (bold/italic for example)
       
   193  * find the right one and return it.
       
   194  *
       
   195  * Returns the freetype face or 0 in case of an empty file or any other problems
       
   196  * (like not being able to open the file)
       
   197  */
       
   198 QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id)
       
   199 {
       
   200     if (face_id.filename.isEmpty())
       
   201         return 0;
       
   202 
       
   203     QtFreetypeData *freetypeData = qt_getFreetypeData();
       
   204     if (!freetypeData->library)
       
   205         FT_Init_FreeType(&freetypeData->library);
       
   206 
       
   207     QFreetypeFace *freetype = freetypeData->faces.value(face_id, 0);
       
   208     if (freetype) {
       
   209         freetype->ref.ref();
       
   210     } else {
       
   211         QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
       
   212         FT_Face face;
       
   213         QFile file(QString::fromUtf8(face_id.filename));
       
   214         if (face_id.filename.startsWith(":qmemoryfonts/")) {
       
   215             // from qfontdatabase.cpp
       
   216             extern QByteArray qt_fontdata_from_index(int);
       
   217             QByteArray idx = face_id.filename;
       
   218             idx.remove(0, 14); // remove ':qmemoryfonts/'
       
   219             bool ok = false;
       
   220             newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
       
   221             if (!ok)
       
   222                 newFreetype->fontData = QByteArray();
       
   223         } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
       
   224             if (!file.open(QIODevice::ReadOnly)) {
       
   225                 return 0;
       
   226             }
       
   227             newFreetype->fontData = file.readAll();
       
   228         }
       
   229         if (!newFreetype->fontData.isEmpty()) {
       
   230             if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
       
   231                 return 0;
       
   232             }
       
   233         } else if (FT_New_Face(freetypeData->library, face_id.filename, face_id.index, &face)) {
       
   234             return 0;
       
   235         }
       
   236         newFreetype->face = face;
       
   237 
       
   238         newFreetype->hbFace = qHBNewFace(face, hb_getSFntTable);
       
   239         Q_CHECK_PTR(newFreetype->hbFace);
       
   240         newFreetype->ref = 1;
       
   241         newFreetype->xsize = 0;
       
   242         newFreetype->ysize = 0;
       
   243         newFreetype->matrix.xx = 0x10000;
       
   244         newFreetype->matrix.yy = 0x10000;
       
   245         newFreetype->matrix.xy = 0;
       
   246         newFreetype->matrix.yx = 0;
       
   247         newFreetype->unicode_map = 0;
       
   248         newFreetype->symbol_map = 0;
       
   249 #ifndef QT_NO_FONTCONFIG
       
   250         newFreetype->charset = 0;
       
   251 #endif
       
   252 
       
   253         memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
       
   254 
       
   255         for (int i = 0; i < newFreetype->face->num_charmaps; ++i) {
       
   256             FT_CharMap cm = newFreetype->face->charmaps[i];
       
   257             switch(cm->encoding) {
       
   258             case FT_ENCODING_UNICODE:
       
   259                 newFreetype->unicode_map = cm;
       
   260                 break;
       
   261             case FT_ENCODING_APPLE_ROMAN:
       
   262             case FT_ENCODING_ADOBE_LATIN_1:
       
   263                 if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
       
   264                     newFreetype->unicode_map = cm;
       
   265                 break;
       
   266             case FT_ENCODING_ADOBE_CUSTOM:
       
   267             case FT_ENCODING_MS_SYMBOL:
       
   268                 if (!newFreetype->symbol_map)
       
   269                     newFreetype->symbol_map = cm;
       
   270                 break;
       
   271             default:
       
   272                 break;
       
   273             }
       
   274         }
       
   275 
       
   276         if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
       
   277             FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0);
       
   278 # if 0
       
   279         FcChar8 *name;
       
   280         FcPatternGetString(pattern, FC_FAMILY, 0, &name);
       
   281         qDebug("%s: using maps: default: %x unicode: %x, symbol: %x", name,
       
   282                newFreetype->face->charmap ? newFreetype->face->charmap->encoding : 0,
       
   283                newFreetype->unicode_map ? newFreetype->unicode_map->encoding : 0,
       
   284                newFreetype->symbol_map ? newFreetype->symbol_map->encoding : 0);
       
   285 
       
   286         for (int i = 0; i < 256; i += 8)
       
   287             qDebug("    %x: %d %d %d %d %d %d %d %d", i,
       
   288                    FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
       
   289                    FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
       
   290                    FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
       
   291                    FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i));
       
   292 #endif
       
   293 
       
   294         FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
       
   295         QT_TRY {
       
   296             freetypeData->faces.insert(face_id, newFreetype.data());
       
   297         } QT_CATCH(...) {
       
   298             newFreetype.take()->release(face_id);
       
   299             // we could return null in principle instead of throwing
       
   300             QT_RETHROW;
       
   301         }
       
   302         freetype = newFreetype.take();
       
   303     }
       
   304     return freetype;
       
   305 }
       
   306 
       
   307 void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
       
   308 {
       
   309     QtFreetypeData *freetypeData = qt_getFreetypeData();
       
   310     if (!ref.deref()) {
       
   311         qHBFreeFace(hbFace);
       
   312         FT_Done_Face(face);
       
   313 #ifndef QT_NO_FONTCONFIG
       
   314         if (charset)
       
   315             FcCharSetDestroy(charset);
       
   316 #endif
       
   317         if(freetypeData->faces.contains(face_id))
       
   318             freetypeData->faces.take(face_id);
       
   319         delete this;
       
   320     }
       
   321     if (freetypeData->faces.isEmpty()) {
       
   322         FT_Done_FreeType(freetypeData->library);
       
   323         freetypeData->library = 0;
       
   324     }
       
   325 }
       
   326 
       
   327 
       
   328 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
       
   329 {
       
   330     *ysize = qRound(fontDef.pixelSize * 64);
       
   331     *xsize = *ysize * fontDef.stretch / 100;
       
   332     *outline_drawing = false;
       
   333 
       
   334     /*
       
   335      * Bitmap only faces must match exactly, so find the closest
       
   336      * one (height dominant search)
       
   337      */
       
   338     if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
       
   339         int best = 0;
       
   340         for (int i = 1; i < face->num_fixed_sizes; i++) {
       
   341             if (qAbs(*ysize -  Y_SIZE(face,i)) <
       
   342                 qAbs (*ysize - Y_SIZE(face, best)) ||
       
   343                 (qAbs (*ysize - Y_SIZE(face, i)) ==
       
   344                  qAbs (*ysize - Y_SIZE(face, best)) &&
       
   345                  qAbs (*xsize - X_SIZE(face, i)) <
       
   346                  qAbs (*xsize - X_SIZE(face, best)))) {
       
   347                 best = i;
       
   348             }
       
   349         }
       
   350         if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
       
   351             *xsize = X_SIZE(face, best);
       
   352             *ysize = Y_SIZE(face, best);
       
   353         } else {
       
   354             int err = 1;
       
   355             if (!(face->face_flags & FT_FACE_FLAG_SCALABLE) && ysize == 0 && face->num_fixed_sizes >= 1) {
       
   356                 // work around FT 2.1.10 problem with BDF without PIXEL_SIZE property
       
   357                 err = FT_Set_Pixel_Sizes(face, face->available_sizes[0].width, face->available_sizes[0].height);
       
   358                 if (err && face->num_fixed_sizes == 1)
       
   359                     err = 0; //even more of a workaround...
       
   360             }
       
   361 
       
   362             if (err)
       
   363                 *xsize = *ysize = 0;
       
   364         }
       
   365     } else {
       
   366         *outline_drawing = (*xsize > (64<<6) || *ysize > (64<<6));
       
   367     }
       
   368 }
       
   369 
       
   370 QFontEngine::Properties QFreetypeFace::properties() const
       
   371 {
       
   372     QFontEngine::Properties p;
       
   373     p.postscriptName = FT_Get_Postscript_Name(face);
       
   374     PS_FontInfoRec font_info;
       
   375     if (FT_Get_PS_Font_Info(face, &font_info) == 0)
       
   376         p.copyright = font_info.notice;
       
   377     if (FT_IS_SCALABLE(face)) {
       
   378         p.ascent = face->ascender;
       
   379         p.descent = -face->descender;
       
   380         p.leading = face->height - face->ascender + face->descender;
       
   381         p.emSquare = face->units_per_EM;
       
   382         p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
       
   383                                face->bbox.xMax - face->bbox.xMin,
       
   384                                face->bbox.yMax - face->bbox.yMin);
       
   385     } else {
       
   386         p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
       
   387         p.descent = QFixed::fromFixed(-face->size->metrics.descender);
       
   388         p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
       
   389         p.emSquare = face->size->metrics.y_ppem;
       
   390 //        p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
       
   391         p.boundingBox = QRectF(0, -p.ascent.toReal(),
       
   392                                face->size->metrics.max_advance/64, (p.ascent + p.descent).toReal() );
       
   393     }
       
   394     p.italicAngle = 0;
       
   395     p.capHeight = p.ascent;
       
   396     p.lineWidth = face->underline_thickness;
       
   397     return p;
       
   398 }
       
   399 
       
   400 bool QFreetypeFace::getSfntTable(uint tag, uchar *buffer, uint *length) const
       
   401 {
       
   402     bool result = false;
       
   403 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
       
   404     if (FT_IS_SFNT(face)) {
       
   405         FT_ULong len = *length;
       
   406         result = FT_Load_Sfnt_Table(face, tag, 0, buffer, &len) == FT_Err_Ok;
       
   407         *length = len;
       
   408     }
       
   409 #endif
       
   410     return result;
       
   411 }
       
   412 
       
   413 /* Some fonts (such as MingLiu rely on hinting to scale different
       
   414    components to their correct sizes. While this is really broken (it
       
   415    should be done in the component glyph itself, not the hinter) we
       
   416    will have to live with it.
       
   417 
       
   418    This means we can not use FT_LOAD_NO_HINTING to get the glyph
       
   419    outline. All we can do is to load the unscaled glyph and scale it
       
   420    down manually when required.
       
   421 */
       
   422 static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
       
   423 {
       
   424     x_scale = FT_MulDiv(x_scale, 1 << 10, face->units_per_EM);
       
   425     y_scale = FT_MulDiv(y_scale, 1 << 10, face->units_per_EM);
       
   426     FT_Vector *p = g->outline.points;
       
   427     const FT_Vector *e = p + g->outline.n_points;
       
   428     while (p < e) {
       
   429         p->x = FT_MulFix(p->x, x_scale);
       
   430         p->y = FT_MulFix(p->y, y_scale);
       
   431         ++p;
       
   432     }
       
   433 }
       
   434 
       
   435 void QFreetypeFace::addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
       
   436 {
       
   437     const qreal factor = 1/64.;
       
   438     scaleOutline(face, g, x_scale, y_scale);
       
   439 
       
   440     QPointF cp = point.toPointF();
       
   441 
       
   442     // convert the outline to a painter path
       
   443     int i = 0;
       
   444     for (int j = 0; j < g->outline.n_contours; ++j) {
       
   445         int last_point = g->outline.contours[j];
       
   446         QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
       
   447         if(!(g->outline.tags[i] & 1)) {
       
   448             start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor);
       
   449             start /= 2;
       
   450         }
       
   451 //         qDebug("contour: %d -- %d", i, g->outline.contours[j]);
       
   452 //         qDebug("first point at %f %f", start.x(), start.y());
       
   453         path->moveTo(start);
       
   454 
       
   455         QPointF c[4];
       
   456         c[0] = start;
       
   457         int n = 1;
       
   458         while (i < last_point) {
       
   459             ++i;
       
   460             c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
       
   461 //             qDebug() << "    i=" << i << " flag=" << (int)g->outline.tags[i] << "point=" << c[n];
       
   462             ++n;
       
   463             switch (g->outline.tags[i] & 3) {
       
   464             case 2:
       
   465                 // cubic bezier element
       
   466                 if (n < 4)
       
   467                     continue;
       
   468                 c[3] = (c[3] + c[2])/2;
       
   469                 --i;
       
   470                 break;
       
   471             case 0:
       
   472                 // quadratic bezier element
       
   473                 if (n < 3)
       
   474                     continue;
       
   475                 c[3] = (c[1] + c[2])/2;
       
   476                 c[2] = (2*c[1] + c[3])/3;
       
   477                 c[1] = (2*c[1] + c[0])/3;
       
   478                 --i;
       
   479                 break;
       
   480             case 1:
       
   481             case 3:
       
   482                 if (n == 2) {
       
   483 //                     qDebug() << "lineTo" << c[1];
       
   484                     path->lineTo(c[1]);
       
   485                     c[0] = c[1];
       
   486                     n = 1;
       
   487                     continue;
       
   488                 } else if (n == 3) {
       
   489                     c[3] = c[2];
       
   490                     c[2] = (2*c[1] + c[3])/3;
       
   491                     c[1] = (2*c[1] + c[0])/3;
       
   492                 }
       
   493                 break;
       
   494             }
       
   495 //             qDebug() << "cubicTo" << c[1] << c[2] << c[3];
       
   496             path->cubicTo(c[1], c[2], c[3]);
       
   497             c[0] = c[3];
       
   498             n = 1;
       
   499         }
       
   500         if (n == 1) {
       
   501 //             qDebug() << "closeSubpath";
       
   502             path->closeSubpath();
       
   503         } else {
       
   504             c[3] = start;
       
   505             if (n == 2) {
       
   506                 c[2] = (2*c[1] + c[3])/3;
       
   507                 c[1] = (2*c[1] + c[0])/3;
       
   508             }
       
   509 //             qDebug() << "cubicTo" << c[1] << c[2] << c[3];
       
   510             path->cubicTo(c[1], c[2], c[3]);
       
   511         }
       
   512         ++i;
       
   513     }
       
   514 }
       
   515 
       
   516 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
       
   517 
       
   518 void QFreetypeFace::addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool)
       
   519 {
       
   520     if (slot->format != FT_GLYPH_FORMAT_BITMAP
       
   521         || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
       
   522         return;
       
   523 
       
   524     QPointF cp = point.toPointF();
       
   525     qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
       
   526                        slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
       
   527 }
       
   528 
       
   529 QFontEngineFT::Glyph::~Glyph()
       
   530 {
       
   531     delete [] data;
       
   532 }
       
   533 
       
   534 static const uint subpixel_filter[3][3] = {
       
   535     { 180, 60, 16 },
       
   536     { 38, 180, 38 },
       
   537     { 16, 60, 180 }
       
   538 };
       
   539 
       
   540 static inline uint filterPixel(uint red, uint green, uint blue, bool legacyFilter)
       
   541 {
       
   542     uint res;
       
   543     if (legacyFilter) {
       
   544         uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
       
   545         uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
       
   546         uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
       
   547         res = (mid << 24) + (high << 16) + (mid << 8) + low;
       
   548     } else {
       
   549         uint alpha = green;
       
   550         res = (alpha << 24) + (red << 16) + (green << 8) + blue;
       
   551     }
       
   552     return res;
       
   553 }
       
   554 
       
   555 static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
       
   556 {
       
   557     int h = height;
       
   558     const int offs = bgr ? -1 : 1;
       
   559     const int w = width * 3;
       
   560     while (h--) {
       
   561         uint *dd = dst;
       
   562         for (int x = 0; x < w; x += 3) {
       
   563             uint red = src[x+1-offs];
       
   564             uint green = src[x+1];
       
   565             uint blue = src[x+1+offs];
       
   566             *dd = filterPixel(red, green, blue, legacyFilter);
       
   567             ++dd;
       
   568         }
       
   569         dst += width;
       
   570         src += src_pitch;
       
   571     }
       
   572 }
       
   573 
       
   574 static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
       
   575 {
       
   576     int h = height;
       
   577     const int offs = bgr ? -src_pitch : src_pitch;
       
   578     while (h--) {
       
   579         for (int x = 0; x < width; x++) {
       
   580             uint red = src[x+src_pitch-offs];
       
   581             uint green = src[x+src_pitch];
       
   582             uint blue = src[x+src_pitch+offs];
       
   583             dst[x] = filterPixel(red, green, blue, legacyFilter);
       
   584         }
       
   585         dst += width;
       
   586         src += 3*src_pitch;
       
   587     }
       
   588 }
       
   589 
       
   590 static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
       
   591 {
       
   592     // convolute the bitmap with a triangle filter to get rid of color fringes
       
   593     // If we take account for a gamma value of 2, we end up with
       
   594     // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
       
   595     // as this nicely sums up to 16 :)
       
   596     int h = height;
       
   597     while (h--) {
       
   598         dst[0] = dst[1] = 0;
       
   599         //
       
   600         for (int x = 2; x < width - 2; ++x) {
       
   601             uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
       
   602             dst[x] = (uchar) (sum >> 4);
       
   603         }
       
   604         dst[width - 2] = dst[width - 1] = 0;
       
   605         src += pitch;
       
   606         dst += pitch;
       
   607     }
       
   608 }
       
   609 
       
   610 QFontEngineFT::QFontEngineFT(const QFontDef &fd)
       
   611 {
       
   612     fontDef = fd;
       
   613     matrix.xx = 0x10000;
       
   614     matrix.yy = 0x10000;
       
   615     matrix.xy = 0;
       
   616     matrix.yx = 0;
       
   617     cache_cost = 100;
       
   618     kerning_pairs_loaded = false;
       
   619     transform = false;
       
   620     antialias = true;
       
   621     freetype = 0;
       
   622     default_load_flags = 0;
       
   623     default_hint_style = HintNone;
       
   624     subpixelType = Subpixel_None;
       
   625     lcdFilterType = 0;
       
   626 #if defined(FT_LCD_FILTER_H)
       
   627     lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
       
   628 #endif
       
   629     defaultFormat = Format_None;
       
   630     canUploadGlyphsToServer = false;
       
   631     embeddedbitmap = false;
       
   632 }
       
   633 
       
   634 QFontEngineFT::~QFontEngineFT()
       
   635 {
       
   636     if (freetype)
       
   637         freetype->release(face_id);
       
   638     hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
       
   639 }
       
   640 
       
   641 void QFontEngineFT::freeGlyphSets()
       
   642 {
       
   643     freeServerGlyphSet(defaultGlyphSet.id);
       
   644     for (int i = 0; i < transformedGlyphSets.count(); ++i)
       
   645         freeServerGlyphSet(transformedGlyphSets.at(i).id);
       
   646 }
       
   647 
       
   648 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format)
       
   649 {
       
   650     defaultFormat = format;
       
   651     this->antialias = antialias;
       
   652 
       
   653     if (!antialias)
       
   654         glyphFormat = QFontEngineGlyphCache::Raster_Mono;
       
   655     else if (format == Format_A8)
       
   656         glyphFormat = QFontEngineGlyphCache::Raster_A8;
       
   657     else if (format == Format_A32)
       
   658         glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
       
   659 
       
   660     face_id = faceId;
       
   661     freetype = QFreetypeFace::getFace(face_id);
       
   662     if (!freetype) {
       
   663         xsize = 0;
       
   664         ysize = 0;
       
   665         return false;
       
   666     }
       
   667 
       
   668     symbol = freetype->symbol_map != 0;
       
   669     PS_FontInfoRec psrec;
       
   670     // don't assume that type1 fonts are symbol fonts by default
       
   671     if (FT_Get_PS_Font_Info(freetype->face, &psrec) == FT_Err_Ok) {
       
   672         symbol = bool(fontDef.family.contains(QLatin1String("symbol"), Qt::CaseInsensitive));
       
   673     }
       
   674     // #####
       
   675     freetype->hbFace->isSymbolFont = symbol;
       
   676 
       
   677     lbearing = rbearing = SHRT_MIN;
       
   678     freetype->computeSize(fontDef, &xsize, &ysize, &defaultGlyphSet.outline_drawing);
       
   679 
       
   680     FT_Face face = lockFace();
       
   681 
       
   682     //underline metrics
       
   683     if (FT_IS_SCALABLE(face)) {
       
   684         line_thickness =  QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
       
   685         underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
       
   686         bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
       
   687         if (fake_oblique)
       
   688             matrix.xy = 0x10000*3/10;
       
   689         FT_Set_Transform(face, &matrix, 0);
       
   690         freetype->matrix = matrix;
       
   691         if (fake_oblique)
       
   692             transform = true;
       
   693     } else {
       
   694         // copied from QFontEngineQPF
       
   695         // ad hoc algorithm
       
   696         int score = fontDef.weight * fontDef.pixelSize;
       
   697         line_thickness = score / 700;
       
   698         // looks better with thicker line for small pointsizes
       
   699         if (line_thickness < 2 && score >= 1050)
       
   700             line_thickness = 2;
       
   701         underline_position =  ((line_thickness * 2) + 3) / 6;
       
   702     }
       
   703     if (line_thickness < 1)
       
   704         line_thickness = 1;
       
   705 
       
   706     hbFont.x_ppem  = face->size->metrics.x_ppem;
       
   707     hbFont.y_ppem  = face->size->metrics.y_ppem;
       
   708     hbFont.x_scale = face->size->metrics.x_scale;
       
   709     hbFont.y_scale = face->size->metrics.y_scale;
       
   710 
       
   711     hbFace = freetype->hbFace;
       
   712 
       
   713     metrics = face->size->metrics;
       
   714 
       
   715 #if defined(Q_WS_QWS)
       
   716     /*
       
   717        TrueType fonts with embedded bitmaps may have a bitmap font specific
       
   718        ascent/descent in the EBLC table. There is no direct public API
       
   719        to extract those values. The only way we've found is to trick freetype
       
   720        into thinking that it's not a scalable font in FT_SelectSize so that
       
   721        the metrics are retrieved from the bitmap strikes.
       
   722     */
       
   723     if (FT_IS_SCALABLE(face)) {
       
   724         for (int i = 0; i < face->num_fixed_sizes; ++i) {
       
   725             if (xsize == X_SIZE(face, i) && ysize == Y_SIZE(face, i)) {
       
   726                 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
       
   727 
       
   728                 FT_Select_Size(face, i);
       
   729                 metrics.ascender = face->size->metrics.ascender;
       
   730                 metrics.descender = face->size->metrics.descender;
       
   731                 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
       
   732 
       
   733                 face->face_flags |= FT_FACE_FLAG_SCALABLE;
       
   734                 break;
       
   735             }
       
   736         }
       
   737     }
       
   738 #endif
       
   739 
       
   740     unlockFace();
       
   741 
       
   742     fsType = freetype->fsType();
       
   743     defaultGlyphSet.id = allocateServerGlyphSet();
       
   744     return true;
       
   745 }
       
   746 
       
   747 QFontEngineFT::Glyph *QFontEngineFT::loadGlyphMetrics(QGlyphSet *set, uint glyph) const
       
   748 {
       
   749     Glyph *g = set->glyph_data.value(glyph);
       
   750     if (g)
       
   751         return g;
       
   752 
       
   753     int load_flags = FT_LOAD_DEFAULT | default_load_flags;
       
   754     if (set->outline_drawing)
       
   755         load_flags = FT_LOAD_NO_BITMAP;
       
   756 
       
   757     // apply our matrix to this, but note that the metrics will not be affected by this.
       
   758     FT_Face face = lockFace();
       
   759     FT_Matrix matrix = this->matrix;
       
   760     FT_Matrix_Multiply(&set->transformationMatrix, &matrix);
       
   761     FT_Set_Transform(face, &matrix, 0);
       
   762     freetype->matrix = matrix;
       
   763 
       
   764     bool transform = matrix.xx != 0x10000 || matrix.yy != 0x10000 || matrix.xy != 0 || matrix.yx != 0;
       
   765     if (transform)
       
   766         load_flags |= FT_LOAD_NO_BITMAP;
       
   767 
       
   768     FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
       
   769     if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
       
   770         load_flags &= ~FT_LOAD_NO_BITMAP;
       
   771         err = FT_Load_Glyph(face, glyph, load_flags);
       
   772     }
       
   773     if (err == FT_Err_Too_Few_Arguments) {
       
   774         // this is an error in the bytecode interpreter, just try to run without it
       
   775         load_flags |= FT_LOAD_FORCE_AUTOHINT;
       
   776         err = FT_Load_Glyph(face, glyph, load_flags);
       
   777     }
       
   778     if (err != FT_Err_Ok)
       
   779         qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
       
   780 
       
   781     unlockFace();
       
   782     if (set->outline_drawing)
       
   783         return 0;
       
   784 
       
   785     if (!g) {
       
   786         g = new Glyph;
       
   787         g->uploadedToServer = false;
       
   788         g->data = 0;
       
   789     }
       
   790 
       
   791     FT_GlyphSlot slot = face->glyph;
       
   792     int left  = slot->metrics.horiBearingX;
       
   793     int right = slot->metrics.horiBearingX + slot->metrics.width;
       
   794     int top    = slot->metrics.horiBearingY;
       
   795     int bottom = slot->metrics.horiBearingY - slot->metrics.height;
       
   796     if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) { // freetype doesn't apply the transformation on the metrics
       
   797         int l, r, t, b;
       
   798         FT_Vector vector;
       
   799         vector.x = left;
       
   800         vector.y = top;
       
   801         FT_Vector_Transform(&vector, &matrix);
       
   802         l = r = vector.x;
       
   803         t = b = vector.y;
       
   804         vector.x = right;
       
   805         vector.y = top;
       
   806         FT_Vector_Transform(&vector, &matrix);
       
   807         if (l > vector.x) l = vector.x;
       
   808         if (r < vector.x) r = vector.x;
       
   809         if (t < vector.y) t = vector.y;
       
   810         if (b > vector.y) b = vector.y;
       
   811         vector.x = right;
       
   812         vector.y = bottom;
       
   813         FT_Vector_Transform(&vector, &matrix);
       
   814         if (l > vector.x) l = vector.x;
       
   815         if (r < vector.x) r = vector.x;
       
   816         if (t < vector.y) t = vector.y;
       
   817         if (b > vector.y) b = vector.y;
       
   818         vector.x = left;
       
   819         vector.y = bottom;
       
   820         FT_Vector_Transform(&vector, &matrix);
       
   821         if (l > vector.x) l = vector.x;
       
   822         if (r < vector.x) r = vector.x;
       
   823         if (t < vector.y) t = vector.y;
       
   824         if (b > vector.y) b = vector.y;
       
   825         left = l;
       
   826         right = r;
       
   827         top = t;
       
   828         bottom = b;
       
   829     }
       
   830     left = FLOOR(left);
       
   831     right = CEIL(right);
       
   832     bottom = FLOOR(bottom);
       
   833     top = CEIL(top);
       
   834 
       
   835     g->linearAdvance = face->glyph->linearHoriAdvance >> 10;
       
   836     g->width = TRUNC(right-left);
       
   837     g->height = TRUNC(top-bottom);
       
   838     g->x = TRUNC(left);
       
   839     g->y = TRUNC(top);
       
   840     g->advance = TRUNC(ROUND(face->glyph->advance.x));
       
   841     g->format = Format_None;
       
   842 
       
   843     return g;
       
   844 }
       
   845 
       
   846 QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, GlyphFormat format, bool fetchMetricsOnly) const
       
   847 {
       
   848 //     Q_ASSERT(freetype->lock == 1);
       
   849 
       
   850     bool uploadToServer = false;
       
   851     if (format == Format_None) {
       
   852         if (defaultFormat != Format_None) {
       
   853             format = defaultFormat;
       
   854             if (canUploadGlyphsToServer)
       
   855                 uploadToServer = true;
       
   856         } else {
       
   857             format = Format_Mono;
       
   858         }
       
   859     }
       
   860 
       
   861     Glyph *g = set->glyph_data.value(glyph);
       
   862     if (g && g->format == format) {
       
   863         if (uploadToServer && !g->uploadedToServer) {
       
   864             set->glyph_data[glyph] = 0;
       
   865             delete g;
       
   866             g = 0;
       
   867         } else {
       
   868             return g;
       
   869         }
       
   870     }
       
   871 
       
   872     QFontEngineFT::GlyphInfo info;
       
   873 
       
   874     Q_ASSERT(format != Format_None);
       
   875     bool hsubpixel = false;
       
   876     int vfactor = 1;
       
   877     int load_flags = FT_LOAD_DEFAULT | default_load_flags;
       
   878 
       
   879     int load_target = default_hint_style == HintLight
       
   880                       ? FT_LOAD_TARGET_LIGHT
       
   881                       : FT_LOAD_TARGET_NORMAL;
       
   882 
       
   883     if (set->outline_drawing)
       
   884         load_flags |= FT_LOAD_NO_BITMAP;
       
   885 
       
   886     if (format == Format_Mono) {
       
   887         load_target = FT_LOAD_TARGET_MONO;
       
   888     } else if (format == Format_A32) {
       
   889         if (subpixelType == QFontEngineFT::Subpixel_RGB || subpixelType == QFontEngineFT::Subpixel_BGR) {
       
   890             if (default_hint_style == HintFull)
       
   891                 load_target = FT_LOAD_TARGET_LCD;
       
   892             hsubpixel = true;
       
   893         } else if (subpixelType == QFontEngineFT::Subpixel_VRGB || subpixelType == QFontEngineFT::Subpixel_VBGR) {
       
   894             if (default_hint_style == HintFull)
       
   895                 load_target = FT_LOAD_TARGET_LCD_V;
       
   896             vfactor = 3;
       
   897         }
       
   898     }
       
   899 
       
   900     if (default_hint_style == HintNone)
       
   901         load_flags |= FT_LOAD_NO_HINTING;
       
   902     else
       
   903         load_flags |= load_target;
       
   904 
       
   905 #ifndef Q_WS_QWS
       
   906     if (format != Format_Mono && !embeddedbitmap)
       
   907         load_flags |= FT_LOAD_NO_BITMAP;
       
   908 #endif
       
   909 
       
   910     FT_Matrix matrix = freetype->matrix;
       
   911     bool transform = matrix.xx != 0x10000
       
   912                      || matrix.yy != 0x10000
       
   913                      || matrix.xy != 0
       
   914                      || matrix.yx != 0;
       
   915 
       
   916     if (transform)
       
   917         load_flags |= FT_LOAD_NO_BITMAP;
       
   918 
       
   919     FT_Face face = freetype->face;
       
   920     FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
       
   921     if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
       
   922         load_flags &= ~FT_LOAD_NO_BITMAP;
       
   923         err = FT_Load_Glyph(face, glyph, load_flags);
       
   924     }
       
   925     if (err == FT_Err_Too_Few_Arguments) {
       
   926         // this is an error in the bytecode interpreter, just try to run without it
       
   927         load_flags |= FT_LOAD_FORCE_AUTOHINT;
       
   928         err = FT_Load_Glyph(face, glyph, load_flags);
       
   929     }
       
   930     if (err != FT_Err_Ok)
       
   931         qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
       
   932 
       
   933     if (set->outline_drawing && fetchMetricsOnly)
       
   934         return 0;
       
   935 
       
   936     FT_GlyphSlot slot = face->glyph;
       
   937     FT_Library library = qt_getFreetype();
       
   938 
       
   939     info.xOff = TRUNC(ROUND(slot->advance.x));
       
   940     info.yOff = 0;
       
   941 
       
   942     uchar *glyph_buffer = 0;
       
   943     int glyph_buffer_size = 0;
       
   944 #if defined(QT_USE_FREETYPE_LCDFILTER)
       
   945     bool useFreetypeRenderGlyph = false;
       
   946     if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
       
   947         err = FT_Library_SetLcdFilter(library, (FT_LcdFilter)lcdFilterType);
       
   948         if (err == FT_Err_Ok)
       
   949             useFreetypeRenderGlyph = true;
       
   950     }
       
   951 
       
   952     if (useFreetypeRenderGlyph) {
       
   953         err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
       
   954 
       
   955         if (err != FT_Err_Ok)
       
   956             qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
       
   957 
       
   958         FT_Library_SetLcdFilter(library, FT_LCD_FILTER_NONE);
       
   959 
       
   960         info.height = slot->bitmap.rows / vfactor;
       
   961         info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
       
   962         info.x = -slot->bitmap_left;
       
   963         info.y = slot->bitmap_top;
       
   964 
       
   965         glyph_buffer_size = info.width * info.height * 4;
       
   966         glyph_buffer = new uchar[glyph_buffer_size];
       
   967 
       
   968         if (hsubpixel)
       
   969             convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, false);
       
   970         else if (vfactor != 1)
       
   971             convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, slot->bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, false);
       
   972     } else
       
   973 #endif
       
   974     {
       
   975     int left  = slot->metrics.horiBearingX;
       
   976     int right = slot->metrics.horiBearingX + slot->metrics.width;
       
   977     int top    = slot->metrics.horiBearingY;
       
   978     int bottom = slot->metrics.horiBearingY - slot->metrics.height;
       
   979     if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
       
   980         int l, r, t, b;
       
   981         FT_Vector vector;
       
   982         vector.x = left;
       
   983         vector.y = top;
       
   984         FT_Vector_Transform(&vector, &matrix);
       
   985         l = r = vector.x;
       
   986         t = b = vector.y;
       
   987         vector.x = right;
       
   988         vector.y = top;
       
   989         FT_Vector_Transform(&vector, &matrix);
       
   990         if (l > vector.x) l = vector.x;
       
   991         if (r < vector.x) r = vector.x;
       
   992         if (t < vector.y) t = vector.y;
       
   993         if (b > vector.y) b = vector.y;
       
   994         vector.x = right;
       
   995         vector.y = bottom;
       
   996         FT_Vector_Transform(&vector, &matrix);
       
   997         if (l > vector.x) l = vector.x;
       
   998         if (r < vector.x) r = vector.x;
       
   999         if (t < vector.y) t = vector.y;
       
  1000         if (b > vector.y) b = vector.y;
       
  1001         vector.x = left;
       
  1002         vector.y = bottom;
       
  1003         FT_Vector_Transform(&vector, &matrix);
       
  1004         if (l > vector.x) l = vector.x;
       
  1005         if (r < vector.x) r = vector.x;
       
  1006         if (t < vector.y) t = vector.y;
       
  1007         if (b > vector.y) b = vector.y;
       
  1008         left = l;
       
  1009         right = r;
       
  1010         top = t;
       
  1011         bottom = b;
       
  1012     }
       
  1013     left = FLOOR(left);
       
  1014     right = CEIL(right);
       
  1015     bottom = FLOOR(bottom);
       
  1016     top = CEIL(top);
       
  1017 
       
  1018     int hpixels = TRUNC(right - left);
       
  1019     if (hsubpixel)
       
  1020         hpixels = hpixels*3 + 8;
       
  1021     info.width = hpixels;
       
  1022     info.height = TRUNC(top - bottom);
       
  1023     info.x = -TRUNC(left);
       
  1024     info.y = TRUNC(top);
       
  1025     if (hsubpixel) {
       
  1026         info.width /= 3;
       
  1027         info.x += 1;
       
  1028     }
       
  1029 
       
  1030     bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
       
  1031                         || ((uchar)(info.width) != info.width)
       
  1032                         || ((uchar)(info.height) != info.height)
       
  1033                         || ((signed char)(info.x) != info.x)
       
  1034                         || ((signed char)(info.y) != info.y)
       
  1035                         || ((signed char)(info.xOff) != info.xOff));
       
  1036 
       
  1037     if (large_glyph) {
       
  1038         delete [] glyph_buffer;
       
  1039         return 0;
       
  1040     }
       
  1041 
       
  1042     int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
       
  1043                  (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
       
  1044     glyph_buffer_size = pitch * info.height;
       
  1045     glyph_buffer = new uchar[glyph_buffer_size];
       
  1046 
       
  1047     if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
       
  1048         FT_Bitmap bitmap;
       
  1049         bitmap.rows = info.height*vfactor;
       
  1050         bitmap.width = hpixels;
       
  1051         bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
       
  1052         if (!hsubpixel && vfactor == 1)
       
  1053             bitmap.buffer = glyph_buffer;
       
  1054         else
       
  1055             bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
       
  1056         memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
       
  1057         bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
       
  1058         FT_Matrix matrix;
       
  1059         matrix.xx = (hsubpixel ? 3 : 1) << 16;
       
  1060         matrix.yy = vfactor << 16;
       
  1061         matrix.yx = matrix.xy = 0;
       
  1062 
       
  1063         FT_Outline_Transform(&slot->outline, &matrix);
       
  1064         FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
       
  1065         FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
       
  1066         if (hsubpixel) {
       
  1067             Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
       
  1068             Q_ASSERT(antialias);
       
  1069             uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
       
  1070             bool useLegacyLcdFilter = false;
       
  1071 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
       
  1072             useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
       
  1073 #endif
       
  1074             uchar *buffer = bitmap.buffer;
       
  1075             if (!useLegacyLcdFilter) {
       
  1076                 convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
       
  1077                 buffer = convoluted;
       
  1078             }
       
  1079             convertRGBToARGB(buffer + 1, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_RGB, useLegacyLcdFilter);
       
  1080             delete [] convoluted;
       
  1081         } else if (vfactor != 1) {
       
  1082             convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer, info.width, info.height, bitmap.pitch, subpixelType != QFontEngineFT::Subpixel_VRGB, true);
       
  1083         }
       
  1084 
       
  1085         if (bitmap.buffer != glyph_buffer)
       
  1086             delete [] bitmap.buffer;
       
  1087     } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
       
  1088         Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
       
  1089         uchar *src = slot->bitmap.buffer;
       
  1090         uchar *dst = glyph_buffer;
       
  1091         int h = slot->bitmap.rows;
       
  1092         if (format == Format_Mono) {
       
  1093             int bytes = ((info.width + 7) & ~7) >> 3;
       
  1094             while (h--) {
       
  1095                 memcpy (dst, src, bytes);
       
  1096                 dst += pitch;
       
  1097                 src += slot->bitmap.pitch;
       
  1098             }
       
  1099         } else {
       
  1100             if (hsubpixel) {
       
  1101                 while (h--) {
       
  1102                     uint *dd = (uint *)dst;
       
  1103                     *dd++ = 0;
       
  1104                     for (int x = 0; x < slot->bitmap.width; x++) {
       
  1105                         uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
       
  1106                         *dd++ = a;
       
  1107                     }
       
  1108                     *dd++ = 0;
       
  1109                     dst += pitch;
       
  1110                     src += slot->bitmap.pitch;
       
  1111                 }
       
  1112             } else if (vfactor != 1) {
       
  1113                 while (h--) {
       
  1114                     uint *dd = (uint *)dst;
       
  1115                     for (int x = 0; x < slot->bitmap.width; x++) {
       
  1116                         uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
       
  1117                         *dd++ = a;
       
  1118                     }
       
  1119                     dst += pitch;
       
  1120                     src += slot->bitmap.pitch;
       
  1121                 }
       
  1122             } else {
       
  1123                 while (h--) {
       
  1124                     for (int x = 0; x < slot->bitmap.width; x++) {
       
  1125                         unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
       
  1126                         dst[x] = a;
       
  1127                     }
       
  1128                     dst += pitch;
       
  1129                     src += slot->bitmap.pitch;
       
  1130                 }
       
  1131             }
       
  1132         }
       
  1133     } else {
       
  1134         qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
       
  1135         delete [] glyph_buffer;
       
  1136         return 0;
       
  1137     }
       
  1138     }
       
  1139 
       
  1140 
       
  1141     if (!g) {
       
  1142         g = new Glyph;
       
  1143         g->uploadedToServer = false;
       
  1144         g->data = 0;
       
  1145     }
       
  1146 
       
  1147     g->linearAdvance = slot->linearHoriAdvance >> 10;
       
  1148     g->width = info.width;
       
  1149     g->height = info.height;
       
  1150     g->x = -info.x;
       
  1151     g->y = info.y;
       
  1152     g->advance = info.xOff;
       
  1153     g->format = format;
       
  1154     delete [] g->data;
       
  1155     g->data = glyph_buffer;
       
  1156 
       
  1157     if (uploadToServer) {
       
  1158         uploadGlyphToServer(set, glyph, g, &info, glyph_buffer_size);
       
  1159     }
       
  1160 
       
  1161     set->glyph_data[glyph] = g;
       
  1162 
       
  1163     return g;
       
  1164 }
       
  1165 
       
  1166 bool QFontEngineFT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
       
  1167 {
       
  1168     Q_UNUSED(set);
       
  1169     Q_UNUSED(glyphid);
       
  1170     Q_UNUSED(g);
       
  1171     Q_UNUSED(info);
       
  1172     Q_UNUSED(glyphDataSize);
       
  1173     return false;
       
  1174 }
       
  1175 
       
  1176 QFontEngine::FaceId QFontEngineFT::faceId() const
       
  1177 {
       
  1178     return face_id;
       
  1179 }
       
  1180 
       
  1181 QFontEngine::Properties QFontEngineFT::properties() const
       
  1182 {
       
  1183     Properties p = freetype->properties();
       
  1184     if (p.postscriptName.isEmpty()) {
       
  1185         p.postscriptName = fontDef.family.toUtf8();
       
  1186 #ifndef QT_NO_PRINTER
       
  1187         p.postscriptName = QPdf::stripSpecialCharacters(p.postscriptName);
       
  1188 #endif
       
  1189     }
       
  1190 
       
  1191     return freetype->properties();
       
  1192 }
       
  1193 
       
  1194 QFixed QFontEngineFT::emSquareSize() const
       
  1195 {
       
  1196     if (FT_IS_SCALABLE(freetype->face))
       
  1197         return freetype->face->units_per_EM;
       
  1198     else
       
  1199         return freetype->face->size->metrics.y_ppem;
       
  1200 }
       
  1201 
       
  1202 bool QFontEngineFT::getSfntTableData(uint tag, uchar *buffer, uint *length) const
       
  1203 {
       
  1204     return freetype->getSfntTable(tag, buffer, length);
       
  1205 }
       
  1206 
       
  1207 int QFontEngineFT::synthesized() const
       
  1208 {
       
  1209     int s = 0;
       
  1210     if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
       
  1211         s = SynthesizedItalic;
       
  1212     if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
       
  1213         s |= SynthesizedStretch;
       
  1214     return s;
       
  1215 }
       
  1216 
       
  1217 QFixed QFontEngineFT::ascent() const
       
  1218 {
       
  1219     return QFixed::fromFixed(metrics.ascender);
       
  1220 }
       
  1221 
       
  1222 QFixed QFontEngineFT::descent() const
       
  1223 {
       
  1224     // subtract a pixel to work around QFontMetrics's built-in + 1
       
  1225     return QFixed::fromFixed(-metrics.descender - 64);
       
  1226 }
       
  1227 
       
  1228 QFixed QFontEngineFT::leading() const
       
  1229 {
       
  1230     return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
       
  1231 }
       
  1232 
       
  1233 QFixed QFontEngineFT::xHeight() const
       
  1234 {
       
  1235     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
       
  1236     if (os2 && os2->sxHeight) {
       
  1237         lockFace();
       
  1238         QFixed answer = QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
       
  1239         unlockFace();
       
  1240         return answer;
       
  1241     }
       
  1242     return QFontEngine::xHeight();
       
  1243 }
       
  1244 
       
  1245 QFixed QFontEngineFT::averageCharWidth() const
       
  1246 {
       
  1247     TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
       
  1248     if (os2 && os2->xAvgCharWidth) {
       
  1249         lockFace();
       
  1250         QFixed answer = QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.x_ppem)/freetype->face->units_per_EM;
       
  1251         unlockFace();
       
  1252         return answer;
       
  1253     }
       
  1254     return QFontEngine::averageCharWidth();
       
  1255 }
       
  1256 
       
  1257 qreal QFontEngineFT::maxCharWidth() const
       
  1258 {
       
  1259     return metrics.max_advance >> 6;
       
  1260 }
       
  1261 
       
  1262 static const ushort char_table[] = {
       
  1263         40,
       
  1264         67,
       
  1265         70,
       
  1266         75,
       
  1267         86,
       
  1268         88,
       
  1269         89,
       
  1270         91,
       
  1271         102,
       
  1272         114,
       
  1273         124,
       
  1274         127,
       
  1275         205,
       
  1276         645,
       
  1277         884,
       
  1278         922,
       
  1279         1070,
       
  1280         12386
       
  1281 };
       
  1282 
       
  1283 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
       
  1284 
       
  1285 
       
  1286 qreal QFontEngineFT::minLeftBearing() const
       
  1287 {
       
  1288     if (lbearing == SHRT_MIN)
       
  1289         (void) minRightBearing(); // calculates both
       
  1290     return lbearing.toReal();
       
  1291 }
       
  1292 
       
  1293 qreal QFontEngineFT::minRightBearing() const
       
  1294 {
       
  1295     if (rbearing == SHRT_MIN) {
       
  1296         lbearing = rbearing = 0;
       
  1297         const QChar *ch = (const QChar *)(const void*)char_table;
       
  1298         QGlyphLayoutArray<char_table_entries> glyphs;
       
  1299         int ng = char_table_entries;
       
  1300         stringToCMap(ch, char_table_entries, &glyphs, &ng, QTextEngine::GlyphIndicesOnly);
       
  1301         while (--ng) {
       
  1302             if (glyphs.glyphs[ng]) {
       
  1303                 glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
       
  1304                 lbearing = qMin(lbearing, gi.x);
       
  1305                 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
       
  1306             }
       
  1307         }
       
  1308     }
       
  1309     return rbearing.toReal();
       
  1310 }
       
  1311 
       
  1312 QFixed QFontEngineFT::lineThickness() const
       
  1313 {
       
  1314     return line_thickness;
       
  1315 }
       
  1316 
       
  1317 QFixed QFontEngineFT::underlinePosition() const
       
  1318 {
       
  1319     return underline_position;
       
  1320 }
       
  1321 
       
  1322 void QFontEngineFT::doKerning(QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
       
  1323 {
       
  1324     if (!kerning_pairs_loaded) {
       
  1325         kerning_pairs_loaded = true;
       
  1326         lockFace();
       
  1327         if (freetype->face->size->metrics.x_ppem != 0) {
       
  1328             QFixed scalingFactor(freetype->face->units_per_EM/freetype->face->size->metrics.x_ppem);
       
  1329             unlockFace();
       
  1330             const_cast<QFontEngineFT *>(this)->loadKerningPairs(scalingFactor);
       
  1331         } else {
       
  1332             unlockFace();
       
  1333         }
       
  1334     }
       
  1335     QFontEngine::doKerning(g, flags);
       
  1336 }
       
  1337 
       
  1338 QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransform &matrix)
       
  1339 {
       
  1340     if (matrix.type() > QTransform::TxShear)
       
  1341         return 0;
       
  1342 
       
  1343     // FT_Set_Transform only supports scalable fonts
       
  1344     if (!FT_IS_SCALABLE(freetype->face))
       
  1345         return 0;
       
  1346 
       
  1347     FT_Matrix m;
       
  1348     m.xx = FT_Fixed(matrix.m11() * 65536);
       
  1349     m.xy = FT_Fixed(-matrix.m21() * 65536);
       
  1350     m.yx = FT_Fixed(-matrix.m12() * 65536);
       
  1351     m.yy = FT_Fixed(matrix.m22() * 65536);
       
  1352 
       
  1353     QGlyphSet *gs = 0;
       
  1354 
       
  1355     for (int i = 0; i < transformedGlyphSets.count(); ++i) {
       
  1356         const QGlyphSet &g = transformedGlyphSets.at(i);
       
  1357         if (g.transformationMatrix.xx == m.xx
       
  1358             && g.transformationMatrix.xy == m.xy
       
  1359             && g.transformationMatrix.yx == m.yx
       
  1360             && g.transformationMatrix.yy == m.yy) {
       
  1361 
       
  1362             // found a match, move it to the front
       
  1363             transformedGlyphSets.move(i, 0);
       
  1364             gs = &transformedGlyphSets[0];
       
  1365             break;
       
  1366         }
       
  1367     }
       
  1368 
       
  1369     if (!gs) {
       
  1370         // don't try to load huge fonts
       
  1371         bool draw_as_outline = fontDef.pixelSize * qSqrt(matrix.det()) >= 64;
       
  1372         if (draw_as_outline)
       
  1373             return 0;
       
  1374 
       
  1375         // don't cache more than 10 transformations
       
  1376         if (transformedGlyphSets.count() >= 10) {
       
  1377             transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
       
  1378             freeServerGlyphSet(transformedGlyphSets.at(0).id);
       
  1379         } else {
       
  1380             transformedGlyphSets.prepend(QGlyphSet());
       
  1381         }
       
  1382         gs = &transformedGlyphSets[0];
       
  1383 
       
  1384         qDeleteAll(gs->glyph_data);
       
  1385         gs->glyph_data.clear();
       
  1386 
       
  1387         gs->id = allocateServerGlyphSet();
       
  1388 
       
  1389         gs->transformationMatrix = m;
       
  1390         gs->outline_drawing = draw_as_outline;
       
  1391     }
       
  1392 
       
  1393     return gs;
       
  1394 }
       
  1395 
       
  1396 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, glyph_t *glyphs, int num_glyphs, GlyphFormat format)
       
  1397 {
       
  1398     FT_Face face = 0;
       
  1399 
       
  1400     for (int i = 0; i < num_glyphs; ++i) {
       
  1401         Glyph *glyph = gs->glyph_data.value(glyphs[i]);
       
  1402         if (glyph == 0 || glyph->format != format) {
       
  1403             if (!face) {
       
  1404                 face = lockFace();
       
  1405                 FT_Matrix m = matrix;
       
  1406                 FT_Matrix_Multiply(&gs->transformationMatrix, &m);
       
  1407                 FT_Set_Transform(face, &m, 0);
       
  1408                 freetype->matrix = m;
       
  1409             }
       
  1410             if (!loadGlyph(gs, glyphs[i], format)) {
       
  1411                 unlockFace();
       
  1412                 return false;
       
  1413             }
       
  1414         }
       
  1415     }
       
  1416 
       
  1417     if (face)
       
  1418         unlockFace();
       
  1419 
       
  1420     return true;
       
  1421 }
       
  1422 
       
  1423 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
       
  1424 {
       
  1425     FT_Face face = lockFace(Unscaled);
       
  1426     FT_Set_Transform(face, 0, 0);
       
  1427     FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
       
  1428 
       
  1429     int left  = face->glyph->metrics.horiBearingX;
       
  1430     int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
       
  1431     int top    = face->glyph->metrics.horiBearingY;
       
  1432     int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
       
  1433 
       
  1434     QFixedPoint p;
       
  1435     p.x = 0;
       
  1436     p.y = 0;
       
  1437 
       
  1438     metrics->width = QFixed::fromFixed(right-left);
       
  1439     metrics->height = QFixed::fromFixed(top-bottom);
       
  1440     metrics->x = QFixed::fromFixed(left);
       
  1441     metrics->y = QFixed::fromFixed(-top);
       
  1442     metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
       
  1443 
       
  1444     if (!FT_IS_SCALABLE(freetype->face))
       
  1445         QFreetypeFace::addBitmapToPath(face->glyph, p, path);
       
  1446     else
       
  1447         QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
       
  1448 
       
  1449     FT_Set_Transform(face, &freetype->matrix, 0);
       
  1450     unlockFace();
       
  1451 }
       
  1452 
       
  1453 static inline unsigned int getChar(const QChar *str, int &i, const int len)
       
  1454 {
       
  1455     unsigned int uc = str[i].unicode();
       
  1456     if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
       
  1457         uint low = str[i+1].unicode();
       
  1458        if (low >= 0xdc00 && low < 0xe000) {
       
  1459             uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
       
  1460             ++i;
       
  1461         }
       
  1462     }
       
  1463     return uc;
       
  1464 }
       
  1465 
       
  1466 bool QFontEngineFT::canRender(const QChar *string, int len)
       
  1467 {
       
  1468     FT_Face face = freetype->face;
       
  1469 #if 0
       
  1470     if (_cmap != -1) {
       
  1471         lockFace();
       
  1472         for ( int i = 0; i < len; i++ ) {
       
  1473             unsigned int uc = getChar(string, i, len);
       
  1474             if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
       
  1475                 allExist = false;
       
  1476                 break;
       
  1477             }
       
  1478         }
       
  1479         unlockFace();
       
  1480     } else
       
  1481 #endif
       
  1482     {
       
  1483         for ( int i = 0; i < len; i++ ) {
       
  1484             unsigned int uc = getChar(string, i, len);
       
  1485             if (!FT_Get_Char_Index(face, uc))
       
  1486                     return false;
       
  1487         }
       
  1488     }
       
  1489     return true;
       
  1490 }
       
  1491 
       
  1492 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
       
  1493 {
       
  1494     if (!glyphs.numGlyphs)
       
  1495         return;
       
  1496 
       
  1497     if (FT_IS_SCALABLE(freetype->face)) {
       
  1498         QFontEngine::addOutlineToPath(x, y, glyphs, path, flags);
       
  1499     } else {
       
  1500         QVarLengthArray<QFixedPoint> positions;
       
  1501         QVarLengthArray<glyph_t> positioned_glyphs;
       
  1502         QTransform matrix;
       
  1503         matrix.translate(x, y);
       
  1504         getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
       
  1505 
       
  1506         FT_Face face = lockFace(Unscaled);
       
  1507         for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
       
  1508             FT_UInt glyph = positioned_glyphs[gl];
       
  1509             FT_Load_Glyph(face, glyph, FT_LOAD_TARGET_MONO);
       
  1510             freetype->addBitmapToPath(face->glyph, positions[gl], path);
       
  1511         }
       
  1512         unlockFace();
       
  1513     }
       
  1514 }
       
  1515 
       
  1516 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
       
  1517                                     QPainterPath *path, QTextItem::RenderFlags)
       
  1518 {
       
  1519     FT_Face face = lockFace(Unscaled);
       
  1520 
       
  1521     for (int gl = 0; gl < numGlyphs; gl++) {
       
  1522         FT_UInt glyph = glyphs[gl];
       
  1523 
       
  1524         FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
       
  1525 
       
  1526         FT_GlyphSlot g = face->glyph;
       
  1527         if (g->format != FT_GLYPH_FORMAT_OUTLINE)
       
  1528             continue;
       
  1529         QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
       
  1530     }
       
  1531     unlockFace();
       
  1532 }
       
  1533 
       
  1534 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
       
  1535                                  QTextEngine::ShaperFlags flags) const
       
  1536 {
       
  1537     if (*nglyphs < len) {
       
  1538         *nglyphs = len;
       
  1539         return false;
       
  1540     }
       
  1541 
       
  1542 #if !defined(QT_NO_FONTCONFIG)
       
  1543     extern QMutex *qt_fontdatabase_mutex();
       
  1544     QMutex *mtx = 0;
       
  1545 #endif
       
  1546 
       
  1547     bool mirrored = flags & QTextEngine::RightToLeft;
       
  1548     int glyph_pos = 0;
       
  1549     if (freetype->symbol_map) {
       
  1550         FT_Face face = freetype->face;
       
  1551         for ( int i = 0; i < len; ++i ) {
       
  1552             unsigned int uc = getChar(str, i, len);
       
  1553             if (mirrored)
       
  1554                 uc = QChar::mirroredChar(uc);
       
  1555             glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
       
  1556             if ( !glyphs->glyphs[glyph_pos] ) {
       
  1557                 glyph_t glyph;
       
  1558 #if !defined(QT_NO_FONTCONFIG)
       
  1559                 if (!mtx) {
       
  1560                     mtx = qt_fontdatabase_mutex();
       
  1561                     mtx->lock();
       
  1562                 }
       
  1563 
       
  1564                 if (FcCharSetHasChar(freetype->charset, uc)) {
       
  1565 #else
       
  1566                 if (false) {
       
  1567 #endif
       
  1568                 redo0:
       
  1569                     glyph = FT_Get_Char_Index(face, uc);
       
  1570                     if (!glyph && (uc == 0xa0 || uc == 0x9)) {
       
  1571                         uc = 0x20;
       
  1572                         goto redo0;
       
  1573                     }
       
  1574                 } else {
       
  1575                     FT_Set_Charmap(face, freetype->symbol_map);
       
  1576                     glyph = FT_Get_Char_Index(face, uc);
       
  1577                     FT_Set_Charmap(face, freetype->unicode_map);
       
  1578                 }
       
  1579                 glyphs->glyphs[glyph_pos] = glyph;
       
  1580                 if (uc < QFreetypeFace::cmapCacheSize)
       
  1581                     freetype->cmapCache[uc] = glyph;
       
  1582             }
       
  1583             ++glyph_pos;
       
  1584         }
       
  1585     } else {
       
  1586         FT_Face face = freetype->face;
       
  1587         for (int i = 0; i < len; ++i) {
       
  1588             unsigned int uc = getChar(str, i, len);
       
  1589             if (mirrored)
       
  1590                 uc = QChar::mirroredChar(uc);
       
  1591             glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
       
  1592             if (!glyphs->glyphs[glyph_pos]) {
       
  1593 #if !defined(QT_NO_FONTCONFIG)
       
  1594                 if (!mtx) {
       
  1595                     mtx = qt_fontdatabase_mutex();
       
  1596                     mtx->lock();
       
  1597                 }
       
  1598 
       
  1599                 if (FcCharSetHasChar(freetype->charset, uc))
       
  1600 #endif
       
  1601                 {
       
  1602                 redo:
       
  1603                     glyph_t glyph = FT_Get_Char_Index(face, uc);
       
  1604                     if (!glyph && (uc == 0xa0 || uc == 0x9)) {
       
  1605                         uc = 0x20;
       
  1606                         goto redo;
       
  1607                     }
       
  1608                     glyphs->glyphs[glyph_pos] = glyph;
       
  1609                     if (uc < QFreetypeFace::cmapCacheSize)
       
  1610                         freetype->cmapCache[uc] = glyph;
       
  1611                 }
       
  1612             }
       
  1613             ++glyph_pos;
       
  1614         }
       
  1615     }
       
  1616 
       
  1617     *nglyphs = glyph_pos;
       
  1618     glyphs->numGlyphs = glyph_pos;
       
  1619 
       
  1620 #if !defined(QT_NO_FONTCONFIG)
       
  1621     if (mtx)
       
  1622         mtx->unlock();
       
  1623 #endif
       
  1624 
       
  1625     if (flags & QTextEngine::GlyphIndicesOnly)
       
  1626         return true;
       
  1627 
       
  1628     recalcAdvances(glyphs, flags);
       
  1629 
       
  1630     return true;
       
  1631 }
       
  1632 
       
  1633 void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
       
  1634 {
       
  1635     FT_Face face = 0;
       
  1636     if (flags & QTextEngine::DesignMetrics) {
       
  1637         for (int i = 0; i < glyphs->numGlyphs; i++) {
       
  1638             Glyph *g = defaultGlyphSet.glyph_data.value(glyphs->glyphs[i]);
       
  1639             if (g) {
       
  1640                 glyphs->advances_x[i] = QFixed::fromFixed(g->linearAdvance);
       
  1641             } else {
       
  1642                 if (!face)
       
  1643                     face = lockFace();
       
  1644                 g = loadGlyph(glyphs->glyphs[i], Format_None, true);
       
  1645                 glyphs->advances_x[i] = QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10);
       
  1646             }
       
  1647             glyphs->advances_y[i] = 0;
       
  1648         }
       
  1649     } else {
       
  1650         for (int i = 0; i < glyphs->numGlyphs; i++) {
       
  1651             Glyph *g = defaultGlyphSet.glyph_data.value(glyphs->glyphs[i]);
       
  1652             if (g) {
       
  1653                 glyphs->advances_x[i] = QFixed(g->advance);
       
  1654             } else {
       
  1655                 if (!face)
       
  1656                     face = lockFace();
       
  1657                 g = loadGlyph(glyphs->glyphs[i], Format_None, true);
       
  1658                 glyphs->advances_x[i] = QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
       
  1659             }
       
  1660             glyphs->advances_y[i] = 0;
       
  1661         }
       
  1662     }
       
  1663     if (face)
       
  1664         unlockFace();
       
  1665 }
       
  1666 
       
  1667 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
       
  1668 {
       
  1669 
       
  1670     FT_Face face = 0;
       
  1671 
       
  1672     glyph_metrics_t overall;
       
  1673     // initialize with line height, we get the same behaviour on all platforms
       
  1674     overall.y = -ascent();
       
  1675     overall.height = ascent() + descent() + 1;
       
  1676 
       
  1677     QFixed ymax = 0;
       
  1678     QFixed xmax = 0;
       
  1679     for (int i = 0; i < glyphs.numGlyphs; i++) {
       
  1680         Glyph *g = defaultGlyphSet.glyph_data.value(glyphs.glyphs[i]);
       
  1681         if (!g) {
       
  1682             if (!face)
       
  1683                 face = lockFace();
       
  1684             g = loadGlyph(glyphs.glyphs[i], Format_None, true);
       
  1685         }
       
  1686         if (g) {
       
  1687             QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
       
  1688             QFixed y = overall.yoff + glyphs.offsets[i].y - g->y;
       
  1689             overall.x = qMin(overall.x, x);
       
  1690             overall.y = qMin(overall.y, y);
       
  1691             xmax = qMax(xmax, x + g->width);
       
  1692             ymax = qMax(ymax, y + g->height);
       
  1693             overall.xoff += qRound(g->advance);
       
  1694         } else {
       
  1695             int left  = FLOOR(face->glyph->metrics.horiBearingX);
       
  1696             int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
       
  1697             int top    = CEIL(face->glyph->metrics.horiBearingY);
       
  1698             int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
       
  1699 
       
  1700             QFixed x = overall.xoff + glyphs.offsets[i].x - (-TRUNC(left));
       
  1701             QFixed y = overall.yoff + glyphs.offsets[i].y - TRUNC(top);
       
  1702             overall.x = qMin(overall.x, x);
       
  1703             overall.y = qMin(overall.y, y);
       
  1704             xmax = qMax(xmax, x + TRUNC(right - left));
       
  1705             ymax = qMax(ymax, y + TRUNC(top - bottom));
       
  1706             overall.xoff += qRound(TRUNC(ROUND(face->glyph->advance.x)));
       
  1707         }
       
  1708     }
       
  1709     overall.height = qMax(overall.height, ymax - overall.y);
       
  1710     overall.width = xmax - overall.x;
       
  1711 
       
  1712     if (face)
       
  1713         unlockFace();
       
  1714 
       
  1715     return overall;
       
  1716 }
       
  1717 
       
  1718 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
       
  1719 {
       
  1720     FT_Face face = 0;
       
  1721     glyph_metrics_t overall;
       
  1722     Glyph *g = defaultGlyphSet.glyph_data.value(glyph);
       
  1723     if (!g) {
       
  1724         face = lockFace();
       
  1725         g = loadGlyph(glyph, Format_None, true);
       
  1726     }
       
  1727     if (g) {
       
  1728         overall.x = g->x;
       
  1729         overall.y = -g->y;
       
  1730         overall.width = g->width;
       
  1731         overall.height = g->height;
       
  1732         overall.xoff = g->advance;
       
  1733     } else {
       
  1734         int left  = FLOOR(face->glyph->metrics.horiBearingX);
       
  1735         int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
       
  1736         int top    = CEIL(face->glyph->metrics.horiBearingY);
       
  1737         int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
       
  1738 
       
  1739         overall.width = TRUNC(right-left);
       
  1740         overall.height = TRUNC(top-bottom);
       
  1741         overall.x = TRUNC(left);
       
  1742         overall.y = -TRUNC(top);
       
  1743         overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
       
  1744     }
       
  1745     if (face)
       
  1746         unlockFace();
       
  1747     return overall;
       
  1748 }
       
  1749 
       
  1750 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
       
  1751 {
       
  1752     FT_Face face = 0;
       
  1753     glyph_metrics_t overall;
       
  1754     QGlyphSet *glyphSet = 0;
       
  1755     if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
       
  1756         // TODO move everything here to a method of its own to access glyphSets
       
  1757         // to be shared with a new method that will replace loadTransformedGlyphSet()
       
  1758         FT_Matrix m;
       
  1759         m.xx = FT_Fixed(matrix.m11() * 65536);
       
  1760         m.xy = FT_Fixed(-matrix.m21() * 65536);
       
  1761         m.yx = FT_Fixed(-matrix.m12() * 65536);
       
  1762         m.yy = FT_Fixed(matrix.m22() * 65536);
       
  1763         for (int i = 0; i < transformedGlyphSets.count(); ++i) {
       
  1764             const QGlyphSet &g = transformedGlyphSets.at(i);
       
  1765             if (g.transformationMatrix.xx == m.xx
       
  1766                 && g.transformationMatrix.xy == m.xy
       
  1767                 && g.transformationMatrix.yx == m.yx
       
  1768                 && g.transformationMatrix.yy == m.yy) {
       
  1769 
       
  1770                 // found a match, move it to the front
       
  1771                 transformedGlyphSets.move(i, 0);
       
  1772                 glyphSet = &transformedGlyphSets[0];
       
  1773                 break;
       
  1774             }
       
  1775         }
       
  1776 
       
  1777         if (!glyphSet) {
       
  1778             // don't cache more than 10 transformations
       
  1779             if (transformedGlyphSets.count() >= 10) {
       
  1780                 transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
       
  1781                 freeServerGlyphSet(transformedGlyphSets.at(0).id);
       
  1782             } else {
       
  1783                 transformedGlyphSets.prepend(QGlyphSet());
       
  1784             }
       
  1785             glyphSet = &transformedGlyphSets[0];
       
  1786             qDeleteAll(glyphSet->glyph_data);
       
  1787             glyphSet->glyph_data.clear();
       
  1788             glyphSet->id = allocateServerGlyphSet();
       
  1789             glyphSet->transformationMatrix = m;
       
  1790         }
       
  1791         Q_ASSERT(glyphSet);
       
  1792     } else {
       
  1793         glyphSet = &defaultGlyphSet;
       
  1794     }
       
  1795     Glyph * g = glyphSet->glyph_data.value(glyph);
       
  1796     if (!g) {
       
  1797         face = lockFace();
       
  1798         g = loadGlyphMetrics(glyphSet, glyph);
       
  1799     }
       
  1800 
       
  1801     if (g) {
       
  1802         overall.x = g->x;
       
  1803         overall.y = -g->y;
       
  1804         overall.width = g->width;
       
  1805         overall.height = g->height;
       
  1806         overall.xoff = g->advance;
       
  1807     } else {
       
  1808         int left  = FLOOR(face->glyph->metrics.horiBearingX);
       
  1809         int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
       
  1810         int top    = CEIL(face->glyph->metrics.horiBearingY);
       
  1811         int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
       
  1812 
       
  1813         overall.width = TRUNC(right-left);
       
  1814         overall.height = TRUNC(top-bottom);
       
  1815         overall.x = TRUNC(left);
       
  1816         overall.y = -TRUNC(top);
       
  1817         overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
       
  1818     }
       
  1819     if (face)
       
  1820         unlockFace();
       
  1821     return overall;
       
  1822 }
       
  1823 
       
  1824 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g)
       
  1825 {
       
  1826     lockFace();
       
  1827 
       
  1828     GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
       
  1829 
       
  1830     Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, glyph_format);
       
  1831     if (!glyph) {
       
  1832         unlockFace();
       
  1833         return QFontEngine::alphaMapForGlyph(g);
       
  1834     }
       
  1835 
       
  1836     const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
       
  1837 
       
  1838     QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Indexed8 : QImage::Format_Mono);
       
  1839     if (antialias) {
       
  1840         QVector<QRgb> colors(256);
       
  1841         for (int i=0; i<256; ++i)
       
  1842             colors[i] = qRgba(0, 0, 0, i);
       
  1843         img.setColorTable(colors);
       
  1844     } else {
       
  1845         QVector<QRgb> colors(2);
       
  1846         colors[0] = qRgba(0, 0, 0, 0);
       
  1847         colors[1] = qRgba(0, 0, 0, 255);
       
  1848         img.setColorTable(colors);
       
  1849     }
       
  1850     Q_ASSERT(img.bytesPerLine() == pitch);
       
  1851     if (glyph->width) {
       
  1852         for (int y = 0; y < glyph->height; ++y)
       
  1853             memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
       
  1854     }
       
  1855     unlockFace();
       
  1856 
       
  1857     return img;
       
  1858 }
       
  1859 
       
  1860 QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, int margin, const QTransform &t)
       
  1861 {
       
  1862     if (t.type() > QTransform::TxTranslate)
       
  1863         return QFontEngine::alphaRGBMapForGlyph(g, margin, t);
       
  1864 
       
  1865     lockFace();
       
  1866 
       
  1867     GlyphFormat glyph_format = Format_A32;
       
  1868 
       
  1869     Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, glyph_format);
       
  1870     if (!glyph) {
       
  1871         unlockFace();
       
  1872         return QFontEngine::alphaRGBMapForGlyph(g, margin, t);
       
  1873     }
       
  1874 
       
  1875     QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
       
  1876     memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
       
  1877     unlockFace();
       
  1878 
       
  1879     return img;
       
  1880 }
       
  1881 
       
  1882 void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
       
  1883 {
       
  1884     delete defaultGlyphSet.glyph_data.take(glyph);
       
  1885 }
       
  1886 
       
  1887 int QFontEngineFT::glyphCount() const
       
  1888 {
       
  1889     int count = 0;
       
  1890     FT_Face face = lockFace();
       
  1891     if (face) {
       
  1892         count = face->num_glyphs;
       
  1893         unlockFace();
       
  1894     }
       
  1895     return count;
       
  1896 }
       
  1897 
       
  1898 FT_Face QFontEngineFT::lockFace(Scaling scale) const
       
  1899 {
       
  1900     freetype->lock();
       
  1901     FT_Face face = freetype->face;
       
  1902     if (scale == Unscaled) {
       
  1903         FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
       
  1904         freetype->xsize = face->units_per_EM << 6;
       
  1905         freetype->ysize = face->units_per_EM << 6;
       
  1906     } else if (freetype->xsize != xsize || freetype->ysize != ysize) {
       
  1907         FT_Set_Char_Size(face, xsize, ysize, 0, 0);
       
  1908         freetype->xsize = xsize;
       
  1909         freetype->ysize = ysize;
       
  1910     }
       
  1911     if (freetype->matrix.xx != matrix.xx ||
       
  1912         freetype->matrix.yy != matrix.yy ||
       
  1913         freetype->matrix.xy != matrix.xy ||
       
  1914         freetype->matrix.yx != matrix.yx) {
       
  1915         freetype->matrix = matrix;
       
  1916         FT_Set_Transform(face, &freetype->matrix, 0);
       
  1917     }
       
  1918 
       
  1919     return face;
       
  1920 }
       
  1921 
       
  1922 void QFontEngineFT::unlockFace() const
       
  1923 {
       
  1924     freetype->unlock();
       
  1925 }
       
  1926 
       
  1927 FT_Face QFontEngineFT::non_locked_face() const
       
  1928 {
       
  1929     return freetype->face;
       
  1930 }
       
  1931 
       
  1932 
       
  1933 QFontEngineFT::QGlyphSet::QGlyphSet()
       
  1934     : id(0), outline_drawing(false)
       
  1935 {
       
  1936     transformationMatrix.xx = 0x10000;
       
  1937     transformationMatrix.yy = 0x10000;
       
  1938     transformationMatrix.xy = 0;
       
  1939     transformationMatrix.yx = 0;
       
  1940 }
       
  1941 
       
  1942 QFontEngineFT::QGlyphSet::~QGlyphSet()
       
  1943 {
       
  1944     qDeleteAll(glyph_data);
       
  1945 }
       
  1946 
       
  1947 unsigned long QFontEngineFT::allocateServerGlyphSet()
       
  1948 {
       
  1949     return 0;
       
  1950 }
       
  1951 
       
  1952 void QFontEngineFT::freeServerGlyphSet(unsigned long id)
       
  1953 {
       
  1954     Q_UNUSED(id);
       
  1955 }
       
  1956 
       
  1957 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
       
  1958 {
       
  1959     lockFace();
       
  1960     HB_Error result = freetype->getPointInOutline(glyph, flags, point, xpos, ypos, nPoints);
       
  1961     unlockFace();
       
  1962     return result;
       
  1963 }
       
  1964 
       
  1965 QT_END_NAMESPACE
       
  1966 
       
  1967 #endif // QT_NO_FREETYPE