Compile with clang when C++11 support is enabled
[profile/ivi/qtbase.git] / src / gui / text / qfontengine_ft.cpp
index 4dae2a3..f83ddd3 100644 (file)
@@ -1,34 +1,34 @@
 /****************************************************************************
 **
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
 **
 ** This file is part of the QtGui module of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
 ** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 **
 ** In addition, as a special exception, Nokia gives you certain additional
-** rights.  These rights are described in the Nokia Qt LGPL Exception
+** rights. These rights are described in the Nokia Qt LGPL Exception
 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 **
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
 **
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
 **
 **
 **
 #include "qtextstream.h"
 #include "qvariant.h"
 #include "qfontengine_ft_p.h"
+#include "private/qimage_p.h"
 
 #ifndef QT_NO_FREETYPE
 
 #include "qfile.h"
-#include "qabstractfileengine.h"
+#include "qfileinfo.h"
 #include "qthreadstorage.h"
 #include <qmath.h>
-#include <private/qharfbuzz_p.h>
 
 #include "qfontengine_ft_p.h"
 #include <ft2build.h>
 #include FT_ERRORS_H
 #endif
 
+#if !defined(QT_MAX_CACHED_GLYPH_SIZE)
+#  define QT_MAX_CACHED_GLYPH_SIZE 64
+#endif
+
 QT_BEGIN_NAMESPACE
 
 /*
@@ -100,6 +104,14 @@ QT_BEGIN_NAMESPACE
 #define Q_FT_GLYPHSLOT_EMBOLDEN(slot)
 #endif
 
+/* FreeType 2.1.10 starts to provide FT_GlyphSlot_Oblique */
+#if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20110
+#define Q_HAS_FT_GLYPHSLOT_OBLIQUE
+#define Q_FT_GLYPHSLOT_OBLIQUE(slot)   FT_GlyphSlot_Oblique(slot)
+#else
+#define Q_FT_GLYPHSLOT_OBLIQUE(slot)
+#endif
+
 #define FLOOR(x)    ((x) & -64)
 #define CEIL(x)            (((x)+63) & -64)
 #define TRUNC(x)    ((x) >> 6)
@@ -193,6 +205,8 @@ HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 p
     return HB_Err_Ok;
 }
 
+extern QByteArray qt_fontdata_from_index(int);
+
 /*
  * One font file can contain more than one font (bold/italic for example)
  * find the right one and return it.
@@ -217,17 +231,17 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
         QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
         FT_Face face;
         if (!face_id.filename.isEmpty()) {
-            QFile file(QString::fromUtf8(face_id.filename));
+            QString fileName = QString::fromUtf8(face_id.filename);
             if (face_id.filename.startsWith(":qmemoryfonts/")) {
                 // from qfontdatabase.cpp
-                extern QByteArray qt_fontdata_from_index(int);
                 QByteArray idx = face_id.filename;
                 idx.remove(0, 14); // remove ':qmemoryfonts/'
                 bool ok = false;
                 newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
                 if (!ok)
                     newFreetype->fontData = QByteArray();
-            } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
+            } else if (!QFileInfo(fileName).isNativePath()) {
+                QFile file(fileName);
                 if (!file.open(QIODevice::ReadOnly)) {
                     return 0;
                 }
@@ -247,7 +261,7 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
 
         newFreetype->hbFace = qHBNewFace(face, hb_getSFntTable);
         Q_CHECK_PTR(newFreetype->hbFace);
-        newFreetype->ref = 1;
+        newFreetype->ref.store(1);
         newFreetype->xsize = 0;
         newFreetype->ysize = 0;
         newFreetype->matrix.xx = 0x10000;
@@ -256,9 +270,6 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
         newFreetype->matrix.yx = 0;
         newFreetype->unicode_map = 0;
         newFreetype->symbol_map = 0;
-#ifndef QT_NO_FONTCONFIG
-        newFreetype->charset = 0;
-#endif
 
         memset(newFreetype->cmapCache, 0, sizeof(newFreetype->cmapCache));
 
@@ -285,21 +296,6 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
 
         if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
             FT_Set_Char_Size (face, X_SIZE(newFreetype->face, 0), Y_SIZE(newFreetype->face, 0), 0, 0);
-# if 0
-        FcChar8 *name;
-        FcPatternGetString(pattern, FC_FAMILY, 0, &name);
-        qDebug("%s: using maps: default: %x unicode: %x, symbol: %x", name,
-               newFreetype->face->charmap ? newFreetype->face->charmap->encoding : 0,
-               newFreetype->unicode_map ? newFreetype->unicode_map->encoding : 0,
-               newFreetype->symbol_map ? newFreetype->symbol_map->encoding : 0);
-
-        for (int i = 0; i < 256; i += 8)
-            qDebug("    %x: %d %d %d %d %d %d %d %d", i,
-                   FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
-                   FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
-                   FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i),
-                   FcCharSetHasChar(newFreetype->charset, i), FcCharSetHasChar(newFreetype->charset, i));
-#endif
 
         FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
         QT_TRY {
@@ -320,10 +316,6 @@ void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
     if (!ref.deref()) {
         qHBFreeFace(hbFace);
         FT_Done_Face(face);
-#ifndef QT_NO_FONTCONFIG
-        if (charset)
-            FcCharSetDestroy(charset);
-#endif
         if(freetypeData->faces.contains(face_id))
             freetypeData->faces.take(face_id);
         delete this;
@@ -373,7 +365,7 @@ void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize,
                 *xsize = *ysize = 0;
         }
     } else {
-        *outline_drawing = (*xsize > (64<<6) || *ysize > (64<<6));
+        *outline_drawing = (*xsize > (QT_MAX_CACHED_GLYPH_SIZE<<6) || *ysize > (QT_MAX_CACHED_GLYPH_SIZE<<6));
     }
 }
 
@@ -628,18 +620,24 @@ QFontEngineFT::QFontEngineFT(const QFontDef &fd)
     kerning_pairs_loaded = false;
     transform = false;
     embolden = false;
+    obliquen = false;
     antialias = true;
     freetype = 0;
     default_load_flags = FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
+#ifndef Q_OS_WIN
     default_hint_style = HintNone;
+#else
+    default_hint_style = HintFull;
+#endif
     subpixelType = Subpixel_None;
     lcdFilterType = 0;
 #if defined(FT_LCD_FILTER_H)
     lcdFilterType = (int)((quintptr) FT_LCD_FILTER_DEFAULT);
 #endif
     defaultFormat = Format_None;
-    canUploadGlyphsToServer = false;
     embeddedbitmap = false;
+    cacheEnabled = qgetenv("QT_NO_FT_CACHE").isEmpty() || qgetenv("QT_NO_FT_CACHE").toInt() == 0;
+    m_subPixelPositionCount = 4;
 }
 
 QFontEngineFT::~QFontEngineFT()
@@ -649,13 +647,6 @@ QFontEngineFT::~QFontEngineFT()
     hbFace = 0; // we share the face in QFreeTypeFace, don't let ~QFontEngine delete it
 }
 
-void QFontEngineFT::freeGlyphSets()
-{
-    freeServerGlyphSet(defaultGlyphSet.id);
-    for (int i = 0; i < transformedGlyphSets.count(); ++i)
-        freeServerGlyphSet(transformedGlyphSets.at(i).id);
-}
-
 bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
                          const QByteArray &fontData)
 {
@@ -699,12 +690,16 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
 
     if (FT_IS_SCALABLE(face)) {
         bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
-        if (fake_oblique)
+        if (fake_oblique) {
+#if !defined(Q_HAS_FT_GLYPHSLOT_OBLIQUE)
             matrix.xy = 0x10000*3/10;
+            transform = true;
+#else
+            obliquen = true;
+#endif
+        }
         FT_Set_Transform(face, &matrix, 0);
         freetype->matrix = matrix;
-        if (fake_oblique)
-            transform = true;
         // fake bold
         if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
             embolden = true;
@@ -733,7 +728,6 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
 
     metrics = face->size->metrics;
 
-#if defined(Q_WS_QWS) || defined(Q_WS_QPA)
     /*
        TrueType fonts with embedded bitmaps may have a bitmap font specific
        ascent/descent in the EBLC table. There is no direct public API
@@ -756,12 +750,12 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
             }
         }
     }
-#endif
+
+    fontDef.styleName = QString::fromUtf8(face->style_name);
 
     unlockFace();
 
     fsType = freetype->fsType();
-    defaultGlyphSet.id = allocateServerGlyphSet();
     return true;
 }
 
@@ -795,7 +789,7 @@ int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
     if (set && set->outline_drawing)
         load_flags = FT_LOAD_NO_BITMAP;
 
-    if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics))
+    if (default_hint_style == HintNone || (flags & HB_ShaperFlag_UseDesignMetrics) || (set && set->outline_drawing))
         load_flags |= FT_LOAD_NO_HINTING;
     else
         load_flags |= load_target;
@@ -810,27 +804,17 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
 {
 //     Q_ASSERT(freetype->lock == 1);
 
-    bool uploadToServer = false;
     if (format == Format_None) {
         if (defaultFormat != Format_None) {
             format = defaultFormat;
-            if (canUploadGlyphsToServer)
-                uploadToServer = true;
         } else {
             format = Format_Mono;
         }
     }
 
-    Glyph *g = set->getGlyph(glyph, subPixelPosition);
-    if (g && g->format == format) {
-        if (uploadToServer && !g->uploadedToServer) {
-            set->setGlyph(glyph, subPixelPosition, 0);
-            delete g;
-            g = 0;
-        } else {
-            return g;
-        }
-    }
+    Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : 0;
+    if (g && g->format == format && (fetchMetricsOnly || g->data))
+        return g;
 
     QFontEngineFT::GlyphInfo info;
 
@@ -839,10 +823,8 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
     int vfactor = 1;
     int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
 
-#ifndef Q_WS_QWS
     if (format != Format_Mono && !embeddedbitmap)
         load_flags |= FT_LOAD_NO_BITMAP;
-#endif
 
     FT_Matrix matrix = freetype->matrix;
     bool transform = matrix.xx != 0x10000
@@ -873,16 +855,53 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
     if (err != FT_Err_Ok)
         qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
 
-    if (set->outline_drawing && fetchMetricsOnly)
-        return 0;
-
     FT_GlyphSlot slot = face->glyph;
+
     if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
+    if (obliquen) {
+        Q_FT_GLYPHSLOT_OBLIQUE(slot);
+
+        // While Embolden alters the metrics of the slot, oblique does not, so we need
+        // to fix this ourselves.
+        transform = true;
+        FT_Matrix m;
+        m.xx = 0x10000;
+        m.yx = 0x0;
+        m.xy = 0x6000;
+        m.yy = 0x10000;
+
+        FT_Matrix_Multiply(&m, &matrix);
+    }
+
     FT_Library library = qt_getFreetype();
 
     info.xOff = TRUNC(ROUND(slot->advance.x));
     info.yOff = 0;
 
+    if ((set && set->outline_drawing) || fetchMetricsOnly) {
+        // If the advance doesn't fit in signed char, don't cache it
+        if (qAbs(info.xOff) >= 128)
+            return 0;
+        g = new Glyph;
+        g->data = 0;
+        g->linearAdvance = slot->linearHoriAdvance >> 10;
+        int left  = FLOOR(slot->metrics.horiBearingX);
+        int right = CEIL(slot->metrics.horiBearingX + slot->metrics.width);
+        int top    = CEIL(slot->metrics.horiBearingY);
+        int bottom = FLOOR(slot->metrics.horiBearingY - slot->metrics.height);
+        g->width = TRUNC(right-left);
+        g->height = TRUNC(top-bottom);
+        g->x = TRUNC(left);
+        g->y = TRUNC(top);
+        g->advance = TRUNC(ROUND(slot->advance.x));
+        g->format = format;
+
+        if (set)
+            set->setGlyph(glyph, subPixelPosition, g);
+
+        return g;
+    }
+
     uchar *glyph_buffer = 0;
     int glyph_buffer_size = 0;
 #if defined(QT_USE_FREETYPE_LCDFILTER)
@@ -1088,7 +1107,6 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
 
     if (!g) {
         g = new Glyph;
-        g->uploadedToServer = false;
         g->data = 0;
     }
 
@@ -1102,25 +1120,12 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
     delete [] g->data;
     g->data = glyph_buffer;
 
-    if (uploadToServer) {
-        uploadGlyphToServer(set, glyph, g, &info, glyph_buffer_size);
-    }
-
-    set->setGlyph(glyph, subPixelPosition, g);
+    if (set)
+        set->setGlyph(glyph, subPixelPosition, g);
 
     return g;
 }
 
-bool QFontEngineFT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
-{
-    Q_UNUSED(set);
-    Q_UNUSED(glyphid);
-    Q_UNUSED(g);
-    Q_UNUSED(info);
-    Q_UNUSED(glyphDataSize);
-    return false;
-}
-
 QFontEngine::FaceId QFontEngineFT::faceId() const
 {
     return face_id;
@@ -1168,8 +1173,7 @@ QFixed QFontEngineFT::ascent() const
 
 QFixed QFontEngineFT::descent() const
 {
-    // subtract a pixel to work around QFontMetrics's built-in + 1
-    return QFixed::fromFixed(-metrics.descender - 64);
+    return QFixed::fromFixed(-metrics.descender);
 }
 
 QFixed QFontEngineFT::leading() const
@@ -1215,6 +1219,7 @@ static const ushort char_table[] = {
         88,
         89,
         91,
+        95,
         102,
         114,
         124,
@@ -1315,23 +1320,18 @@ QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransfor
 
     if (!gs) {
         // don't try to load huge fonts
-        bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= 64;
+        bool draw_as_outline = fontDef.pixelSize * qSqrt(qAbs(matrix.det())) >= QT_MAX_CACHED_GLYPH_SIZE;
         if (draw_as_outline)
             return 0;
 
         // don't cache more than 10 transformations
         if (transformedGlyphSets.count() >= 10) {
             transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
-            freeServerGlyphSet(transformedGlyphSets.at(0).id);
         } else {
             transformedGlyphSets.prepend(QGlyphSet());
         }
         gs = &transformedGlyphSets[0];
-
         gs->clear();
-
-        gs->id = allocateServerGlyphSet();
-
         gs->transformationMatrix = m;
         gs->outline_drawing = draw_as_outline;
     }
@@ -1339,21 +1339,6 @@ QFontEngineFT::QGlyphSet *QFontEngineFT::loadTransformedGlyphSet(const QTransfor
     return gs;
 }
 
-QFixed QFontEngineFT::subPixelPositionForX(QFixed x)
-{
-    int m_subPixelPositionCount = 4;
-    if (!supportsSubPixelPositions())
-        return 0;
-
-    QFixed subPixelPosition;
-    if (x != 0) {
-        subPixelPosition = x - x.floor();
-        QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
-        subPixelPosition = fraction / QFixed(m_subPixelPositionCount);
-    }
-    return subPixelPosition;
-}
-
 bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_glyphs,
                                const QFixedPoint *positions,
                                GlyphFormat format)
@@ -1362,7 +1347,7 @@ bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, const glyph_t *glyphs, int num_gly
 
     for (int i = 0; i < num_glyphs; ++i) {
         QFixed spp = subPixelPositionForX(positions[i].x);
-        Glyph *glyph = gs->getGlyph(glyphs[i], spp);
+        Glyph *glyph = gs ? gs->getGlyph(glyphs[i], spp) : 0;
         if (glyph == 0 || glyph->format != format) {
             if (!face) {
                 face = lockFace();
@@ -1416,33 +1401,17 @@ void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_me
 
 static inline unsigned int getChar(const QChar *str, int &i, const int len)
 {
-    unsigned int uc = str[i].unicode();
-    if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
-        uint low = str[i+1].unicode();
-       if (low >= 0xdc00 && low < 0xe000) {
-            uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
-            ++i;
-        }
+    uint ucs4 = str[i].unicode();
+    if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
+        ++i;
+        ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
     }
-    return uc;
+    return ucs4;
 }
 
 bool QFontEngineFT::canRender(const QChar *string, int len)
 {
     FT_Face face = freetype->face;
-#if 0
-    if (_cmap != -1) {
-        lockFace();
-        for ( int i = 0; i < len; i++ ) {
-            unsigned int uc = getChar(string, i, len);
-            if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
-                allExist = false;
-                break;
-            }
-        }
-        unlockFace();
-    } else
-#endif
     {
         for ( int i = 0; i < len; i++ ) {
             unsigned int uc = getChar(string, i, len);
@@ -1490,6 +1459,8 @@ void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int
         FT_GlyphSlot g = face->glyph;
         if (g->format != FT_GLYPH_FORMAT_OUTLINE)
             continue;
+        if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(g);
+        if (obliquen) Q_FT_GLYPHSLOT_OBLIQUE(g);
         QFreetypeFace::addGlyphToPath(face, g, positions[gl], path, xsize, ysize);
     }
     unlockFace();
@@ -1503,11 +1474,6 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
         return false;
     }
 
-#if !defined(QT_NO_FONTCONFIG)
-    extern QMutex *qt_fontdatabase_mutex();
-    QMutex *mtx = 0;
-#endif
-
     bool mirrored = flags & QTextEngine::RightToLeft;
     int glyph_pos = 0;
     if (freetype->symbol_map) {
@@ -1516,24 +1482,20 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
             unsigned int uc = getChar(str, i, len);
             glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
             if ( !glyphs->glyphs[glyph_pos] ) {
-                glyph_t glyph;
-#if !defined(QT_NO_FONTCONFIG)
-                if (!mtx) {
-                    mtx = qt_fontdatabase_mutex();
-                    mtx->lock();
-                }
-
-                if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
-#else
-                if (false) {
-#endif
-                redo0:
+                // Symbol fonts can have more than one CMAPs, FreeType should take the
+                // correct one for us by default, so we always try FT_Get_Char_Index
+                // first. If it didn't work (returns 0), we will explicitly set the
+                // CMAP to symbol font one and try again. symbol_map is not always the
+                // correct one because in certain fonts like Wingdings symbol_map only
+                // contains PUA codepoints instead of the common ones.
+                glyph_t glyph = FT_Get_Char_Index(face, uc);
+                // Certain symbol fonts don't have no-break space (0xa0) and tab (0x9),
+                // while we usually want to render them as space
+                if (!glyph && (uc == 0xa0 || uc == 0x9)) {
+                    uc = 0x20;
                     glyph = FT_Get_Char_Index(face, uc);
-                    if (!glyph && (uc == 0xa0 || uc == 0x9)) {
-                        uc = 0x20;
-                        goto redo0;
-                    }
-                } else {
+                }
+                if (!glyph) {
                     FT_Set_Charmap(face, freetype->symbol_map);
                     glyph = FT_Get_Char_Index(face, uc);
                     FT_Set_Charmap(face, freetype->unicode_map);
@@ -1552,14 +1514,6 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
                 uc = QChar::mirroredChar(uc);
             glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
             if (!glyphs->glyphs[glyph_pos]) {
-#if !defined(QT_NO_FONTCONFIG)
-                if (!mtx) {
-                    mtx = qt_fontdatabase_mutex();
-                    mtx->lock();
-                }
-
-                if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
-#endif
                 {
                 redo:
                     glyph_t glyph = FT_Get_Char_Index(face, uc);
@@ -1579,11 +1533,6 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
     *nglyphs = glyph_pos;
     glyphs->numGlyphs = glyph_pos;
 
-#if !defined(QT_NO_FONTCONFIG)
-    if (mtx)
-        mtx->unlock();
-#endif
-
     if (flags & QTextEngine::GlyphIndicesOnly)
         return true;
 
@@ -1599,13 +1548,15 @@ void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlag
                    default_hint_style == HintLight ||
                    (flags & HB_ShaperFlag_UseDesignMetrics)) && FT_IS_SCALABLE(freetype->face);
     for (int i = 0; i < glyphs->numGlyphs; i++) {
-        Glyph *g = defaultGlyphSet.getGlyph(glyphs->glyphs[i]);
-        if (g) {
+        Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : 0;
+        // Since we are passing Format_None to loadGlyph, use same default format logic as loadGlyph
+        GlyphFormat acceptableFormat = (defaultFormat != Format_None) ? defaultFormat : Format_Mono;
+        if (g && g->format == acceptableFormat) {
             glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
         } else {
             if (!face)
                 face = lockFace();
-            g = loadGlyph(glyphs->glyphs[i], 0, Format_None, true);
+            g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
             glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
                                            : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
         }
@@ -1619,22 +1570,21 @@ void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlag
 
 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
 {
-
     FT_Face face = 0;
 
     glyph_metrics_t overall;
     // initialize with line height, we get the same behaviour on all platforms
     overall.y = -ascent();
-    overall.height = ascent() + descent() + 1;
+    overall.height = ascent() + descent();
 
     QFixed ymax = 0;
     QFixed xmax = 0;
     for (int i = 0; i < glyphs.numGlyphs; i++) {
-        Glyph *g = defaultGlyphSet.getGlyph(glyphs.glyphs[i]);
+        Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs.glyphs[i]) : 0;
         if (!g) {
             if (!face)
                 face = lockFace();
-            g = loadGlyph(glyphs.glyphs[i], 0, Format_None, true);
+            g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs.glyphs[i], 0, Format_None, true);
         }
         if (g) {
             QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
@@ -1643,7 +1593,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
             overall.y = qMin(overall.y, y);
             xmax = qMax(xmax, x + g->width);
             ymax = qMax(ymax, y + g->height);
-            overall.xoff += qRound(g->advance);
+            overall.xoff += g->advance;
         } else {
             int left  = FLOOR(face->glyph->metrics.horiBearingX);
             int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
@@ -1656,7 +1606,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
             overall.y = qMin(overall.y, y);
             xmax = qMax(xmax, x + TRUNC(right - left));
             ymax = qMax(ymax, y + TRUNC(top - bottom));
-            overall.xoff += qRound(TRUNC(ROUND(face->glyph->advance.x)));
+            overall.xoff += int(TRUNC(ROUND(face->glyph->advance.x)));
         }
     }
     overall.height = qMax(overall.height, ymax - overall.y);
@@ -1672,10 +1622,10 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
 {
     FT_Face face = 0;
     glyph_metrics_t overall;
-    Glyph *g = defaultGlyphSet.getGlyph(glyph);
+    Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : 0;
     if (!g) {
         face = lockFace();
-        g = loadGlyph(glyph, 0, Format_None, true);
+        g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, 0, Format_None, true);
     }
     if (g) {
         overall.x = g->x;
@@ -1707,57 +1657,65 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matr
     return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
 }
 
+static FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
+{
+    FT_Matrix m;
+
+    m.xx = FT_Fixed(matrix.m11() * 65536);
+    m.xy = FT_Fixed(-matrix.m21() * 65536);
+    m.yx = FT_Fixed(-matrix.m12() * 65536);
+    m.yy = FT_Fixed(matrix.m22() * 65536);
+
+    return m;
+}
+
 glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
 {
     FT_Face face = 0;
     glyph_metrics_t overall;
     QGlyphSet *glyphSet = 0;
-    if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
-        // TODO move everything here to a method of its own to access glyphSets
-        // to be shared with a new method that will replace loadTransformedGlyphSet()
-        FT_Matrix m;
-        m.xx = FT_Fixed(matrix.m11() * 65536);
-        m.xy = FT_Fixed(-matrix.m21() * 65536);
-        m.yx = FT_Fixed(-matrix.m12() * 65536);
-        m.yy = FT_Fixed(matrix.m22() * 65536);
-        for (int i = 0; i < transformedGlyphSets.count(); ++i) {
-            const QGlyphSet &g = transformedGlyphSets.at(i);
-            if (g.transformationMatrix.xx == m.xx
-                && g.transformationMatrix.xy == m.xy
-                && g.transformationMatrix.yx == m.yx
-                && g.transformationMatrix.yy == m.yy) {
-
-                // found a match, move it to the front
-                transformedGlyphSets.move(i, 0);
-                glyphSet = &transformedGlyphSets[0];
-                break;
+    FT_Matrix ftMatrix = QTransformToFTMatrix(matrix);
+    if (cacheEnabled) {
+        if (matrix.type() > QTransform::TxTranslate && FT_IS_SCALABLE(freetype->face)) {
+            // TODO move everything here to a method of its own to access glyphSets
+            // to be shared with a new method that will replace loadTransformedGlyphSet()
+            for (int i = 0; i < transformedGlyphSets.count(); ++i) {
+                const QGlyphSet &g = transformedGlyphSets.at(i);
+                if (g.transformationMatrix.xx == ftMatrix.xx
+                    && g.transformationMatrix.xy == ftMatrix.xy
+                    && g.transformationMatrix.yx == ftMatrix.yx
+                    && g.transformationMatrix.yy == ftMatrix.yy) {
+
+                    // found a match, move it to the front
+                    transformedGlyphSets.move(i, 0);
+                    glyphSet = &transformedGlyphSets[0];
+                    break;
+                }
             }
-        }
 
-        if (!glyphSet) {
-            // don't cache more than 10 transformations
-            if (transformedGlyphSets.count() >= 10) {
-                transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
-                freeServerGlyphSet(transformedGlyphSets.at(0).id);
-            } else {
-                transformedGlyphSets.prepend(QGlyphSet());
+            if (!glyphSet) {
+                // don't cache more than 10 transformations
+                if (transformedGlyphSets.count() >= 10) {
+                    transformedGlyphSets.move(transformedGlyphSets.size() - 1, 0);
+                } else {
+                    transformedGlyphSets.prepend(QGlyphSet());
+                }
+                glyphSet = &transformedGlyphSets[0];
+                glyphSet->clear();
+                glyphSet->transformationMatrix = ftMatrix;
             }
-            glyphSet = &transformedGlyphSets[0];
-            glyphSet->clear();
-            glyphSet->id = allocateServerGlyphSet();
-            glyphSet->transformationMatrix = m;
+            Q_ASSERT(glyphSet);
+        } else {
+            glyphSet = &defaultGlyphSet;
         }
-        Q_ASSERT(glyphSet);
-    } else {
-        glyphSet = &defaultGlyphSet;
     }
-    Glyph * g = glyphSet->getGlyph(glyph);
+    Glyph * g = glyphSet ? glyphSet->getGlyph(glyph) : 0;
     if (!g || g->format != format) {
         face = lockFace();
         FT_Matrix m = this->matrix;
-        FT_Matrix_Multiply(&glyphSet->transformationMatrix, &m);
+        FT_Matrix_Multiply(&ftMatrix, &m);
         freetype->matrix = m;
-        g = loadGlyph(glyphSet, glyph, subPixelPosition, format);
+        g = loadGlyph(glyphSet, glyph, subPixelPosition, format, false);
     }
 
     if (g) {
@@ -1783,14 +1741,121 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixe
     return overall;
 }
 
-QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
+QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
+                                              QFontEngine::GlyphFormat neededFormat,
+                                              const QTransform &t, QPoint *offset)
 {
+    Q_ASSERT(currentlyLockedAlphaMap.isNull());
     lockFace();
 
-    GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
+    if (isBitmapFont())
+        neededFormat = Format_Mono;
+    else if (neededFormat == Format_None && defaultFormat != Format_None)
+        neededFormat = defaultFormat;
+    else if (neededFormat == Format_None)
+        neededFormat = Format_A8;
+
+    QImage::Format format;
+    switch (neededFormat) {
+    case Format_Mono:
+        format = QImage::Format_Mono;
+        break;
+    case Format_A8:
+        format = QImage::Format_Indexed8;
+        break;
+    case Format_A32:
+        format = QImage::Format_ARGB32;
+        break;
+    default:
+        Q_ASSERT(false);
+        format = QImage::Format_Invalid;
+    };
+
+    QFontEngineFT::Glyph *glyph;
+    if (cacheEnabled) {
+        QFontEngineFT::QGlyphSet *gset = &defaultGlyphSet;
+        if (t.type() >= QTransform::TxScale) {
+            if (t.isAffine())
+                gset = loadTransformedGlyphSet(t);
+            else
+                gset = 0;
+        }
+
+        if (gset) {
+            FT_Matrix m = matrix;
+            FT_Matrix_Multiply(&gset->transformationMatrix, &m);
+            FT_Set_Transform(freetype->face, &m, 0);
+            freetype->matrix = m;
+        }
+
+        if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
+                                                         neededFormat)) {
+            return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
+                                                       offset);
+        }
+
+        glyph = gset->getGlyph(glyphIndex, subPixelPosition);
+    } else {
+        FT_Matrix m = matrix;
+        FT_Matrix extra = QTransformToFTMatrix(t);
+        FT_Matrix_Multiply(&extra, &m);
+        FT_Set_Transform(freetype->face, &m, 0);
+        freetype->matrix = m;
+        glyph = loadGlyph(0, glyphIndex, subPixelPosition, neededFormat);
+    }
+
+    if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
+        unlockFace();
+        return 0;
+    }
+
+    int pitch;
+    switch (neededFormat) {
+    case Format_Mono:
+        pitch = ((glyph->width + 31) & ~31) >> 3;
+        break;
+    case Format_A8:
+        pitch = (glyph->width + 3) & ~3;
+        break;
+    case Format_A32:
+        pitch = glyph->width * 4;
+        break;
+    default:
+        Q_ASSERT(false);
+        pitch = 0;
+    };
+
+    if (offset != 0)
+        *offset = QPoint(glyph->x, -glyph->y);
+
+    currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
+    Q_ASSERT(!currentlyLockedAlphaMap.isNull());
+
+    QImageData *data = currentlyLockedAlphaMap.data_ptr();
+    data->is_locked = true;
+
+    return &currentlyLockedAlphaMap;
+}
+
+void QFontEngineFT::unlockAlphaMapForGlyph()
+{
+    Q_ASSERT(!currentlyLockedAlphaMap.isNull());
+    unlockFace();
+    currentlyLockedAlphaMap = QImage();
+}
+
+QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format)
+{
+    return defaultGlyphSet.outline_drawing ? 0 :
+            loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, g, subPixelPosition, format);
+}
+
+QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
+{
+    lockFace();
 
-    Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
-    if (!glyph) {
+    Glyph *glyph = loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono);
+    if (!glyph || !glyph->data) {
         unlockFace();
         return QFontEngine::alphaMapForGlyph(g);
     }
@@ -1819,19 +1884,17 @@ QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
     return img;
 }
 
-QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, int margin, const QTransform &t)
+QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
 {
     if (t.type() > QTransform::TxTranslate)
-        return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
+        return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
 
     lockFace();
 
-    GlyphFormat glyph_format = Format_A32;
-
-    Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
-    if (!glyph) {
+    Glyph *glyph = loadGlyphFor(g, subPixelPosition, Format_A32);
+    if (!glyph || !glyph->data) {
         unlockFace();
-        return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
+        return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
     }
 
     QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
@@ -1893,7 +1956,7 @@ FT_Face QFontEngineFT::non_locked_face() const
 
 
 QFontEngineFT::QGlyphSet::QGlyphSet()
-    : id(0), outline_drawing(false)
+    : outline_drawing(false)
 {
     transformationMatrix.xx = 0x10000;
     transformationMatrix.yy = 0x10000;
@@ -1948,16 +2011,6 @@ void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition,
     }
 }
 
-unsigned long QFontEngineFT::allocateServerGlyphSet()
-{
-    return 0;
-}
-
-void QFontEngineFT::freeServerGlyphSet(unsigned long id)
-{
-    Q_UNUSED(id);
-}
-
 HB_Error QFontEngineFT::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
 {
     lockFace();
@@ -1983,9 +2036,9 @@ bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
     antialias = fe->antialias;
     transform = fe->transform;
     embolden = fe->embolden;
+    obliquen = fe->obliquen;
     subpixelType = fe->subpixelType;
     lcdFilterType = fe->lcdFilterType;
-    canUploadGlyphsToServer = fe->canUploadGlyphsToServer;
     embeddedbitmap = fe->embeddedbitmap;
 
     return true;
@@ -1993,7 +2046,7 @@ bool QFontEngineFT::initFromFontEngine(const QFontEngineFT *fe)
 
 QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
 {
-    QFontDef fontDef;
+    QFontDef fontDef(this->fontDef);
     fontDef.pixelSize = pixelSize;
     QFontEngineFT *fe = new QFontEngineFT(fontDef);
     if (!fe->initFromFontEngine(this)) {