1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
44 // #define FONTENGINE_DEBUG
46 #include <qapplication.h>
47 #include <qbytearray.h>
49 #include <qtextcodec.h>
52 #include "qfontdatabase.h"
53 #include "qpaintdevice.h"
55 #include "qvarlengtharray.h"
57 #include "qsettings.h"
60 #include <private/qpaintengine_x11_p.h>
63 #include "qfontengine_p.h"
66 #include <private/qpainter_p.h>
67 #include <private/qunicodetables_p.h>
69 #include <private/qt_x11_p.h>
70 #include <private/qpixmap_x11_p.h>
71 #include "qx11info_x11.h"
72 #include "qfontengine_x11_p.h"
77 #if defined(FT_LCD_FILTER_H)
78 #include FT_LCD_FILTER_H
81 #if defined(FC_LCD_FILTER)
83 #ifndef FC_LCD_FILTER_NONE
84 #define FC_LCD_FILTER_NONE FC_LCD_NONE
87 #ifndef FC_LCD_FILTER_DEFAULT
88 #define FC_LCD_FILTER_DEFAULT FC_LCD_DEFAULT
91 #ifndef FC_LCD_FILTER_LIGHT
92 #define FC_LCD_FILTER_LIGHT FC_LCD_LIGHT
95 #ifndef FC_LCD_FILTER_LEGACY
96 #define FC_LCD_FILTER_LEGACY FC_LCD_LEGACY
104 // ------------------------------------------------------------------
106 // ------------------------------------------------------------------
108 QFontEngineMultiXLFD::QFontEngineMultiXLFD(const QFontDef &r, const QList<int> &l, int s)
109 : QFontEngineMulti(l.size()), encodings(l), screen(s), request(r)
112 fontDef = engines[0]->fontDef;
115 QFontEngineMultiXLFD::~QFontEngineMultiXLFD()
118 void QFontEngineMultiXLFD::loadEngine(int at)
120 Q_ASSERT(at < engines.size());
121 Q_ASSERT(engines.at(at) == 0);
122 const int encoding = encodings.at(at);
123 QFontEngine *fontEngine = QFontDatabase::loadXlfd(0, QUnicodeTables::Common, request, encoding);
124 Q_ASSERT(fontEngine != 0);
125 fontEngine->ref.ref();
126 engines[at] = fontEngine;
129 // ------------------------------------------------------------------
131 // ------------------------------------------------------------------
133 #ifndef QT_NO_FREETYPE
135 static QStringList *qt_fontpath = 0;
137 static QStringList fontPath()
142 // append qsettings fontpath
143 QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
144 settings.beginGroup(QLatin1String("Qt"));
146 QStringList fontpath;
150 font_path = XGetFontPath(X11->display, &npaths);
151 bool xfsconfig_read = false;
152 for (int i=0; i<npaths; i++) {
153 // If we're using xfs, append font paths from /etc/X11/fs/config
154 // can't hurt, and chances are we'll get all fonts that way.
155 if (((font_path[i])[0] != '/') && !xfsconfig_read) {
156 // We're using xfs -> read its config
157 bool finished = false;
158 QFile f(QLatin1String("/etc/X11/fs/config"));
160 f.setFileName(QLatin1String("/usr/X11R6/lib/X11/fs/config"));
162 f.setFileName(QLatin1String("/usr/X11/lib/X11/fs/config"));
164 f.open(QIODevice::ReadOnly);
165 while (f.error()==QFile::NoError && !finished) {
166 QString fs = QString::fromLocal8Bit(f.readLine(1024));
168 if (fs.left(9)==QLatin1String("catalogue") && fs.contains(QLatin1Char('='))) {
169 fs = fs.mid(fs.indexOf(QLatin1Char('=')) + 1).trimmed();
171 while (f.error()==QFile::NoError && !end) {
172 if (fs[int(fs.length())-1] == QLatin1Char(','))
173 fs = fs.left(fs.length()-1);
177 fs = fs.left(fs.indexOf(QLatin1String(":unscaled")));
178 if (fs[0] != QLatin1Char('#'))
180 fs = QLatin1String(f.readLine(1024));
190 xfsconfig_read = true;
192 QString fs = QString::fromLocal8Bit(font_path[i]);
193 fontpath += fs.left(fs.indexOf(QLatin1String(":unscaled")));
196 XFreeFontPath(font_path);
198 // append qsettings fontpath
199 QStringList fp = settings.value(QLatin1String("fontPath")).toStringList();
203 qt_fontpath = new QStringList(fontpath);
207 static QFontEngine::FaceId fontFile(const QByteArray &_xname, QFreetypeFace **freetype, int *synth)
212 QByteArray xname = _xname.toLower();
216 while (minus < 5 && (pos = xname.indexOf('-', pos + 1)))
218 QByteArray searchname = xname.left(pos);
219 while (minus < 12 && (pos = xname.indexOf('-', pos + 1)))
221 QByteArray encoding = xname.mid(pos + 1);
222 //qDebug("xname='%s', searchname='%s', encoding='%s'", xname.data(), searchname.data(), encoding.data());
223 QStringList fontpath = fontPath();
224 QFontEngine::FaceId face_id;
227 QByteArray best_mapping;
229 for (QStringList::ConstIterator it = fontpath.constBegin(); it != fontpath.constEnd(); ++it) {
230 if (!(*it).startsWith(QLatin1Char('/')))
231 continue; // not a path name, a font server
234 // search font.dir and font.scale for the right file
237 fontmapname = (*it) + QLatin1String("/fonts.scale");
239 fontmapname = (*it) + QLatin1String("/fonts.dir");
241 //qWarning(fontmapname);
242 QFile fontmap(fontmapname);
243 if (!fontmap.open(QIODevice::ReadOnly))
245 while (!fontmap.atEnd()) {
246 QByteArray mapping = fontmap.readLine();
247 QByteArray lmapping = mapping.toLower();
249 //qWarning(xfontname);
251 if (!lmapping.contains(searchname))
253 int index = mapping.indexOf(' ');
254 QByteArray ffn = mapping.mid(0,index);
255 // remove bitmap formats freetype can't handle
256 if (ffn.contains(".spd") || ffn.contains(".phont"))
258 bool best_match = false;
259 if (!best_mapping.isEmpty()) {
260 if (lmapping.contains("-0-0-0-0-")) { // scalable font
264 if (lmapping.contains(encoding) && !best_mapping.toLower().contains(encoding))
270 int colon = ffn.lastIndexOf(':');
272 QByteArray s = ffn.left(colon);
273 ffn = ffn.mid(colon + 1);
274 if (s.contains("ds="))
275 *synth |= QFontEngine::SynthesizedBold;
276 if (s.contains("ai="))
277 *synth |= QFontEngine::SynthesizedItalic;
279 face_id.filename = (*it).toLocal8Bit() + '/' + ffn;
280 best_mapping = mapping;
287 // qDebug("fontfile for %s is from '%s'\n got %s synth=%d", xname.data(),
288 // best_mapping.data(), face_id.filename.data(), *synth);
289 *freetype = QFreetypeFace::getFace(face_id);
292 face_id.filename = QByteArray();
297 #endif // QT_NO_FREETYPE
299 // defined in qfontdatabase_x11.cpp
300 extern int qt_mib_for_xlfd_encoding(const char *encoding);
301 extern int qt_xlfd_encoding_id(const char *encoding);
303 static inline XCharStruct *charStruct(XFontStruct *xfs, uint ch)
305 XCharStruct *xcs = 0;
306 unsigned char r = ch>>8;
307 unsigned char c = ch&0xff;
309 r >= xfs->min_byte1 &&
310 r <= xfs->max_byte1 &&
311 c >= xfs->min_char_or_byte2 &&
312 c <= xfs->max_char_or_byte2) {
313 xcs = xfs->per_char + ((r - xfs->min_byte1) *
314 (xfs->max_char_or_byte2 -
315 xfs->min_char_or_byte2 + 1)) +
316 (c - xfs->min_char_or_byte2);
317 if (xcs->width == 0 && xcs->ascent == 0 && xcs->descent == 0)
323 QFontEngineXLFD::QFontEngineXLFD(XFontStruct *fs, const QByteArray &name, int mib)
324 : _fs(fs), _name(name), _codec(0), _cmap(mib)
326 if (_cmap) _codec = QTextCodec::codecForMib(_cmap);
328 cache_cost = (((fs->max_byte1 - fs->min_byte1) *
329 (fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1)) +
330 fs->max_char_or_byte2 - fs->min_char_or_byte2);
331 cache_cost = ((fs->max_bounds.ascent + fs->max_bounds.descent) *
332 (fs->max_bounds.width * cache_cost / 8));
340 QFontEngineXLFD::~QFontEngineXLFD()
342 XFreeFont(QX11Info::display(), _fs);
344 #ifndef QT_NO_FREETYPE
346 freetype->release(face_id);
350 bool QFontEngineXLFD::stringToCMap(const QChar *s, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
352 if (*nglyphs < len) {
357 // filter out surrogates, we can't handle them anyway with XLFD fonts
358 QVarLengthArray<ushort> _s(len);
359 QChar *str = (QChar *)_s.data();
360 for (int i = 0; i < len; ++i) {
362 && s[i].unicode() >= 0xd800 && s[i].unicode() < 0xdc00
363 && s[i+1].unicode() >= 0xdc00 && s[i].unicode() < 0xe000) {
372 len = str - (QChar *)_s.data();
373 str = (QChar *)_s.data();
375 bool mirrored = flags & QTextEngine::RightToLeft;
377 bool haveNbsp = false;
378 for (int i = 0; i < len; i++)
379 if (str[i].unicode() == 0xa0) {
384 QVarLengthArray<unsigned short> ch(len);
385 QChar *chars = (QChar *)ch.data();
386 if (haveNbsp || mirrored) {
387 for (int i = 0; i < len; i++)
388 chars[i] = (str[i].unicode() == 0xa0 ? 0x20 :
389 (mirrored ? QChar::mirroredChar(str[i].unicode()) : str[i].unicode()));
391 for (int i = 0; i < len; i++)
392 chars[i] = str[i].unicode();
394 QTextCodec::ConverterState state;
395 state.flags = QTextCodec::ConvertInvalidToNull;
396 QByteArray ba = _codec->fromUnicode(chars, len, &state);
397 if (ba.length() == 2*len) {
398 // double byte encoding
399 const uchar *data = (const uchar *)ba.constData();
400 for (int i = 0; i < len; i++) {
401 glyphs->glyphs[i] = ((ushort)data[0] << 8) + data[1];
405 const uchar *data = (const uchar *)ba.constData();
406 for (int i = 0; i < len; i++)
407 glyphs->glyphs[i] = (ushort)data[i];
411 const QChar *c = str + len;
414 glyphs->glyphs[--i] = (--c)->unicode() == 0xa0 ? 0x20 : QChar::mirroredChar(c->unicode());
417 glyphs->glyphs[--i] = (--c)->unicode() == 0xa0 ? 0x20 : c->unicode();
421 glyphs->numGlyphs = len;
423 if (!(flags & QTextEngine::GlyphIndicesOnly))
424 recalcAdvances(glyphs, flags);
428 void QFontEngineXLFD::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags /*flags*/) const
430 int i = glyphs->numGlyphs;
432 // inlined for better performance
433 if (!_fs->per_char) {
434 xcs = &_fs->min_bounds;
437 const unsigned char r = glyphs->glyphs[i] >> 8;
438 const unsigned char c = glyphs->glyphs[i] & 0xff;
439 if (r >= _fs->min_byte1 &&
440 r <= _fs->max_byte1 &&
441 c >= _fs->min_char_or_byte2 &&
442 c <= _fs->max_char_or_byte2) {
443 glyphs->advances_x[i] = xcs->width;
445 glyphs->glyphs[i] = 0;
449 else if (!_fs->max_byte1) {
450 XCharStruct *base = _fs->per_char - _fs->min_char_or_byte2;
452 unsigned int gl = glyphs->glyphs[--i];
453 xcs = (gl >= _fs->min_char_or_byte2 && gl <= _fs->max_char_or_byte2) ?
455 if (!xcs || (!xcs->width && !xcs->ascent && !xcs->descent)) {
456 glyphs->glyphs[i] = 0;
458 glyphs->advances_x[i] = xcs->width;
464 xcs = charStruct(_fs, glyphs->glyphs[--i]);
466 glyphs->glyphs[i] = 0;
468 glyphs->advances_x[i] = xcs->width;
474 glyph_metrics_t QFontEngineXLFD::boundingBox(const QGlyphLayout &glyphs)
478 glyph_metrics_t overall;
479 // initialize with line height, we get the same behaviour on all platforms
480 overall.y = -ascent();
481 overall.height = ascent() + descent() + 1;
484 for (i = 0; i < glyphs.numGlyphs; i++) {
485 XCharStruct *xcs = charStruct(_fs, glyphs.glyphs[i]);
487 QFixed x = overall.xoff + glyphs.offsets[i].x + xcs->lbearing;
488 QFixed y = overall.yoff + glyphs.offsets[i].y - xcs->ascent;
489 overall.x = qMin(overall.x, x);
490 overall.y = qMin(overall.y, y);
491 // XCharStruct::rbearing is defined as distance from left edge to rightmost pixel
492 xmax = qMax(xmax, overall.xoff + glyphs.offsets[i].x + xcs->rbearing);
493 ymax = qMax(ymax, y + xcs->ascent + xcs->descent);
494 overall.xoff += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
496 QFixed size = _fs->ascent;
497 overall.x = qMin(overall.x, overall.xoff);
498 overall.y = qMin(overall.y, overall.yoff - size);
499 ymax = qMax(ymax, overall.yoff);
500 overall.xoff += size;
501 xmax = qMax(xmax, overall.xoff);
504 overall.height = qMax(overall.height, ymax - overall.y);
505 overall.width = xmax - overall.x;
510 glyph_metrics_t QFontEngineXLFD::boundingBox(glyph_t glyph)
513 XCharStruct *xcs = charStruct(_fs, glyph);
515 // XCharStruct::rbearing is defined as distance from left edge to rightmost pixel
516 // XCharStruct::width is defined as the advance
517 gm = glyph_metrics_t(xcs->lbearing, -xcs->ascent, xcs->rbearing- xcs->lbearing, xcs->ascent + xcs->descent,
520 QFixed size = ascent();
521 gm = glyph_metrics_t(0, size, size, size, size, 0);
526 QFixed QFontEngineXLFD::ascent() const
531 QFixed QFontEngineXLFD::descent() const
533 return (_fs->descent-1);
536 QFixed QFontEngineXLFD::leading() const
538 QFixed l = QFixed(qMin<int>(_fs->ascent, _fs->max_bounds.ascent)
539 + qMin<int>(_fs->descent, _fs->max_bounds.descent)) * QFixed::fromReal(0.15);
543 qreal QFontEngineXLFD::maxCharWidth() const
545 return _fs->max_bounds.width;
549 // Loads the font for the specified script
550 static inline int maxIndex(XFontStruct *f) {
551 return (((f->max_byte1 - f->min_byte1) *
552 (f->max_char_or_byte2 - f->min_char_or_byte2 + 1)) +
553 f->max_char_or_byte2 - f->min_char_or_byte2);
556 qreal QFontEngineXLFD::minLeftBearing() const
558 if (lbearing == SHRT_MIN) {
560 XCharStruct *cs = _fs->per_char;
561 int nc = maxIndex(_fs) + 1;
562 int mx = cs->lbearing;
564 for (int c = 1; c < nc; c++) {
565 // ignore the bearings for characters whose ink is
566 // completely outside the normal bounding box
567 if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
568 (cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
571 int nmx = cs[c].lbearing;
577 ((QFontEngineXLFD *)this)->lbearing = mx;
579 ((QFontEngineXLFD *)this)->lbearing = _fs->min_bounds.lbearing;
584 qreal QFontEngineXLFD::minRightBearing() const
586 if (rbearing == SHRT_MIN) {
588 XCharStruct *cs = _fs->per_char;
589 int nc = maxIndex(_fs) + 1;
590 int mx = cs->rbearing;
592 for (int c = 1; c < nc; c++) {
593 // ignore the bearings for characters whose ink is
594 // completely outside the normal bounding box
595 if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
596 (cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
599 int nmx = cs[c].rbearing;
605 ((QFontEngineXLFD *)this)->rbearing = mx;
607 ((QFontEngineXLFD *)this)->rbearing = _fs->min_bounds.rbearing;
612 const char *QFontEngineXLFD::name() const
617 bool QFontEngineXLFD::canRender(const QChar *string, int len)
619 QVarLengthGlyphLayoutArray glyphs(len);
621 if (stringToCMap(string, len, &glyphs, &nglyphs, 0) == false) {
622 glyphs.resize(nglyphs);
623 stringToCMap(string, len, &glyphs, &nglyphs, 0);
626 bool allExist = true;
627 for (int i = 0; i < nglyphs; i++) {
628 if (!glyphs.glyphs[i] || !charStruct(_fs, glyphs.glyphs[i])) {
637 QBitmap QFontEngineXLFD::bitmapForGlyphs(const QGlyphLayout &glyphs, const glyph_metrics_t &metrics, QTextItem::RenderFlags flags)
639 int w = metrics.width.toInt();
640 int h = metrics.height.toInt();
641 if (w <= 0 || h <= 0)
644 QPixmapData *data = new QX11PixmapData(QPixmapData::BitmapType);
648 p.fillRect(0, 0, w, h, Qt::color0);
649 p.setPen(Qt::color1);
653 item.ascent = -metrics.y;
654 item.descent = metrics.height - item.ascent;
655 item.width = metrics.width;
658 item.logClusters = 0;
659 item.glyphs = glyphs;
660 item.fontEngine = this;
663 p.drawTextItem(QPointF(-metrics.x.toReal(), item.ascent.toReal()), item);
669 void QFontEngineXLFD::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
671 // cannot use QFontEngine::addBitmapFontToPath(), since we don't
672 // have direct access to the glyph bitmaps, so we have to draw
673 // onto a QBitmap, then convert to QImage, then to path
674 glyph_metrics_t metrics = boundingBox(glyphs);
676 QImage image = bitmapForGlyphs(glyphs, metrics, flags).toImage();
680 image = image.convertToFormat(QImage::Format_Mono);
681 const uchar *image_data = image.bits();
682 uint bpl = image.bytesPerLine();
683 // from qfontengine.cpp
684 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data,
685 int bpl, int w, int h, QPainterPath *path);
686 qt_addBitmapToPath(x, y + metrics.y.toReal(), image_data, bpl, image.width(), image.height(), path);
689 QFontEngine::FaceId QFontEngineXLFD::faceId() const
691 #ifndef QT_NO_FREETYPE
692 if (face_id.index == -1) {
693 face_id = fontFile(_name, &freetype, &synth);
695 face_id.encoding = _codec->mibEnum();
697 const_cast<QFontEngineXLFD *>(this)->fsType = freetype->fsType();
700 face_id.filename = '-' + QFontEngine::properties().postscriptName;
708 QFontEngine::Properties QFontEngineXLFD::properties() const
710 if (face_id.index == -1)
713 #ifndef QT_NO_FREETYPE
715 return freetype->properties();
717 return QFontEngine::properties();
720 void QFontEngineXLFD::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
722 if (face_id.index == -1)
724 #ifndef QT_NO_FREETYPE
728 QFontEngine::getUnscaledGlyph(glyph, path, metrics);
732 #ifndef QT_NO_FREETYPE
735 FT_Face face = freetype->face;
736 FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
737 freetype->xsize = face->units_per_EM << 6;
738 freetype->ysize = face->units_per_EM << 6;
739 FT_Set_Transform(face, 0, 0);
740 glyph = glyphIndexToFreetypeGlyphIndex(glyph);
741 FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
743 int left = face->glyph->metrics.horiBearingX;
744 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
745 int top = face->glyph->metrics.horiBearingY;
746 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
751 metrics->width = QFixed::fromFixed(right-left);
752 metrics->height = QFixed::fromFixed(top-bottom);
753 metrics->x = QFixed::fromFixed(left);
754 metrics->y = QFixed::fromFixed(-top);
755 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
757 if (!FT_IS_SCALABLE(freetype->face))
758 QFreetypeFace::addBitmapToPath(face->glyph, p, path);
760 QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
762 FT_Set_Transform(face, &freetype->matrix, 0);
764 #endif // QT_NO_FREETYPE
768 bool QFontEngineXLFD::getSfntTableData(uint tag, uchar *buffer, uint *length) const
770 #ifndef QT_NO_FREETYPE
771 if (face_id.index == -1)
775 return freetype->getSfntTable(tag, buffer, length);
784 int QFontEngineXLFD::synthesized() const
789 QImage QFontEngineXLFD::alphaMapForGlyph(glyph_t glyph)
791 glyph_metrics_t metrics = boundingBox(glyph);
794 printf("a) w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f\n",
795 metrics.width.toReal(),
796 metrics.height.toReal(),
797 metrics.xoff.toReal(),
798 metrics.yoff.toReal(),
803 QGlyphLayoutArray<1> glyphs;
804 glyphs.glyphs[0] = glyph;
806 QImage image = bitmapForGlyphs(glyphs, metrics).toImage();
807 //image.save(QString::fromLatin1("x11cache-%1.png").arg((int)glyph));
809 image = image.convertToFormat(QImage::Format_Indexed8);
810 QVector<QRgb> colors(256);
811 for (int i = 0; i < 256; ++i)
812 colors[i] = qRgba(0, 0, 0, i);
813 image.setColorTable(colors);
815 int width = image.width();
816 int height = image.height();
817 for (int y = 0; y < height; ++y) {
818 uchar *bits = image.scanLine(y);
819 for (int x = 0; x < width; ++x)
820 bits[x] = ~(bits[x]-1);
826 #ifndef QT_NO_FREETYPE
828 FT_Face QFontEngineXLFD::non_locked_face() const
830 return freetype ? freetype->face : 0;
833 uint QFontEngineXLFD::toUnicode(glyph_t g) const
836 QTextCodec::ConverterState state;
837 state.flags = QTextCodec::ConvertInvalidToNull;
847 QString s = _codec->toUnicode((char *)data, l, &state);
848 Q_ASSERT(s.length() == 1);
849 g = s.at(0).unicode();
854 glyph_t QFontEngineXLFD::glyphIndexToFreetypeGlyphIndex(glyph_t g) const
856 return FT_Get_Char_Index(freetype->face, toUnicode(g));
860 #ifndef QT_NO_FONTCONFIG
862 // ------------------------------------------------------------------
864 // ------------------------------------------------------------------
866 static QFontEngine *engineForPattern(FcPattern *match, const QFontDef &request, int screen)
868 QFontEngineX11FT *engine = new QFontEngineX11FT(match, request, screen);
869 if (!engine->invalid())
873 QFontEngine *fe = new QFontEngineBox(request.pixelSize);
874 fe->fontDef = request;
878 QFontEngineMultiFT::QFontEngineMultiFT(QFontEngine *fe, FcPattern *matchedPattern, FcPattern *p, int s, const QFontDef &req)
879 : QFontEngineMulti(2), request(req), pattern(p), fontSet(0), screen(s)
881 firstEnginePattern = FcPatternDuplicate(matchedPattern);
883 engines.at(0)->ref.ref();
884 fontDef = engines[0]->fontDef;
889 QFontEngineMultiFT::~QFontEngineMultiFT()
891 extern QMutex *qt_fontdatabase_mutex();
892 QMutexLocker locker(qt_fontdatabase_mutex());
894 FcPatternDestroy(pattern);
895 if (firstEnginePattern)
896 FcPatternDestroy(firstEnginePattern);
898 FcFontSetDestroy(fontSet);
902 void QFontEngineMultiFT::loadEngine(int at)
904 extern QMutex *qt_fontdatabase_mutex();
905 QMutexLocker locker(qt_fontdatabase_mutex());
907 extern QFontDef qt_FcPatternToQFontDef(FcPattern *pattern, const QFontDef &);
908 extern FcFontSet *qt_fontSetForPattern(FcPattern *pattern, const QFontDef &request);
912 fontSet = qt_fontSetForPattern(pattern, request);
914 // it may happen that the fontset of fallbacks consists of only one font. In this case we
915 // have to fall back to the box fontengine as we cannot render the glyph.
916 if (fontSet->nfont == 1 && at == 1 && engines.size() == 2) {
917 Q_ASSERT(engines.at(at) == 0);
918 QFontEngine *fe = new QFontEngineBox(request.pixelSize);
919 fe->fontDef = request;
924 if (firstEnginePattern) {
926 if (!FcPatternEqual(firstEnginePattern, fontSet->fonts[0]))
929 FcPatternDestroy(firstEnginePattern);
930 firstEnginePattern = 0;
933 engines.resize(fontSet->nfont + 1 - firstFontIndex);
935 Q_ASSERT(at < engines.size());
936 Q_ASSERT(engines.at(at) == 0);
938 FcPattern *match = FcFontRenderPrepare(NULL, pattern, fontSet->fonts[at + firstFontIndex - 1]);
939 QFontDef fontDef = qt_FcPatternToQFontDef(match, this->request);
941 // note: we use -1 for the script to make sure that we keep real
942 // FT engines separate from Multi engines in the font cache
943 QFontCache::Key key(fontDef, -1, screen);
944 QFontEngine *fontEngine = QFontCache::instance()->findEngine(key);
946 fontEngine = engineForPattern(match, request, screen);
947 QFontCache::instance()->insertEngine(key, fontEngine);
949 FcPatternDestroy(match);
950 fontEngine->ref.ref();
951 engines[at] = fontEngine;
954 // ------------------------------------------------------------------
956 // ------------------------------------------------------------------
960 Q_GUI_EXPORT void qt_x11ft_convert_pattern(FcPattern *pattern, QByteArray *file_name, int *index, bool *antialias)
963 FcPatternGetString(pattern, FC_FILE, 0, &fileName);
964 *file_name = (const char *)fileName;
965 if (!FcPatternGetInteger(pattern, FC_INDEX, 0, index))
968 if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &b) == FcResultMatch)
973 QFontEngineX11FT::QFontEngineX11FT(FcPattern *pattern, const QFontDef &fd, int screen)
976 // FcPatternPrint(pattern);
978 bool antialias = X11->fc_antialias;
979 QByteArray file_name;
981 qt_x11ft_convert_pattern(pattern, &file_name, &face_index, &antialias);
982 QFontEngine::FaceId face_id;
983 face_id.filename = file_name;
984 face_id.index = face_index;
986 canUploadGlyphsToServer = QApplication::testAttribute(Qt::AA_X11InitThreads) || (qApp->thread() == QThread::currentThread());
988 subpixelType = Subpixel_None;
990 int subpixel = X11->display ? X11->screens[screen].subpixel : FC_RGBA_UNKNOWN;
991 if (subpixel == FC_RGBA_UNKNOWN)
992 (void) FcPatternGetInteger(pattern, FC_RGBA, 0, &subpixel);
993 if (!antialias || subpixel == FC_RGBA_UNKNOWN)
994 subpixel = FC_RGBA_NONE;
997 case FC_RGBA_NONE: subpixelType = Subpixel_None; break;
998 case FC_RGBA_RGB: subpixelType = Subpixel_RGB; break;
999 case FC_RGBA_BGR: subpixelType = Subpixel_BGR; break;
1000 case FC_RGBA_VRGB: subpixelType = Subpixel_VRGB; break;
1001 case FC_RGBA_VBGR: subpixelType = Subpixel_VBGR; break;
1006 if (fd.hintingPreference != QFont::PreferDefaultHinting) {
1007 switch (fd.hintingPreference) {
1008 case QFont::PreferNoHinting:
1009 default_hint_style = HintNone;
1011 case QFont::PreferVerticalHinting:
1012 default_hint_style = HintLight;
1014 case QFont::PreferFullHinting:
1016 default_hint_style = HintFull;
1020 #ifdef FC_HINT_STYLE
1023 // Try to use Xft.hintstyle from XDefaults first if running in GNOME, to match
1024 // the behavior of cairo
1025 if (X11->fc_hint_style > -1 && X11->desktopEnvironment == DE_GNOME)
1026 hint_style = X11->fc_hint_style;
1027 else if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch
1028 && X11->fc_hint_style > -1)
1029 hint_style = X11->fc_hint_style;
1031 switch (hint_style) {
1033 default_hint_style = HintNone;
1035 case FC_HINT_SLIGHT:
1036 default_hint_style = HintLight;
1038 case FC_HINT_MEDIUM:
1039 default_hint_style = HintMedium;
1042 default_hint_style = HintFull;
1048 #if defined(FC_AUTOHINT) && defined(FT_LOAD_FORCE_AUTOHINT)
1050 bool autohint = false;
1053 if (FcPatternGetBool(pattern, FC_AUTOHINT, 0, &b) == FcResultMatch)
1057 default_load_flags |= FT_LOAD_FORCE_AUTOHINT;
1061 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1063 int filter = FC_LCD_FILTER_NONE;
1064 if (FcPatternGetInteger(pattern, FC_LCD_FILTER, 0, &filter) == FcResultMatch) {
1066 case FC_LCD_FILTER_NONE:
1067 lcdFilterType = FT_LCD_FILTER_NONE;
1069 case FC_LCD_FILTER_DEFAULT:
1070 lcdFilterType = FT_LCD_FILTER_DEFAULT;
1072 case FC_LCD_FILTER_LIGHT:
1073 lcdFilterType = FT_LCD_FILTER_LIGHT;
1075 case FC_LCD_FILTER_LEGACY:
1076 lcdFilterType = FT_LCD_FILTER_LEGACY;
1079 // new unknown lcd filter type?!
1086 #ifdef FC_EMBEDDED_BITMAP
1089 if (FcPatternGetBool(pattern, FC_EMBEDDED_BITMAP, 0, &b) == FcResultMatch)
1094 GlyphFormat defaultFormat = Format_None;
1096 #ifndef QT_NO_XRENDER
1097 if (X11->use_xrender) {
1098 int format = PictStandardA8;
1100 format = PictStandardA1;
1101 else if (subpixelType == Subpixel_RGB
1102 || subpixelType == Subpixel_BGR
1103 || subpixelType == Subpixel_VRGB
1104 || subpixelType == Subpixel_VBGR)
1105 format = PictStandardARGB32;
1106 xglyph_format = format;
1108 if (subpixelType != QFontEngineFT::Subpixel_None)
1109 defaultFormat = Format_A32;
1111 defaultFormat = Format_A8;
1113 defaultFormat = Format_Mono;
1117 if (!init(face_id, antialias, defaultFormat))
1120 if (!freetype->charset) {
1122 FcPatternGetCharSet (pattern, FC_CHARSET, 0, &cs);
1123 freetype->charset = FcCharSetCopy(cs);
1127 QFontEngineX11FT::~QFontEngineX11FT()
1132 unsigned long QFontEngineX11FT::allocateServerGlyphSet()
1134 #ifndef QT_NO_XRENDER
1135 if (!canUploadGlyphsToServer || !X11->use_xrender)
1137 return XRenderCreateGlyphSet(X11->display, XRenderFindStandardFormat(X11->display, xglyph_format));
1143 void QFontEngineX11FT::freeServerGlyphSet(unsigned long id)
1145 #ifndef QT_NO_XRENDER
1148 XRenderFreeGlyphSet(X11->display, id);
1152 bool QFontEngineX11FT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
1154 #ifndef QT_NO_XRENDER
1155 if (!canUploadGlyphsToServer)
1157 if (g->format == Format_Mono) {
1159 * swap bit order around; FreeType is always MSBFirst
1161 if (BitmapBitOrder(X11->display) != MSBFirst) {
1162 unsigned char *line = g->data;
1163 int i = glyphDataSize;
1167 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1168 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1169 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1175 ::Glyph xglyph = glyphid;
1176 XRenderAddGlyphs (X11->display, set->id, &xglyph, info, 1, (const char *)g->data, glyphDataSize);
1179 g->format = Format_None;
1180 g->uploadedToServer = true;
1187 QFontEngine *QFontEngineX11FT::cloneWithSize(qreal pixelSize) const
1190 fontDef.pixelSize = pixelSize;
1191 QFontEngineX11FT *fe = new QFontEngineX11FT(fontDef);
1192 if (!fe->initFromFontEngine(this)) {
1196 #ifndef QT_NO_XRENDER
1197 fe->xglyph_format = xglyph_format;
1203 #endif // QT_NO_FONTCONFIG