Fix uses of qRound on non-floating-point types.
[profile/ivi/qtbase.git] / src / gui / text / qfontengine_x11.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
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.
17 **
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.
21 **
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.
29 **
30 ** Other Usage
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.
33 **
34 **
35 **
36 **
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
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
115 QFontEngineMultiXLFD::~QFontEngineMultiXLFD()
116 { }
117
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
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
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
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
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
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
350 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 (i < len - 1
362             && s[i].unicode() >= 0xd800 && s[i].unicode() < 0xdc00
363             && s[i+1].unicode() >= 0xdc00 && s[i].unicode() < 0xe000) {
364             *str = QChar();
365             ++i;
366         } else {
367             *str = s[i];
368         }
369         ++str;
370     }
371
372     len = str - (QChar *)_s.data();
373     str = (QChar *)_s.data();
374
375     bool mirrored = flags & QTextEngine::RightToLeft;
376     if (_codec) {
377         bool haveNbsp = false;
378         for (int i = 0; i < len; i++)
379             if (str[i].unicode() == 0xa0) {
380                 haveNbsp = true;
381                 break;
382             }
383
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()));
390         } else {
391             for (int i = 0; i < len; i++)
392                 chars[i] = str[i].unicode();
393         }
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];
402                 data += 2;
403             }
404         } else {
405             const uchar *data = (const uchar *)ba.constData();
406             for (int i = 0; i < len; i++)
407                 glyphs->glyphs[i] = (ushort)data[i];
408         }
409     } else {
410         int i = len;
411         const QChar *c = str + len;
412         if (mirrored) {
413             while (c != str)
414                 glyphs->glyphs[--i] = (--c)->unicode() == 0xa0 ? 0x20 : QChar::mirroredChar(c->unicode());
415         } else {
416             while (c != str)
417                 glyphs->glyphs[--i] = (--c)->unicode() == 0xa0 ? 0x20 : c->unicode();
418         }
419     }
420     *nglyphs = len;
421     glyphs->numGlyphs = len;
422
423     if (!(flags & QTextEngine::GlyphIndicesOnly))
424         recalcAdvances(glyphs, flags);
425     return true;
426 }
427
428 void QFontEngineXLFD::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags /*flags*/) const
429 {
430     int i = glyphs->numGlyphs;
431     XCharStruct *xcs;
432     // inlined for better performance
433     if (!_fs->per_char) {
434         xcs = &_fs->min_bounds;
435         while (i != 0) {
436             --i;
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;
444             } else {
445                 glyphs->glyphs[i] = 0;
446             }
447         }
448     }
449     else if (!_fs->max_byte1) {
450         XCharStruct *base = _fs->per_char - _fs->min_char_or_byte2;
451         while (i != 0) {
452             unsigned int gl = glyphs->glyphs[--i];
453             xcs = (gl >= _fs->min_char_or_byte2 && gl <= _fs->max_char_or_byte2) ?
454                   base + gl : 0;
455             if (!xcs || (!xcs->width && !xcs->ascent && !xcs->descent)) {
456                 glyphs->glyphs[i] = 0;
457             } else {
458                 glyphs->advances_x[i] = xcs->width;
459             }
460         }
461     }
462     else {
463         while (i != 0) {
464             xcs = charStruct(_fs, glyphs->glyphs[--i]);
465             if (!xcs) {
466                 glyphs->glyphs[i] = 0;
467             } else {
468                 glyphs->advances_x[i] = xcs->width;
469             }
470         }
471     }
472 }
473
474 glyph_metrics_t QFontEngineXLFD::boundingBox(const QGlyphLayout &glyphs)
475 {
476     int i;
477
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;
482     QFixed ymax;
483     QFixed xmax;
484     for (i = 0; i < glyphs.numGlyphs; i++) {
485         XCharStruct *xcs = charStruct(_fs, glyphs.glyphs[i]);
486         if (xcs) {
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);
495         } else {
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);
502         }
503     }
504     overall.height = qMax(overall.height, ymax - overall.y);
505     overall.width = xmax - overall.x;
506
507     return overall;
508 }
509
510 glyph_metrics_t QFontEngineXLFD::boundingBox(glyph_t glyph)
511 {
512     glyph_metrics_t gm;
513     XCharStruct *xcs = charStruct(_fs, glyph);
514     if (xcs) {
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,
518                               xcs->width, 0);
519     } else {
520         QFixed size = ascent();
521         gm = glyph_metrics_t(0, size, size, size, size, 0);
522     }
523     return gm;
524 }
525
526 QFixed QFontEngineXLFD::ascent() const
527 {
528     return _fs->ascent;
529 }
530
531 QFixed QFontEngineXLFD::descent() const
532 {
533     return (_fs->descent-1);
534 }
535
536 QFixed QFontEngineXLFD::leading() const
537 {
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);
540     return l.ceil();
541 }
542
543 qreal QFontEngineXLFD::maxCharWidth() const
544 {
545     return _fs->max_bounds.width;
546 }
547
548
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);
554 }
555
556 qreal QFontEngineXLFD::minLeftBearing() const
557 {
558     if (lbearing == SHRT_MIN) {
559         if (_fs->per_char) {
560             XCharStruct *cs = _fs->per_char;
561             int nc = maxIndex(_fs) + 1;
562             int mx = cs->lbearing;
563
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))
569                     continue;
570
571                 int nmx = cs[c].lbearing;
572
573                 if (nmx < mx)
574                     mx = nmx;
575             }
576
577             ((QFontEngineXLFD *)this)->lbearing = mx;
578         } else
579             ((QFontEngineXLFD *)this)->lbearing = _fs->min_bounds.lbearing;
580     }
581     return lbearing;
582 }
583
584 qreal QFontEngineXLFD::minRightBearing() const
585 {
586     if (rbearing == SHRT_MIN) {
587         if (_fs->per_char) {
588             XCharStruct *cs = _fs->per_char;
589             int nc = maxIndex(_fs) + 1;
590             int mx = cs->rbearing;
591
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))
597                     continue;
598
599                 int nmx = cs[c].rbearing;
600
601                 if (nmx < mx)
602                     mx = nmx;
603             }
604
605             ((QFontEngineXLFD *)this)->rbearing = mx;
606         } else
607             ((QFontEngineXLFD *)this)->rbearing = _fs->min_bounds.rbearing;
608     }
609     return rbearing;
610 }
611
612 const char *QFontEngineXLFD::name() const
613 {
614     return _name;
615 }
616
617 bool QFontEngineXLFD::canRender(const QChar *string, int len)
618 {
619     QVarLengthGlyphLayoutArray glyphs(len);
620     int nglyphs = len;
621     if (stringToCMap(string, len, &glyphs, &nglyphs, 0) == false) {
622         glyphs.resize(nglyphs);
623         stringToCMap(string, len, &glyphs, &nglyphs, 0);
624     }
625
626     bool allExist = true;
627     for (int i = 0; i < nglyphs; i++) {
628         if (!glyphs.glyphs[i] || !charStruct(_fs, glyphs.glyphs[i])) {
629             allExist = false;
630             break;
631         }
632     }
633
634     return allExist;
635 }
636
637 QBitmap QFontEngineXLFD::bitmapForGlyphs(const QGlyphLayout &glyphs, const glyph_metrics_t &metrics, QTextItem::RenderFlags flags)
638 {
639     int w = metrics.width.toInt();
640     int h = metrics.height.toInt();
641     if (w <= 0 || h <= 0)
642         return QBitmap();
643
644     QPixmapData *data = new QX11PixmapData(QPixmapData::BitmapType);
645     data->resize(w, h);
646     QPixmap bm(data);
647     QPainter p(&bm);
648     p.fillRect(0, 0, w, h, Qt::color0);
649     p.setPen(Qt::color1);
650
651     QTextItemInt item;
652     item.flags = flags;
653     item.ascent = -metrics.y;
654     item.descent = metrics.height - item.ascent;
655     item.width = metrics.width;
656     item.chars = 0;
657     item.num_chars = 0;
658     item.logClusters = 0;
659     item.glyphs = glyphs;
660     item.fontEngine = this;
661     item.f = 0;
662
663     p.drawTextItem(QPointF(-metrics.x.toReal(), item.ascent.toReal()), item);
664     p.end();
665
666     return QBitmap(bm);
667 }
668
669 void QFontEngineXLFD::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
670 {
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);
675
676     QImage image = bitmapForGlyphs(glyphs, metrics, flags).toImage();
677     if (image.isNull())
678         return;
679
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);
687 }
688
689 QFontEngine::FaceId QFontEngineXLFD::faceId() const
690 {
691 #ifndef QT_NO_FREETYPE
692     if (face_id.index == -1) {
693         face_id = fontFile(_name, &freetype, &synth);
694         if (_codec)
695             face_id.encoding = _codec->mibEnum();
696         if (freetype) {
697             const_cast<QFontEngineXLFD *>(this)->fsType = freetype->fsType();
698         } else {
699             face_id.index = 0;
700             face_id.filename = '-' + QFontEngine::properties().postscriptName;
701         }
702     }
703 #endif
704
705     return face_id;
706 }
707
708 QFontEngine::Properties QFontEngineXLFD::properties() const
709 {
710     if (face_id.index == -1)
711         (void)faceId();
712
713 #ifndef QT_NO_FREETYPE
714     if (freetype)
715         return freetype->properties();
716 #endif
717     return QFontEngine::properties();
718 }
719
720 void QFontEngineXLFD::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
721 {
722     if (face_id.index == -1)
723         (void)faceId();
724 #ifndef QT_NO_FREETYPE
725     if (!freetype)
726 #endif
727     {
728         QFontEngine::getUnscaledGlyph(glyph, path, metrics);
729         return;
730     }
731
732 #ifndef QT_NO_FREETYPE
733     freetype->lock();
734
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);
742
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;
747
748     QFixedPoint p;
749     p.x = 0;
750     p.y = 0;
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);
756
757     if (!FT_IS_SCALABLE(freetype->face))
758         QFreetypeFace::addBitmapToPath(face->glyph, p, path);
759     else
760         QFreetypeFace::addGlyphToPath(face, face->glyph, p, path, face->units_per_EM << 6, face->units_per_EM << 6);
761
762     FT_Set_Transform(face, &freetype->matrix, 0);
763     freetype->unlock();
764 #endif // QT_NO_FREETYPE
765 }
766
767
768 bool QFontEngineXLFD::getSfntTableData(uint tag, uchar *buffer, uint *length) const
769 {
770 #ifndef QT_NO_FREETYPE
771     if (face_id.index == -1)
772         (void)faceId();
773     if (!freetype)
774         return false;
775     return freetype->getSfntTable(tag, buffer, length);
776 #else
777     Q_UNUSED(tag);
778     Q_UNUSED(buffer);
779     Q_UNUSED(length);
780     return false;
781 #endif
782 }
783
784 int QFontEngineXLFD::synthesized() const
785 {
786     return synth;
787 }
788
789 QImage QFontEngineXLFD::alphaMapForGlyph(glyph_t glyph)
790 {
791     glyph_metrics_t metrics = boundingBox(glyph);
792
793 /*
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(),
799            metrics.x.toReal(),
800            metrics.y.toReal());
801 */
802
803     QGlyphLayoutArray<1> glyphs;
804     glyphs.glyphs[0] = glyph;
805
806     QImage image = bitmapForGlyphs(glyphs, metrics).toImage();
807 //image.save(QString::fromLatin1("x11cache-%1.png").arg((int)glyph));
808
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);
814
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);
821     }
822
823     return image;
824 }
825
826 #ifndef QT_NO_FREETYPE
827
828 FT_Face QFontEngineXLFD::non_locked_face() const
829 {
830     return freetype ? freetype->face : 0;
831 }
832
833 uint QFontEngineXLFD::toUnicode(glyph_t g) const
834 {
835     if (_codec) {
836         QTextCodec::ConverterState state;
837         state.flags = QTextCodec::ConvertInvalidToNull;
838         uchar data[2];
839         int l = 1;
840         if (g > 255) {
841             data[0] = (g >> 8);
842             data[1] = (g & 255);
843             l = 2;
844         } else {
845             data[0] = g;
846         }
847         QString s = _codec->toUnicode((char *)data, l, &state);
848         Q_ASSERT(s.length() == 1);
849         g = s.at(0).unicode();
850     }
851     return g;
852 }
853
854 glyph_t QFontEngineXLFD::glyphIndexToFreetypeGlyphIndex(glyph_t g) const
855 {
856     return FT_Get_Char_Index(freetype->face, toUnicode(g));
857 }
858 #endif
859
860 #ifndef QT_NO_FONTCONFIG
861
862 // ------------------------------------------------------------------
863 // Multi FT engine
864 // ------------------------------------------------------------------
865
866 static QFontEngine *engineForPattern(FcPattern *match, const QFontDef &request, int screen)
867 {
868     QFontEngineX11FT *engine = new QFontEngineX11FT(match, request, screen);
869     if (!engine->invalid())
870         return engine;
871
872     delete engine;
873     QFontEngine *fe = new QFontEngineBox(request.pixelSize);
874     fe->fontDef = request;
875     return fe;
876 }
877
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)
880 {
881     firstEnginePattern = FcPatternDuplicate(matchedPattern);
882     engines[0] = fe;
883     engines.at(0)->ref.ref();
884     fontDef = engines[0]->fontDef;
885     cache_cost = 100;
886     firstFontIndex = 1;
887 }
888
889 QFontEngineMultiFT::~QFontEngineMultiFT()
890 {
891     extern QMutex *qt_fontdatabase_mutex();
892     QMutexLocker locker(qt_fontdatabase_mutex());
893
894     FcPatternDestroy(pattern);
895     if (firstEnginePattern)
896         FcPatternDestroy(firstEnginePattern);
897     if (fontSet)
898         FcFontSetDestroy(fontSet);
899 }
900
901
902 void QFontEngineMultiFT::loadEngine(int at)
903 {
904     extern QMutex *qt_fontdatabase_mutex();
905     QMutexLocker locker(qt_fontdatabase_mutex());
906
907     extern QFontDef qt_FcPatternToQFontDef(FcPattern *pattern, const QFontDef &);
908     extern FcFontSet *qt_fontSetForPattern(FcPattern *pattern, const QFontDef &request);
909
910     Q_ASSERT(at > 0);
911     if (!fontSet) {
912         fontSet = qt_fontSetForPattern(pattern, request);
913
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;
920             engines[at] = fe;
921             return;
922         }
923
924         if (firstEnginePattern) {
925
926             if (!FcPatternEqual(firstEnginePattern, fontSet->fonts[0]))
927                 firstFontIndex = 0;
928
929             FcPatternDestroy(firstEnginePattern);
930             firstEnginePattern = 0;
931         }
932
933         engines.resize(fontSet->nfont + 1 - firstFontIndex);
934     }
935     Q_ASSERT(at < engines.size());
936     Q_ASSERT(engines.at(at) == 0);
937
938     FcPattern *match = FcFontRenderPrepare(NULL, pattern, fontSet->fonts[at + firstFontIndex - 1]);
939     QFontDef fontDef = qt_FcPatternToQFontDef(match, this->request);
940
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);
945     if (!fontEngine) {
946         fontEngine = engineForPattern(match, request, screen);
947         QFontCache::instance()->insertEngine(key, fontEngine);
948     }
949     FcPatternDestroy(match);
950     fontEngine->ref.ref();
951     engines[at] = fontEngine;
952 }
953
954 // ------------------------------------------------------------------
955 // X11 FT engine
956 // ------------------------------------------------------------------
957
958
959
960 Q_GUI_EXPORT void qt_x11ft_convert_pattern(FcPattern *pattern, QByteArray *file_name, int *index, bool *antialias)
961 {
962     FcChar8 *fileName;
963     FcPatternGetString(pattern, FC_FILE, 0, &fileName);
964     *file_name = (const char *)fileName;
965     if (!FcPatternGetInteger(pattern, FC_INDEX, 0, index))
966         index = 0;
967     FcBool b;
968     if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &b) == FcResultMatch)
969         *antialias = b;
970 }
971
972
973 QFontEngineX11FT::QFontEngineX11FT(FcPattern *pattern, const QFontDef &fd, int screen)
974     : QFontEngineFT(fd)
975 {
976 //     FcPatternPrint(pattern);
977
978     bool antialias = X11->fc_antialias;
979     QByteArray file_name;
980     int face_index;
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;
985
986     canUploadGlyphsToServer = QApplication::testAttribute(Qt::AA_X11InitThreads) || (qApp->thread() == QThread::currentThread());
987
988     subpixelType = Subpixel_None;
989     if (antialias) {
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;
995
996         switch (subpixel) {
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;
1002             default: break;
1003         }
1004     }
1005
1006     if (fd.hintingPreference != QFont::PreferDefaultHinting) {
1007         switch (fd.hintingPreference) {
1008         case QFont::PreferNoHinting:
1009             default_hint_style = HintNone;
1010             break;
1011         case QFont::PreferVerticalHinting:
1012             default_hint_style = HintLight;
1013             break;
1014         case QFont::PreferFullHinting:
1015         default:
1016             default_hint_style = HintFull;
1017             break;
1018         }
1019     }
1020 #ifdef FC_HINT_STYLE
1021     else {
1022         int hint_style = 0;
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;
1030
1031         switch (hint_style) {
1032         case FC_HINT_NONE:
1033             default_hint_style = HintNone;
1034             break;
1035         case FC_HINT_SLIGHT:
1036             default_hint_style = HintLight;
1037             break;
1038         case FC_HINT_MEDIUM:
1039             default_hint_style = HintMedium;
1040             break;
1041         default:
1042             default_hint_style = HintFull;
1043             break;
1044         }
1045     }
1046 #endif
1047
1048 #if defined(FC_AUTOHINT) && defined(FT_LOAD_FORCE_AUTOHINT)
1049     {
1050         bool autohint = false;
1051
1052         FcBool b;
1053         if (FcPatternGetBool(pattern, FC_AUTOHINT, 0, &b) == FcResultMatch)
1054             autohint = b;
1055
1056         if (autohint)
1057             default_load_flags |= FT_LOAD_FORCE_AUTOHINT;
1058     }
1059 #endif
1060
1061 #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
1062     {
1063         int filter = FC_LCD_FILTER_NONE;
1064         if (FcPatternGetInteger(pattern, FC_LCD_FILTER, 0, &filter) == FcResultMatch) {
1065             switch (filter) {
1066             case FC_LCD_FILTER_NONE:
1067                 lcdFilterType = FT_LCD_FILTER_NONE;
1068                 break;
1069             case FC_LCD_FILTER_DEFAULT:
1070                 lcdFilterType = FT_LCD_FILTER_DEFAULT;
1071                 break;
1072             case FC_LCD_FILTER_LIGHT:
1073                 lcdFilterType = FT_LCD_FILTER_LIGHT;
1074                 break;
1075             case FC_LCD_FILTER_LEGACY:
1076                 lcdFilterType = FT_LCD_FILTER_LEGACY;
1077                 break;
1078             default:
1079                 // new unknown lcd filter type?!
1080                 break;
1081             }
1082         }
1083     }
1084 #endif
1085
1086 #ifdef FC_EMBEDDED_BITMAP
1087     {
1088         FcBool b;
1089         if (FcPatternGetBool(pattern, FC_EMBEDDED_BITMAP, 0, &b) == FcResultMatch)
1090             embeddedbitmap = b;
1091     }
1092 #endif
1093
1094     GlyphFormat defaultFormat = Format_None;
1095
1096 #ifndef QT_NO_XRENDER
1097     if (X11->use_xrender) {
1098         int format = PictStandardA8;
1099         if (!antialias)
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;
1107
1108         if (subpixelType != QFontEngineFT::Subpixel_None)
1109             defaultFormat = Format_A32;
1110         else if (antialias)
1111             defaultFormat = Format_A8;
1112         else
1113             defaultFormat = Format_Mono;
1114     }
1115 #endif
1116
1117     if (!init(face_id, antialias, defaultFormat))
1118         return;
1119
1120     if (!freetype->charset) {
1121         FcCharSet *cs;
1122         FcPatternGetCharSet (pattern, FC_CHARSET, 0, &cs);
1123         freetype->charset = FcCharSetCopy(cs);
1124     }
1125 }
1126
1127 QFontEngineX11FT::~QFontEngineX11FT()
1128 {
1129     freeGlyphSets();
1130 }
1131
1132 unsigned long QFontEngineX11FT::allocateServerGlyphSet()
1133 {
1134 #ifndef QT_NO_XRENDER
1135     if (!canUploadGlyphsToServer || !X11->use_xrender)
1136         return 0;
1137     return XRenderCreateGlyphSet(X11->display, XRenderFindStandardFormat(X11->display, xglyph_format));
1138 #else
1139     return 0;
1140 #endif
1141 }
1142
1143 void QFontEngineX11FT::freeServerGlyphSet(unsigned long id)
1144 {
1145 #ifndef QT_NO_XRENDER
1146     if (!id)
1147         return;
1148     XRenderFreeGlyphSet(X11->display, id);
1149 #endif
1150 }
1151
1152 bool QFontEngineX11FT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
1153 {
1154 #ifndef QT_NO_XRENDER
1155     if (!canUploadGlyphsToServer)
1156         return false;
1157     if (g->format == Format_Mono) {
1158         /*
1159          * swap bit order around; FreeType is always MSBFirst
1160          */
1161         if (BitmapBitOrder(X11->display) != MSBFirst) {
1162             unsigned char *line = g->data;
1163             int i = glyphDataSize;
1164             while (i--) {
1165                 unsigned char c;
1166                 c = *line;
1167                 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
1168                 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
1169                 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
1170                 *line++ = c;
1171             }
1172         }
1173     }
1174
1175     ::Glyph xglyph = glyphid;
1176     XRenderAddGlyphs (X11->display, set->id, &xglyph, info, 1, (const char *)g->data, glyphDataSize);
1177     delete [] g->data;
1178     g->data = 0;
1179     g->format = Format_None;
1180     g->uploadedToServer = true;
1181     return true;
1182 #else
1183     return false;
1184 #endif
1185 }
1186
1187 QFontEngine *QFontEngineX11FT::cloneWithSize(qreal pixelSize) const
1188 {
1189     QFontDef fontDef;
1190     fontDef.pixelSize = pixelSize;
1191     QFontEngineX11FT *fe = new QFontEngineX11FT(fontDef);
1192     if (!fe->initFromFontEngine(this)) {
1193         delete fe;
1194         return 0;
1195     } else {
1196 #ifndef QT_NO_XRENDER
1197         fe->xglyph_format = xglyph_format;
1198 #endif
1199         return fe;
1200     }
1201 }
1202
1203 #endif // QT_NO_FONTCONFIG
1204
1205 QT_END_NAMESPACE