1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qbitmap.h"
43 
44 // #define FONTENGINE_DEBUG
45 
46 #include <qapplication.h>
47 #include <qbytearray.h>
48 #include <qdebug.h>
49 #include <qtextcodec.h>
50 #include <qthread.h>
51 
52 #include "qfontdatabase.h"
53 #include "qpaintdevice.h"
54 #include "qpainter.h"
55 #include "qvarlengtharray.h"
56 #include "qwidget.h"
57 #include "qsettings.h"
58 #include "qfile.h"
59 
60 #include <private/qpaintengine_x11_p.h>
61 #include "qfont.h"
62 #include "qfont_p.h"
63 #include "qfontengine_p.h"
64 #include <qhash.h>
65 
66 #include <private/qpainter_p.h>
67 #include <private/qunicodetables_p.h>
68 
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"
73 
74 #include <limits.h>
75 
76 #include <ft2build.h>
77 #if defined(FT_LCD_FILTER_H)
78 #include FT_LCD_FILTER_H
79 #endif
80 
81 #if defined(FC_LCD_FILTER)
82 
83 #ifndef FC_LCD_FILTER_NONE
84 #define FC_LCD_FILTER_NONE FC_LCD_NONE
85 #endif
86 
87 #ifndef FC_LCD_FILTER_DEFAULT
88 #define FC_LCD_FILTER_DEFAULT FC_LCD_DEFAULT
89 #endif
90 
91 #ifndef FC_LCD_FILTER_LIGHT
92 #define FC_LCD_FILTER_LIGHT FC_LCD_LIGHT
93 #endif
94 
95 #ifndef FC_LCD_FILTER_LEGACY
96 #define FC_LCD_FILTER_LEGACY FC_LCD_LEGACY
97 #endif
98 
99 #endif
100 
101 QT_BEGIN_NAMESPACE
102 
103 
104 // ------------------------------------------------------------------
105 // Multi XLFD engine
106 // ------------------------------------------------------------------
107 
QFontEngineMultiXLFD(const QFontDef & r,const QList<int> & l,int s)108 QFontEngineMultiXLFD::QFontEngineMultiXLFD(const QFontDef &r, const QList<int> &l, int s)
109     : QFontEngineMulti(l.size()), encodings(l), screen(s), request(r)
110 {
111     loadEngine(0);
112     fontDef = engines[0]->fontDef;
113 }
114 
~QFontEngineMultiXLFD()115 QFontEngineMultiXLFD::~QFontEngineMultiXLFD()
116 { }
117 
loadEngine(int at)118 void QFontEngineMultiXLFD::loadEngine(int at)
119 {
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;
127 }
128 
129 // ------------------------------------------------------------------
130 // Xlfd font engine
131 // ------------------------------------------------------------------
132 
133 #ifndef QT_NO_FREETYPE
134 
135 static QStringList *qt_fontpath = 0;
136 
fontPath()137 static QStringList fontPath()
138 {
139     if (qt_fontpath)
140         return *qt_fontpath;
141 
142     // append qsettings fontpath
143     QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
144     settings.beginGroup(QLatin1String("Qt"));
145 
146     QStringList fontpath;
147 
148     int npaths;
149     char** font_path;
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"));
159             if (!f.exists())
160                 f.setFileName(QLatin1String("/usr/X11R6/lib/X11/fs/config"));
161             if (!f.exists())
162                 f.setFileName(QLatin1String("/usr/X11/lib/X11/fs/config"));
163             if (f.exists()) {
164                 f.open(QIODevice::ReadOnly);
165                 while (f.error()==QFile::NoError && !finished) {
166                     QString fs = QString::fromLocal8Bit(f.readLine(1024));
167                     fs=fs.trimmed();
168                     if (fs.left(9)==QLatin1String("catalogue") && fs.contains(QLatin1Char('='))) {
169                         fs = fs.mid(fs.indexOf(QLatin1Char('=')) + 1).trimmed();
170                         bool end = false;
171                         while (f.error()==QFile::NoError && !end) {
172                             if (fs[int(fs.length())-1] == QLatin1Char(','))
173                                 fs = fs.left(fs.length()-1);
174                             else
175                                 end = true;
176 
177                             fs = fs.left(fs.indexOf(QLatin1String(":unscaled")));
178                             if (fs[0] != QLatin1Char('#'))
179                                 fontpath += fs;
180                             fs = QLatin1String(f.readLine(1024));
181                             fs = fs.trimmed();
182                             if (fs.isEmpty())
183                                 end = true;
184                         }
185                         finished = true;
186                     }
187                 }
188                 f.close();
189             }
190             xfsconfig_read = true;
191         } else {
192             QString fs = QString::fromLocal8Bit(font_path[i]);
193             fontpath += fs.left(fs.indexOf(QLatin1String(":unscaled")));
194         }
195     }
196     XFreeFontPath(font_path);
197 
198     // append qsettings fontpath
199     QStringList fp = settings.value(QLatin1String("fontPath")).toStringList();
200     if (!fp.isEmpty())
201         fontpath += fp;
202 
203     qt_fontpath = new QStringList(fontpath);
204     return fontpath;
205 }
206 
fontFile(const QByteArray & _xname,QFreetypeFace ** freetype,int * synth)207 static QFontEngine::FaceId fontFile(const QByteArray &_xname, QFreetypeFace **freetype, int *synth)
208 {
209     *freetype = 0;
210     *synth = 0;
211 
212     QByteArray xname = _xname.toLower();
213 
214     int pos = 0;
215     int minus = 0;
216     while (minus < 5 && (pos = xname.indexOf('-', pos + 1)))
217         ++minus;
218     QByteArray searchname = xname.left(pos);
219     while (minus < 12 && (pos = xname.indexOf('-', pos + 1)))
220         ++minus;
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;
225     face_id.index = 0;
226 
227     QByteArray best_mapping;
228 
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
232         QString fontmapname;
233         int num = 0;
234         // search font.dir and font.scale for the right file
235         while (num < 2) {
236             if (num == 0)
237                 fontmapname = (*it) + QLatin1String("/fonts.scale");
238             else
239                 fontmapname = (*it) + QLatin1String("/fonts.dir");
240             ++num;
241             //qWarning(fontmapname);
242             QFile fontmap(fontmapname);
243             if (!fontmap.open(QIODevice::ReadOnly))
244                 continue;
245             while (!fontmap.atEnd()) {
246                 QByteArray mapping = fontmap.readLine();
247                 QByteArray lmapping = mapping.toLower();
248 
249                 //qWarning(xfontname);
250                 //qWarning(mapping);
251                 if (!lmapping.contains(searchname))
252                     continue;
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"))
257                     continue;
258                 bool best_match = false;
259                 if (!best_mapping.isEmpty()) {
260                     if (lmapping.contains("-0-0-0-0-")) { // scalable font
261                         best_match = true;
262                         goto found;
263                     }
264                     if (lmapping.contains(encoding) && !best_mapping.toLower().contains(encoding))
265                         goto found;
266                     continue;
267                 }
268 
269             found:
270                 int colon = ffn.lastIndexOf(':');
271                 if (colon != -1) {
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;
278                 }
279                 face_id.filename = (*it).toLocal8Bit() + '/' + ffn;
280                 best_mapping = mapping;
281                 if (best_match)
282                     goto end;
283             }
284         }
285     }
286 end:
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);
290     if (!*freetype) {
291         face_id.index = 0;
292         face_id.filename = QByteArray();
293     }
294     return face_id;
295 }
296 
297 #endif // QT_NO_FREETYPE
298 
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);
302 
charStruct(XFontStruct * xfs,uint ch)303 static inline XCharStruct *charStruct(XFontStruct *xfs, uint ch)
304 {
305     XCharStruct *xcs = 0;
306     unsigned char r = ch>>8;
307     unsigned char c = ch&0xff;
308     if (xfs->per_char &&
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)
318             xcs = 0;
319     }
320     return xcs;
321 }
322 
QFontEngineXLFD(XFontStruct * fs,const QByteArray & name,int mib)323 QFontEngineXLFD::QFontEngineXLFD(XFontStruct *fs, const QByteArray &name, int mib)
324     : _fs(fs), _name(name), _codec(0), _cmap(mib)
325 {
326     if (_cmap) _codec = QTextCodec::codecForMib(_cmap);
327 
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));
333     lbearing = SHRT_MIN;
334     rbearing = SHRT_MIN;
335     face_id.index = -1;
336     freetype = 0;
337     synth = 0;
338 }
339 
~QFontEngineXLFD()340 QFontEngineXLFD::~QFontEngineXLFD()
341 {
342     XFreeFont(QX11Info::display(), _fs);
343     _fs = 0;
344 #ifndef QT_NO_FREETYPE
345     if (freetype)
346         freetype->release(face_id);
347 #endif
348 }
349 
stringToCMap(const QChar * s,int len,QGlyphLayout * glyphs,int * nglyphs,QTextEngine::ShaperFlags flags) const350 bool QFontEngineXLFD::stringToCMap(const QChar *s, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
351 {
352     if (*nglyphs < len) {
353         *nglyphs = len;
354         return false;
355     }
356 
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) {
361         if (s[i].isHighSurrogate() && i < len-1 && s[i+1].isLowSurrogate()) {
362             *str = QChar();
363             ++i;
364         } else {
365             *str = s[i];
366         }
367         ++str;
368     }
369 
370     len = str - (QChar *)_s.data();
371     str = (QChar *)_s.data();
372 
373     bool mirrored = flags & QTextEngine::RightToLeft;
374     if (_codec) {
375         bool haveNbsp = false;
376         for (int i = 0; i < len; i++)
377             if (str[i].unicode() == 0xa0) {
378                 haveNbsp = true;
379                 break;
380             }
381 
382         QVarLengthArray<unsigned short> ch(len);
383         QChar *chars = (QChar *)ch.data();
384         if (haveNbsp || mirrored) {
385             for (int i = 0; i < len; i++)
386                 chars[i] = (str[i].unicode() == 0xa0 ? 0x20 :
387                             (mirrored ? QChar::mirroredChar(str[i].unicode()) : str[i].unicode()));
388         } else {
389             for (int i = 0; i < len; i++)
390                 chars[i] = str[i].unicode();
391         }
392         QTextCodec::ConverterState state;
393         state.flags = QTextCodec::ConvertInvalidToNull;
394         QByteArray ba = _codec->fromUnicode(chars, len, &state);
395         if (ba.length() == 2*len) {
396             // double byte encoding
397             const uchar *data = (const uchar *)ba.constData();
398             for (int i = 0; i < len; i++) {
399                 glyphs->glyphs[i] = ((ushort)data[0] << 8) + data[1];
400                 data += 2;
401             }
402         } else {
403             const uchar *data = (const uchar *)ba.constData();
404             for (int i = 0; i < len; i++)
405                 glyphs->glyphs[i] = (ushort)data[i];
406         }
407     } else {
408         int i = len;
409         const QChar *c = str + len;
410         if (mirrored) {
411             while (c != str)
412                 glyphs->glyphs[--i] = (--c)->unicode() == 0xa0 ? 0x20 : QChar::mirroredChar(c->unicode());
413         } else {
414             while (c != str)
415                 glyphs->glyphs[--i] = (--c)->unicode() == 0xa0 ? 0x20 : c->unicode();
416         }
417     }
418     *nglyphs = len;
419     glyphs->numGlyphs = len;
420 
421     if (!(flags & QTextEngine::GlyphIndicesOnly))
422         recalcAdvances(glyphs, flags);
423     return true;
424 }
425 
recalcAdvances(QGlyphLayout * glyphs,QTextEngine::ShaperFlags) const426 void QFontEngineXLFD::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags /*flags*/) const
427 {
428     int i = glyphs->numGlyphs;
429     XCharStruct *xcs;
430     // inlined for better performance
431     if (!_fs->per_char) {
432         xcs = &_fs->min_bounds;
433         while (i != 0) {
434             --i;
435             const unsigned char r = glyphs->glyphs[i] >> 8;
436             const unsigned char c = glyphs->glyphs[i] & 0xff;
437             if (r >= _fs->min_byte1 &&
438                 r <= _fs->max_byte1 &&
439                 c >= _fs->min_char_or_byte2 &&
440                 c <= _fs->max_char_or_byte2) {
441                 glyphs->advances_x[i] = xcs->width;
442             } else {
443                 glyphs->glyphs[i] = 0;
444             }
445         }
446     }
447     else if (!_fs->max_byte1) {
448         XCharStruct *base = _fs->per_char - _fs->min_char_or_byte2;
449         while (i != 0) {
450             unsigned int gl = glyphs->glyphs[--i];
451             xcs = (gl >= _fs->min_char_or_byte2 && gl <= _fs->max_char_or_byte2) ?
452                   base + gl : 0;
453             if (!xcs || (!xcs->width && !xcs->ascent && !xcs->descent)) {
454                 glyphs->glyphs[i] = 0;
455             } else {
456                 glyphs->advances_x[i] = xcs->width;
457             }
458         }
459     }
460     else {
461         while (i != 0) {
462             xcs = charStruct(_fs, glyphs->glyphs[--i]);
463             if (!xcs) {
464                 glyphs->glyphs[i] = 0;
465             } else {
466                 glyphs->advances_x[i] = xcs->width;
467             }
468         }
469     }
470 }
471 
boundingBox(const QGlyphLayout & glyphs)472 glyph_metrics_t QFontEngineXLFD::boundingBox(const QGlyphLayout &glyphs)
473 {
474     int i;
475 
476     glyph_metrics_t overall;
477     // initialize with line height, we get the same behaviour on all platforms
478     overall.y = -ascent();
479     overall.height = ascent() + descent() + 1;
480     QFixed ymax;
481     QFixed xmax;
482     for (i = 0; i < glyphs.numGlyphs; i++) {
483         XCharStruct *xcs = charStruct(_fs, glyphs.glyphs[i]);
484         if (xcs) {
485             QFixed x = overall.xoff + glyphs.offsets[i].x + xcs->lbearing;
486             QFixed y = overall.yoff + glyphs.offsets[i].y - xcs->ascent;
487             overall.x = qMin(overall.x, x);
488             overall.y = qMin(overall.y, y);
489             // XCharStruct::rbearing is defined as distance from left edge to rightmost pixel
490             xmax = qMax(xmax, overall.xoff + glyphs.offsets[i].x + xcs->rbearing);
491             ymax = qMax(ymax, y + xcs->ascent + xcs->descent);
492             overall.xoff += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
493         } else {
494             QFixed size = _fs->ascent;
495             overall.x = qMin(overall.x, overall.xoff);
496             overall.y = qMin(overall.y, overall.yoff - size);
497             ymax = qMax(ymax, overall.yoff);
498             overall.xoff += size;
499             xmax = qMax(xmax, overall.xoff);
500         }
501     }
502     overall.height = qMax(overall.height, ymax - overall.y);
503     overall.width = xmax - overall.x;
504 
505     return overall;
506 }
507 
boundingBox(glyph_t glyph)508 glyph_metrics_t QFontEngineXLFD::boundingBox(glyph_t glyph)
509 {
510     glyph_metrics_t gm;
511     XCharStruct *xcs = charStruct(_fs, glyph);
512     if (xcs) {
513         // XCharStruct::rbearing is defined as distance from left edge to rightmost pixel
514         // XCharStruct::width is defined as the advance
515         gm = glyph_metrics_t(xcs->lbearing, -xcs->ascent, xcs->rbearing- xcs->lbearing, xcs->ascent + xcs->descent,
516                               xcs->width, 0);
517     } else {
518         QFixed size = ascent();
519         gm = glyph_metrics_t(0, size, size, size, size, 0);
520     }
521     return gm;
522 }
523 
ascent() const524 QFixed QFontEngineXLFD::ascent() const
525 {
526     return _fs->ascent;
527 }
528 
descent() const529 QFixed QFontEngineXLFD::descent() const
530 {
531     return (_fs->descent-1);
532 }
533 
leading() const534 QFixed QFontEngineXLFD::leading() const
535 {
536     QFixed l = QFixed(qMin<int>(_fs->ascent, _fs->max_bounds.ascent)
537                       + qMin<int>(_fs->descent, _fs->max_bounds.descent)) * QFixed::fromReal(0.15);
538     return l.ceil();
539 }
540 
maxCharWidth() const541 qreal QFontEngineXLFD::maxCharWidth() const
542 {
543     return _fs->max_bounds.width;
544 }
545 
546 
547 // Loads the font for the specified script
maxIndex(XFontStruct * f)548 static inline int maxIndex(XFontStruct *f) {
549     return (((f->max_byte1 - f->min_byte1) *
550              (f->max_char_or_byte2 - f->min_char_or_byte2 + 1)) +
551             f->max_char_or_byte2 - f->min_char_or_byte2);
552 }
553 
minLeftBearing() const554 qreal QFontEngineXLFD::minLeftBearing() const
555 {
556     if (lbearing == SHRT_MIN) {
557         if (_fs->per_char) {
558             XCharStruct *cs = _fs->per_char;
559             int nc = maxIndex(_fs) + 1;
560             int mx = cs->lbearing;
561 
562             for (int c = 1; c < nc; c++) {
563                 // ignore the bearings for characters whose ink is
564                 // completely outside the normal bounding box
565                 if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
566                     (cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
567                     continue;
568 
569                 int nmx = cs[c].lbearing;
570 
571                 if (nmx < mx)
572                     mx = nmx;
573             }
574 
575             ((QFontEngineXLFD *)this)->lbearing = mx;
576         } else
577             ((QFontEngineXLFD *)this)->lbearing = _fs->min_bounds.lbearing;
578     }
579     return lbearing;
580 }
581 
minRightBearing() const582 qreal QFontEngineXLFD::minRightBearing() const
583 {
584     if (rbearing == SHRT_MIN) {
585         if (_fs->per_char) {
586             XCharStruct *cs = _fs->per_char;
587             int nc = maxIndex(_fs) + 1;
588             int mx = cs->rbearing;
589 
590             for (int c = 1; c < nc; c++) {
591                 // ignore the bearings for characters whose ink is
592                 // completely outside the normal bounding box
593                 if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
594                     (cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
595                     continue;
596 
597                 int nmx = cs[c].rbearing;
598 
599                 if (nmx < mx)
600                     mx = nmx;
601             }
602 
603             ((QFontEngineXLFD *)this)->rbearing = mx;
604         } else
605             ((QFontEngineXLFD *)this)->rbearing = _fs->min_bounds.rbearing;
606     }
607     return rbearing;
608 }
609 
name() const610 const char *QFontEngineXLFD::name() const
611 {
612     return _name;
613 }
614 
canRender(const QChar * string,int len)615 bool QFontEngineXLFD::canRender(const QChar *string, int len)
616 {
617     QVarLengthGlyphLayoutArray glyphs(len);
618     int nglyphs = len;
619     if (stringToCMap(string, len, &glyphs, &nglyphs, 0) == false) {
620         glyphs.resize(nglyphs);
621         stringToCMap(string, len, &glyphs, &nglyphs, 0);
622     }
623 
624     bool allExist = true;
625     for (int i = 0; i < nglyphs; i++) {
626         if (!glyphs.glyphs[i] || !charStruct(_fs, glyphs.glyphs[i])) {
627             allExist = false;
628             break;
629         }
630     }
631 
632     return allExist;
633 }
634 
bitmapForGlyphs(const QGlyphLayout & glyphs,const glyph_metrics_t & metrics,QTextItem::RenderFlags flags)635 QBitmap QFontEngineXLFD::bitmapForGlyphs(const QGlyphLayout &glyphs, const glyph_metrics_t &metrics, QTextItem::RenderFlags flags)
636 {
637     int w = metrics.width.toInt();
638     int h = metrics.height.toInt();
639     if (w <= 0 || h <= 0)
640         return QBitmap();
641 
642     QPixmapData *data = new QX11PixmapData(QPixmapData::BitmapType);
643     data->resize(w, h);
644     QPixmap bm(data);
645     QPainter p(&bm);
646     p.fillRect(0, 0, w, h, Qt::color0);
647     p.setPen(Qt::color1);
648 
649     QTextItemInt item;
650     item.flags = flags;
651     item.ascent = -metrics.y;
652     item.descent = metrics.height - item.ascent;
653     item.width = metrics.width;
654     item.chars = 0;
655     item.num_chars = 0;
656     item.logClusters = 0;
657     item.glyphs = glyphs;
658     item.fontEngine = this;
659     item.f = 0;
660 
661     p.drawTextItem(QPointF(-metrics.x.toReal(), item.ascent.toReal()), item);
662     p.end();
663 
664     return QBitmap(bm);
665 }
666 
addOutlineToPath(qreal x,qreal y,const QGlyphLayout & glyphs,QPainterPath * path,QTextItem::RenderFlags flags)667 void QFontEngineXLFD::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
668 {
669     // cannot use QFontEngine::addBitmapFontToPath(), since we don't
670     // have direct access to the glyph bitmaps, so we have to draw
671     // onto a QBitmap, then convert to QImage, then to path
672     glyph_metrics_t metrics = boundingBox(glyphs);
673 
674     QImage image = bitmapForGlyphs(glyphs, metrics, flags).toImage();
675     if (image.isNull())
676         return;
677 
678     image = image.convertToFormat(QImage::Format_Mono);
679     const uchar *image_data = image.bits();
680     uint bpl = image.bytesPerLine();
681     // from qfontengine.cpp
682     extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data,
683                                    int bpl, int w, int h, QPainterPath *path);
684     qt_addBitmapToPath(x, y + metrics.y.toReal(), image_data, bpl, image.width(), image.height(), path);
685 }
686 
faceId() const687 QFontEngine::FaceId QFontEngineXLFD::faceId() const
688 {
689 #ifndef QT_NO_FREETYPE
690     if (face_id.index == -1) {
691         face_id = fontFile(_name, &freetype, &synth);
692         if (_codec)
693             face_id.encoding = _codec->mibEnum();
694         if (freetype) {
695             const_cast<QFontEngineXLFD *>(this)->fsType = freetype->fsType();
696         } else {
697             face_id.index = 0;
698             face_id.filename = '-' + QFontEngine::properties().postscriptName;
699         }
700     }
701 #endif
702 
703     return face_id;
704 }
705 
properties() const706 QFontEngine::Properties QFontEngineXLFD::properties() const
707 {
708     if (face_id.index == -1)
709         (void)faceId();
710 
711 #ifndef QT_NO_FREETYPE
712     if (freetype)
713         return freetype->properties();
714 #endif
715     return QFontEngine::properties();
716 }
717 
getUnscaledGlyph(glyph_t glyph,QPainterPath * path,glyph_metrics_t * metrics)718 void QFontEngineXLFD::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
719 {
720     if (face_id.index == -1)
721         (void)faceId();
722 #ifndef QT_NO_FREETYPE
723     if (!freetype)
724 #endif
725     {
726         QFontEngine::getUnscaledGlyph(glyph, path, metrics);
727         return;
728     }
729 
730 #ifndef QT_NO_FREETYPE
731     freetype->lock();
732 
733     FT_Face face = freetype->face;
734     FT_Set_Char_Size(face, face->units_per_EM << 6, face->units_per_EM << 6, 0, 0);
735     freetype->xsize = face->units_per_EM << 6;
736     freetype->ysize = face->units_per_EM << 6;
737     FT_Set_Transform(face, 0, 0);
738     glyph = glyphIndexToFreetypeGlyphIndex(glyph);
739     FT_Load_Glyph(face, glyph, FT_LOAD_NO_BITMAP);
740 
741     int left  = face->glyph->metrics.horiBearingX;
742     int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
743     int top    = face->glyph->metrics.horiBearingY;
744     int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
745 
746     QFixedPoint p;
747     p.x = 0;
748     p.y = 0;
749     metrics->width = QFixed::fromFixed(right-left);
750     metrics->height = QFixed::fromFixed(top-bottom);
751     metrics->x = QFixed::fromFixed(left);
752     metrics->y = QFixed::fromFixed(-top);
753     metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
754 
755     if (!FT_IS_SCALABLE(freetype->face))
756         QFreetypeFace::addBitmapToPath(face->glyph, p, path);
757     else
758         QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
759 
760     FT_Set_Transform(face, &freetype->matrix, 0);
761     freetype->unlock();
762 #endif // QT_NO_FREETYPE
763 }
764 
765 
getSfntTableData(uint tag,uchar * buffer,uint * length) const766 bool QFontEngineXLFD::getSfntTableData(uint tag, uchar *buffer, uint *length) const
767 {
768 #ifndef QT_NO_FREETYPE
769     if (face_id.index == -1)
770         (void)faceId();
771     if (!freetype)
772         return false;
773     return freetype->getSfntTable(tag, buffer, length);
774 #else
775     Q_UNUSED(tag);
776     Q_UNUSED(buffer);
777     Q_UNUSED(length);
778     return false;
779 #endif
780 }
781 
synthesized() const782 int QFontEngineXLFD::synthesized() const
783 {
784     return synth;
785 }
786 
alphaMapForGlyph(glyph_t glyph)787 QImage QFontEngineXLFD::alphaMapForGlyph(glyph_t glyph)
788 {
789     glyph_metrics_t metrics = boundingBox(glyph);
790 
791 /*
792     printf("a) w=%.2f, h=%.2f, xoff=%.2f, yoff=%.2f, x=%.2f, y=%.2f\n",
793            metrics.width.toReal(),
794            metrics.height.toReal(),
795            metrics.xoff.toReal(),
796            metrics.yoff.toReal(),
797            metrics.x.toReal(),
798            metrics.y.toReal());
799 */
800 
801     QGlyphLayoutArray<1> glyphs;
802     glyphs.glyphs[0] = glyph;
803 
804     QImage image = bitmapForGlyphs(glyphs, metrics).toImage();
805 //image.save(QString::fromLatin1("x11cache-%1.png").arg((int)glyph));
806 
807     image = image.convertToFormat(QImage::Format_Indexed8);
808     QVector<QRgb> colors(256);
809     for (int i = 0; i < 256; ++i)
810         colors[i] = qRgba(0, 0, 0, i);
811     image.setColorTable(colors);
812 
813     int width = image.width();
814     int height = image.height();
815     for (int y = 0; y < height; ++y) {
816         uchar *bits = image.scanLine(y);
817         for (int x = 0; x < width; ++x)
818             bits[x] = ~(bits[x]-1);
819     }
820 
821     return image;
822 }
823 
824 #ifndef QT_NO_FREETYPE
825 
non_locked_face() const826 FT_Face QFontEngineXLFD::non_locked_face() const
827 {
828     return freetype ? freetype->face : 0;
829 }
830 
toUnicode(glyph_t g) const831 uint QFontEngineXLFD::toUnicode(glyph_t g) const
832 {
833     if (_codec) {
834         QTextCodec::ConverterState state;
835         state.flags = QTextCodec::ConvertInvalidToNull;
836         uchar data[2];
837         int l = 1;
838         if (g > 255) {
839             data[0] = (g >> 8);
840             data[1] = (g & 255);
841             l = 2;
842         } else {
843             data[0] = g;
844         }
845         QString s = _codec->toUnicode((char *)data, l, &state);
846         Q_ASSERT(s.length() == 1);
847         g = s.at(0).unicode();
848     }
849     return g;
850 }
851 
glyphIndexToFreetypeGlyphIndex(glyph_t g) const852 glyph_t QFontEngineXLFD::glyphIndexToFreetypeGlyphIndex(glyph_t g) const
853 {
854     return FT_Get_Char_Index(freetype->face, toUnicode(g));
855 }
856 #endif
857 
858 #ifndef QT_NO_FONTCONFIG
859 
860 // ------------------------------------------------------------------
861 // Multi FT engine
862 // ------------------------------------------------------------------
863 
engineForPattern(FcPattern * match,const QFontDef & request,int screen)864 static QFontEngine *engineForPattern(FcPattern *match, const QFontDef &request, int screen)
865 {
866     QFontEngineX11FT *engine = new QFontEngineX11FT(match, request, screen);
867     if (!engine->invalid())
868         return engine;
869 
870     delete engine;
871     QFontEngine *fe = new QFontEngineBox(request.pixelSize);
872     fe->fontDef = request;
873     return fe;
874 }
875 
QFontEngineMultiFT(QFontEngine * fe,FcPattern * matchedPattern,FcPattern * p,int s,const QFontDef & req)876 QFontEngineMultiFT::QFontEngineMultiFT(QFontEngine *fe, FcPattern *matchedPattern, FcPattern *p, int s, const QFontDef &req)
877     : QFontEngineMulti(2), request(req), pattern(p), fontSet(0), screen(s)
878 {
879     firstEnginePattern = FcPatternDuplicate(matchedPattern);
880     engines[0] = fe;
881     engines.at(0)->ref.ref();
882     fontDef = engines[0]->fontDef;
883     cache_cost = 100;
884     firstFontIndex = 1;
885 }
886 
~QFontEngineMultiFT()887 QFontEngineMultiFT::~QFontEngineMultiFT()
888 {
889     extern QMutex *qt_fontdatabase_mutex();
890     QMutexLocker locker(qt_fontdatabase_mutex());
891 
892     FcPatternDestroy(pattern);
893     if (firstEnginePattern)
894         FcPatternDestroy(firstEnginePattern);
895     if (fontSet)
896         FcFontSetDestroy(fontSet);
897 }
898 
899 
loadEngine(int at)900 void QFontEngineMultiFT::loadEngine(int at)
901 {
902     extern QMutex *qt_fontdatabase_mutex();
903     QMutexLocker locker(qt_fontdatabase_mutex());
904 
905     extern QFontDef qt_FcPatternToQFontDef(FcPattern *pattern, const QFontDef &);
906     extern FcFontSet *qt_fontSetForPattern(FcPattern *pattern, const QFontDef &request);
907 
908     Q_ASSERT(at > 0);
909     if (!fontSet) {
910         fontSet = qt_fontSetForPattern(pattern, request);
911 
912         // it may happen that the fontset of fallbacks consists of only one font. In this case we
913         // have to fall back to the box fontengine as we cannot render the glyph.
914         if (fontSet->nfont == 1 && at == 1 && engines.size() == 2) {
915             Q_ASSERT(engines.at(at) == 0);
916             QFontEngine *fe = new QFontEngineBox(request.pixelSize);
917             fe->fontDef = request;
918             engines[at] = fe;
919             return;
920         }
921 
922         if (firstEnginePattern) {
923 
924             if (!FcPatternEqual(firstEnginePattern, fontSet->fonts[0]))
925                 firstFontIndex = 0;
926 
927             FcPatternDestroy(firstEnginePattern);
928             firstEnginePattern = 0;
929         }
930 
931         engines.resize(fontSet->nfont + 1 - firstFontIndex);
932     }
933     Q_ASSERT(at < engines.size());
934     Q_ASSERT(engines.at(at) == 0);
935 
936     FcPattern *match = FcFontRenderPrepare(NULL, pattern, fontSet->fonts[at + firstFontIndex - 1]);
937     QFontDef fontDef = qt_FcPatternToQFontDef(match, this->request);
938 
939     // note: we use -1 for the script to make sure that we keep real
940     // FT engines separate from Multi engines in the font cache
941     QFontCache::Key key(fontDef, -1, screen);
942     QFontEngine *fontEngine = QFontCache::instance()->findEngine(key);
943     if (!fontEngine) {
944         fontEngine = engineForPattern(match, request, screen);
945         QFontCache::instance()->insertEngine(key, fontEngine);
946     }
947     FcPatternDestroy(match);
948     fontEngine->ref.ref();
949     engines[at] = fontEngine;
950 }
951 
952 // ------------------------------------------------------------------
953 // X11 FT engine
954 // ------------------------------------------------------------------
955 
956 
957 
qt_x11ft_convert_pattern(FcPattern * pattern,QByteArray * file_name,int * index,bool * antialias)958 Q_GUI_EXPORT void qt_x11ft_convert_pattern(FcPattern *pattern, QByteArray *file_name, int *index, bool *antialias)
959 {
960     FcChar8 *fileName;
961     FcPatternGetString(pattern, FC_FILE, 0, &fileName);
962     *file_name = (const char *)fileName;
963     if (!FcPatternGetInteger(pattern, FC_INDEX, 0, index))
964         index = 0;
965     FcBool b;
966     if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &b) == FcResultMatch)
967         *antialias = b;
968 }
969 
970 
QFontEngineX11FT(FcPattern * pattern,const QFontDef & fd,int screen)971 QFontEngineX11FT::QFontEngineX11FT(FcPattern *pattern, const QFontDef &fd, int screen)
972     : QFontEngineFT(fd)
973 {
974 //     FcPatternPrint(pattern);
975 
976     bool antialias = X11->fc_antialias;
977     QByteArray file_name;
978     int face_index;
979     qt_x11ft_convert_pattern(pattern, &file_name, &face_index, &antialias);
980     QFontEngine::FaceId face_id;
981     face_id.filename = file_name;
982     face_id.index = face_index;
983 
984     canUploadGlyphsToServer = QApplication::testAttribute(Qt::AA_X11InitThreads) || (qApp->thread() == QThread::currentThread());
985 
986     subpixelType = Subpixel_None;
987     if (antialias) {
988         int subpixel = X11->display ? X11->screens[screen].subpixel : FC_RGBA_UNKNOWN;
989         if (subpixel == FC_RGBA_UNKNOWN)
990             (void) FcPatternGetInteger(pattern, FC_RGBA, 0, &subpixel);
991         if (!antialias || subpixel == FC_RGBA_UNKNOWN)
992             subpixel = FC_RGBA_NONE;
993 
994         switch (subpixel) {
995             case FC_RGBA_NONE: subpixelType = Subpixel_None; break;
996             case FC_RGBA_RGB: subpixelType = Subpixel_RGB; break;
997             case FC_RGBA_BGR: subpixelType = Subpixel_BGR; break;
998             case FC_RGBA_VRGB: subpixelType = Subpixel_VRGB; break;
999             case FC_RGBA_VBGR: subpixelType = Subpixel_VBGR; break;
1000             default: break;
1001         }
1002     }
1003 
1004     if (fd.hintingPreference != QFont::PreferDefaultHinting) {
1005         switch (fd.hintingPreference) {
1006         case QFont::PreferNoHinting:
1007             default_hint_style = HintNone;
1008             break;
1009         case QFont::PreferVerticalHinting:
1010             default_hint_style = HintLight;
1011             break;
1012         case QFont::PreferFullHinting:
1013         default:
1014             default_hint_style = HintFull;
1015             break;
1016         }
1017     }
1018 #ifdef FC_HINT_STYLE
1019     else {
1020         int hint_style = 0;
1021         // Try to use Xft.hintstyle from XDefaults first if running in GNOME, to match
1022         // the behavior of cairo
1023         if (X11->fc_hint_style > -1 && X11->desktopEnvironment == DE_GNOME)
1024             hint_style = X11->fc_hint_style;
1025         else if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch
1026                  && X11->fc_hint_style > -1)
1027             hint_style = X11->fc_hint_style;
1028 
1029         switch (hint_style) {
1030         case FC_HINT_NONE:
1031             default_hint_style = HintNone;
1032             break;
1033         case FC_HINT_SLIGHT:
1034             default_hint_style = HintLight;
1035             break;
1036         case FC_HINT_MEDIUM:
1037             default_hint_style = HintMedium;
1038             break;
1039         default:
1040             default_hint_style = HintFull;
1041             break;
1042         }
1043     }
1044 #endif
1045 
1046 #if defined(FC_AUTOHINT) && defined(FT_LOAD_FORCE_AUTOHINT)
1047     {
1048         bool autohint = false;
1049 
1050         FcBool b;
1051         if (FcPatternGetBool(pattern, FC_AUTOHINT, 0, &b) == FcResultMatch)
1052             autohint = b;
1053 
1054         if (autohint)
1055             default_load_flags |= FT_LOAD_FORCE_AUTOHINT;
1056     }
1057 #endif
1058 
1059 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1060     {
1061         int filter = FC_LCD_FILTER_NONE;
1062         if (FcPatternGetInteger(pattern, FC_LCD_FILTER, 0, &filter) == FcResultMatch) {
1063             switch (filter) {
1064             case FC_LCD_FILTER_NONE:
1065                 lcdFilterType = FT_LCD_FILTER_NONE;
1066                 break;
1067             case FC_LCD_FILTER_DEFAULT:
1068                 lcdFilterType = FT_LCD_FILTER_DEFAULT;
1069                 break;
1070             case FC_LCD_FILTER_LIGHT:
1071                 lcdFilterType = FT_LCD_FILTER_LIGHT;
1072                 break;
1073             case FC_LCD_FILTER_LEGACY:
1074                 lcdFilterType = FT_LCD_FILTER_LEGACY;
1075                 break;
1076             default:
1077                 // new unknown lcd filter type?!
1078                 break;
1079             }
1080         }
1081     }
1082 #endif
1083 
1084 #ifdef FC_EMBEDDED_BITMAP
1085     {
1086         FcBool b;
1087         if (FcPatternGetBool(pattern, FC_EMBEDDED_BITMAP, 0, &b) == FcResultMatch)
1088             embeddedbitmap = b;
1089     }
1090 #endif
1091 
1092     GlyphFormat defaultFormat = Format_None;
1093 
1094 #ifndef QT_NO_XRENDER
1095     if (X11->use_xrender) {
1096         int format = PictStandardA8;
1097         if (!antialias)
1098             format = PictStandardA1;
1099         else if (subpixelType == Subpixel_RGB
1100                  || subpixelType == Subpixel_BGR
1101                  || subpixelType == Subpixel_VRGB
1102                  || subpixelType == Subpixel_VBGR)
1103             format = PictStandardARGB32;
1104         xglyph_format = format;
1105 
1106         if (subpixelType != QFontEngineFT::Subpixel_None)
1107             defaultFormat = Format_A32;
1108         else if (antialias)
1109             defaultFormat = Format_A8;
1110         else
1111             defaultFormat = Format_Mono;
1112     }
1113 #endif
1114 
1115     if (!init(face_id, antialias, defaultFormat))
1116         return;
1117 
1118     if (!freetype->charset) {
1119         FcCharSet *cs;
1120         FcPatternGetCharSet (pattern, FC_CHARSET, 0, &cs);
1121         freetype->charset = FcCharSetCopy(cs);
1122     }
1123 }
1124 
~QFontEngineX11FT()1125 QFontEngineX11FT::~QFontEngineX11FT()
1126 {
1127     freeGlyphSets();
1128 }
1129 
allocateServerGlyphSet()1130 unsigned long QFontEngineX11FT::allocateServerGlyphSet()
1131 {
1132 #ifndef QT_NO_XRENDER
1133     if (!canUploadGlyphsToServer || !X11->use_xrender)
1134         return 0;
1135     return XRenderCreateGlyphSet(X11->display, XRenderFindStandardFormat(X11->display, xglyph_format));
1136 #else
1137     return 0;
1138 #endif
1139 }
1140 
freeServerGlyphSet(unsigned long id)1141 void QFontEngineX11FT::freeServerGlyphSet(unsigned long id)
1142 {
1143 #ifndef QT_NO_XRENDER
1144     if (!id)
1145         return;
1146     XRenderFreeGlyphSet(X11->display, id);
1147 #endif
1148 }
1149 
uploadGlyphToServer(QGlyphSet * set,uint glyphid,Glyph * g,GlyphInfo * info,int glyphDataSize) const1150 bool QFontEngineX11FT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
1151 {
1152 #ifndef QT_NO_XRENDER
1153     if (!canUploadGlyphsToServer)
1154         return false;
1155     if (g->format == Format_Mono) {
1156         /*
1157          * swap bit order around; FreeType is always MSBFirst
1158          */
1159         if (BitmapBitOrder(X11->display) != MSBFirst) {
1160             unsigned char *line = g->data;
1161             int i = glyphDataSize;
1162             while (i--) {
1163                 unsigned char c;
1164                 c = *line;
1165                 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1166                 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1167                 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1168                 *line++ = c;
1169             }
1170         }
1171     }
1172 
1173     ::Glyph xglyph = glyphid;
1174     XRenderAddGlyphs (X11->display, set->id, &xglyph, info, 1, (const char *)g->data, glyphDataSize);
1175     delete [] g->data;
1176     g->data = 0;
1177     g->format = Format_None;
1178     g->uploadedToServer = true;
1179     return true;
1180 #else
1181     return false;
1182 #endif
1183 }
1184 
cloneWithSize(qreal pixelSize) const1185 QFontEngine *QFontEngineX11FT::cloneWithSize(qreal pixelSize) const
1186 {
1187     QFontDef fontDef;
1188     fontDef.pixelSize = pixelSize;
1189     QFontEngineX11FT *fe = new QFontEngineX11FT(fontDef);
1190     if (!fe->initFromFontEngine(this)) {
1191         delete fe;
1192         return 0;
1193     } else {
1194 #ifndef QT_NO_XRENDER
1195         fe->xglyph_format = xglyph_format;
1196 #endif
1197         return fe;
1198     }
1199 }
1200 
1201 #endif // QT_NO_FONTCONFIG
1202 
1203 QT_END_NAMESPACE
1204