/****************************************************************************
**
-** 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_END_LICENSE$
**
****************************************************************************/
#ifndef QT_NO_FREETYPE
#include "qfile.h"
-#include "qabstractfileengine.h"
+#include "qfileinfo.h"
#include "qthreadstorage.h"
#include <qmath.h>
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.
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;
}
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;
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()
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)
{
unlockFace();
fsType = freetype->fsType();
- defaultGlyphSet.id = allocateServerGlyphSet();
return true;
}
{
// 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)
+ return g;
QFontEngineFT::GlyphInfo info;
if (err != FT_Err_Ok)
qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
- if (set->outline_drawing && fetchMetricsOnly)
+ if ((!set || set->outline_drawing) && fetchMetricsOnly)
return 0;
FT_GlyphSlot slot = face->glyph;
if (!g) {
g = new Glyph;
- g->uploadedToServer = false;
g->data = 0;
}
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;
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
88,
89,
91,
+ 95,
102,
114,
124,
// 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;
}
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();
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) {
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) {
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
{
*nglyphs = glyph_pos;
glyphs->numGlyphs = glyph_pos;
-#if !defined(QT_NO_FONTCONFIG)
- if (mtx)
- mtx->unlock();
-#endif
-
if (flags & QTextEngine::GlyphIndicesOnly)
return true;
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]);
+ Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyphs->glyphs[i]) : 0;
if (g) {
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();
}
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;
{
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;
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) {
else if (neededFormat == Format_None)
neededFormat = Format_A8;
- QFontEngineFT::QGlyphSet *gset = defaultGlyphs();
- if (t.type() >= QTransform::TxScale) {
- if (t.isAffine())
- gset = loadTransformedGlyphSet(t);
- else
- gset = 0;
- }
-
- if (!gset || gset->outline_drawing || !loadGlyph(gset, glyphIndex, subPixelPosition,
- neededFormat)) {
- unlockFace();
- return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
- offset);
- }
-
QImage::Format format;
switch (neededFormat) {
- case QFontEngine::Format_Mono:
+ case Format_Mono:
format = QImage::Format_Mono;
break;
- case QFontEngine::Format_A8:
+ case Format_A8:
format = QImage::Format_Indexed8;
break;
- case QFontEngine::Format_A32:
+ case Format_A32:
format = QImage::Format_ARGB32;
break;
default:
format = QImage::Format_Invalid;
};
- QFontEngineFT::Glyph *glyph = gset->getGlyph(glyphIndex, subPixelPosition);
+ 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 QFontEngineFT::Format_Mono:
+ case Format_Mono:
pitch = ((glyph->width + 31) & ~31) >> 3;
break;
- case QFontEngineFT::Format_A8:
+ case Format_A8:
pitch = (glyph->width + 3) & ~3;
break;
- case QFontEngineFT::Format_A32:
+ case Format_A32:
pitch = glyph->width * 4;
break;
default:
if (offset != 0)
*offset = QPoint(glyph->x, -glyph->y);
-
currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
Q_ASSERT(!currentlyLockedAlphaMap.isNull());
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();
- GlyphFormat glyph_format = antialias ? Format_A8 : Format_Mono;
-
- Glyph *glyph = defaultGlyphSet.outline_drawing ? 0 : loadGlyph(g, subPixelPosition, glyph_format);
+ Glyph *glyph = loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono);
if (!glyph) {
unlockFace();
return QFontEngine::alphaMapForGlyph(g);
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);
+ Glyph *glyph = loadGlyphFor(g, subPixelPosition, Format_A32);
if (!glyph) {
unlockFace();
- return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, margin, t);
+ return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
}
QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
QFontEngineFT::QGlyphSet::QGlyphSet()
- : id(0), outline_drawing(false)
+ : outline_drawing(false)
{
transformationMatrix.xx = 0x10000;
transformationMatrix.yy = 0x10000;
}
}
-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();
obliquen = fe->obliquen;
subpixelType = fe->subpixelType;
lcdFilterType = fe->lcdFilterType;
- canUploadGlyphsToServer = fe->canUploadGlyphsToServer;
embeddedbitmap = fe->embeddedbitmap;
return true;
QFontEngine *QFontEngineFT::cloneWithSize(qreal pixelSize) const
{
- QFontDef fontDef;
+ QFontDef fontDef(this->fontDef);
fontDef.pixelSize = pixelSize;
QFontEngineFT *fe = new QFontEngineFT(fontDef);
if (!fe->initFromFontEngine(this)) {