1
/****************************************************************************
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
5
** This file is part of the text module of the Qt Toolkit.
7
** This file may be distributed under the terms of the Q Public License
8
** as defined by Trolltech AS of Norway and appearing in the file
9
** LICENSE.QPL included in the packaging of this file.
11
** This file may be distributed and/or modified under the terms of the
12
** GNU General Public License version 2 as published by the Free Software
13
** Foundation and appearing in the file LICENSE.GPL included in the
14
** packaging of this file.
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
17
** information about Qt Commercial License Agreements.
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
21
** Contact info@trolltech.com if any conditions of this licensing are
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27
****************************************************************************/
31
// #define FONTENGINE_DEBUG
33
#include <qbytearray.h>
34
#include <qtextcodec.h>
36
#include "qfontdatabase.h"
37
#include "qpaintdevice.h"
39
#include "qvarlengtharray.h"
42
#include <private/qpaintengine_x11_p.h>
45
#include "qfontengine_p.h"
46
#include "qopentype_p.h"
49
#include <private/qpainter_p.h>
50
#include <private/qunicodetables_p.h>
52
#include <private/qt_x11_p.h>
59
QFontEngine::~QFontEngine()
63
qreal QFontEngine::lineThickness() const
66
int score = fontDef.weight * fontDef.pixelSize;
69
// looks better with thicker line for small pointsizes
70
if (lw < 2 && score >= 1050) lw = 2;
76
qreal QFontEngine::underlinePosition() const
78
return ((lineThickness() * 2) + 3) / 6;
82
// ------------------------------------------------------------------
84
// ------------------------------------------------------------------
86
QFontEngineMultiXLFD::QFontEngineMultiXLFD(const QFontDef &r, const QList<int> &l, int s)
87
: QFontEngineMulti(l.size()), encodings(l), screen(s)
93
QFontEngineMultiXLFD::~QFontEngineMultiXLFD()
96
void QFontEngineMultiXLFD::loadEngine(int at)
98
Q_ASSERT(at < engines.size());
99
Q_ASSERT(engines.at(at) == 0);
100
const int encoding = encodings.at(at);
101
QFontDef req = fontDef;
102
QFontEngine *fontEngine = QFontDatabase::findFont(QUnicodeTables::Common, 0, req, encoding);
105
fontEngine = QFontDatabase::findFont(QUnicodeTables::Common, 0, req, encoding);
107
Q_ASSERT(fontEngine != 0);
108
fontEngine->ref.ref();
109
engines[at] = fontEngine;
112
// ------------------------------------------------------------------
114
// ------------------------------------------------------------------
116
// defined in qfontdatbase_x11.cpp
117
extern int qt_mib_for_xlfd_encoding(const char *encoding);
118
extern int qt_xlfd_encoding_id(const char *encoding);
120
static inline XCharStruct *charStruct(XFontStruct *xfs, uint ch)
122
XCharStruct *xcs = 0;
123
unsigned char r = ch>>8;
124
unsigned char c = ch&0xff;
125
if (r >= xfs->min_byte1 &&
126
r <= xfs->max_byte1 &&
127
c >= xfs->min_char_or_byte2 &&
128
c <= xfs->max_char_or_byte2) {
130
xcs = &(xfs->min_bounds);
132
xcs = xfs->per_char + ((r - xfs->min_byte1) *
133
(xfs->max_char_or_byte2 -
134
xfs->min_char_or_byte2 + 1)) +
135
(c - xfs->min_char_or_byte2);
136
if (xcs->width == 0 && xcs->ascent == 0 && xcs->descent == 0)
143
QFontEngineXLFD::QFontEngineXLFD(XFontStruct *fs, const char *name, int mib)
144
: _fs(fs), _name(name), _codec(0), _cmap(mib)
146
if (_cmap) _codec = QTextCodec::codecForMib(_cmap);
148
cache_cost = (((fs->max_byte1 - fs->min_byte1) *
149
(fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1)) +
150
fs->max_char_or_byte2 - fs->min_char_or_byte2);
151
cache_cost = ((fs->max_bounds.ascent + fs->max_bounds.descent) *
152
(fs->max_bounds.width * cache_cost / 8));
157
QFontEngineXLFD::~QFontEngineXLFD()
159
XFreeFont(QX11Info::display(), _fs);
163
QFontEngine::FECaps QFontEngineXLFD::capabilites() const
165
return FullTransformations;
168
bool QFontEngineXLFD::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
170
if (*nglyphs < len) {
175
bool mirrored = flags & QTextEngine::RightToLeft;
177
bool haveNbsp = false;
178
for (int i = 0; i < len; i++)
179
if (str[i].unicode() == 0xa0) {
184
QVarLengthArray<unsigned short> ch(len);
185
QChar *chars = (QChar *)ch.data();
186
if (haveNbsp || mirrored) {
187
for (int i = 0; i < len; i++)
188
chars[i] = (str[i].unicode() == 0xa0 ? 0x20 :
189
(mirrored ? ::mirroredChar(str[i]).unicode() : str[i].unicode()));
191
for (int i = 0; i < len; i++)
192
chars[i] = str[i].unicode();
194
QTextCodec::ConverterState state;
195
state.flags = QTextCodec::ConvertInvalidToNull;
196
QByteArray ba = _codec->fromUnicode(chars, len, &state);
197
if (ba.length() == 2*len) {
198
// double byte encoding
199
const uchar *data = (const uchar *)ba.constData();
200
for (int i = 0; i < len; i++) {
201
glyphs[i].glyph = ((ushort)data[0] << 8) + data[1];
205
const uchar *data = (const uchar *)ba.constData();
206
for (int i = 0; i < len; i++)
207
glyphs[i].glyph = (ushort)data[i];
210
QGlyphLayout *g = glyphs + len;
211
const QChar *c = str + len;
214
(--g)->glyph = (--c)->unicode() == 0xa0 ? 0x20 : ::mirroredChar(*c).unicode();
217
(--g)->glyph = (--c)->unicode() == 0xa0 ? 0x20 : c->unicode();
222
QGlyphLayout *g = glyphs + len;
224
// inlined for better perfomance
225
if (!_fs->per_char) {
226
xcs = &_fs->min_bounds;
227
while (g != glyphs) {
229
g->advance.rx() = xcs->width;
233
else if (!_fs->max_byte1) {
234
XCharStruct *base = _fs->per_char - _fs->min_char_or_byte2;
235
while (g != glyphs) {
236
unsigned int gl = (--g)->glyph;
237
xcs = (gl >= _fs->min_char_or_byte2 && gl <= _fs->max_char_or_byte2) ?
239
g->advance.rx() = (!xcs || (!xcs->width && !xcs->ascent && !xcs->descent)) ? _fs->ascent : xcs->width;
244
while (g != glyphs) {
245
xcs = charStruct(_fs, (--g)->glyph);
246
g->advance.rx() = xcs ? xcs->width : _fs->ascent;
253
glyph_metrics_t QFontEngineXLFD::boundingBox(const QGlyphLayout *glyphs, int numGlyphs)
257
glyph_metrics_t overall;
260
for (i = 0; i < numGlyphs; i++) {
261
XCharStruct *xcs = charStruct(_fs, glyphs[i].glyph);
263
qreal x = overall.xoff + glyphs[i].offset.x() - xcs->lbearing;
264
qreal y = overall.yoff + glyphs[i].offset.y() - xcs->ascent;
265
overall.x = qMin(overall.x, x);
266
overall.y = qMin(overall.y, y);
267
xmax = qMax(xmax, overall.xoff + glyphs[i].offset.x() + xcs->rbearing);
268
ymax = qMax(ymax, y + xcs->ascent + xcs->descent);
269
overall.xoff += glyphs[i].advance.x();
271
qreal size = _fs->ascent;
272
overall.x = qMin(overall.x, overall.xoff);
273
overall.y = qMin(overall.y, overall.yoff - size);
274
ymax = qMax(ymax, overall.yoff);
275
overall.xoff += size;
276
xmax = qMax(xmax, overall.xoff);
279
overall.height = ymax - overall.y;
280
overall.width = xmax - overall.x;
285
glyph_metrics_t QFontEngineXLFD::boundingBox(glyph_t glyph)
288
XCharStruct *xcs = charStruct(_fs, glyph);
290
gm = glyph_metrics_t(xcs->lbearing, -xcs->ascent, xcs->rbearing- xcs->lbearing, xcs->ascent + xcs->descent,
293
qreal size = ascent();
294
gm = glyph_metrics_t(0, size, size, size, size, 0);
300
qreal QFontEngineXLFD::ascent() const
305
qreal QFontEngineXLFD::descent() const
307
return (_fs->descent-1);
310
qreal QFontEngineXLFD::leading() const
312
qreal l = (qMin<int>(_fs->ascent, _fs->max_bounds.ascent)
313
+ qMin<int>(_fs->descent, _fs->max_bounds.descent)) * qreal(0.15);
317
qreal QFontEngineXLFD::maxCharWidth() const
319
return _fs->max_bounds.width;
323
// Loads the font for the specified script
324
static inline int maxIndex(XFontStruct *f) {
325
return (((f->max_byte1 - f->min_byte1) *
326
(f->max_char_or_byte2 - f->min_char_or_byte2 + 1)) +
327
f->max_char_or_byte2 - f->min_char_or_byte2);
330
qreal QFontEngineXLFD::minLeftBearing() const
332
if (lbearing == SHRT_MIN) {
334
XCharStruct *cs = _fs->per_char;
335
int nc = maxIndex(_fs) + 1;
336
int mx = cs->lbearing;
338
for (int c = 1; c < nc; c++) {
339
// ignore the bearings for characters whose ink is
340
// completely outside the normal bounding box
341
if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
342
(cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
345
int nmx = cs[c].lbearing;
351
((QFontEngineXLFD *)this)->lbearing = mx;
353
((QFontEngineXLFD *)this)->lbearing = _fs->min_bounds.lbearing;
358
qreal QFontEngineXLFD::minRightBearing() const
360
if (rbearing == SHRT_MIN) {
362
XCharStruct *cs = _fs->per_char;
363
int nc = maxIndex(_fs) + 1;
364
int mx = cs->rbearing;
366
for (int c = 1; c < nc; c++) {
367
// ignore the bearings for characters whose ink is
368
// completely outside the normal bounding box
369
if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
370
(cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
373
int nmx = cs[c].rbearing;
379
((QFontEngineXLFD *)this)->rbearing = mx;
381
((QFontEngineXLFD *)this)->rbearing = _fs->min_bounds.rbearing;
386
int QFontEngineXLFD::cmap() const
391
const char *QFontEngineXLFD::name() const
396
bool QFontEngineXLFD::canRender(const QChar *string, int len)
398
QVarLengthArray<QGlyphLayout, 256> glyphs(len);
400
if (stringToCMap(string, len, glyphs.data(), &nglyphs, 0) == false) {
401
glyphs.resize(nglyphs);
402
stringToCMap(string, len, glyphs.data(), &nglyphs, 0);
405
bool allExist = true;
406
for (int i = 0; i < nglyphs; i++) {
407
if (!glyphs[i].glyph || !charStruct(_fs, glyphs[i].glyph)) {
417
#ifndef QT_NO_FONTCONFIG
419
// ------------------------------------------------------------------
421
// ------------------------------------------------------------------
423
#include FT_OUTLINE_H
425
QFontEngineMultiFT::QFontEngineMultiFT(FcFontSet *fs, int s)
426
: QFontEngineMulti(fs->nfont), fontSet(fs), screen(s)
432
QFontEngineMultiFT::~QFontEngineMultiFT()
434
FcFontSetDestroy(fontSet);
437
void QFontEngineMultiFT::loadEngine(int at)
439
Q_ASSERT(at < engines.size());
440
Q_ASSERT(engines.at(at) == 0);
441
FcPattern *pattern = fontSet->fonts[at];
442
extern QFontDef FcPatternToQFontDef(FcPattern *pattern);
443
QFontDef fontDef = FcPatternToQFontDef(fontSet->fonts[at]);
444
// note: we use -1 for the script to make sure that we keep real
445
// FT engines separate from Multi engines in the font cache
446
QFontCache::Key key(fontDef, -1, screen);
447
QFontEngine *fontEngine = QFontCache::instance->findEngine(key);
449
FcConfigSubstitute(0, pattern, FcMatchPattern);
450
FcDefaultSubstitute(pattern);
452
FcPattern *match = FcFontMatch(0, pattern, &res);
453
QFontEngineFT *engine = new QFontEngineFT(match, fontDef, screen);
454
if (engine->invalid())
459
fontEngine = new QFontEngineBox(fontDef.pixelSize);
460
fontEngine->fontDef = fontDef;
462
QFontCache::instance->insertEngine(key, fontEngine);
464
fontEngine->ref.ref();
465
engines[at] = fontEngine;
469
// ------------------------------------------------------------------
471
// ------------------------------------------------------------------
474
* Freetype 2.1.7 and earlier used width/height
475
* for matching sizes in the BDF and PCF loaders.
476
* This has been fixed for 2.1.8.
478
#if HAVE_FT_BITMAP_SIZE_Y_PPEM
479
#define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
480
#define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
482
#define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
483
#define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
486
void QFontEngineFT::computeSize()
488
ysize = fontDef.pixelSize << 6;
489
xsize = ysize * fontDef.stretch / 100;
491
FT_Face face = freetype->face;
493
* Bitmap only faces must match exactly, so find the closest
494
* one (height dominant search)
496
if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
498
for (int i = 1; i < face->num_fixed_sizes; i++) {
499
if (qAbs(ysize - Y_SIZE(face,i)) <
500
qAbs (ysize - Y_SIZE(face, best)) ||
501
(qAbs (ysize - Y_SIZE(face, i)) ==
502
qAbs (ysize - Y_SIZE(face, best)) &&
503
qAbs (xsize - X_SIZE(face, i)) <
504
qAbs (xsize - X_SIZE(face, best)))) {
508
if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
509
xsize = X_SIZE(face, best);
510
ysize = Y_SIZE(face, best);
517
static FT_Library library = 0;
518
QHash<QFreetypeFaceId, QFreetypeFace *> *QFontEngineFT::freetypeFaces = 0;
520
QFontEngineFT::Glyph::~Glyph()
525
static QFreetypeFaceId face_id(FcPattern *pattern)
528
FcPatternGetString(pattern, FC_FILE, 0, (FcChar8 **)&file_name);
530
if (!FcPatternGetInteger(pattern, FC_INDEX, 0, &face_index))
532
QFreetypeFaceId face_id;
533
face_id.filename = file_name;
534
face_id.index = face_index;
538
QFontEngineFT::QFontEngineFT(FcPattern *pattern, const QFontDef &fd, int screen)
543
// FcPatternPrint(pattern);
545
antialias = X11->fc_antialias;
547
if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &b) == FcResultMatch)
549
if (FcPatternGetInteger(pattern, FC_RGBA, 0, &subpixel) == FcResultNoMatch)
550
subpixel = X11->screens[screen].subpixel;
551
if (!antialias || subpixel == FC_RGBA_UNKNOWN)
552
subpixel = FC_RGBA_NONE;
555
FT_Init_FreeType(&library);
558
freetypeFaces = new QHash<QFreetypeFaceId, QFreetypeFace *>();
560
QFreetypeFaceId face_id = ::face_id(pattern);
562
freetype = freetypeFaces->value(face_id, 0);
564
freetype = new QFreetypeFace;
570
FcPatternGetCharSet (pattern, FC_CHARSET, 0, &cs);
571
freetype->charset = FcCharSetCopy(cs);
573
memset(freetype->cmapCache, 0, sizeof(freetype->cmapCache));
574
FT_New_Face(library, face_id.filename, face_id.index, &freetype->face);
575
freetypeFaces->insert(face_id, freetype);
579
lbearing = rbearing = SHRT_MIN;
581
outline_drawing = xsize > (64<<6) || ysize > (64<<6);
586
FT_Face face = freetype->face;
587
if (FT_IS_SCALABLE(face)) {
588
line_thickness = FT_MulFix(face->underline_thickness, face->size->metrics.y_scale)/64.;
589
underline_position = -FT_MulFix(face->underline_position, face->size->metrics.y_scale)/64.;
591
// copied from QFontEngineQPF
593
int score = fontDef.weight * fontDef.pixelSize;
594
line_thickness = score / 700;
595
// looks better with thicker line for small pointsizes
596
if (line_thickness < 2 && score >= 1050)
598
underline_position = ((line_thickness * 2) + 3) / 6;
600
if (line_thickness < 1)
603
metrics = freetype->face->size->metrics;
605
int load_flags = FT_LOAD_DEFAULT;
606
int format = PictStandardA8;
608
load_flags |= FT_LOAD_TARGET_MONO;
609
format = PictStandardA1;
611
if (subpixel == FC_RGBA_RGB || subpixel == FC_RGBA_BGR) {
612
load_flags |= FT_LOAD_TARGET_LCD;
613
format = PictStandardARGB32;
614
} else if (subpixel == FC_RGBA_VRGB || subpixel == FC_RGBA_VBGR) {
615
load_flags |= FT_LOAD_TARGET_LCD_V;
616
format = PictStandardARGB32;
621
glyphSet = XRenderCreateGlyphSet(X11->display, XRenderFindStandardFormat(X11->display, format));
625
QFontEngineFT::~QFontEngineFT()
627
if (!freetype->ref.deref()) {
628
FT_Done_Face(freetype->face);
629
FcCharSetDestroy(freetype->charset);
631
freetypeFaces->take(::face_id(_pattern));
633
if (!freetypeFaces->size()) {
634
delete freetypeFaces;
636
FT_Done_FreeType(library);
639
FcPatternDestroy(_pattern);
642
qDeleteAll(glyph_data);
643
XRenderFreeGlyphSet(X11->display, glyphSet);
647
FT_Face QFontEngineFT::lockFace() const
649
Q_ASSERT(freetype->lock == 0);
650
while (!freetype->lock.testAndSet(0, 1))
652
FT_Face face = freetype->face;
653
if (freetype->xsize != xsize && freetype->ysize != ysize) {
654
FT_Set_Char_Size(face, xsize, ysize, 0, 0);
655
freetype->xsize = xsize;
656
freetype->ysize = ysize;
661
void QFontEngineFT::unlockFace() const
663
if (!freetype->lock.testAndSet(1, 0))
667
#define FLOOR(x) ((x) & -64)
668
#define CEIL(x) (((x)+63) & -64)
669
#define TRUNC(x) ((x) >> 6)
670
#define ROUND(x) (((x)+32) & -64)
672
QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(uint glyph, GlyphFormat format) const
674
Q_ASSERT(freetype->lock == 1);
676
bool add_to_glyphset = false;
677
if (format == Format_None) {
678
format = Format_Mono;
679
if (X11->use_xrender) {
680
add_to_glyphset = true;
681
if (subpixel != FC_RGBA_NONE)
687
Q_ASSERT(format != Format_None);
690
int load_flags = FT_LOAD_DEFAULT;
691
if (outline_drawing) {
692
load_flags = FT_LOAD_NO_BITMAP|FT_LOAD_NO_HINTING;
693
} else if (format == Format_Mono) {
694
load_flags |= FT_LOAD_TARGET_MONO;
695
} else if (format == Format_A32) {
696
if (subpixel == FC_RGBA_RGB || subpixel == FC_RGBA_BGR) {
697
load_flags |= FT_LOAD_TARGET_LCD;
699
} else if (subpixel == FC_RGBA_VRGB || subpixel == FC_RGBA_VBGR) {
700
load_flags |= FT_LOAD_TARGET_LCD_V;
707
Glyph *g = glyph_data.value(glyph);
708
if (g && g->format == format)
712
FT_Face face = freetype->face;
713
FT_Load_Glyph(face, glyph, load_flags);
718
FT_GlyphSlot slot = face->glyph;
720
int left = FLOOR(slot->metrics.horiBearingX);
721
int right = CEIL(slot->metrics.horiBearingX + slot->metrics.width);
722
int top = CEIL(slot->metrics.horiBearingY);
723
int bottom = FLOOR(slot->metrics.horiBearingY - slot->metrics.height);
726
info.width = TRUNC(right - left);
727
info.height = TRUNC(top - bottom);
728
info.x = -TRUNC(left);
730
info.xOff = TRUNC(ROUND(slot->advance.x));
733
int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
734
(format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
735
int size = pitch * info.height * vfactor;
736
uchar *buffer = new uchar[size];
737
memset (buffer, 0, size);
739
if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
741
bitmap.rows = info.height*vfactor;
742
bitmap.width = info.width*hfactor;
743
bitmap.pitch = pitch;
744
bitmap.buffer = buffer;
745
bitmap.pixel_mode = format == Format_Mono ? ft_pixel_mode_mono : ft_pixel_mode_grays;
747
matrix.xx = hfactor << 16;
748
matrix.yy = vfactor << 16;
749
matrix.yx = matrix.xy = 0;
751
FT_Outline_Transform(&slot->outline, &matrix);
752
FT_Outline_Translate (&slot->outline, -left*hfactor, -bottom*vfactor);
753
FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
755
Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
758
size = info.width * 4 * info.height;
759
uchar *newBuf = new uchar[size];
760
uint *dst = (uint *)newBuf;
762
const uint r = (subpixel == FC_RGBA_RGB || subpixel == FC_RGBA_VRGB) ? 16 : 0;
763
const uint b = 16 - r;
766
for (int x = 0; x < bitmap.width; x += 3) {
767
// ############# filter
768
uint res = (src[x] << r) + (src[x+1] << 8) + (src[x+2] << b);
777
} else if (vfactor != 1) {
779
size = info.width * 4 * info.height;
780
uchar *newBuf = new uchar[size];
781
uint *dst = (uint *)newBuf;
783
const uint r = (subpixel == FC_RGBA_RGB || subpixel == FC_RGBA_VRGB) ? 16 : 0;
784
const uint b = 16 - r;
786
for (int x = 0; x < info.width; x++) {
787
// ############# filter
788
uint res = src[x] << r + src[x+bitmap.pitch] << 8 + src[x+2*bitmap.pitch] << b;
792
src += 3*bitmap.pitch;
797
} else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
798
Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
799
uchar *src = slot->bitmap.buffer;
801
int h = slot->bitmap.rows;
802
if (format == Format_Mono) {
803
int bytes = ((info.width + 7) & ~7) >> 3;
805
memcpy (dst, src, bytes);
807
src += slot->bitmap.pitch;
813
for (int x = 0; x < slot->bitmap.width; x++) {
814
unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
820
dst += pitch * vfactor;
821
src += slot->bitmap.pitch;
824
} else if (vfactor != 1) {
826
for (int x = 0; x < slot->bitmap.width; x++) {
827
unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
830
memcpy(dst + pitch, dst, pitch);
832
memcpy(dst + pitch, dst, pitch);
834
src += slot->bitmap.pitch;
838
for (int x = 0; x < slot->bitmap.width; x++) {
839
unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
843
src += slot->bitmap.pitch;
848
qWarning("glyph neither outline nor bitmap");
852
#ifndef QT_NO_XRENDER
853
if (add_to_glyphset) {
854
if (format == Format_Mono) {
856
* swap bit order around; FreeType is always MSBFirst
858
if (BitmapBitOrder(X11->display) != MSBFirst) {
859
unsigned char *line = (unsigned char *) buffer;
865
c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
866
c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
867
c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
873
::Glyph xglyph = glyph;
874
XRenderAddGlyphs (X11->display, glyphSet, &xglyph, &info, 1, (const char *)buffer, size);
881
bool large_glyph = (((signed char)(slot->linearHoriAdvance>>16) != slot->linearHoriAdvance>>16)
882
|| ((uchar)(info.width) != info.width)
883
|| ((uchar)(info.height) != info.height)
884
|| ((signed char)(info.x) != info.x)
885
|| ((signed char)(info.y) != info.y)
886
|| ((signed char)(info.xOff) != info.xOff));
889
// qDebug("got a large glyph!");
893
Glyph *g = new Glyph;
895
g->linearAdvance = slot->linearHoriAdvance >> 10;
896
g->width = TRUNC(right - left);
897
g->height = TRUNC(top - bottom);
900
g->advance = TRUNC(ROUND(slot->advance.x));
901
g->format = add_to_glyphset ? Format_None : format;
904
// make sure we delete the old cached glyph
905
delete glyph_data.value(glyph);
906
glyph_data[glyph] = g;
912
static inline glyph_t getAdobeCharIndex(FT_Face _face, int cmap, uint ucs4)
914
// ############## save and restore charmap
915
FT_Set_Charmap(_face, _face->charmaps[cmap]);
916
glyph_t g = FT_Get_Char_Index(_face, ucs4);
921
inline unsigned int getChar(const QChar *str, int &i, const int len)
923
unsigned int uc = str[i].unicode();
924
if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
925
uint low = str[i+1].unicode();
926
if (low >= 0xdc00 && low < 0xe000) {
927
uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
934
bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
935
QTextEngine::ShaperFlags flags) const
937
if (*nglyphs < len) {
942
bool mirrored = flags & QTextEngine::RightToLeft;
946
FT_Face _face = lockFace();
947
for ( int i = 0; i < len; ++i ) {
948
unsigned int uc = getChar(str, i, len);
949
glyphs[glyph_pos].glyph = uc < cmapCacheSize ? cmapCache[uc] : 0;
950
if ( !glyphs[glyph_pos].glyph ) {
951
glyph_t glyph = FT_Get_Char_Index(_face, uc);
953
glyph = getAdobeCharIndex(_face, _cmap, uc);
954
glyphs[glyph_pos].glyph = glyph;
955
if ( uc < cmapCacheSize )
956
((QFontEngineFT *)this)->cmapCache[uc] = glyph;
964
FT_Face face = freetype->face;
965
for (int i = 0; i < len; ++i) {
966
unsigned int uc = getChar(str, i, len);
968
uc = QUnicodeTables::mirroredChar(uc);
969
glyphs[glyph_pos].glyph = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
970
if (!glyphs[glyph_pos].glyph && FcCharSetHasChar(freetype->charset, uc)) {
972
glyph_t glyph = FT_Get_Char_Index(face, uc);
973
if (!glyph && (uc == 0xa0 || uc == 0x9)) {
977
glyphs[glyph_pos].glyph = glyph;
978
if (uc < QFreetypeFace::cmapCacheSize)
979
freetype->cmapCache[uc] = glyph;
985
*nglyphs = glyph_pos;
986
recalcAdvances(*nglyphs, glyphs, flags);
991
void QFontEngineFT::recalcAdvances(int len, QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
994
if (flags & QTextEngine::DesignMetrics) {
995
for (int i = 0; i < len; i++) {
996
Glyph *g = glyph_data.value(glyphs[i].glyph);
1000
g = loadGlyph(glyphs[i].glyph);
1002
// for uncachable glyph, get advance from glyphslot
1003
glyphs[i].advance.rx() = g ? g->linearAdvance/65536. : face->glyph->linearHoriAdvance/65536.;
1004
glyphs[i].advance.ry() = 0.;
1007
for (int i = 0; i < len; i++) {
1008
Glyph *g = glyph_data.value(glyphs[i].glyph);
1012
g = loadGlyph(glyphs[i].glyph);
1014
// for uncachable glyph, get advance from glyphslot
1015
glyphs[i].advance.rx() = g ? g->advance : face->glyph->metrics.horiAdvance/64.;
1016
glyphs[i].advance.ry() = 0.;
1023
glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout *glyphs, int numGlyphs)
1028
glyph_metrics_t overall;
1031
for (int i = 0; i < numGlyphs; i++) {
1032
Glyph *g = glyph_data.value(glyphs[i].glyph);
1036
g = loadGlyph(glyphs[i].glyph);
1039
qreal x = overall.xoff + glyphs[i].offset.x() - g->x;
1040
qreal y = overall.yoff + glyphs[i].offset.y() - g->y;
1041
overall.x = qMin(overall.x, x);
1042
overall.y = qMin(overall.y, y);
1043
xmax = qMax(xmax, x + g->width);
1044
ymax = qMax(ymax, y + g->height);
1045
overall.xoff += qRound(g->advance);
1047
int left = FLOOR(face->glyph->metrics.horiBearingX);
1048
int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1049
int top = CEIL(face->glyph->metrics.horiBearingY);
1050
int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1052
qreal x = overall.xoff + glyphs[i].offset.x() - (-TRUNC(left));
1053
qreal y = overall.yoff + glyphs[i].offset.y() - TRUNC(top);
1054
overall.x = qMin(overall.x, x);
1055
overall.y = qMin(overall.y, y);
1056
xmax = qMax(xmax, x + TRUNC(right - left));
1057
ymax = qMax(ymax, y + TRUNC(top - bottom));
1058
overall.xoff += qRound(TRUNC(ROUND(face->glyph->advance.x)));
1061
overall.height = ymax - overall.y;
1062
overall.width = xmax - overall.x;
1070
glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
1073
glyph_metrics_t overall;
1074
Glyph *g = glyph_data.value(glyph);
1077
g = loadGlyph(glyph);
1082
overall.width = g->width;
1083
overall.height = g->height;
1084
overall.xoff = g->advance;
1086
int left = FLOOR(face->glyph->metrics.horiBearingX);
1087
int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
1088
int top = CEIL(face->glyph->metrics.horiBearingY);
1089
int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
1091
overall.width = TRUNC(right-left);
1092
overall.height = TRUNC(top-bottom);
1093
overall.x = TRUNC(left);
1094
overall.y = -TRUNC(top);
1095
overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
1102
bool QFontEngineFT::canRender(const QChar *string, int len)
1104
FT_Face face = freetype->face;
1108
for ( int i = 0; i < len; i++ ) {
1109
unsigned int uc = getChar(string, i, len);
1110
if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
1119
for ( int i = 0; i < len; i++ ) {
1120
unsigned int uc = getChar(string, i, len);
1121
if (!FT_Get_Char_Index(face, uc))
1128
void QFontEngineFT::doKerning(int num_glyphs, QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
1130
if (!FT_HAS_KERNING(freetype->face))
1132
FT_Face face = lockFace();
1133
uint f = (flags == QTextEngine::DesignMetrics ? FT_KERNING_UNFITTED : FT_KERNING_DEFAULT);
1134
for (int i = 0; i < num_glyphs-1; ++i) {
1136
FT_Get_Kerning(face, g[i].glyph, g[i+1].glyph, f, &kerning);
1137
g[i].advance.rx() += kerning.x / 64.;
1138
g[i].advance.ry() += kerning.y / 64.;
1143
static void addCurve(QPainterPath *path, const QPointF &cp, const QPointF &endPoint,
1144
int startOff, int nOff, FT_GlyphSlot g)
1147
QPointF c0 = QPointF(g->outline.points[startOff-1].x/64., -g->outline.points[startOff-1].y/64.);
1148
QPointF current = QPointF(g->outline.points[startOff].x/64., -g->outline.points[startOff].y/64.);
1149
for(j = 1; j <= nOff; j++) {
1150
QPointF next = (j == nOff)
1152
: QPointF(g->outline.points[startOff + j].x/64., -g->outline.points[startOff + j].y/64.);
1153
QPointF c3 = (j == nOff) ? next : (next + current)/2;
1154
QPointF c1 = (2*current + c0)/3;
1155
QPointF c2 = (2*current + c3)/3;
1156
// qDebug("cubicTo %f/%f %f/%f %f/%f", (cp + c1).x(), (cp + c1).y(),
1157
// (cp + c2).x(), (cp + c2).y(), (cp + c3).x(), (cp + c3).y());
1158
path->cubicTo(cp + c1, cp + c2, cp + c3);
1164
void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout *glyphs, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1166
if (FT_IS_SCALABLE(freetype->face)) {
1167
FT_Face face = lockFace();
1168
QPointF point = QPointF(x, y);
1169
if (flags & QTextItem::RightToLeft) {
1170
for (int gl = 0; gl < numGlyphs; gl++)
1171
point += glyphs[gl].advance;
1173
for (int gl = 0; gl < numGlyphs; gl++) {
1174
FT_UInt glyph = glyphs[gl].glyph;
1175
if (flags & QTextItem::RightToLeft)
1176
point -= glyphs[gl].advance;
1177
QPointF cp = point + glyphs[gl].offset;
1178
if (!(flags & QTextItem::RightToLeft))
1179
point += glyphs[gl].advance;
1181
FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING|FT_LOAD_NO_BITMAP);
1183
FT_GlyphSlot g = face->glyph;
1184
if (g->format != FT_GLYPH_FORMAT_OUTLINE)
1187
// convert the outline to a painter path
1189
for (int c = 0; c < g->outline.n_contours; ++c) {
1190
QPointF p = cp + QPointF(g->outline.points[i].x/64., -g->outline.points[i].y/64.);
1191
// qDebug("contour: %d -- %d", i, g->outline.contours[c]);
1192
// qDebug("first point at %f %f", p.x(), p.y());
1199
while (i <= g->outline.contours[c]) {
1200
QPointF p = cp + QPointF(g->outline.points[i].x/64., -g->outline.points[i].y/64.);
1201
// qDebug(" point at %f %f, on curve=%d", p.x(), p.y(), g->outline.tags[i] & 1);
1202
if (!(g->outline.tags[i] & 1)) {
1213
// ###### fix 3rd order beziers
1214
addCurve(path, cp, QPointF(g->outline.points[i].x/64., -g->outline.points[i].y/64.),
1218
p = cp + QPointF(g->outline.points[i].x/64., -g->outline.points[i].y/64.);
1224
QPointF end(g->outline.points[first].x/64., -g->outline.points[first].y/64.);
1226
addCurve(path, cp, end, startOff, nOff, g);
1228
path->lineTo(end + cp);
1233
addBitmapFontToPath(x, y, glyphs, numGlyphs, path, flags);
1237
qreal QFontEngineFT::ascent() const
1239
return TRUNC(ROUND(metrics.ascender));
1242
qreal QFontEngineFT::descent() const
1244
return -TRUNC(ROUND(metrics.descender)) + 1;
1247
qreal QFontEngineFT::leading() const
1249
return (metrics.height - metrics.ascender + metrics.descender) >> 6;
1252
qreal QFontEngineFT::maxCharWidth() const
1254
return metrics.max_advance >> 6;
1257
static const ushort char_table[] = {
1278
static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
1281
qreal QFontEngineFT::minLeftBearing() const
1283
if (lbearing == SHRT_MIN)
1284
(void) minRightBearing(); // calculates both
1288
qreal QFontEngineFT::minRightBearing() const
1290
if (rbearing == SHRT_MIN) {
1291
lbearing = rbearing = 0;
1292
const QChar *ch = (const QChar *)char_table;
1293
QGlyphLayout glyphs[char_table_entries];
1294
int ng = char_table_entries;
1295
stringToCMap(ch, char_table_entries, glyphs, &ng, 0);
1297
if (glyphs[ng].glyph) {
1298
glyph_metrics_t gi = ((QFontEngineFT *)this)->boundingBox(glyphs[ng].glyph);
1299
lbearing = qMin(lbearing, gi.x);
1300
rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
1307
qreal QFontEngineFT::lineThickness() const
1309
return line_thickness;
1312
qreal QFontEngineFT::underlinePosition() const
1314
return underline_position;
1318
QOpenType *QFontEngineFT::openType() const
1323
FT_Face face = lockFace();
1324
if (!face || !FT_IS_SFNT(face)) {
1329
_openType = new QOpenType(const_cast<QFontEngineFT *>(this), face);
1334
#endif // QT_NO_FONTCONFIG