1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation ([email protected])
|
---|
6 | **
|
---|
7 | ** This file is part of the QtGui module of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
14 | ** a written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Lesser General Public License Usage
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
18 | ** General Public License version 2.1 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
20 | ** packaging of this file. Please review the following information to
|
---|
21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
23 | **
|
---|
24 | ** In addition, as a special exception, Nokia gives you certain additional
|
---|
25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
---|
26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you have questions regarding the use of this file, please contact
|
---|
37 | ** Nokia at [email protected].
|
---|
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 *pattern, const QFontDef &request,
|
---|
867 | int screen)
|
---|
868 | {
|
---|
869 | FcResult res;
|
---|
870 | FcPattern *match = FcFontMatch(0, pattern, &res);
|
---|
871 | QFontEngineX11FT *engine = new QFontEngineX11FT(match, request, screen);
|
---|
872 | if (!engine->invalid())
|
---|
873 | return engine;
|
---|
874 |
|
---|
875 | delete engine;
|
---|
876 | QFontEngine *fe = new QFontEngineBox(request.pixelSize);
|
---|
877 | fe->fontDef = request;
|
---|
878 | return fe;
|
---|
879 | }
|
---|
880 |
|
---|
881 | QFontEngineMultiFT::QFontEngineMultiFT(QFontEngine *fe, FcPattern *matchedPattern, FcPattern *p, int s, const QFontDef &req)
|
---|
882 | : QFontEngineMulti(2), request(req), pattern(p), firstEnginePattern(matchedPattern), fontSet(0), screen(s)
|
---|
883 | {
|
---|
884 |
|
---|
885 | engines[0] = fe;
|
---|
886 | engines.at(0)->ref.ref();
|
---|
887 | fontDef = engines[0]->fontDef;
|
---|
888 | cache_cost = 100;
|
---|
889 | firstFontIndex = 1;
|
---|
890 | }
|
---|
891 |
|
---|
892 | QFontEngineMultiFT::~QFontEngineMultiFT()
|
---|
893 | {
|
---|
894 | extern QMutex *qt_fontdatabase_mutex();
|
---|
895 | QMutexLocker locker(qt_fontdatabase_mutex());
|
---|
896 |
|
---|
897 | FcPatternDestroy(pattern);
|
---|
898 | if (firstEnginePattern)
|
---|
899 | FcPatternDestroy(firstEnginePattern);
|
---|
900 | if (fontSet)
|
---|
901 | FcFontSetDestroy(fontSet);
|
---|
902 | }
|
---|
903 |
|
---|
904 |
|
---|
905 | void QFontEngineMultiFT::loadEngine(int at)
|
---|
906 | {
|
---|
907 | extern QMutex *qt_fontdatabase_mutex();
|
---|
908 | QMutexLocker locker(qt_fontdatabase_mutex());
|
---|
909 |
|
---|
910 | extern void qt_addPatternProps(FcPattern *pattern, int screen, int script,
|
---|
911 | const QFontDef &request);
|
---|
912 | extern QFontDef qt_FcPatternToQFontDef(FcPattern *pattern, const QFontDef &);
|
---|
913 | extern FcFontSet *qt_fontSetForPattern(FcPattern *pattern, const QFontDef &request);
|
---|
914 |
|
---|
915 | Q_ASSERT(at > 0);
|
---|
916 | if (!fontSet) {
|
---|
917 | fontSet = qt_fontSetForPattern(pattern, request);
|
---|
918 |
|
---|
919 | // it may happen that the fontset of fallbacks consists of only one font. In this case we
|
---|
920 | // have to fall back to the box fontengine as we cannot render the glyph.
|
---|
921 | if (fontSet->nfont == 1 && at == 1 && engines.size() == 2) {
|
---|
922 | Q_ASSERT(engines.at(at) == 0);
|
---|
923 | QFontEngine *fe = new QFontEngineBox(request.pixelSize);
|
---|
924 | fe->fontDef = request;
|
---|
925 | engines[at] = fe;
|
---|
926 | return;
|
---|
927 | }
|
---|
928 |
|
---|
929 | if (firstEnginePattern) {
|
---|
930 |
|
---|
931 | if (!FcPatternEqual(firstEnginePattern, fontSet->fonts[0]))
|
---|
932 | firstFontIndex = 0;
|
---|
933 |
|
---|
934 | FcPatternDestroy(firstEnginePattern);
|
---|
935 | firstEnginePattern = 0;
|
---|
936 | }
|
---|
937 |
|
---|
938 | engines.resize(fontSet->nfont + 1 - firstFontIndex);
|
---|
939 | }
|
---|
940 | Q_ASSERT(at < engines.size());
|
---|
941 | Q_ASSERT(engines.at(at) == 0);
|
---|
942 |
|
---|
943 | FcPattern *pattern = FcPatternDuplicate(fontSet->fonts[at + firstFontIndex - 1]);
|
---|
944 | qt_addPatternProps(pattern, screen, QUnicodeTables::Common, request);
|
---|
945 |
|
---|
946 | QFontDef fontDef = qt_FcPatternToQFontDef(pattern, this->request);
|
---|
947 |
|
---|
948 | // note: we use -1 for the script to make sure that we keep real
|
---|
949 | // FT engines separate from Multi engines in the font cache
|
---|
950 | QFontCache::Key key(fontDef, -1, screen);
|
---|
951 | QFontEngine *fontEngine = QFontCache::instance()->findEngine(key);
|
---|
952 | if (!fontEngine) {
|
---|
953 | FcConfigSubstitute(0, pattern, FcMatchPattern);
|
---|
954 | FcDefaultSubstitute(pattern);
|
---|
955 | fontEngine = engineForPattern(pattern, request, screen);
|
---|
956 | QFontCache::instance()->insertEngine(key, fontEngine);
|
---|
957 | }
|
---|
958 | FcPatternDestroy(pattern);
|
---|
959 | fontEngine->ref.ref();
|
---|
960 | engines[at] = fontEngine;
|
---|
961 | }
|
---|
962 |
|
---|
963 | // ------------------------------------------------------------------
|
---|
964 | // X11 FT engine
|
---|
965 | // ------------------------------------------------------------------
|
---|
966 |
|
---|
967 |
|
---|
968 |
|
---|
969 | Q_GUI_EXPORT void qt_x11ft_convert_pattern(FcPattern *pattern, QByteArray *file_name, int *index, bool *antialias)
|
---|
970 | {
|
---|
971 | FcChar8 *fileName;
|
---|
972 | FcPatternGetString(pattern, FC_FILE, 0, &fileName);
|
---|
973 | *file_name = (const char *)fileName;
|
---|
974 | if (!FcPatternGetInteger(pattern, FC_INDEX, 0, index))
|
---|
975 | index = 0;
|
---|
976 | FcBool b;
|
---|
977 | if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &b) == FcResultMatch)
|
---|
978 | *antialias = b;
|
---|
979 | }
|
---|
980 |
|
---|
981 |
|
---|
982 | QFontEngineX11FT::QFontEngineX11FT(FcPattern *pattern, const QFontDef &fd, int screen)
|
---|
983 | : QFontEngineFT(fd)
|
---|
984 | {
|
---|
985 | // FcPatternPrint(pattern);
|
---|
986 |
|
---|
987 | bool antialias = X11->fc_antialias;
|
---|
988 | QByteArray file_name;
|
---|
989 | int face_index;
|
---|
990 | qt_x11ft_convert_pattern(pattern, &file_name, &face_index, &antialias);
|
---|
991 | QFontEngine::FaceId face_id;
|
---|
992 | face_id.filename = file_name;
|
---|
993 | face_id.index = face_index;
|
---|
994 |
|
---|
995 | canUploadGlyphsToServer = qApp->thread() == QThread::currentThread();
|
---|
996 |
|
---|
997 | subpixelType = Subpixel_None;
|
---|
998 | if (antialias) {
|
---|
999 | int subpixel = X11->display ? X11->screens[screen].subpixel : FC_RGBA_UNKNOWN;
|
---|
1000 | if (subpixel == FC_RGBA_UNKNOWN)
|
---|
1001 | (void) FcPatternGetInteger(pattern, FC_RGBA, 0, &subpixel);
|
---|
1002 | if (!antialias || subpixel == FC_RGBA_UNKNOWN)
|
---|
1003 | subpixel = FC_RGBA_NONE;
|
---|
1004 |
|
---|
1005 | switch (subpixel) {
|
---|
1006 | case FC_RGBA_NONE: subpixelType = Subpixel_None; break;
|
---|
1007 | case FC_RGBA_RGB: subpixelType = Subpixel_RGB; break;
|
---|
1008 | case FC_RGBA_BGR: subpixelType = Subpixel_BGR; break;
|
---|
1009 | case FC_RGBA_VRGB: subpixelType = Subpixel_VRGB; break;
|
---|
1010 | case FC_RGBA_VBGR: subpixelType = Subpixel_VBGR; break;
|
---|
1011 | default: break;
|
---|
1012 | }
|
---|
1013 | }
|
---|
1014 |
|
---|
1015 | #ifdef FC_HINT_STYLE
|
---|
1016 | {
|
---|
1017 | int hint_style = 0;
|
---|
1018 | if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch)
|
---|
1019 | hint_style = X11->fc_hint_style;
|
---|
1020 |
|
---|
1021 | switch (hint_style) {
|
---|
1022 | case FC_HINT_NONE:
|
---|
1023 | default_hint_style = HintNone;
|
---|
1024 | break;
|
---|
1025 | case FC_HINT_SLIGHT:
|
---|
1026 | default_hint_style = HintLight;
|
---|
1027 | break;
|
---|
1028 | case FC_HINT_MEDIUM:
|
---|
1029 | default_hint_style = HintMedium;
|
---|
1030 | break;
|
---|
1031 | default:
|
---|
1032 | default_hint_style = HintFull;
|
---|
1033 | break;
|
---|
1034 | }
|
---|
1035 | }
|
---|
1036 | #endif
|
---|
1037 |
|
---|
1038 | #if defined(FC_AUTOHINT) && defined(FT_LOAD_FORCE_AUTOHINT)
|
---|
1039 | {
|
---|
1040 | bool autohint = false;
|
---|
1041 |
|
---|
1042 | FcBool b;
|
---|
1043 | if (FcPatternGetBool(pattern, FC_AUTOHINT, 0, &b) == FcResultMatch)
|
---|
1044 | autohint = b;
|
---|
1045 |
|
---|
1046 | if (autohint)
|
---|
1047 | default_load_flags |= FT_LOAD_FORCE_AUTOHINT;
|
---|
1048 | }
|
---|
1049 | #endif
|
---|
1050 |
|
---|
1051 | #if defined(FC_LCD_FILTER) && defined(FT_LCD_FILTER_H)
|
---|
1052 | {
|
---|
1053 | int filter = FC_LCD_FILTER_NONE;
|
---|
1054 | if (FcPatternGetInteger(pattern, FC_LCD_FILTER, 0, &filter) == FcResultMatch) {
|
---|
1055 | switch (filter) {
|
---|
1056 | case FC_LCD_FILTER_NONE:
|
---|
1057 | lcdFilterType = FT_LCD_FILTER_NONE;
|
---|
1058 | break;
|
---|
1059 | case FC_LCD_FILTER_DEFAULT:
|
---|
1060 | lcdFilterType = FT_LCD_FILTER_DEFAULT;
|
---|
1061 | break;
|
---|
1062 | case FC_LCD_FILTER_LIGHT:
|
---|
1063 | lcdFilterType = FT_LCD_FILTER_LIGHT;
|
---|
1064 | break;
|
---|
1065 | case FC_LCD_FILTER_LEGACY:
|
---|
1066 | lcdFilterType = FT_LCD_FILTER_LEGACY;
|
---|
1067 | break;
|
---|
1068 | default:
|
---|
1069 | // new unknown lcd filter type?!
|
---|
1070 | break;
|
---|
1071 | }
|
---|
1072 | }
|
---|
1073 | }
|
---|
1074 | #endif
|
---|
1075 |
|
---|
1076 | #ifdef FC_EMBEDDED_BITMAP
|
---|
1077 | {
|
---|
1078 | FcBool b;
|
---|
1079 | if (FcPatternGetBool(pattern, FC_EMBEDDED_BITMAP, 0, &b) == FcResultMatch)
|
---|
1080 | embeddedbitmap = b;
|
---|
1081 | }
|
---|
1082 | #endif
|
---|
1083 |
|
---|
1084 | GlyphFormat defaultFormat = Format_None;
|
---|
1085 |
|
---|
1086 | #ifndef QT_NO_XRENDER
|
---|
1087 | if (X11->use_xrender) {
|
---|
1088 | int format = PictStandardA8;
|
---|
1089 | if (!antialias)
|
---|
1090 | format = PictStandardA1;
|
---|
1091 | else if (subpixelType == Subpixel_RGB
|
---|
1092 | || subpixelType == Subpixel_BGR
|
---|
1093 | || subpixelType == Subpixel_VRGB
|
---|
1094 | || subpixelType == Subpixel_VBGR)
|
---|
1095 | format = PictStandardARGB32;
|
---|
1096 | xglyph_format = format;
|
---|
1097 |
|
---|
1098 | if (subpixelType != QFontEngineFT::Subpixel_None)
|
---|
1099 | defaultFormat = Format_A32;
|
---|
1100 | else if (antialias)
|
---|
1101 | defaultFormat = Format_A8;
|
---|
1102 | else
|
---|
1103 | defaultFormat = Format_Mono;
|
---|
1104 | }
|
---|
1105 | #endif
|
---|
1106 |
|
---|
1107 | if (!init(face_id, antialias, defaultFormat)) {
|
---|
1108 | FcPatternDestroy(pattern);
|
---|
1109 | return;
|
---|
1110 | }
|
---|
1111 |
|
---|
1112 | if (!freetype->charset) {
|
---|
1113 | FcCharSet *cs;
|
---|
1114 | FcPatternGetCharSet (pattern, FC_CHARSET, 0, &cs);
|
---|
1115 | freetype->charset = FcCharSetCopy(cs);
|
---|
1116 | }
|
---|
1117 | FcPatternDestroy(pattern);
|
---|
1118 | }
|
---|
1119 |
|
---|
1120 | QFontEngineX11FT::~QFontEngineX11FT()
|
---|
1121 | {
|
---|
1122 | freeGlyphSets();
|
---|
1123 | }
|
---|
1124 |
|
---|
1125 | unsigned long QFontEngineX11FT::allocateServerGlyphSet()
|
---|
1126 | {
|
---|
1127 | #ifndef QT_NO_XRENDER
|
---|
1128 | if (!canUploadGlyphsToServer || !X11->use_xrender)
|
---|
1129 | return 0;
|
---|
1130 | return XRenderCreateGlyphSet(X11->display, XRenderFindStandardFormat(X11->display, xglyph_format));
|
---|
1131 | #else
|
---|
1132 | return 0;
|
---|
1133 | #endif
|
---|
1134 | }
|
---|
1135 |
|
---|
1136 | void QFontEngineX11FT::freeServerGlyphSet(unsigned long id)
|
---|
1137 | {
|
---|
1138 | #ifndef QT_NO_XRENDER
|
---|
1139 | if (!id)
|
---|
1140 | return;
|
---|
1141 | XRenderFreeGlyphSet(X11->display, id);
|
---|
1142 | #endif
|
---|
1143 | }
|
---|
1144 |
|
---|
1145 | bool QFontEngineX11FT::uploadGlyphToServer(QGlyphSet *set, uint glyphid, Glyph *g, GlyphInfo *info, int glyphDataSize) const
|
---|
1146 | {
|
---|
1147 | #ifndef QT_NO_XRENDER
|
---|
1148 | if (!canUploadGlyphsToServer)
|
---|
1149 | return false;
|
---|
1150 | if (g->format == Format_Mono) {
|
---|
1151 | /*
|
---|
1152 | * swap bit order around; FreeType is always MSBFirst
|
---|
1153 | */
|
---|
1154 | if (BitmapBitOrder(X11->display) != MSBFirst) {
|
---|
1155 | unsigned char *line = g->data;
|
---|
1156 | int i = glyphDataSize;
|
---|
1157 | while (i--) {
|
---|
1158 | unsigned char c;
|
---|
1159 | c = *line;
|
---|
1160 | c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
|
---|
1161 | c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
|
---|
1162 | c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
|
---|
1163 | *line++ = c;
|
---|
1164 | }
|
---|
1165 | }
|
---|
1166 | }
|
---|
1167 |
|
---|
1168 | ::Glyph xglyph = glyphid;
|
---|
1169 | XRenderAddGlyphs (X11->display, set->id, &xglyph, info, 1, (const char *)g->data, glyphDataSize);
|
---|
1170 | delete [] g->data;
|
---|
1171 | g->data = 0;
|
---|
1172 | g->format = Format_None;
|
---|
1173 | g->uploadedToServer = true;
|
---|
1174 | return true;
|
---|
1175 | #else
|
---|
1176 | return false;
|
---|
1177 | #endif
|
---|
1178 | }
|
---|
1179 |
|
---|
1180 | #endif // QT_NO_FONTCONFIG
|
---|
1181 |
|
---|
1182 | QT_END_NAMESPACE
|
---|