00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "qbitmap.h"
00025
00026
00027
00028 #include <qbytearray.h>
00029 #include <qdebug.h>
00030 #include <qtextcodec.h>
00031
00032 #include "qfontdatabase.h"
00033 #include "qpaintdevice.h"
00034 #include "qpainter.h"
00035 #include "qvarlengtharray.h"
00036 #include "qwidget.h"
00037 #include "qsettings.h"
00038 #include "qfile.h"
00039 #include "qabstractfileengine.h"
00040
00041 #include <private/qpaintengine_x11_p.h>
00042 #include "qfont.h"
00043 #include "qfont_p.h"
00044 #include "qfontengine_p.h"
00045 #include "qopentype_p.h"
00046 #include <qhash.h>
00047
00048 #include <private/qpainter_p.h>
00049 #include <private/qunicodetables_p.h>
00050 #include <private/qpdf_p.h>
00051
00052 #include <private/qt_x11_p.h>
00053 #include "qx11info_x11.h"
00054
00055 #include <math.h>
00056 #include <limits.h>
00057
00058 #ifndef QT_NO_FREETYPE
00059
00060 #include <ft2build.h>
00061 #include FT_FREETYPE_H
00062 #include FT_OUTLINE_H
00063 #include FT_TRUETYPE_TABLES_H
00064 #include FT_TYPE1_TABLES_H
00065 #include FT_GLYPH_H
00066
00067
00068
00069
00070
00071
00072 #if (FREETYPE_MAJOR*10000+FREETYPE_MINOR*100+FREETYPE_PATCH) >= 20105
00073 #define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
00074 #define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
00075 #else
00076 #define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
00077 #define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
00078 #endif
00079
00080 #define FLOOR(x) ((x) & -64)
00081 #define CEIL(x) (((x)+63) & -64)
00082 #define TRUNC(x) ((x) >> 6)
00083 #define ROUND(x) (((x)+32) & -64)
00084
00085
00086
00087
00088 struct QFreetypeFace
00089 {
00090 void computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing);
00091 QFontEngine::Properties properties() const;
00092 QByteArray getSfntTable(uint tag) const;
00093
00094 static QFreetypeFace *getFace(const QFontEngine::FaceId &face_id);
00095 void release(const QFontEngine::FaceId &face_id);
00096
00097 void lock() {
00098 Q_ASSERT(_lock == 0);
00099 while (!_lock.testAndSet(0, 1))
00100 usleep(100);
00101 }
00102 void unlock() {
00103 if (!_lock.testAndSet(1, 0))
00104 Q_ASSERT(false);
00105 }
00106
00107 FT_Face face;
00108 #ifndef QT_NO_FONTCONFIG
00109 FcCharSet *charset;
00110 #endif
00111 int xsize;
00112 int ysize;
00113 FT_Matrix matrix;
00114 FT_CharMap unicode_map;
00115 FT_CharMap symbol_map;
00116
00117 enum { cmapCacheSize = 0x200 };
00118 glyph_t cmapCache[cmapCacheSize];
00119
00120 int fsType() const;
00121
00122 private:
00123 QFreetypeFace() {}
00124 ~QFreetypeFace() {}
00125 QAtomic ref;
00126 QAtomic _lock;
00127 QByteArray fontData;
00128 };
00129
00130 static FT_Library library = 0;
00131 FT_Library qt_getFreetype()
00132 {
00133 if (!library)
00134 FT_Init_FreeType(&library);
00135 return library;
00136 }
00137 static QHash<QFontEngine::FaceId, QFreetypeFace *> *freetypeFaces = 0;
00138
00139 int QFreetypeFace::fsType() const
00140 {
00141 int fsType = 0;
00142 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2);
00143 if (os2)
00144 fsType = os2->fsType;
00145 return fsType;
00146 }
00147
00148 QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id)
00149 {
00150 if (face_id.filename.isEmpty())
00151 return 0;
00152
00153 if (!library)
00154 FT_Init_FreeType(&library);
00155 if (!freetypeFaces)
00156 freetypeFaces = new QHash<QFontEngine::FaceId, QFreetypeFace *>();
00157
00158 QFreetypeFace *freetype = freetypeFaces->value(face_id, 0);
00159 if (!freetype) {
00160 freetype = new QFreetypeFace;
00161 FT_Face face;
00162 QFile file(QString::fromUtf8(face_id.filename));
00163 if (face_id.filename.startsWith(":qmemoryfonts/")) {
00164
00165 extern QByteArray qt_fontdata_from_index(int);
00166 QByteArray idx = face_id.filename;
00167 idx.remove(0, 14);
00168 bool ok = false;
00169 freetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
00170 if (!ok)
00171 freetype->fontData = QByteArray();
00172 } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
00173 if (!file.open(QIODevice::ReadOnly)) {
00174 delete freetype;
00175 return 0;
00176 }
00177 freetype->fontData = file.readAll();
00178 }
00179 if (!freetype->fontData.isEmpty()) {
00180 if (FT_New_Memory_Face(library, (const FT_Byte *)freetype->fontData.constData(), freetype->fontData.size(), face_id.index, &face)) {
00181 delete freetype;
00182 return 0;
00183 }
00184 } else if (FT_New_Face(library, face_id.filename, face_id.index, &face)) {
00185 delete freetype;
00186 return 0;
00187 }
00188 freetype->face = face;
00189 freetype->ref = 0;
00190 freetype->_lock = 0;
00191 freetype->xsize = 0;
00192 freetype->ysize = 0;
00193 freetype->matrix.xx = 0x10000;
00194 freetype->matrix.yy = 0x10000;
00195 freetype->matrix.xy = 0;
00196 freetype->matrix.yx = 0;
00197 freetype->unicode_map = 0;
00198 freetype->symbol_map = 0;
00199 #ifndef QT_NO_FONTCONFIG
00200 freetype->charset = 0;
00201 #endif
00202
00203 memset(freetype->cmapCache, 0, sizeof(freetype->cmapCache));
00204
00205 for (int i = 0; i < freetype->face->num_charmaps; ++i) {
00206 FT_CharMap cm = freetype->face->charmaps[i];
00207 switch(cm->encoding) {
00208 case ft_encoding_unicode:
00209 freetype->unicode_map = cm;
00210 break;
00211 case ft_encoding_apple_roman:
00212 case ft_encoding_latin_1:
00213 if (!freetype->unicode_map || freetype->unicode_map->encoding != ft_encoding_unicode)
00214 freetype->unicode_map = cm;
00215 break;
00216 case ft_encoding_adobe_custom:
00217 case ft_encoding_symbol:
00218 if (!freetype->symbol_map)
00219 freetype->symbol_map = cm;
00220 break;
00221 default:
00222 break;
00223 }
00224 }
00225
00226 if (!FT_IS_SCALABLE(freetype->face) && freetype->face->num_fixed_sizes == 1)
00227 FT_Set_Char_Size (face, X_SIZE(freetype->face, 0), Y_SIZE(freetype->face, 0), 0, 0);
00228 # if 0
00229 FcChar8 *name;
00230 FcPatternGetString(pattern, FC_FAMILY, 0, &name);
00231 qDebug("%s: using maps: default: %x unicode: %x, symbol: %x", name,
00232 freetype->face->charmap ? freetype->face->charmap->encoding : 0,
00233 freetype->unicode_map ? freetype->unicode_map->encoding : 0,
00234 freetype->symbol_map ? freetype->symbol_map->encoding : 0);
00235
00236 for (int i = 0; i < 256; i += 8)
00237 qDebug(" %x: %d %d %d %d %d %d %d %d", i,
00238 FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i),
00239 FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i),
00240 FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i),
00241 FcCharSetHasChar(freetype->charset, i), FcCharSetHasChar(freetype->charset, i));
00242 #endif
00243
00244 FT_Set_Charmap(freetype->face, freetype->unicode_map);
00245 freetypeFaces->insert(face_id, freetype);
00246 }
00247 freetype->ref.ref();
00248 return freetype;
00249 }
00250
00251 void QFreetypeFace::release(const QFontEngine::FaceId &face_id)
00252 {
00253 if (!ref.deref()) {
00254 FT_Done_Face(face);
00255 #ifndef QT_NO_FONTCONFIG
00256 if (charset)
00257 FcCharSetDestroy(charset);
00258 #endif
00259 freetypeFaces->take(face_id);
00260 delete this;
00261 }
00262 if (!freetypeFaces->size()) {
00263 delete freetypeFaces;
00264 freetypeFaces = 0;
00265 FT_Done_FreeType(library);
00266 library = 0;
00267 }
00268 }
00269
00270
00271 void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
00272 {
00273 *ysize = fontDef.pixelSize << 6;
00274 *xsize = *ysize * fontDef.stretch / 100;
00275 *outline_drawing = false;
00276
00277
00278
00279
00280
00281 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
00282 int best = 0;
00283 for (int i = 1; i < face->num_fixed_sizes; i++) {
00284 if (qAbs(*ysize - Y_SIZE(face,i)) <
00285 qAbs (*ysize - Y_SIZE(face, best)) ||
00286 (qAbs (*ysize - Y_SIZE(face, i)) ==
00287 qAbs (*ysize - Y_SIZE(face, best)) &&
00288 qAbs (*xsize - X_SIZE(face, i)) <
00289 qAbs (*xsize - X_SIZE(face, best)))) {
00290 best = i;
00291 }
00292 }
00293 if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
00294 *xsize = X_SIZE(face, best);
00295 *ysize = Y_SIZE(face, best);
00296 } else
00297 *xsize = *ysize = 0;
00298 } else {
00299 *outline_drawing = (*xsize > (64<<6) || *ysize > (64<<6));
00300 }
00301 }
00302
00303 QFontEngine::Properties QFreetypeFace::properties() const
00304 {
00305 QFontEngine::Properties p;
00306 p.postscriptName = FT_Get_Postscript_Name(face);
00307 PS_FontInfoRec font_info;
00308 if (FT_Get_PS_Font_Info(face, &font_info) == 0)
00309 p.copyright = font_info.notice;
00310 if (FT_IS_SCALABLE(face)) {
00311 p.ascent = face->ascender;
00312 p.descent = -face->descender;
00313 p.leading = face->height - face->ascender + face->descender;
00314 p.emSquare = face->units_per_EM;
00315 p.boundingBox = QRectF(face->bbox.xMin, -face->bbox.yMax,
00316 face->bbox.xMax - face->bbox.xMin,
00317 face->bbox.yMax - face->bbox.yMin);
00318 } else {
00319 p.ascent = QFixed::fromFixed(face->size->metrics.ascender);
00320 p.descent = QFixed::fromFixed(-face->size->metrics.descender);
00321 p.leading = QFixed::fromFixed(face->size->metrics.height - face->size->metrics.ascender + face->size->metrics.descender);
00322 p.emSquare = face->size->metrics.y_ppem;
00323 p.boundingBox = QRectF(-p.ascent.toReal(), 0, (p.ascent + p.descent).toReal(), face->size->metrics.max_advance/64.);
00324 }
00325 p.italicAngle = 0;
00326 p.capHeight = p.ascent;
00327 p.lineWidth = face->underline_thickness;
00328 return p;
00329 }
00330
00331 QByteArray QFreetypeFace::getSfntTable(uint tag) const
00332 {
00333 QByteArray table;
00334 #if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) > 20103
00335 if (FT_IS_SFNT(face)) {
00336 FT_ULong length = 0;
00337 FT_Load_Sfnt_Table(face, tag, 0, 0, &length);
00338 if (length != 0) {
00339 table.resize(length);
00340 FT_Load_Sfnt_Table(face, tag, 0, (FT_Byte *)table.data(), &length);
00341 }
00342 }
00343 #endif
00344 return table;
00345 }
00346
00347 static void addGlyphToPath(FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, bool no_scale = false)
00348 {
00349 qreal factor = no_scale ? 1. : 1./64.;
00350
00351 QPointF cp = point.toPointF();
00352
00353
00354 int i = 0;
00355 for (int j = 0; j < g->outline.n_contours; ++j) {
00356 int last_point = g->outline.contours[j];
00357 QPointF start = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
00358 if(!(g->outline.tags[i] & 1)) {
00359 start += cp + QPointF(g->outline.points[last_point].x*factor, -g->outline.points[last_point].y*factor);
00360 start /= 2;
00361 }
00362
00363
00364 path->moveTo(start);
00365
00366 QPointF c[4];
00367 c[0] = start;
00368 int n = 1;
00369 while (i < last_point) {
00370 ++i;
00371 c[n] = cp + QPointF(g->outline.points[i].x*factor, -g->outline.points[i].y*factor);
00372
00373 ++n;
00374 switch (g->outline.tags[i] & 3) {
00375 case 2:
00376
00377 if (n < 4)
00378 continue;
00379 c[3] = (c[3] + c[2])/2;
00380 --i;
00381 break;
00382 case 0:
00383
00384 if (n < 3)
00385 continue;
00386 c[3] = (c[1] + c[2])/2;
00387 c[2] = (2*c[1] + c[3])/3;
00388 c[1] = (2*c[1] + c[0])/3;
00389 --i;
00390 break;
00391 case 1:
00392 case 3:
00393 if (n == 2) {
00394
00395 path->lineTo(c[1]);
00396 c[0] = c[1];
00397 n = 1;
00398 continue;
00399 } else if (n == 3) {
00400 c[3] = c[2];
00401 c[2] = (2*c[1] + c[3])/3;
00402 c[1] = (2*c[1] + c[0])/3;
00403 }
00404 break;
00405 }
00406
00407 path->cubicTo(c[1], c[2], c[3]);
00408 c[0] = c[3];
00409 n = 1;
00410 }
00411 if (n == 1) {
00412
00413 path->closeSubpath();
00414 } else {
00415 c[3] = start;
00416 if (n == 2) {
00417 c[2] = (2*c[1] + c[3])/3;
00418 c[1] = (2*c[1] + c[0])/3;
00419 }
00420
00421 path->cubicTo(c[1], c[2], c[3]);
00422 }
00423 ++i;
00424 }
00425 }
00426
00427 extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
00428
00429 static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool = false)
00430 {
00431 if (slot->format != FT_GLYPH_FORMAT_BITMAP
00432 || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
00433 return;
00434
00435 QPointF cp = point.toPointF();
00436 qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
00437 slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
00438 }
00439
00440 #endif // QT_NO_FREETYPE
00441
00442
00443
00444
00445
00446
00447 QFontEngineMultiXLFD::QFontEngineMultiXLFD(const QFontDef &r, const QList<int> &l, int s)
00448 : QFontEngineMulti(l.size()), encodings(l), screen(s), request(r)
00449 {
00450 loadEngine(0);
00451 fontDef = engines[0]->fontDef;
00452 }
00453
00454 QFontEngineMultiXLFD::~QFontEngineMultiXLFD()
00455 { }
00456
00457 void QFontEngineMultiXLFD::loadEngine(int at)
00458 {
00459 Q_ASSERT(at < engines.size());
00460 Q_ASSERT(engines.at(at) == 0);
00461 const int encoding = encodings.at(at);
00462 QFontEngine *fontEngine = QFontDatabase::loadXlfd(0, QUnicodeTables::Common, request, encoding);
00463 Q_ASSERT(fontEngine != 0);
00464 fontEngine->ref.ref();
00465 engines[at] = fontEngine;
00466 }
00467
00468
00469
00470
00471
00472 #ifndef QT_NO_FREETYPE
00473
00474 static QStringList *qt_fontpath = 0;
00475
00476 static QStringList fontPath()
00477 {
00478 if (qt_fontpath)
00479 return *qt_fontpath;
00480
00481
00482 QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
00483 settings.beginGroup(QLatin1String("Qt"));
00484
00485 QStringList fontpath;
00486
00487 int npaths;
00488 char** font_path;
00489 font_path = XGetFontPath(X11->display, &npaths);
00490 bool xfsconfig_read = false;
00491 for (int i=0; i<npaths; i++) {
00492
00493
00494 if (((font_path[i])[0] != '/') && !xfsconfig_read) {
00495
00496 bool finished = false;
00497 QFile f(QLatin1String("/etc/X11/fs/config"));
00498 if (!f.exists())
00499 f.setFileName(QLatin1String("/usr/X11R6/lib/X11/fs/config"));
00500 if (!f.exists())
00501 f.setFileName(QLatin1String("/usr/X11/lib/X11/fs/config"));
00502 if (f.exists()) {
00503 f.open(QIODevice::ReadOnly);
00504 while (f.error()==QFile::NoError && !finished) {
00505 QString fs = QString::fromLocal8Bit(f.readLine(1024));
00506 fs=fs.trimmed();
00507 if (fs.left(9)==QLatin1String("catalogue") && fs.contains(QLatin1Char('='))) {
00508 fs = fs.mid(fs.indexOf(QLatin1Char('=')) + 1).trimmed();
00509 bool end = false;
00510 while (f.error()==QFile::NoError && !end) {
00511 if (fs[int(fs.length())-1] == QLatin1Char(','))
00512 fs = fs.left(fs.length()-1);
00513 else
00514 end = true;
00515
00516 fs = fs.left(fs.indexOf(QLatin1String(":unscaled")));
00517 if (fs[0] != QLatin1Char('#'))
00518 fontpath += fs;
00519 fs = QLatin1String(f.readLine(1024));
00520 fs = fs.trimmed();
00521 if (fs.isEmpty())
00522 end = true;
00523 }
00524 finished = true;
00525 }
00526 }
00527 f.close();
00528 }
00529 xfsconfig_read = true;
00530 } else {
00531 QString fs = QString::fromLocal8Bit(font_path[i]);
00532 fontpath += fs.left(fs.indexOf(QLatin1String(":unscaled")));
00533 }
00534 }
00535 XFreeFontPath(font_path);
00536
00537
00538 QStringList fp = settings.value(QLatin1String("fontPath")).toStringList();
00539 if (!fp.isEmpty())
00540 fontpath += fp;
00541
00542 qt_fontpath = new QStringList(fontpath);
00543 return fontpath;
00544 }
00545
00546 static QFontEngine::FaceId fontFile(const QByteArray &_xname, QFreetypeFace **freetype, int *synth)
00547 {
00548 *freetype = 0;
00549 *synth = 0;
00550
00551 QByteArray xname = _xname.toLower();
00552
00553 int pos = 0;
00554 int minus = 0;
00555 while (minus < 5 && (pos = xname.indexOf('-', pos + 1)))
00556 ++minus;
00557 QByteArray searchname = xname.left(pos);
00558 while (minus < 12 && (pos = xname.indexOf('-', pos + 1)))
00559 ++minus;
00560 QByteArray encoding = xname.mid(pos + 1);
00561
00562 QStringList fontpath = ::fontPath();
00563 QFontEngine::FaceId face_id;
00564 face_id.index = 0;
00565
00566 QByteArray best_mapping;
00567
00568 for (QStringList::ConstIterator it = fontpath.constBegin(); it != fontpath.constEnd(); ++it) {
00569 if ((*it).left(1) != QLatin1String("/"))
00570 continue;
00571 QString fontmapname;
00572 int num = 0;
00573
00574 while (num < 2) {
00575 if (num == 0)
00576 fontmapname = (*it) + QLatin1String("/fonts.scale");
00577 else
00578 fontmapname = (*it) + QLatin1String("/fonts.dir");
00579 ++num;
00580
00581 QFile fontmap(fontmapname);
00582 if (!fontmap.open(QIODevice::ReadOnly))
00583 continue;
00584 while (!fontmap.atEnd()) {
00585 QByteArray mapping = fontmap.readLine();
00586 QByteArray lmapping = mapping.toLower();
00587
00588
00589
00590 if (!lmapping.contains(searchname))
00591 continue;
00592 int index = mapping.indexOf(' ');
00593 QByteArray ffn = mapping.mid(0,index);
00594
00595 if (ffn.contains(".spd") || ffn.contains(".phont"))
00596 continue;
00597 bool best_match = false;
00598 if (!best_mapping.isEmpty()) {
00599 if (lmapping.contains("-0-0-0-0-")) {
00600 best_match = true;
00601 goto found;
00602 }
00603 if (lmapping.contains(encoding) && !best_mapping.toLower().contains(encoding))
00604 goto found;
00605 continue;
00606 }
00607
00608 found:
00609 int colon = ffn.lastIndexOf(':');
00610 if (colon != -1) {
00611 QByteArray s = ffn.left(colon);
00612 ffn = ffn.mid(colon + 1);
00613 if (s.contains("ds="))
00614 *synth |= QFontEngine::SynthesizedBold;
00615 if (s.contains("ai="))
00616 *synth |= QFontEngine::SynthesizedItalic;
00617 }
00618 face_id.filename = (*it).toLocal8Bit() + '/' + ffn;
00619 best_mapping = mapping;
00620 if (best_match)
00621 goto end;
00622 }
00623 }
00624 }
00625 end:
00626
00627
00628 *freetype = QFreetypeFace::getFace(face_id);
00629 if (!*freetype) {
00630 face_id.index = 0;
00631 face_id.filename = QByteArray();
00632 }
00633 return face_id;
00634 }
00635
00636 #endif // QT_NO_FREETYPE
00637
00638
00639 extern int qt_mib_for_xlfd_encoding(const char *encoding);
00640 extern int qt_xlfd_encoding_id(const char *encoding);
00641
00642 static inline XCharStruct *charStruct(XFontStruct *xfs, uint ch)
00643 {
00644 XCharStruct *xcs = 0;
00645 unsigned char r = ch>>8;
00646 unsigned char c = ch&0xff;
00647 if (xfs->per_char &&
00648 r >= xfs->min_byte1 &&
00649 r <= xfs->max_byte1 &&
00650 c >= xfs->min_char_or_byte2 &&
00651 c <= xfs->max_char_or_byte2) {
00652 xcs = xfs->per_char + ((r - xfs->min_byte1) *
00653 (xfs->max_char_or_byte2 -
00654 xfs->min_char_or_byte2 + 1)) +
00655 (c - xfs->min_char_or_byte2);
00656 if (xcs->width == 0 && xcs->ascent == 0 && xcs->descent == 0)
00657 xcs = 0;
00658 }
00659 return xcs;
00660 }
00661
00662 QFontEngineXLFD::QFontEngineXLFD(XFontStruct *fs, const QByteArray &name, int mib)
00663 : _fs(fs), _name(name), _codec(0), _cmap(mib)
00664 {
00665 if (_cmap) _codec = QTextCodec::codecForMib(_cmap);
00666
00667 cache_cost = (((fs->max_byte1 - fs->min_byte1) *
00668 (fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1)) +
00669 fs->max_char_or_byte2 - fs->min_char_or_byte2);
00670 cache_cost = ((fs->max_bounds.ascent + fs->max_bounds.descent) *
00671 (fs->max_bounds.width * cache_cost / 8));
00672 lbearing = SHRT_MIN;
00673 rbearing = SHRT_MIN;
00674 face_id.index = -1;
00675 freetype = 0;
00676 synth = 0;
00677 }
00678
00679 QFontEngineXLFD::~QFontEngineXLFD()
00680 {
00681 XFreeFont(QX11Info::display(), _fs);
00682 _fs = 0;
00683 #ifndef QT_NO_FREETYPE
00684 if (freetype)
00685 freetype->release(face_id);
00686 #endif
00687 }
00688
00689 bool QFontEngineXLFD::stringToCMap(const QChar *s, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
00690 {
00691 if (*nglyphs < len) {
00692 *nglyphs = len;
00693 return false;
00694 }
00695
00696
00697 QVarLengthArray<ushort> _s(len);
00698 QChar *str = (QChar *)_s.data();
00699 for (int i = 0; i < len; ++i) {
00700 if (i < len - 1
00701 && s[i].unicode() >= 0xd800 && s[i].unicode() < 0xdc00
00702 && s[i+1].unicode() >= 0xdc00 && s[i].unicode() < 0xe000) {
00703 *str = QChar();
00704 ++i;
00705 } else {
00706 *str = s[i];
00707 }
00708 ++str;
00709 }
00710
00711 len = str - (QChar *)_s.data();
00712 str = (QChar *)_s.data();
00713
00714 bool mirrored = flags & QTextEngine::RightToLeft;
00715 if (_codec) {
00716 bool haveNbsp = false;
00717 for (int i = 0; i < len; i++)
00718 if (str[i].unicode() == 0xa0) {
00719 haveNbsp = true;
00720 break;
00721 }
00722
00723 QVarLengthArray<unsigned short> ch(len);
00724 QChar *chars = (QChar *)ch.data();
00725 if (haveNbsp || mirrored) {
00726 for (int i = 0; i < len; i++)
00727 chars[i] = (str[i].unicode() == 0xa0 ? 0x20 :
00728 (mirrored ? QUnicodeTables::mirroredChar(str[i]).unicode() : str[i].unicode()));
00729 } else {
00730 for (int i = 0; i < len; i++)
00731 chars[i] = str[i].unicode();
00732 }
00733 QTextCodec::ConverterState state;
00734 state.flags = QTextCodec::ConvertInvalidToNull;
00735 QByteArray ba = _codec->fromUnicode(chars, len, &state);
00736 if (ba.length() == 2*len) {
00737
00738 const uchar *data = (const uchar *)ba.constData();
00739 for (int i = 0; i < len; i++) {
00740 glyphs[i].glyph = ((ushort)data[0] << 8) + data[1];
00741 data += 2;
00742 }
00743 } else {
00744 const uchar *data = (const uchar *)ba.constData();
00745 for (int i = 0; i < len; i++)
00746 glyphs[i].glyph = (ushort)data[i];
00747 }
00748 } else {
00749 QGlyphLayout *g = glyphs + len;
00750 const QChar *c = str + len;
00751 if (mirrored) {
00752 while (c != str)
00753 (--g)->glyph = (--c)->unicode() == 0xa0 ? 0x20 : QUnicodeTables::mirroredChar(*c).unicode();
00754 } else {
00755 while (c != str)
00756 (--g)->glyph = (--c)->unicode() == 0xa0 ? 0x20 : c->unicode();
00757 }
00758 }
00759 *nglyphs = len;
00760
00761 QGlyphLayout *g = glyphs + len;
00762 XCharStruct *xcs;
00763
00764 if (!_fs->per_char) {
00765 xcs = &_fs->min_bounds;
00766 while (g != glyphs) {
00767 --g;
00768 const unsigned char r = g->glyph >> 8;
00769 const unsigned char c = g->glyph & 0xff;
00770 if (r >= _fs->min_byte1 &&
00771 r <= _fs->max_byte1 &&
00772 c >= _fs->min_char_or_byte2 &&
00773 c <= _fs->max_char_or_byte2) {
00774 g->advance.x = xcs->width;
00775 } else {
00776 g->glyph = 0;
00777 }
00778 }
00779 }
00780 else if (!_fs->max_byte1) {
00781 XCharStruct *base = _fs->per_char - _fs->min_char_or_byte2;
00782 while (g != glyphs) {
00783 unsigned int gl = (--g)->glyph;
00784 xcs = (gl >= _fs->min_char_or_byte2 && gl <= _fs->max_char_or_byte2) ?
00785 base + gl : 0;
00786 if (!xcs || (!xcs->width && !xcs->ascent && !xcs->descent)) {
00787 g->glyph = 0;
00788 } else {
00789 g->advance.x = xcs->width;
00790 }
00791 }
00792 }
00793 else {
00794 while (g != glyphs) {
00795 xcs = charStruct(_fs, (--g)->glyph);
00796 if (!xcs) {
00797 g->glyph = 0;
00798 } else {
00799 g->advance.x = xcs->width;
00800 }
00801 }
00802 }
00803 return true;
00804 }
00805
00806 glyph_metrics_t QFontEngineXLFD::boundingBox(const QGlyphLayout *glyphs, int numGlyphs)
00807 {
00808 int i;
00809
00810 glyph_metrics_t overall;
00811
00812 overall.y = -ascent();
00813 overall.height = ascent() + descent() + 1;
00814 QFixed ymax;
00815 QFixed xmax;
00816 for (i = 0; i < numGlyphs; i++) {
00817 XCharStruct *xcs = charStruct(_fs, glyphs[i].glyph);
00818 if (xcs) {
00819 QFixed x = overall.xoff + glyphs[i].offset.x + xcs->lbearing;
00820 QFixed y = overall.yoff + glyphs[i].offset.y - xcs->ascent;
00821 overall.x = qMin(overall.x, x);
00822 overall.y = qMin(overall.y, y);
00823 xmax = qMax(xmax, overall.xoff + glyphs[i].offset.x + xcs->rbearing);
00824 ymax = qMax(ymax, y + xcs->ascent + xcs->descent);
00825 overall.xoff += glyphs[i].advance.x;
00826 } else {
00827 QFixed size = _fs->ascent;
00828 overall.x = qMin(overall.x, overall.xoff);
00829 overall.y = qMin(overall.y, overall.yoff - size);
00830 ymax = qMax(ymax, overall.yoff);
00831 overall.xoff += size;
00832 xmax = qMax(xmax, overall.xoff);
00833 }
00834 }
00835 overall.height = qMax(overall.height, ymax - overall.y);
00836 overall.width = xmax - overall.x;
00837
00838 return overall;
00839 }
00840
00841 glyph_metrics_t QFontEngineXLFD::boundingBox(glyph_t glyph)
00842 {
00843 glyph_metrics_t gm;
00844 XCharStruct *xcs = charStruct(_fs, glyph);
00845 if (xcs) {
00846 gm = glyph_metrics_t(xcs->lbearing, -xcs->ascent, xcs->rbearing- xcs->lbearing, xcs->ascent + xcs->descent,
00847 xcs->width, 0);
00848 } else {
00849 QFixed size = ascent();
00850 gm = glyph_metrics_t(0, size, size, size, size, 0);
00851 }
00852 return gm;
00853 }
00854
00855 QFixed QFontEngineXLFD::ascent() const
00856 {
00857 return _fs->ascent;
00858 }
00859
00860 QFixed QFontEngineXLFD::descent() const
00861 {
00862 return (_fs->descent-1);
00863 }
00864
00865 QFixed QFontEngineXLFD::leading() const
00866 {
00867 QFixed l = QFixed(qMin<int>(_fs->ascent, _fs->max_bounds.ascent)
00868 + qMin<int>(_fs->descent, _fs->max_bounds.descent)) * QFixed::fromReal(0.15);
00869 return l.ceil();
00870 }
00871
00872 qreal QFontEngineXLFD::maxCharWidth() const
00873 {
00874 return _fs->max_bounds.width;
00875 }
00876
00877
00878
00879 static inline int maxIndex(XFontStruct *f) {
00880 return (((f->max_byte1 - f->min_byte1) *
00881 (f->max_char_or_byte2 - f->min_char_or_byte2 + 1)) +
00882 f->max_char_or_byte2 - f->min_char_or_byte2);
00883 }
00884
00885 qreal QFontEngineXLFD::minLeftBearing() const
00886 {
00887 if (lbearing == SHRT_MIN) {
00888 if (_fs->per_char) {
00889 XCharStruct *cs = _fs->per_char;
00890 int nc = maxIndex(_fs) + 1;
00891 int mx = cs->lbearing;
00892
00893 for (int c = 1; c < nc; c++) {
00894
00895
00896 if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
00897 (cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
00898 continue;
00899
00900 int nmx = cs[c].lbearing;
00901
00902 if (nmx < mx)
00903 mx = nmx;
00904 }
00905
00906 ((QFontEngineXLFD *)this)->lbearing = mx;
00907 } else
00908 ((QFontEngineXLFD *)this)->lbearing = _fs->min_bounds.lbearing;
00909 }
00910 return lbearing;
00911 }
00912
00913 qreal QFontEngineXLFD::minRightBearing() const
00914 {
00915 if (rbearing == SHRT_MIN) {
00916 if (_fs->per_char) {
00917 XCharStruct *cs = _fs->per_char;
00918 int nc = maxIndex(_fs) + 1;
00919 int mx = cs->rbearing;
00920
00921 for (int c = 1; c < nc; c++) {
00922
00923
00924 if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
00925 (cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
00926 continue;
00927
00928 int nmx = cs[c].rbearing;
00929
00930 if (nmx < mx)
00931 mx = nmx;
00932 }
00933
00934 ((QFontEngineXLFD *)this)->rbearing = mx;
00935 } else
00936 ((QFontEngineXLFD *)this)->rbearing = _fs->min_bounds.rbearing;
00937 }
00938 return rbearing;
00939 }
00940
00941 const char *QFontEngineXLFD::name() const
00942 {
00943 return _name;
00944 }
00945
00946 bool QFontEngineXLFD::canRender(const QChar *string, int len)
00947 {
00948 QVarLengthArray<QGlyphLayout, 256> glyphs(len);
00949 int nglyphs = len;
00950 if (stringToCMap(string, len, glyphs.data(), &nglyphs, 0) == false) {
00951 glyphs.resize(nglyphs);
00952 stringToCMap(string, len, glyphs.data(), &nglyphs, 0);
00953 }
00954
00955 bool allExist = true;
00956 for (int i = 0; i < nglyphs; i++) {
00957 if (!glyphs[i].glyph || !charStruct(_fs, glyphs[i].glyph)) {
00958 allExist = false;
00959 break;
00960 }
00961 }
00962
00963 return allExist;
00964 }
00965
00966 void QFontEngineXLFD::addOutlineToPath(qreal x, qreal y, const QGlyphLayout *glyphs, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags flags)
00967 {
00968 addBitmapFontToPath(x, y, glyphs, numGlyphs, path, flags);
00969 }
00970
00971 QFontEngine::FaceId QFontEngineXLFD::faceId() const
00972 {
00973 #ifndef QT_NO_FREETYPE
00974 if (face_id.index == -1) {
00975 face_id = ::fontFile(_name, &freetype, &synth);
00976 if (_codec)
00977 face_id.encoding = _codec->mibEnum();
00978 if (freetype) {
00979 const_cast<QFontEngineXLFD *>(this)->fsType = freetype->fsType();
00980 } else {
00981 QFontEngine::Properties properties = QFontEngine::properties();
00982 face_id.index = 0;
00983 face_id.filename = "-" + properties.postscriptName;
00984 }
00985 }
00986 #endif
00987
00988 return face_id;
00989 }
00990
00991 QFontEngine::Properties QFontEngineXLFD::properties() const
00992 {
00993 if (face_id.index == -1)
00994 (void)faceId();
00995
00996 #ifndef QT_NO_FREETYPE
00997 if (freetype)
00998 return freetype->properties();
00999 #endif
01000 return QFontEngine::properties();
01001 }
01002
01003 void QFontEngineXLFD::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
01004 {
01005 if (face_id.index == -1)
01006 (void)faceId();
01007 #ifndef QT_NO_FREETYPE
01008 if (!freetype)
01009 #endif
01010 {
01011 QFontEngine::getUnscaledGlyph(glyph, path, metrics);
01012 return;
01013 }
01014
01015 #ifndef QT_NO_FREETYPE
01016 freetype->lock();
01017
01018 FT_Face face = freetype->face;
01019 FT_Set_Transform(face, 0, 0);
01020 glyph = glyphIndexToFreetypeGlyphIndex(glyph);
01021 FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING|FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE);
01022
01023 int left = face->glyph->metrics.horiBearingX;
01024 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
01025 int top = face->glyph->metrics.horiBearingY;
01026 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
01027
01028 QFixedPoint p;
01029 p.x = 0;
01030 p.y = 0;
01031 if (!FT_IS_SCALABLE(freetype->face)) {
01032 metrics->width = QFixed::fromFixed(right-left);
01033 metrics->height = QFixed::fromFixed(top-bottom);
01034 metrics->x = QFixed::fromFixed(left);
01035 metrics->y = QFixed::fromFixed(-top);
01036 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
01037
01038 ::addBitmapToPath(face->glyph, p, path);
01039 } else {
01040 metrics->width = right-left;
01041 metrics->height = top-bottom;
01042 metrics->x = left;
01043 metrics->y = -top;
01044 metrics->xoff = face->glyph->advance.x;
01045
01046 ::addGlyphToPath(face->glyph, p, path, true );
01047 }
01048 FT_Set_Transform(face, &freetype->matrix, 0);
01049 freetype->unlock();
01050 #endif // QT_NO_FREETYPE
01051 }
01052
01053
01054 QByteArray QFontEngineXLFD::getSfntTable(uint tag) const
01055 {
01056 #ifndef QT_NO_FREETYPE
01057 if (face_id.index == -1)
01058 (void)faceId();
01059 if (!freetype)
01060 return QByteArray();
01061 return freetype->getSfntTable(tag);
01062 #else
01063 Q_UNUSED(tag);
01064 return QByteArray();
01065 #endif
01066 }
01067
01068 int QFontEngineXLFD::synthesized() const
01069 {
01070 return synth;
01071 }
01072
01073 #ifndef QT_NO_FREETYPE
01074
01075 FT_Face QFontEngineXLFD::non_locked_face() const
01076 {
01077 return freetype ? freetype->face : 0;
01078 }
01079
01080 uint QFontEngineXLFD::toUnicode(glyph_t g) const
01081 {
01082 if (_codec) {
01083 QTextCodec::ConverterState state;
01084 state.flags = QTextCodec::ConvertInvalidToNull;
01085 uchar data[2];
01086 int l = 1;
01087 if (g > 255) {
01088 data[0] = (g >> 8);
01089 data[1] = (g & 255);
01090 l = 2;
01091 } else {
01092 data[0] = g;
01093 }
01094 QString s = _codec->toUnicode((char *)data, l, &state);
01095 Q_ASSERT(s.length() == 1);
01096 g = s.at(0).unicode();
01097 }
01098 return g;
01099 }
01100
01101 glyph_t QFontEngineXLFD::glyphIndexToFreetypeGlyphIndex(glyph_t g) const
01102 {
01103 return FT_Get_Char_Index(freetype->face, toUnicode(g));
01104 }
01105 #endif
01106
01107 #ifndef QT_NO_FONTCONFIG
01108
01109
01110
01111
01112
01113 static QFontEngine *engineForPattern(FcPattern *pattern, const QFontDef &request,
01114 int screen)
01115 {
01116 FcResult res;
01117 FcPattern *match = FcFontMatch(0, pattern, &res);
01118 QFontEngineFT *engine = new QFontEngineFT(match, request, screen);
01119 if (!engine->invalid())
01120 return engine;
01121
01122 delete engine;
01123 QFontEngine *fe = new QFontEngineBox(request.pixelSize);
01124 fe->fontDef = request;
01125 return fe;
01126 }
01127
01128 QFontEngineMultiFT::QFontEngineMultiFT(QFontEngine *fe, FcPattern *p, int s, const QFontDef &req)
01129 : QFontEngineMulti(2), request(req), pattern(p), fontSet(0), screen(s)
01130 {
01131
01132 engines[0] = fe;
01133 engines.at(0)->ref.ref();
01134 fontDef = engines[0]->fontDef;
01135 cache_cost = 100;
01136 }
01137
01138 QFontEngineMultiFT::~QFontEngineMultiFT()
01139 {
01140 FcPatternDestroy(pattern);
01141 if (fontSet)
01142 FcFontSetDestroy(fontSet);
01143 }
01144
01145
01146 void QFontEngineMultiFT::loadEngine(int at)
01147 {
01148 extern void qt_addPatternProps(FcPattern *pattern, int screen, int script,
01149 const QFontDef &request);
01150 extern QFontDef qt_FcPatternToQFontDef(FcPattern *pattern, const QFontDef &);
01151 extern FcFontSet *qt_fontSetForPattern(FcPattern *pattern, const QFontDef &request);
01152
01153 Q_ASSERT(at > 0);
01154 if (!fontSet) {
01155 fontSet = qt_fontSetForPattern(pattern, request);
01156 engines.resize(fontSet->nfont);
01157 }
01158 Q_ASSERT(at < engines.size());
01159 Q_ASSERT(engines.at(at) == 0);
01160
01161 FcPattern *pattern = FcPatternDuplicate(fontSet->fonts[at]);
01162 qt_addPatternProps(pattern, screen, QUnicodeTables::Common, request);
01163
01164 QFontDef fontDef = qt_FcPatternToQFontDef(pattern, this->request);
01165
01166
01167
01168 QFontCache::Key key(fontDef, -1, screen);
01169 QFontEngine *fontEngine = QFontCache::instance->findEngine(key);
01170 if (!fontEngine) {
01171 FcConfigSubstitute(0, pattern, FcMatchPattern);
01172 FcDefaultSubstitute(pattern);
01173 fontEngine = engineForPattern(pattern, request, screen);
01174 FcPatternDestroy(pattern);
01175 QFontCache::instance->insertEngine(key, fontEngine);
01176 }
01177 fontEngine->ref.ref();
01178 engines[at] = fontEngine;
01179 }
01180
01181
01182
01183
01184
01185
01186 QFontEngineFT::Glyph::~Glyph()
01187 {
01188 delete [] data;
01189 }
01190
01191 static QFontEngine::FaceId face_id(FcPattern *pattern)
01192 {
01193 char *file_name;
01194 FcPatternGetString(pattern, FC_FILE, 0, (FcChar8 **)&file_name);
01195 int face_index;
01196 if (!FcPatternGetInteger(pattern, FC_INDEX, 0, &face_index))
01197 face_index = 0;
01198 QFontEngine::FaceId face_id;
01199 face_id.filename = file_name;
01200 face_id.index = face_index;
01201 return face_id;
01202 }
01203
01204 QFontEngineFT::QFontEngineFT(FcPattern *pattern, const QFontDef &fd, int screen)
01205 {
01206 _openType = 0;
01207 cache_cost = 100;
01208 fontDef = fd;
01209 _pattern = pattern;
01210 transform = false;
01211 matrix.xx = 0x10000;
01212 matrix.yy = 0x10000;
01213 matrix.xy = 0;
01214 matrix.yx = 0;
01215
01216
01217 antialias = X11->fc_antialias;
01218 FcBool b;
01219 if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &b) == FcResultMatch)
01220 antialias = b;
01221 if (FcPatternGetInteger(pattern, FC_RGBA, 0, &subpixel) == FcResultNoMatch)
01222 subpixel = X11->screens[screen].subpixel;
01223 if (!antialias || subpixel == FC_RGBA_UNKNOWN)
01224 subpixel = FC_RGBA_NONE;
01225
01226 #ifdef FC_HINT_STYLE
01227 if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style) == FcResultNoMatch)
01228 hint_style = X11->fc_hint_style;
01229 #endif
01230
01231 autohint = false;
01232 #ifdef FC_AUTOHINT
01233 if (FcPatternGetBool(pattern, FC_AUTOHINT, 0, &b) == FcResultMatch)
01234 autohint = b;
01235 #endif
01236
01237 face_id = ::face_id(pattern);
01238
01239 freetype = QFreetypeFace::getFace(face_id);
01240 if (!freetype) {
01241 xsize = 0;
01242 ysize = 0;
01243 return;
01244 }
01245
01246 if (!freetype->charset) {
01247 FcCharSet *cs;
01248 FcPatternGetCharSet (pattern, FC_CHARSET, 0, &cs);
01249 freetype->charset = FcCharSetCopy(cs);
01250 }
01251 symbol = freetype->symbol_map != 0;
01252
01253 lbearing = rbearing = SHRT_MIN;
01254 freetype->computeSize(fontDef, &xsize, &ysize, &outline_drawing);
01255
01256 FT_Face face = lockFace();
01257
01258
01259 if (FT_IS_SCALABLE(face)) {
01260 line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
01261 underline_position = QFixed::fromFixed(-FT_MulFix(face->underline_position, face->size->metrics.y_scale));
01262 bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !(face->style_flags & FT_STYLE_FLAG_ITALIC);
01263 if (fake_oblique)
01264 matrix.xy = 0x10000*3/10;
01265 FT_Set_Transform(face, &matrix, 0);
01266 if (fake_oblique)
01267 transform = true;
01268 } else {
01269
01270
01271 int score = fontDef.weight * fontDef.pixelSize;
01272 line_thickness = score / 700;
01273
01274 if (line_thickness < 2 && score >= 1050)
01275 line_thickness = 2;
01276 underline_position = ((line_thickness * 2) + 3) / 6;
01277 }
01278 if (line_thickness < 1)
01279 line_thickness = 1;
01280
01281 metrics = face->size->metrics;
01282
01283 unlockFace();
01284
01285 fsType = freetype->fsType();
01286
01287 #ifndef QT_NO_XRENDER
01288 if (X11->use_xrender) {
01289 int format = PictStandardA8;
01290 if (!antialias)
01291 format = PictStandardA1;
01292 else if (subpixel == FC_RGBA_RGB
01293 || subpixel == FC_RGBA_BGR
01294 || subpixel == FC_RGBA_VRGB
01295 || subpixel == FC_RGBA_VBGR)
01296 format = PictStandardARGB32;
01297 fnt.glyphSet = XRenderCreateGlyphSet(X11->display,
01298 XRenderFindStandardFormat(X11->display, format));
01299 xglyph_format = format;
01300 } else {
01301 fnt.glyphSet = 0;
01302 }
01303 #endif
01304 }
01305
01306 QFontEngineFT::~QFontEngineFT()
01307 {
01308 delete _openType;
01309 _openType = 0;
01310
01311 if (freetype)
01312 freetype->release(face_id);
01313
01314 FcPatternDestroy(_pattern);
01315 _pattern = 0;
01316 }
01317
01318 FT_Face QFontEngineFT::lockFace() const
01319 {
01320 freetype->lock();
01321 FT_Face face = freetype->face;
01322 if (freetype->xsize != xsize || freetype->ysize != ysize) {
01323 FT_Set_Char_Size(face, xsize, ysize, 0, 0);
01324 freetype->xsize = xsize;
01325 freetype->ysize = ysize;
01326 }
01327 if (freetype->matrix.xx != matrix.xx ||
01328 freetype->matrix.yy != matrix.yy ||
01329 freetype->matrix.xy != matrix.xy ||
01330 freetype->matrix.yx != matrix.yx) {
01331 freetype->matrix = matrix;
01332 FT_Set_Transform(face, &freetype->matrix, 0);
01333 }
01334
01335 return face;
01336 }
01337
01338 void QFontEngineFT::unlockFace() const
01339 {
01340 freetype->unlock();
01341 }
01342
01343 FT_Face QFontEngineFT::non_locked_face() const
01344 {
01345 return freetype->face;
01346 }
01347
01348 static const uint subpixel_filter[3][3] = {
01349 { 180, 60, 16 },
01350 { 38, 180, 38 },
01351 { 16, 60, 180 }
01352 };
01353
01354 QFontEngineFT::Font::Font()
01355 #ifndef QT_NO_XRENDER
01356 : glyphSet(0)
01357 #endif
01358 {
01359 transformationMatrix.xx = 0x10000;
01360 transformationMatrix.yy = 0x10000;
01361 transformationMatrix.xy = 0;
01362 transformationMatrix.yx = 0;
01363 }
01364
01365 QFontEngineFT::Font::~Font()
01366 {
01367 qDeleteAll(glyph_data);
01368 #ifndef QT_NO_XRENDER
01369 if (glyphSet != 0)
01370 XRenderFreeGlyphSet(X11->display, glyphSet);
01371 #endif
01372 }
01373
01374 QFontEngineFT::Glyph *QFontEngineFT::Font::loadGlyph(const QFontEngineFT *fe, uint glyph, GlyphFormat format) const
01375 {
01376
01377
01378 bool add_to_glyphset = false;
01379 if (format == Format_None) {
01380 format = Format_Mono;
01381 if (X11->use_xrender) {
01382 add_to_glyphset = true;
01383 if (fe->subpixel != FC_RGBA_NONE)
01384 format = Format_A32;
01385 else if (fe->antialias)
01386 format = Format_A8;
01387 }
01388 }
01389 Q_ASSERT(format != Format_None);
01390 bool hsubpixel = false;
01391 int vfactor = 1;
01392 int load_flags = FT_LOAD_DEFAULT;
01393 if (fe->outline_drawing) {
01394 load_flags = FT_LOAD_NO_BITMAP|FT_LOAD_NO_HINTING;
01395 } else if (format == Format_Mono) {
01396 load_flags |= FT_LOAD_TARGET_MONO;
01397 } else if (format == Format_A32) {
01398 if (fe->subpixel == FC_RGBA_RGB || fe->subpixel == FC_RGBA_BGR) {
01399 load_flags |= FT_LOAD_TARGET_LCD;
01400 hsubpixel = true;
01401 } else if (fe->subpixel == FC_RGBA_VRGB || fe->subpixel == FC_RGBA_VBGR) {
01402 load_flags |= FT_LOAD_TARGET_LCD_V;
01403 vfactor = 3;
01404 }
01405
01406 }
01407 if (format != Format_Mono)
01408 load_flags |= FT_LOAD_NO_BITMAP;
01409
01410 #ifdef FC_HINT_STYLE
01411 if (fe->hint_style == FC_HINT_NONE)
01412 load_flags |= FT_LOAD_NO_HINTING;
01413 else if (fe->hint_style < FC_HINT_FULL)
01414 load_flags |= FT_LOAD_TARGET_LIGHT;
01415 #endif
01416
01417 #ifdef FT_LOAD_FORCE_AUTOHINT
01418 if (fe->autohint)
01419 load_flags |= FT_LOAD_FORCE_AUTOHINT;
01420 #endif
01421
01422 bool transform = fe->transform
01423 || transformationMatrix.xx != 0x10000
01424 || transformationMatrix.yy != 0x10000
01425 || transformationMatrix.xy != 0
01426 || transformationMatrix.yx != 0;
01427
01428 if (transform)
01429 load_flags |= FT_LOAD_NO_BITMAP;
01430
01431 {
01432 Glyph *g = glyph_data.value(glyph);
01433 if (g && g->format == format)
01434 return g;
01435 }
01436
01437 const QFreetypeFace * const freetype = fe->freetype;
01438 FT_Face face = freetype->face;
01439 FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
01440 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
01441 load_flags &= ~FT_LOAD_NO_BITMAP;
01442 err = FT_Load_Glyph(face, glyph, load_flags);
01443 }
01444 if (err == FT_Err_Too_Few_Arguments) {
01445
01446 load_flags |= FT_LOAD_FORCE_AUTOHINT;
01447 err = FT_Load_Glyph(face, glyph, load_flags);
01448 }
01449 if (err != FT_Err_Ok)
01450 qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
01451
01452 if (fe->outline_drawing)
01453 return 0;
01454
01455 FT_GlyphSlot slot = face->glyph;
01456
01457 FT_Matrix matrix = freetype->matrix;
01458
01459 int left = slot->metrics.horiBearingX;
01460 int right = slot->metrics.horiBearingX + slot->metrics.width;
01461 int top = slot->metrics.horiBearingY;
01462 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
01463 if(transform && slot->format != FT_GLYPH_FORMAT_BITMAP) {
01464 int l, r, t, b;
01465 FT_Vector vector;
01466 vector.x = left;
01467 vector.y = top;
01468 FT_Vector_Transform(&vector, &matrix);
01469 l = r = vector.x;
01470 t = b = vector.y;
01471 vector.x = right;
01472 vector.y = top;
01473 FT_Vector_Transform(&vector, &matrix);
01474 if (l > vector.x) l = vector.x;
01475 if (r < vector.x) r = vector.x;
01476 if (t < vector.y) t = vector.y;
01477 if (b > vector.y) b = vector.y;
01478 vector.x = right;
01479 vector.y = bottom;
01480 FT_Vector_Transform(&vector, &matrix);
01481 if (l > vector.x) l = vector.x;
01482 if (r < vector.x) r = vector.x;
01483 if (t < vector.y) t = vector.y;
01484 if (b > vector.y) b = vector.y;
01485 vector.x = left;
01486 vector.y = bottom;
01487 FT_Vector_Transform(&vector, &matrix);
01488 if (l > vector.x) l = vector.x;
01489 if (r < vector.x) r = vector.x;
01490 if (t < vector.y) t = vector.y;
01491 if (b > vector.y) b = vector.y;
01492 left = l;
01493 right = r;
01494 top = t;
01495 bottom = b;
01496 }
01497 left = FLOOR(left);
01498 right = CEIL(right);
01499 bottom = FLOOR(bottom);
01500 top = CEIL(top);
01501
01502 int hpixels = TRUNC(right - left);
01503 if (hsubpixel)
01504 hpixels = hpixels*3 + 8;
01505 #ifndef QT_NO_XRENDER
01506 XGlyphInfo info;
01507 #else
01508 typedef struct _XGlyphInfoDummy {
01509 unsigned short width;
01510 unsigned short height;
01511 short x;
01512 short y;
01513 short xOff;
01514 short yOff;
01515 } XGlyphInfoDummy;
01516 XGlyphInfoDummy info;
01517 #endif
01518 info.width = hpixels;
01519 info.height = TRUNC(top - bottom);
01520 info.x = -TRUNC(left);
01521 info.y = TRUNC(top);
01522 info.xOff = TRUNC(ROUND(slot->advance.x));
01523 info.yOff = 0;
01524 if (hsubpixel) {
01525 info.width /= 3;
01526 info.x += 1;
01527 }
01528
01529 int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
01530 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
01531 int size = pitch * info.height;
01532 uchar *glyph_buffer = new uchar[size];
01533
01534 if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
01535 FT_Bitmap bitmap;
01536 bitmap.rows = info.height*vfactor;
01537 bitmap.width = hpixels;
01538 bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
01539 if (!hsubpixel && vfactor == 1)
01540 bitmap.buffer = glyph_buffer;
01541 else
01542 bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
01543 memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
01544 bitmap.pixel_mode = format == Format_Mono ? ft_pixel_mode_mono : ft_pixel_mode_grays;
01545 FT_Matrix matrix;
01546 matrix.xx = (hsubpixel ? 3 : 1) << 16;
01547 matrix.yy = vfactor << 16;
01548 matrix.yx = matrix.xy = 0;
01549
01550 FT_Outline_Transform(&slot->outline, &matrix);
01551 FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
01552 FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
01553 if (hsubpixel) {
01554 Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
01555 Q_ASSERT(fe->antialias);
01556 const uchar *src = bitmap.buffer;
01557 uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
01558 uchar *c = convoluted;
01559
01560
01561
01562
01563 int h = info.height;
01564 while (h--) {
01565 c[0] = c[1] = 0;
01566
01567 for (int x = 2; x < bitmap.width - 2; ++x) {
01568 uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
01569 c[x] = (uchar) (sum >> 4);
01570 }
01571 c[bitmap.width - 2] = c[bitmap.width -1] = 0;
01572 src += bitmap.pitch;
01573 c += bitmap.pitch;
01574 }
01575
01576 uint *dst = (uint *)glyph_buffer;
01577 src = convoluted;
01578 h = info.height;
01579 if (fe->subpixel == FC_RGBA_RGB) {
01580 while (h--) {
01581 uint *dd = dst;
01582 for (int x = 1; x < bitmap.width - 1; x += 3) {
01583 uint red = src[x];
01584 uint green = src[x+1];
01585 uint blue = src[x+2];
01586 uint res = (red << 16) + (green << 8) + blue;
01587 *dd = res;
01588 ++dd;
01589 }
01590 dst += info.width;
01591 src += bitmap.pitch;
01592 }
01593 } else {
01594 while (h--) {
01595 uint *dd = dst;
01596 for (int x = 1; x < bitmap.width - 1; x += 3) {
01597 uint blue = src[x];
01598 uint green = src[x+1];
01599 uint red = src[x+2];
01600 uint res = (red << 16) + (green << 8) + blue;
01601 *dd = res;
01602 ++dd;
01603 }
01604 dst += info.width;
01605 src += bitmap.pitch;
01606 }
01607 }
01608 delete [] convoluted;
01609 delete [] bitmap.buffer;
01610 } else if (vfactor != 1) {
01611 uchar *src = bitmap.buffer;
01612 size = info.width * 4 * info.height;
01613 uint *dst = (uint *)glyph_buffer;
01614 int h = info.height;
01615 if (fe->subpixel == FC_RGBA_VRGB) {
01616 while (h--) {
01617 for (int x = 0; x < info.width; x++) {
01618 uint red = src[x];
01619 uint green = src[x+bitmap.pitch];
01620 uint blue = src[x+2*bitmap.pitch];
01621 uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
01622 uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
01623 uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
01624 uint res = (high << 16) + (mid << 8) + low;
01625 dst[x] = res;
01626 }
01627 dst += info.width;
01628 src += 3*bitmap.pitch;
01629 }
01630 } else {
01631 while (h--) {
01632 for (int x = 0; x < info.width; x++) {
01633 uint blue = src[x];
01634 uint green = src[x+bitmap.pitch];
01635 uint red = src[x+2*bitmap.pitch];
01636 uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
01637 uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
01638 uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
01639 uint res = (high << 16) + (mid << 8) + low;
01640 dst[x] = res;
01641 }
01642 dst += info.width;
01643 src += 3*bitmap.pitch;
01644 }
01645 }
01646 delete [] bitmap.buffer;
01647 }
01648 } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
01649 Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
01650 uchar *src = slot->bitmap.buffer;
01651 uchar *dst = glyph_buffer;
01652 int h = slot->bitmap.rows;
01653 if (format == Format_Mono) {
01654 int bytes = ((info.width + 7) & ~7) >> 3;
01655 while (h--) {
01656 memcpy (dst, src, bytes);
01657 dst += pitch;
01658 src += slot->bitmap.pitch;
01659 }
01660 } else {
01661 if (hsubpixel) {
01662 while (h--) {
01663 uint *dd = (uint *)dst;
01664 *dd++ = 0;
01665 for (int x = 0; x < slot->bitmap.width; x++) {
01666 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
01667 *dd++ = a;
01668 }
01669 *dd++ = 0;
01670 dst += pitch;
01671 src += slot->bitmap.pitch;
01672 }
01673 } else if (vfactor != 1) {
01674 while (h--) {
01675 uint *dd = (uint *)dst;
01676 for (int x = 0; x < slot->bitmap.width; x++) {
01677 uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
01678 *dd++ = a;
01679 }
01680 dst += pitch;
01681 src += slot->bitmap.pitch;
01682 }
01683 } else {
01684 while (h--) {
01685 for (int x = 0; x < slot->bitmap.width; x++) {
01686 unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
01687 dst[x] = a;
01688 }
01689 dst += pitch;
01690 src += slot->bitmap.pitch;
01691 }
01692 }
01693 }
01694 } else {
01695 qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
01696 delete [] glyph_buffer;
01697 return 0;
01698 }
01699
01700 #ifndef QT_NO_XRENDER
01701 if (add_to_glyphset) {
01702 if (format == Format_Mono) {
01703
01704
01705
01706 if (BitmapBitOrder(X11->display) != MSBFirst) {
01707 unsigned char *line = (unsigned char *) glyph_buffer;
01708 int i = size;
01709 i = size;
01710 while (i--) {
01711 unsigned char c;
01712 c = *line;
01713 c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
01714 c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
01715 c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
01716 *line++ = c;
01717 }
01718 }
01719 }
01720
01721 ::Glyph xglyph = glyph;
01722 XRenderAddGlyphs (X11->display, glyphSet, &xglyph, &info, 1, (const char *)glyph_buffer, size);
01723 delete [] glyph_buffer;
01724 glyph_buffer = 0;
01725 }
01726 #endif
01727
01728
01729 bool large_glyph = (((signed char)(slot->linearHoriAdvance>>16) != slot->linearHoriAdvance>>16)
01730 || ((uchar)(info.width) != info.width)
01731 || ((uchar)(info.height) != info.height)
01732 || ((signed char)(info.x) != info.x)
01733 || ((signed char)(info.y) != info.y)
01734 || ((signed char)(info.xOff) != info.xOff));
01735
01736 if (large_glyph) {
01737
01738 return 0;
01739 }
01740
01741 Glyph *g = new Glyph;
01742
01743 g->linearAdvance = slot->linearHoriAdvance >> 10;
01744 g->width = info.width;
01745 g->height = TRUNC(top - bottom);
01746 g->x = -info.x;
01747 g->y = TRUNC(top);
01748 g->advance = TRUNC(ROUND(slot->advance.x));
01749 g->format = add_to_glyphset ? Format_None : format;
01750 g->data = glyph_buffer;
01751
01752
01753 delete glyph_data.value(glyph);
01754 glyph_data[glyph] = g;
01755
01756 return g;
01757 }
01758 #ifndef QT_NO_XRENDER
01759 bool QFontEngineFT::loadTransformedGlyphSet(glyph_t *glyphs, int num_glyphs, const QMatrix &matrix, GlyphSet *gs)
01760 {
01761
01762 if (fontDef.pixelSize * sqrt(matrix.det()) >= 64) {
01763 *gs = 0;
01764 return false;
01765 }
01766
01767 FT_Matrix m;
01768 m.xx = FT_Fixed(matrix.m11() * 65536);
01769 m.xy = FT_Fixed(-matrix.m21() * 65536);
01770 m.yx = FT_Fixed(-matrix.m12() * 65536);
01771 m.yy = FT_Fixed(matrix.m22() * 65536);
01772
01773 Font *font = 0;
01774
01775 for (int i = 0; i < transformedFonts.count(); ++i) {
01776 const Font &f = transformedFonts.at(i);
01777 if (f.transformationMatrix.xx == m.xx
01778 && f.transformationMatrix.xy == m.xy
01779 && f.transformationMatrix.yx == m.yx
01780 && f.transformationMatrix.yy == m.yy) {
01781
01782
01783 transformedFonts.move(i, 0);
01784 font = &transformedFonts[0];
01785 break;
01786 }
01787 }
01788
01789 if (!font) {
01790
01791 if (transformedFonts.count() >= 10) {
01792 transformedFonts.move(transformedFonts.size() - 1, 0);
01793 XRenderFreeGlyphSet(X11->display, transformedFonts.at(0).glyphSet);
01794 } else {
01795 transformedFonts.prepend(Font());
01796 }
01797 font = &transformedFonts[0];
01798
01799 qDeleteAll(font->glyph_data);
01800 font->glyph_data.clear();
01801
01802 font->glyphSet = XRenderCreateGlyphSet(X11->display,
01803 XRenderFindStandardFormat(X11->display, xglyph_format));
01804
01805 font->transformationMatrix = m;
01806 }
01807
01808 FT_Face face = 0;
01809 bool lockedFace = false;
01810
01811 for (int i = 0; i < num_glyphs; ++i) {
01812 if (!font->glyph_data.contains(glyphs[i])) {
01813 if (!lockedFace) {
01814 face = lockFace();
01815 m = this->matrix;
01816 FT_Matrix_Multiply(&font->transformationMatrix, &m);
01817 FT_Set_Transform(face, &m, 0);
01818 freetype->matrix = m;
01819 lockedFace = true;
01820 }
01821 if (!font->loadGlyph(this, glyphs[i])) {
01822 FT_Set_Transform(face, &freetype->matrix, 0);
01823 unlockFace();
01824 return false;
01825 }
01826 }
01827 }
01828 *gs = font->glyphSet;
01829
01830 if (lockedFace) {
01831 FT_Set_Transform(face, &freetype->matrix, 0);
01832 unlockFace();
01833 }
01834
01835 return true;
01836 }
01837 #endif
01838
01839 inline unsigned int getChar(const QChar *str, int &i, const int len)
01840 {
01841 unsigned int uc = str[i].unicode();
01842 if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
01843 uint low = str[i+1].unicode();
01844 if (low >= 0xdc00 && low < 0xe000) {
01845 uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
01846 ++i;
01847 }
01848 }
01849 return uc;
01850 }
01851
01852 bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
01853 QTextEngine::ShaperFlags flags) const
01854 {
01855 if (*nglyphs < len) {
01856 *nglyphs = len;
01857 return false;
01858 }
01859
01860 bool mirrored = flags & QTextEngine::RightToLeft;
01861 int glyph_pos = 0;
01862 if (freetype->symbol_map) {
01863 FT_Face face = freetype->face;
01864 for ( int i = 0; i < len; ++i ) {
01865 unsigned int uc = getChar(str, i, len);
01866 if (mirrored)
01867 uc = QUnicodeTables::mirroredChar(uc);
01868 glyphs[glyph_pos].glyph = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
01869 if ( !glyphs[glyph_pos].glyph ) {
01870 glyph_t glyph;
01871 if (FcCharSetHasChar(freetype->charset, uc)) {
01872 redo0:
01873 glyph = FT_Get_Char_Index(face, uc);
01874 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
01875 uc = 0x20;
01876 goto redo0;
01877 }
01878 } else {
01879 FT_Set_Charmap(face, freetype->symbol_map);
01880 glyph = FT_Get_Char_Index(face, uc);
01881 FT_Set_Charmap(face, freetype->unicode_map);
01882 }
01883 glyphs[glyph_pos].glyph = glyph;
01884 if (uc < QFreetypeFace::cmapCacheSize)
01885 freetype->cmapCache[uc] = glyph;
01886 }
01887 ++glyph_pos;
01888 }
01889 } else {
01890 FT_Face face = freetype->face;
01891 for (int i = 0; i < len; ++i) {
01892 unsigned int uc = getChar(str, i, len);
01893 if (mirrored)
01894 uc = QUnicodeTables::mirroredChar(uc);
01895 glyphs[glyph_pos].glyph = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
01896 if (!glyphs[glyph_pos].glyph && FcCharSetHasChar(freetype->charset, uc)) {
01897 redo:
01898 glyph_t glyph = FT_Get_Char_Index(face, uc);
01899 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
01900 uc = 0x20;
01901 goto redo;
01902 }
01903 glyphs[glyph_pos].glyph = glyph;
01904 if (uc < QFreetypeFace::cmapCacheSize)
01905 freetype->cmapCache[uc] = glyph;
01906 }
01907 ++glyph_pos;
01908 }
01909 }
01910
01911 *nglyphs = glyph_pos;
01912 recalcAdvances(*nglyphs, glyphs, flags);
01913
01914 return true;
01915 }
01916
01917 void QFontEngineFT::recalcAdvances(int len, QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
01918 {
01919 FT_Face face = 0;
01920 if (flags & QTextEngine::DesignMetrics) {
01921 for (int i = 0; i < len; i++) {
01922 Glyph *g = fnt.glyph_data.value(glyphs[i].glyph);
01923 if (!g) {
01924 if (!face)
01925 face = lockFace();
01926 g = loadGlyph(glyphs[i].glyph);
01927 }
01928
01929 glyphs[i].advance.x = QFixed::fromFixed(g ? g->linearAdvance : (face->glyph->linearHoriAdvance >> 10));
01930 glyphs[i].advance.y = 0;
01931 }
01932 } else {
01933 for (int i = 0; i < len; i++) {
01934 Glyph *g = fnt.glyph_data.value(glyphs[i].glyph);
01935 if (!g) {
01936 if (!face)
01937 face = lockFace();
01938 g = loadGlyph(glyphs[i].glyph);
01939 }
01940
01941 glyphs[i].advance.x = g ? QFixed(g->advance) : QFixed::fromFixed(face->glyph->metrics.horiAdvance);
01942 glyphs[i].advance.y = 0;
01943 }
01944 }
01945 if (face)
01946 unlockFace();
01947 }
01948
01949 glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout *glyphs, int numGlyphs)
01950 {
01951
01952 FT_Face face = 0;
01953
01954 glyph_metrics_t overall;
01955
01956 overall.y = -ascent();
01957 overall.height = ascent() + descent() + 1;
01958
01959 QFixed ymax = 0;
01960 QFixed xmax = 0;
01961 for (int i = 0; i < numGlyphs; i++) {
01962 Glyph *g = fnt.glyph_data.value(glyphs[i].glyph);
01963 if (!g) {
01964 if (!face)
01965 face = lockFace();
01966 g = loadGlyph(glyphs[i].glyph);
01967 }
01968 if (g) {
01969 QFixed x = overall.xoff + glyphs[i].offset.x + g->x;
01970 QFixed y = overall.yoff + glyphs[i].offset.y - g->y;
01971 overall.x = qMin(overall.x, x);
01972 overall.y = qMin(overall.y, y);
01973 xmax = qMax(xmax, x + g->width);
01974 ymax = qMax(ymax, y + g->height);
01975 overall.xoff += qRound(g->advance);
01976 } else {
01977 int left = FLOOR(face->glyph->metrics.horiBearingX);
01978 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
01979 int top = CEIL(face->glyph->metrics.horiBearingY);
01980 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
01981
01982 QFixed x = overall.xoff + glyphs[i].offset.x - (-TRUNC(left));
01983 QFixed y = overall.yoff + glyphs[i].offset.y - TRUNC(top);
01984 overall.x = qMin(overall.x, x);
01985 overall.y = qMin(overall.y, y);
01986 xmax = qMax(xmax, x + TRUNC(right - left));
01987 ymax = qMax(ymax, y + TRUNC(top - bottom));
01988 overall.xoff += qRound(TRUNC(ROUND(face->glyph->advance.x)));
01989 }
01990 }
01991 overall.height = qMax(overall.height, ymax - overall.y);
01992 overall.width = xmax - overall.x;
01993
01994 if (face)
01995 unlockFace();
01996
01997 return overall;
01998 }
01999
02000 glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
02001 {
02002 FT_Face face = 0;
02003 glyph_metrics_t overall;
02004 Glyph *g = fnt.glyph_data.value(glyph);
02005 if (!g) {
02006 face = lockFace();
02007 g = loadGlyph(glyph);
02008 }
02009 if (g) {
02010 overall.x = g->x;
02011 overall.y = -g->y;
02012 overall.width = g->width;
02013 overall.height = g->height;
02014 overall.xoff = g->advance;
02015 } else {
02016 int left = FLOOR(face->glyph->metrics.horiBearingX);
02017 int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
02018 int top = CEIL(face->glyph->metrics.horiBearingY);
02019 int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
02020
02021 overall.width = TRUNC(right-left);
02022 overall.height = TRUNC(top-bottom);
02023 overall.x = TRUNC(left);
02024 overall.y = -TRUNC(top);
02025 overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
02026 }
02027 if (face)
02028 unlockFace();
02029 return overall;
02030 }
02031
02032 bool QFontEngineFT::canRender(const QChar *string, int len)
02033 {
02034 FT_Face face = freetype->face;
02035 #if 0
02036 if (_cmap != -1) {
02037 lockFace();
02038 for ( int i = 0; i < len; i++ ) {
02039 unsigned int uc = getChar(string, i, len);
02040 if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
02041 allExist = false;
02042 break;
02043 }
02044 }
02045 unlockFace();
02046 } else
02047 #endif
02048 {
02049 for ( int i = 0; i < len; i++ ) {
02050 unsigned int uc = getChar(string, i, len);
02051 if (!FT_Get_Char_Index(face, uc))
02052 return false;
02053 }
02054 }
02055 return true;
02056 }
02057
02058 void QFontEngineFT::doKerning(int num_glyphs, QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
02059 {
02060 if (!FT_HAS_KERNING(freetype->face))
02061 return;
02062 FT_Face face = lockFace();
02063 uint f = (flags == QTextEngine::DesignMetrics ? FT_KERNING_UNFITTED : FT_KERNING_DEFAULT);
02064 for (int i = 0; i < num_glyphs-1; ++i) {
02065 FT_Vector kerning;
02066 FT_Get_Kerning(face, g[i].glyph, g[i+1].glyph, f, &kerning);
02067 g[i].advance.x += QFixed::fromFixed(kerning.x);
02068 g[i].advance.y += QFixed::fromFixed(kerning.y);
02069 }
02070 unlockFace();
02071 }
02072
02073
02074 void QFontEngineFT::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
02075 QPainterPath *path, QTextItem::RenderFlags)
02076 {
02077 FT_Face face = lockFace();
02078
02079 for (int gl = 0; gl < numGlyphs; gl++) {
02080 FT_UInt glyph = glyphs[gl];
02081
02082 FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING|FT_LOAD_NO_BITMAP);
02083
02084 FT_GlyphSlot g = face->glyph;
02085 if (g->format != FT_GLYPH_FORMAT_OUTLINE)
02086 continue;
02087 addGlyphToPath(g, positions[gl], path);
02088 }
02089 unlockFace();
02090 }
02091
02092 void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout *glyphs, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags flags)
02093 {
02094 if (FT_IS_SCALABLE(freetype->face)) {
02095 QFontEngine::addOutlineToPath(x, y, glyphs, numGlyphs, path, flags);
02096 } else {
02097 addBitmapFontToPath(x, y, glyphs, numGlyphs, path, flags);
02098 }
02099 }
02100
02101 QImage QFontEngineFT::alphaMapForGlyph(glyph_t g)
02102 {
02103 lockFace();
02104
02105 Glyph *glyph = loadGlyph(g, Format_A8);
02106 if (!glyph) {
02107 unlockFace();
02108 return QFontEngine::alphaMapForGlyph(g);
02109 }
02110
02111 Q_ASSERT(glyph->format == QFontEngineFT::Format_A8);
02112
02113 const int pitch = (glyph->width + 3) & ~3;
02114
02115 QImage img(glyph->width, glyph->height, QImage::Format_Indexed8);
02116 QVector<QRgb> colors(256);
02117 for (int i=0; i<256; ++i)
02118 colors[i] = qRgba(0, 0, 0, i);
02119 img.setColorTable(colors);
02120
02121 for (int y = 0; y < glyph->height; ++y)
02122 memcpy(img.scanLine(y), &glyph->data[y * pitch], glyph->width);
02123 unlockFace();
02124
02125 return img;
02126 }
02127
02128 QFixed QFontEngineFT::ascent() const
02129 {
02130 return QFixed::fromFixed(metrics.ascender);
02131 }
02132
02133 QFixed QFontEngineFT::descent() const
02134 {
02135 return QFixed::fromFixed(-metrics.descender + (1<<6));
02136 }
02137
02138 QFixed QFontEngineFT::leading() const
02139 {
02140 return QFixed::fromFixed(metrics.height - metrics.ascender + metrics.descender);
02141 }
02142
02143 QFixed QFontEngineFT::xHeight() const
02144 {
02145 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
02146 if (os2 && os2->sxHeight)
02147 return QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
02148 return QFontEngine::xHeight();
02149 }
02150
02151 QFixed QFontEngineFT::averageCharWidth() const
02152 {
02153 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
02154 if (os2 && os2->xAvgCharWidth)
02155 return QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
02156 return QFontEngine::averageCharWidth();
02157 }
02158
02159
02160 qreal QFontEngineFT::maxCharWidth() const
02161 {
02162 return metrics.max_advance >> 6;
02163 }
02164
02165 static const ushort char_table[] = {
02166 40,
02167 67,
02168 70,
02169 75,
02170 86,
02171 88,
02172 89,
02173 91,
02174 102,
02175 114,
02176 124,
02177 127,
02178 205,
02179 645,
02180 884,
02181 922,
02182 1070,
02183 12386
02184 };
02185
02186 static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
02187
02188
02189 qreal QFontEngineFT::minLeftBearing() const
02190 {
02191 if (lbearing == SHRT_MIN)
02192 (void) minRightBearing();
02193 return lbearing.toReal();
02194 }
02195
02196 qreal QFontEngineFT::minRightBearing() const
02197 {
02198 if (rbearing == SHRT_MIN) {
02199 lbearing = rbearing = 0;
02200 const QChar *ch = (const QChar *)char_table;
02201 QGlyphLayout glyphs[char_table_entries];
02202 int ng = char_table_entries;
02203 stringToCMap(ch, char_table_entries, glyphs, &ng, 0);
02204 while (--ng) {
02205 if (glyphs[ng].glyph) {
02206 glyph_metrics_t gi = ((QFontEngineFT *)this)->boundingBox(glyphs[ng].glyph);
02207 lbearing = qMin(lbearing, gi.x);
02208 rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
02209 }
02210 }
02211 }
02212 return rbearing.toReal();
02213 }
02214
02215 QFixed QFontEngineFT::lineThickness() const
02216 {
02217 return line_thickness;
02218 }
02219
02220 QFixed QFontEngineFT::underlinePosition() const
02221 {
02222 return underline_position;
02223 }
02224
02225 QFontEngine::FaceId QFontEngineFT::faceId() const
02226 {
02227 return face_id;
02228 }
02229
02230 QFontEngine::Properties QFontEngineFT::properties() const
02231 {
02232 Properties p = freetype->properties();
02233 if (p.postscriptName.isEmpty()) {
02234 p.postscriptName = fontDef.family.toUtf8();
02235 p.postscriptName = QPdf::stripSpecialCharacters(p.postscriptName);
02236 }
02237
02238 return freetype->properties();
02239 }
02240
02241
02242 void QFontEngineFT::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
02243 {
02244 FT_Face face = lockFace();
02245 FT_Set_Transform(face, 0, 0);
02246 FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING|FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE);
02247
02248 int left = face->glyph->metrics.horiBearingX;
02249 int right = face->glyph->metrics.horiBearingX + face->glyph->metrics.width;
02250 int top = face->glyph->metrics.horiBearingY;
02251 int bottom = face->glyph->metrics.horiBearingY - face->glyph->metrics.height;
02252
02253 QFixedPoint p;
02254 p.x = 0;
02255 p.y = 0;
02256
02257 if (!FT_IS_SCALABLE(freetype->face)) {
02258 metrics->width = QFixed::fromFixed(right-left);
02259 metrics->height = QFixed::fromFixed(top-bottom);
02260 metrics->x = QFixed::fromFixed(left);
02261 metrics->y = QFixed::fromFixed(-top);
02262 metrics->xoff = QFixed::fromFixed(face->glyph->advance.x);
02263
02264 ::addBitmapToPath(face->glyph, p, path);
02265 } else {
02266 metrics->width = right-left;
02267 metrics->height = top-bottom;
02268 metrics->x = left;
02269 metrics->y = -top;
02270 metrics->xoff = face->glyph->advance.x;
02271
02272 ::addGlyphToPath(face->glyph, p, path, true );
02273 }
02274
02275 FT_Set_Transform(face, &freetype->matrix, 0);
02276 unlockFace();
02277 }
02278
02279 QByteArray QFontEngineFT::getSfntTable(uint tag) const
02280 {
02281 return freetype->getSfntTable(tag);
02282 }
02283
02284 int QFontEngineFT::synthesized() const
02285 {
02286 int s = 0;
02287 if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
02288 s = SynthesizedItalic;
02289 if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
02290 s |= SynthesizedStretch;
02291 return s;
02292 }
02293
02294 QOpenType *QFontEngineFT::openType() const
02295 {
02296 if (_openType)
02297 return _openType;
02298
02299 FT_Face face = lockFace();
02300 if (!face || !FT_IS_SFNT(face)) {
02301 unlockFace();
02302 return 0;
02303 }
02304
02305 _openType = new QOpenType(const_cast<QFontEngineFT *>(this), face);
02306 unlockFace();
02307 return _openType;
02308 }
02309
02310 #endif // QT_NO_FONTCONFIG