148
158
QFreetypeFace *freetype = freetypeFaces->value(face_id, 0);
160
freetype = new QFreetypeFace;
151
if (FT_New_Face(library, face_id.filename, face_id.index, &face))
162
QFile file(QString::fromUtf8(face_id.filename));
163
if (face_id.filename.startsWith(":qmemoryfonts/")) {
164
// from qfontdatabase_x11.cpp
165
extern QByteArray qt_fontdata_from_index(int);
166
QByteArray idx = face_id.filename;
167
idx.remove(0, 14); // remove ':qmemoryfonts/'
169
freetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
171
freetype->fontData = QByteArray();
172
} else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
173
if (!file.open(QIODevice::ReadOnly)) {
177
freetype->fontData = file.readAll();
179
if (!freetype->fontData.isEmpty()) {
180
if (FT_New_Memory_Face(library, (const FT_Byte *)freetype->fontData.constData(), freetype->fontData.size(), face_id.index, &face)) {
184
} else if (FT_New_Face(library, face_id.filename, face_id.index, &face)) {
153
freetype = new QFreetypeFace;
154
188
freetype->face = face;
155
189
freetype->ref = 0;
156
190
freetype->_lock = 0;
396
435
QPointF cp = point.toPointF();
398
uchar *src = slot->bitmap.buffer;
399
int h = slot->bitmap.rows;
400
int w = slot->bitmap.width;
401
for (int y = 0; y < h; ++y) {
402
for (int x = 0; x < w; ++x) {
403
uchar pixel = src[x >> 3];
408
if (pixel & (0x80 >> (x & 7))) {
410
while (x < w && src[(x+1) >> 3] & (0x80 >> ((x+1) & 7)))
412
path->addRect(QRectF(cp.x() + rx + TRUNC(slot->metrics.horiBearingX),
413
cp.y() + y - TRUNC(slot->metrics.horiBearingY),
417
src += slot->bitmap.pitch;
436
qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
437
slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
421
440
#endif // QT_NO_FREETYPE
475
494
if (((font_path[i])[0] != '/') && !xfsconfig_read) {
476
495
// We're using xfs -> read its config
477
496
bool finished = false;
478
QFile f("/etc/X11/fs/config");
480
f.setFileName("/usr/X11R6/lib/X11/fs/config");
482
f.setFileName("/usr/X11/lib/X11/fs/config");
497
QFile f(QLatin1String("/etc/X11/fs/config"));
499
f.setFileName(QLatin1String("/usr/X11R6/lib/X11/fs/config"));
501
f.setFileName(QLatin1String("/usr/X11/lib/X11/fs/config"));
483
502
if (f.exists()) {
484
503
f.open(QIODevice::ReadOnly);
485
504
while (f.error()==QFile::NoError && !finished) {
486
QString fs = f.readLine(1024);
505
QString fs = QString::fromLocal8Bit(f.readLine(1024));
488
if (fs.left(9)=="catalogue" && fs.contains('=')) {
489
fs = fs.mid(fs.indexOf('=') + 1).trimmed();
507
if (fs.left(9)==QLatin1String("catalogue") && fs.contains(QLatin1Char('='))) {
508
fs = fs.mid(fs.indexOf(QLatin1Char('=')) + 1).trimmed();
490
509
bool end = false;
491
510
while (f.error()==QFile::NoError && !end) {
492
if (fs[int(fs.length())-1] == ',')
511
if (fs[int(fs.length())-1] == QLatin1Char(','))
493
512
fs = fs.left(fs.length()-1);
497
fs = fs.left(fs.indexOf(":unscaled"));
516
fs = fs.left(fs.indexOf(QLatin1String(":unscaled")));
517
if (fs[0] != QLatin1Char('#'))
500
fs = f.readLine(1024);
519
fs = QLatin1String(f.readLine(1024));
501
520
fs = fs.trimmed();
502
521
if (fs.isEmpty())
547
566
QByteArray best_mapping;
549
568
for (QStringList::ConstIterator it = fontpath.constBegin(); it != fontpath.constEnd(); ++it) {
550
if ((*it).left(1) != "/")
569
if ((*it).left(1) != QLatin1String("/"))
551
570
continue; // not a path name, a font server
552
571
QString fontmapname;
554
573
// search font.dir and font.scale for the right file
555
574
while (num < 2) {
557
fontmapname = (*it) + "/fonts.scale";
576
fontmapname = (*it) + QLatin1String("/fonts.scale");
559
fontmapname = (*it) + "/fonts.dir";
578
fontmapname = (*it) + QLatin1String("/fonts.dir");
561
580
//qWarning(fontmapname);
562
581
QFile fontmap(fontmapname);
1079
1110
// Multi FT engine
1080
1111
// ------------------------------------------------------------------
1082
QFontEngineMultiFT::QFontEngineMultiFT(FcFontSet *fs, int s, const QFontDef &request)
1083
: QFontEngineMulti(fs->nfont), fontSet(fs), screen(s)
1113
static QFontEngine *engineForPattern(FcPattern *pattern, const QFontDef &request,
1117
FcPattern *match = FcFontMatch(0, pattern, &res);
1118
QFontEngineFT *engine = new QFontEngineFT(match, request, screen);
1119
if (!engine->invalid())
1123
QFontEngine *fe = new QFontEngineBox(request.pixelSize);
1124
fe->fontDef = request;
1128
QFontEngineMultiFT::QFontEngineMultiFT(QFontEngine *fe, FcPattern *p, int s, const QFontDef &req)
1129
: QFontEngineMulti(2), request(req), pattern(p), fontSet(0), screen(s)
1133
engines.at(0)->ref.ref();
1087
1134
fontDef = engines[0]->fontDef;
1088
1135
cache_cost = 100;
1091
1138
QFontEngineMultiFT::~QFontEngineMultiFT()
1093
FcFontSetDestroy(fontSet);
1140
FcPatternDestroy(pattern);
1142
FcFontSetDestroy(fontSet);
1096
1146
void QFontEngineMultiFT::loadEngine(int at)
1098
Q_ASSERT(at < engines.size());
1099
Q_ASSERT(engines.at(at) == 0);
1100
FcPattern *pattern = fontSet->fonts[at];
1148
extern void qt_addPatternProps(FcPattern *pattern, int screen, int script,
1149
const QFontDef &request);
1101
1150
extern QFontDef qt_FcPatternToQFontDef(FcPattern *pattern, const QFontDef &);
1102
QFontDef fontDef = qt_FcPatternToQFontDef(fontSet->fonts[at], this->fontDef);
1151
extern FcFontSet *qt_fontSetForPattern(FcPattern *pattern, const QFontDef &request);
1155
fontSet = qt_fontSetForPattern(pattern, request);
1156
engines.resize(fontSet->nfont);
1158
Q_ASSERT(at < engines.size());
1159
Q_ASSERT(engines.at(at) == 0);
1161
FcPattern *pattern = FcPatternDuplicate(fontSet->fonts[at]);
1162
qt_addPatternProps(pattern, screen, QUnicodeTables::Common, request);
1164
QFontDef fontDef = qt_FcPatternToQFontDef(pattern, this->request);
1103
1166
// note: we use -1 for the script to make sure that we keep real
1104
1167
// FT engines separate from Multi engines in the font cache
1105
1168
QFontCache::Key key(fontDef, -1, screen);
1107
1170
if (!fontEngine) {
1108
1171
FcConfigSubstitute(0, pattern, FcMatchPattern);
1109
1172
FcDefaultSubstitute(pattern);
1111
FcPattern *match = FcFontMatch(0, pattern, &res);
1112
QFontEngineFT *engine = new QFontEngineFT(match, fontDef, screen);
1113
if (engine->invalid())
1116
fontEngine = engine;
1118
fontEngine = new QFontEngineBox(fontDef.pixelSize);
1119
fontEngine->fontDef = fontDef;
1173
fontEngine = engineForPattern(pattern, request, screen);
1174
FcPatternDestroy(pattern);
1121
1175
QFontCache::instance->insertEngine(key, fontEngine);
1123
1177
fontEngine->ref.ref();
1182
1237
face_id = ::face_id(pattern);
1184
1239
freetype = QFreetypeFace::getFace(face_id);
1185
1246
if (!freetype->charset) {
1187
1248
FcPatternGetCharSet (pattern, FC_CHARSET, 0, &cs);
1188
1249
freetype->charset = FcCharSetCopy(cs);
1251
symbol = freetype->symbol_map != 0;
1191
1253
lbearing = rbearing = SHRT_MIN;
1192
freetype->computeSize(fontDef, &xsize, &ysize);
1193
outline_drawing = xsize > (64<<6) || ysize > (64<<6);
1254
freetype->computeSize(fontDef, &xsize, &ysize, &outline_drawing);
1195
1256
FT_Face face = lockFace();
1233
1294
|| subpixel == FC_RGBA_VRGB
1234
1295
|| subpixel == FC_RGBA_VBGR)
1235
1296
format = PictStandardARGB32;
1236
glyphSet = XRenderCreateGlyphSet(X11->display,
1237
XRenderFindStandardFormat(X11->display, format));
1297
fnt.glyphSet = XRenderCreateGlyphSet(X11->display,
1298
XRenderFindStandardFormat(X11->display, format));
1238
1299
xglyph_format = format;
1247
1306
QFontEngineFT::~QFontEngineFT()
1297
1351
{ 16, 60, 180 }
1301
QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(uint glyph, GlyphFormat format) const
1354
QFontEngineFT::Font::Font()
1355
#ifndef QT_NO_XRENDER
1359
transformationMatrix.xx = 0x10000;
1360
transformationMatrix.yy = 0x10000;
1361
transformationMatrix.xy = 0;
1362
transformationMatrix.yx = 0;
1365
QFontEngineFT::Font::~Font()
1367
qDeleteAll(glyph_data);
1368
#ifndef QT_NO_XRENDER
1370
XRenderFreeGlyphSet(X11->display, glyphSet);
1374
QFontEngineFT::Glyph *QFontEngineFT::Font::loadGlyph(const QFontEngineFT *fe, uint glyph, GlyphFormat format) const
1303
1376
// Q_ASSERT(freetype->lock == 1);
1307
1380
format = Format_Mono;
1308
1381
if (X11->use_xrender) {
1309
1382
add_to_glyphset = true;
1310
if (subpixel != FC_RGBA_NONE)
1383
if (fe->subpixel != FC_RGBA_NONE)
1311
1384
format = Format_A32;
1385
else if (fe->antialias)
1313
1386
format = Format_A8;
1316
1389
Q_ASSERT(format != Format_None);
1390
bool hsubpixel = false;
1318
1391
int vfactor = 1;
1319
1392
int load_flags = FT_LOAD_DEFAULT;
1320
if (outline_drawing) {
1393
if (fe->outline_drawing) {
1321
1394
load_flags = FT_LOAD_NO_BITMAP|FT_LOAD_NO_HINTING;
1322
1395
} else if (format == Format_Mono) {
1323
1396
load_flags |= FT_LOAD_TARGET_MONO;
1324
1397
} else if (format == Format_A32) {
1325
if (subpixel == FC_RGBA_RGB || subpixel == FC_RGBA_BGR) {
1398
if (fe->subpixel == FC_RGBA_RGB || fe->subpixel == FC_RGBA_BGR) {
1326
1399
load_flags |= FT_LOAD_TARGET_LCD;
1328
} else if (subpixel == FC_RGBA_VRGB || subpixel == FC_RGBA_VBGR) {
1401
} else if (fe->subpixel == FC_RGBA_VRGB || fe->subpixel == FC_RGBA_VBGR) {
1329
1402
load_flags |= FT_LOAD_TARGET_LCD_V;
1335
1408
load_flags |= FT_LOAD_NO_BITMAP;
1337
1410
#ifdef FC_HINT_STYLE
1338
if (hint_style == FC_HINT_NONE)
1411
if (fe->hint_style == FC_HINT_NONE)
1339
1412
load_flags |= FT_LOAD_NO_HINTING;
1340
else if (hint_style < FC_HINT_FULL)
1413
else if (fe->hint_style < FC_HINT_FULL)
1341
1414
load_flags |= FT_LOAD_TARGET_LIGHT;
1344
1417
#ifdef FT_LOAD_FORCE_AUTOHINT
1346
1419
load_flags |= FT_LOAD_FORCE_AUTOHINT;
1422
bool transform = fe->transform
1423
|| transformationMatrix.xx != 0x10000
1424
|| transformationMatrix.yy != 0x10000
1425
|| transformationMatrix.xy != 0
1426
|| transformationMatrix.yx != 0;
1350
1429
load_flags |= FT_LOAD_NO_BITMAP;
1430
1515
} XGlyphInfoDummy;
1431
1516
XGlyphInfoDummy info;
1433
info.width = TRUNC(right - left);
1518
info.width = hpixels;
1434
1519
info.height = TRUNC(top - bottom);
1435
1520
info.x = -TRUNC(left);
1436
1521
info.y = TRUNC(top);
1437
1522
info.xOff = TRUNC(ROUND(slot->advance.x));
1440
1529
int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1441
1530
(format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1442
int size = pitch * info.height * vfactor;
1443
uchar *buffer = new uchar[size];
1444
memset (buffer, 0, size);
1531
int size = pitch * info.height;
1532
uchar *glyph_buffer = new uchar[size];
1446
1534
if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1447
1535
FT_Bitmap bitmap;
1448
1536
bitmap.rows = info.height*vfactor;
1449
bitmap.width = info.width*hfactor;
1450
bitmap.pitch = pitch;
1451
bitmap.buffer = buffer;
1537
bitmap.width = hpixels;
1538
bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
1539
if (!hsubpixel && vfactor == 1)
1540
bitmap.buffer = glyph_buffer;
1542
bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
1543
memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1452
1544
bitmap.pixel_mode = format == Format_Mono ? ft_pixel_mode_mono : ft_pixel_mode_grays;
1453
1545
FT_Matrix matrix;
1454
matrix.xx = hfactor << 16;
1546
matrix.xx = (hsubpixel ? 3 : 1) << 16;
1455
1547
matrix.yy = vfactor << 16;
1456
1548
matrix.yx = matrix.xy = 0;
1458
1550
FT_Outline_Transform(&slot->outline, &matrix);
1459
FT_Outline_Translate (&slot->outline, -left*hfactor, -bottom*vfactor);
1551
FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1460
1552
FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1462
1554
Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1463
Q_ASSERT(antialias);
1464
uchar *src = buffer;
1465
size = info.width * 4 * info.height;
1466
uchar *newBuf = new uchar[size];
1467
uint *dst = (uint *)newBuf;
1555
Q_ASSERT(fe->antialias);
1556
const uchar *src = bitmap.buffer;
1557
uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
1558
uchar *c = convoluted;
1559
// convolute the bitmap with a triangle filter to get rid of color fringes
1560
// If we take account for a gamma value of 2, we end up with
1561
// weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
1562
// as this nicely sums up to 16 :)
1468
1563
int h = info.height;
1469
if (subpixel == FC_RGBA_RGB) {
1567
for (int x = 2; x < bitmap.width - 2; ++x) {
1568
uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
1569
c[x] = (uchar) (sum >> 4);
1571
c[bitmap.width - 2] = c[bitmap.width -1] = 0;
1572
src += bitmap.pitch;
1576
uint *dst = (uint *)glyph_buffer;
1579
if (fe->subpixel == FC_RGBA_RGB) {
1471
1581
uint *dd = dst;
1472
for (int x = 0; x < bitmap.width; x += 3) {
1582
for (int x = 1; x < bitmap.width - 1; x += 3) {
1473
1583
uint red = src[x];
1474
1584
uint green = src[x+1];
1475
1585
uint blue = src[x+2];
1476
uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
1477
uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
1478
uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
1479
uint res = (high << 16) + (mid << 8) + low;
1586
uint res = (red << 16) + (green << 8) + blue;
1556
1658
src += slot->bitmap.pitch;
1559
if (hfactor != 1 || vfactor != 1) {
1561
uint *dd = (uint *)dst;
1562
for (int x = 0; x < slot->bitmap.width; x++) {
1563
unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1564
*dd++ = (a << 16) | (a << 8) | a;
1663
uint *dd = (uint *)dst;
1665
for (int x = 0; x < slot->bitmap.width; x++) {
1666
uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1671
src += slot->bitmap.pitch;
1673
} else if (vfactor != 1) {
1675
uint *dd = (uint *)dst;
1676
for (int x = 0; x < slot->bitmap.width; x++) {
1677
uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
1567
1681
src += slot->bitmap.pitch;
1758
#ifndef QT_NO_XRENDER
1759
bool QFontEngineFT::loadTransformedGlyphSet(glyph_t *glyphs, int num_glyphs, const QMatrix &matrix, GlyphSet *gs)
1761
// don't try to load huge fonts
1762
if (fontDef.pixelSize * sqrt(matrix.det()) >= 64) {
1768
m.xx = FT_Fixed(matrix.m11() * 65536);
1769
m.xy = FT_Fixed(-matrix.m21() * 65536);
1770
m.yx = FT_Fixed(-matrix.m12() * 65536);
1771
m.yy = FT_Fixed(matrix.m22() * 65536);
1775
for (int i = 0; i < transformedFonts.count(); ++i) {
1776
const Font &f = transformedFonts.at(i);
1777
if (f.transformationMatrix.xx == m.xx
1778
&& f.transformationMatrix.xy == m.xy
1779
&& f.transformationMatrix.yx == m.yx
1780
&& f.transformationMatrix.yy == m.yy) {
1782
// found a match, move it to the front
1783
transformedFonts.move(i, 0);
1784
font = &transformedFonts[0];
1790
// don't cache more than 10 transformations
1791
if (transformedFonts.count() >= 10) {
1792
transformedFonts.move(transformedFonts.size() - 1, 0);
1793
XRenderFreeGlyphSet(X11->display, transformedFonts.at(0).glyphSet);
1795
transformedFonts.prepend(Font());
1797
font = &transformedFonts[0];
1799
qDeleteAll(font->glyph_data);
1800
font->glyph_data.clear();
1802
font->glyphSet = XRenderCreateGlyphSet(X11->display,
1803
XRenderFindStandardFormat(X11->display, xglyph_format));
1805
font->transformationMatrix = m;
1809
bool lockedFace = false;
1811
for (int i = 0; i < num_glyphs; ++i) {
1812
if (!font->glyph_data.contains(glyphs[i])) {
1816
FT_Matrix_Multiply(&font->transformationMatrix, &m);
1817
FT_Set_Transform(face, &m, 0);
1818
freetype->matrix = m;
1821
if (!font->loadGlyph(this, glyphs[i])) {
1822
FT_Set_Transform(face, &freetype->matrix, 0);
1828
*gs = font->glyphSet;
1831
FT_Set_Transform(face, &freetype->matrix, 0);
1645
1839
inline unsigned int getChar(const QChar *str, int &i, const int len)
2101
QImage QFontEngineFT::alphaMapForGlyph(glyph_t g)
2105
Glyph *glyph = loadGlyph(g, Format_A8);
2108
return QFontEngine::alphaMapForGlyph(g);
2111
Q_ASSERT(glyph->format == QFontEngineFT::Format_A8);
2113
const int pitch = (glyph->width + 3) & ~3;
2115
QImage img(glyph->width, glyph->height, QImage::Format_Indexed8);
2116
QVector<QRgb> colors(256);
2117
for (int i=0; i<256; ++i)
2118
colors[i] = qRgba(0, 0, 0, i);
2119
img.setColorTable(colors);
2121
for (int y = 0; y < glyph->height; ++y)
2122
memcpy(img.scanLine(y), &glyph->data[y * pitch], glyph->width);
1903
2128
QFixed QFontEngineFT::ascent() const
1905
2130
return QFixed::fromFixed(metrics.ascender);
1918
2143
QFixed QFontEngineFT::xHeight() const
1920
TT_PCLT *pct = (TT_PCLT *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_pclt);
1921
if (pct && pct->xHeight) {
1922
return QFixed(pct->xHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
2145
TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
2146
if (os2 && os2->sxHeight)
2147
return QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1924
2148
return QFontEngine::xHeight();
2151
QFixed QFontEngineFT::averageCharWidth() const
2153
TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
2154
if (os2 && os2->xAvgCharWidth)
2155
return QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
2156
return QFontEngine::averageCharWidth();
1928
2160
qreal QFontEngineFT::maxCharWidth() const