source: trunk/src/gui/text/qfontengine_x11.cpp@ 1168

Last change on this file since 1168 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 36.5 KB
Line 
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
101QT_BEGIN_NAMESPACE
102
103
104// ------------------------------------------------------------------
105// Multi XLFD engine
106// ------------------------------------------------------------------
107
108QFontEngineMultiXLFD::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
115QFontEngineMultiXLFD::~QFontEngineMultiXLFD()
116{ }
117
118void 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
135static QStringList *qt_fontpath = 0;
136
137static 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
207static 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 }
286end:
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
300extern int qt_mib_for_xlfd_encoding(const char *encoding);
301extern int qt_xlfd_encoding_id(const char *encoding);
302
303static 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
323QFontEngineXLFD::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
340QFontEngineXLFD::~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
350bool 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
428void 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
474glyph_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
510glyph_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
526QFixed QFontEngineXLFD::ascent() const
527{
528 return _fs->ascent;
529}
530
531QFixed QFontEngineXLFD::descent() const
532{
533 return (_fs->descent-1);
534}
535
536QFixed 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
543qreal QFontEngineXLFD::maxCharWidth() const
544{
545 return _fs->max_bounds.width;
546}
547
548
549// Loads the font for the specified script
550static 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
556qreal 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
584qreal 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
612const char *QFontEngineXLFD::name() const
613{
614 return _name;
615}
616
617bool 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
637QBitmap 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
669void 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
689QFontEngine::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
708QFontEngine::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
720void 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
768bool 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
784int QFontEngineXLFD::synthesized() const
785{
786 return synth;
787}
788
789QImage 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
828FT_Face QFontEngineXLFD::non_locked_face() const
829{
830 return freetype ? freetype->face : 0;
831}
832
833uint 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
854glyph_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
866static 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
881QFontEngineMultiFT::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
892QFontEngineMultiFT::~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
905void 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
969Q_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
982QFontEngineX11FT::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
1120QFontEngineX11FT::~QFontEngineX11FT()
1121{
1122 freeGlyphSets();
1123}
1124
1125unsigned 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
1136void 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
1145bool 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
1182QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.