9#include "private/qimage_p.h"
10#include <private/qstringiterator_p.h>
13#include <qpa/qplatformscreen.h>
14#include <QtCore/QUuid>
15#include <QtCore/QLoggingCategory>
16#include <QtGui/QPainterPath>
32#include FT_SYNTHESIS_H
33#include FT_TRUETYPE_TABLES_H
34#include FT_TYPE1_TABLES_H
37#include FT_LCD_FILTER_H
38#include FT_MULTIPLE_MASTERS_H
40#if defined(FT_CONFIG_OPTIONS_H)
41#include FT_CONFIG_OPTIONS_H
44#if defined(FT_FONT_FORMATS_H)
45#include FT_FONT_FORMATS_H
52#if !defined(QT_MAX_CACHED_GLYPH_SIZE)
53# define QT_MAX_CACHED_GLYPH_SIZE 64
62#define FLOOR(x) ((x) & -64)
63#define CEIL(x) (((x)+63) & -64)
64#define TRUNC(x) ((x) >> 6)
65#define ROUND(x) (((x)+32) & -64)
72 if (FT_IS_SFNT(
face)) {
112 QHash<QFontEngine::FaceId, QFreetypeFace *>
faces;
119 iter.value()->cleanup();
120 if (!
iter.value()->ref.deref())
130 return style1.faceFileName == style2.faceFileName && style1.styleName == style2.styleName;
145 if (!freetypeData->library) {
146 FT_Init_FreeType(&freetypeData->library);
147#if defined(FT_FONT_FORMATS_H)
149 FT_Bool no_darkening =
false;
150 FT_Property_Set(freetypeData->library,
"cff",
"no-stem-darkening", &no_darkening);
160 return freetypeData->library;
166 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(
face, ft_sfnt_os2);
177 if (
face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)
180 *nPoints =
face->glyph->outline.n_points;
184 if (point > *nPoints)
195 return FT_IS_SCALABLE(
face);
225 auto it = freetypeData->faces.
find(face_id);
226 if (
it != freetypeData->faces.
end()) {
237 freetypeData->faces.erase(
it);
254 idx.
remove(0, strlen(prefix));
269 if (!newFreetype->fontData.isEmpty()) {
270 if (FT_New_Memory_Face(freetypeData->library, (
const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.
index, &
face)) {
273 }
else if (FT_New_Face(freetypeData->library, face_id.
filename, face_id.
index, &
face)) {
277#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 20900
285 newFreetype->face =
face;
286 newFreetype->mm_var =
nullptr;
287 if (FT_IS_NAMED_INSTANCE(newFreetype->face)) {
289 ftresult = FT_Get_MM_Var(
face, &newFreetype->mm_var);
290 if (ftresult != FT_Err_Ok)
291 newFreetype->mm_var =
nullptr;
294 newFreetype->ref.storeRelaxed(1);
295 newFreetype->xsize = 0;
296 newFreetype->ysize = 0;
297 newFreetype->matrix.xx = 0x10000;
298 newFreetype->matrix.yy = 0x10000;
299 newFreetype->matrix.xy = 0;
300 newFreetype->matrix.yx = 0;
301 newFreetype->unicode_map =
nullptr;
302 newFreetype->symbol_map =
nullptr;
304 memset(newFreetype->cmapCache, 0,
sizeof(newFreetype->cmapCache));
306 for (
int i = 0;
i < newFreetype->face->num_charmaps; ++
i) {
307 FT_CharMap cm = newFreetype->face->charmaps[
i];
308 switch(cm->encoding) {
309 case FT_ENCODING_UNICODE:
310 newFreetype->unicode_map = cm;
312 case FT_ENCODING_APPLE_ROMAN:
313 case FT_ENCODING_ADOBE_LATIN_1:
314 if (!newFreetype->unicode_map || newFreetype->unicode_map->encoding != FT_ENCODING_UNICODE)
315 newFreetype->unicode_map = cm;
317 case FT_ENCODING_ADOBE_CUSTOM:
318 case FT_ENCODING_MS_SYMBOL:
319 if (!newFreetype->symbol_map)
320 newFreetype->symbol_map = cm;
327 if (!FT_IS_SCALABLE(newFreetype->face) && newFreetype->face->num_fixed_sizes == 1)
328 FT_Set_Char_Size(
face, newFreetype->face->available_sizes[0].x_ppem, newFreetype->face->available_sizes[0].y_ppem, 0, 0);
330 FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
333 FT_MM_Var *
var =
nullptr;
334 FT_Get_MM_Var(newFreetype->face, &
var);
335 if (
var !=
nullptr) {
336 QVarLengthArray<FT_Fixed, 16>
coords(
var->num_axis);
338 for (FT_UInt
i = 0;
i <
var->num_axis; ++
i) {
339 if (
const auto tag = QFont::Tag::fromValue(
var->axis[
i].tag)) {
351 freetypeData->faces.insert(face_id, newFreetype.get());
353 newFreetype.release()->release(face_id);
357 freetype = newFreetype.
release();
363void QFreetypeFace::cleanup()
376 bool deleteThis = !
ref.deref();
382 if (
face &&
ref.loadRelaxed() == 1) {
385 if (
it.value()->ref.loadRelaxed() == 1) {
386 it.value()->cleanup();
387 if (
it.value() ==
this)
397 if (freetypeData->faces.isEmpty()) {
398 FT_Done_FreeType(freetypeData->library);
399 freetypeData->library =
nullptr;
418 if (
error != FT_Err_Ok) {
424 numFaces =
face->num_faces;
442 int faceIndex = freetypeData->faceIndices.value(faceStyle, -1);
449 freetypeData->faceIndices.insert(faceStyle,
faceIndex);
458 *scalableBitmapScaleFactor = 1;
459 *outline_drawing =
false;
461 if (!(
face->face_flags & FT_FACE_FLAG_SCALABLE)) {
468 for (
int i = 1;
i <
face->num_fixed_sizes;
i++) {
480 for (
int i = 1;
i <
face->num_fixed_sizes;
i++) {
481 if (
face->available_sizes[
i].y_ppem < *
ysize) {
482 if (
face->available_sizes[
i].y_ppem >
face->available_sizes[best].y_ppem)
484 }
else if (
face->available_sizes[best].y_ppem < *
ysize) {
486 }
else if (
face->available_sizes[
i].y_ppem <
face->available_sizes[best].y_ppem) {
494 if (FT_Select_Size(
face, best) == 0) {
497 *
xsize =
face->available_sizes[best].x_ppem;
498 *
ysize =
face->available_sizes[best].y_ppem;
511 PS_FontInfoRec font_info;
512 if (FT_Get_PS_Font_Info(
face, &font_info) == 0)
513 p.copyright = font_info.notice;
514 if (FT_IS_SCALABLE(
face)) {
515 p.ascent =
face->ascender;
516 p.descent = -
face->descender;
518 p.emSquare =
face->units_per_EM;
526 p.emSquare =
face->size->metrics.y_ppem;
528 p.boundingBox =
QRectF(0, -
p.ascent.toReal(),
529 face->size->metrics.max_advance/64, (
p.ascent +
p.descent).toReal() );
532 p.capHeight =
p.ascent;
533 p.lineWidth =
face->underline_thickness;
554 x_scale = FT_MulDiv(x_scale, 1 << 10,
face->units_per_EM);
555 y_scale = FT_MulDiv(y_scale, 1 << 10,
face->units_per_EM);
556 FT_Vector *
p =
g->outline.points;
557 const FT_Vector *e =
p +
g->outline.n_points;
559 p->x = FT_MulFix(
p->x, x_scale);
560 p->y = FT_MulFix(
p->y, y_scale);
565#define GLYPH2PATH_DEBUG QT_NO_QDEBUG_MACRO
568 const qreal factor = 1/64.;
575 for (
int j = 0;
j <
g->outline.n_contours; ++
j) {
576 int last_point =
g->outline.contours[
j];
579 if (!(
g->outline.tags[
i] & 1)) {
580 if (!(
g->outline.tags[last_point] & 1)) {
583 -
g->outline.points[last_point].y*factor) +
start) / 2.0;
587 -
g->outline.points[last_point].y*factor);
598 while (
i < last_point) {
600 c[
n] = cp +
QPointF(
g->outline.points[
i].x*factor, -
g->outline.points[
i].y*factor);
602 <<
": on curve =" << (
bool)(
g->outline.tags[
i] & 1);
604 switch (
g->outline.tags[
i] & 3) {
609 c[3] = (
c[3] +
c[2])/2;
616 c[3] = (
c[1] +
c[2])/2;
617 c[2] = (2*
c[1] +
c[3])/3;
618 c[1] = (2*
c[1] +
c[0])/3;
631 c[2] = (2*
c[1] +
c[3])/3;
632 c[1] = (2*
c[1] +
c[0])/3;
637 path->cubicTo(
c[1],
c[2],
c[3]);
644 path->closeSubpath();
648 c[2] = (2*
c[1] +
c[3])/3;
649 c[1] = (2*
c[1] +
c[0])/3;
652 path->cubicTo(
c[1],
c[2],
c[3]);
662 if (slot->format != FT_GLYPH_FORMAT_BITMAP
663 || slot->bitmap.pixel_mode != FT_PIXEL_MODE_MONO)
668 slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows,
path);
673 const int offs = bgr ? -1 : 1;
677 for (
int x = 0;
x <
w;
x += 3) {
681 *dd++ = (0xFFU << 24) | (
red << 16) | (
green << 8) |
blue;
690 const int offs = bgr ? -src_pitch : src_pitch;
704 static int type = -1;
731 qWarning(
"QFontEngineFT: Failed to create FreeType font engine");
747 void updateFamilyNameAndStyle()
751 if (freetype->face->style_flags & FT_STYLE_FLAG_ITALIC)
754 if (freetype->face->style_flags & FT_STYLE_FLAG_BOLD)
758 bool initFromData(
const QByteArray &
fontData,
const QMap<QFont::Tag, float> &variableAxisValues)
761 faceId.filename =
"";
764 faceId.variableAxes = variableAxisValues;
774 const QMap<QFont::Tag, float> &variableAxisValues)
782 QFontEngineFTRawData *fe =
new QFontEngineFTRawData(
fontDef);
783 if (!fe->initFromData(
fontData, variableAxisValues)) {
788 fe->updateFamilyNameAndStyle();
803 kerning_pairs_loaded =
false;
838 FT_MM_Var *
var = freetypeFace->mm_var;
840 for (FT_UInt axis = 0; axis <
var->num_axis; ++axis) {
846 if (
const TT_OS2 *os2 =
reinterpret_cast<const TT_OS2 *
>(FT_Get_Sfnt_Table(
face, ft_sfnt_os2))) {
847 return os2->usWeightClass;
855 FT_MM_Var *
var = freetypeFace->mm_var;
857 for (FT_UInt axis = 0; axis <
var->num_axis; ++axis) {
864 return (
face->style_flags & FT_STYLE_FLAG_ITALIC);
887 PS_FontInfoRec psrec;
889 if (FT_Get_PS_Font_Info(
freetype->
face, &psrec) == FT_Err_Ok) {
897 if (FT_IS_SCALABLE(
face)) {
907 if (actualWeight < 700 &&
915 underline_position = center_position - line_thickness / 2;
919 line_thickness = score / 7000;
921 if (line_thickness < 2 && score >= 1050)
923 underline_position = ((line_thickness * 2) + 3) / 6;
929 if (line_thickness < 1)
941 if (FT_IS_SCALABLE(
face)) {
942 for (
int i = 0;
i <
face->num_fixed_sizes; ++
i) {
943 if (xsize ==
face->available_sizes[
i].x_ppem && ysize ==
face->available_sizes[
i].y_ppem) {
944 face->face_flags &= ~FT_FACE_FLAG_SCALABLE;
946 FT_Select_Size(
face,
i);
947 if (
face->size->metrics.ascender +
face->size->metrics.descender > 0) {
957 FT_Set_Char_Size(
face, xsize, ysize, 0, 0);
959 face->face_flags |= FT_FACE_FLAG_SCALABLE;
964#if defined(FT_FONT_FORMATS_H)
965 const char *
fmt = FT_Get_Font_Format(
face);
967 FT_Bool no_stem_darkening =
true;
968 FT_Error err = FT_Property_Get(
qt_getFreetype(),
"cff",
"no-stem-darkening", &no_stem_darkening);
969 if (err == FT_Err_Ok)
997 switch (hintingPreference) {
1023int QFontEngineFT::loadFlags(QGlyphSet *
set, GlyphFormat
format,
int flags,
1024 bool &hsubpixel,
int &vfactor)
const
1028 ? FT_LOAD_TARGET_LIGHT
1029 : FT_LOAD_TARGET_NORMAL;
1032 load_target = FT_LOAD_TARGET_MONO;
1040 load_flags |= FT_LOAD_COLOR;
1044 if (
set &&
set->outline_drawing)
1045 load_flags |= FT_LOAD_NO_BITMAP;
1048 load_flags |= FT_LOAD_NO_HINTING;
1050 load_flags |= load_target;
1053 load_flags |= FT_LOAD_FORCE_AUTOHINT;
1061 return info.width > 0xFF ||
info.height > 0xFF ||
info.linearAdvance > 0x7FFF;
1103 bool fetchMetricsOnly,
1104 bool disableOutlineDrawing)
const
1112 Glyph *
g =
set ?
set->getGlyph(glyph, subPixelPosition) :
nullptr;
1113 if (
g &&
g->format ==
format && (fetchMetricsOnly ||
g->data))
1116 if (!
g &&
set &&
set->isGlyphMissing(glyph))
1129 bool hsubpixel =
false;
1131 int load_flags = loadFlags(
set,
format, 0, hsubpixel, vfactor);
1139 load_flags |= FT_LOAD_NO_BITMAP;
1141 FT_Error err = FT_Load_Glyph(
face, glyph, load_flags);
1142 if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
1143 load_flags &= ~FT_LOAD_NO_BITMAP;
1144 err = FT_Load_Glyph(
face, glyph, load_flags);
1146 if (err == FT_Err_Too_Few_Arguments) {
1148 load_flags |= FT_LOAD_FORCE_AUTOHINT;
1149 err = FT_Load_Glyph(
face, glyph, load_flags);
1150 }
else if (err == FT_Err_Execution_Too_Long) {
1153 qWarning(
"load glyph failed due to broken hinting bytecode in font, switching to auto hinting");
1155 load_flags |= FT_LOAD_FORCE_AUTOHINT;
1156 err = FT_Load_Glyph(
face, glyph, load_flags);
1158 if (err != FT_Err_Ok) {
1159 qWarning(
"load glyph failed err=%x face=%p, glyph=%d", err,
face, glyph);
1161 set->setGlyphMissing(glyph);
1165 FT_GlyphSlot slot =
face->glyph;
1168 FT_GlyphSlot_Embolden(slot);
1170 FT_GlyphSlot_Oblique(slot);
1181 FT_Matrix_Multiply(&
m, &
matrix);
1185 info.linearAdvance = slot->linearHoriAdvance >> 10;
1189 if ((
set &&
set->outline_drawing && !disableOutlineDrawing) || fetchMetricsOnly) {
1190 int left = slot->metrics.horiBearingX;
1191 int right = slot->metrics.horiBearingX + slot->metrics.width;
1192 int top = slot->metrics.horiBearingY;
1193 int bottom = slot->metrics.horiBearingY - slot->metrics.height;
1195 if (
transform && slot->format != FT_GLYPH_FORMAT_BITMAP)
1215 g->linearAdvance =
info.linearAdvance;
1216 g->width =
info.width;
1217 g->height =
info.height;
1220 g->advance =
info.xOff;
1224 set->setGlyph(glyph, subPixelPosition,
g);
1229 int glyph_buffer_size = 0;
1230 std::unique_ptr<uchar[]> glyph_buffer;
1234 renderMode = FT_RENDER_MODE_MONO;
1237 if (!hsubpixel && vfactor == 1) {
1238 qWarning(
"Format_A32 requested, but subpixel layout is unknown.");
1242 renderMode = hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V;
1250 FT_Library_SetLcdFilter(slot->library, (FT_LcdFilter)
lcdFilterType);
1252 err = FT_Render_Glyph(slot, renderMode);
1253 if (err != FT_Err_Ok)
1254 qWarning(
"render glyph failed err=%x face=%p, glyph=%d", err,
face, glyph);
1256 FT_Library_SetLcdFilter(slot->library, FT_LCD_FILTER_NONE);
1258 info.height = slot->bitmap.rows;
1259 info.width = slot->bitmap.width;
1260 info.x = slot->bitmap_left;
1261 info.y = slot->bitmap_top;
1262 if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD)
1264 if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V)
1265 info.height =
info.height / vfactor;
1270 glyph_buffer_size =
info.height * pitch;
1271 glyph_buffer.reset(
new uchar[glyph_buffer_size]);
1273 if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
1276 int h = slot->bitmap.rows;
1279 int bytes = ((
info.width + 7) & ~7) >> 3;
1281 memcpy (
dst,
src, bytes);
1283 src += slot->bitmap.pitch;
1287 for (
int x = 0;
x <
int{
info.width};
x++)
1288 dst[
x] = ((
src[
x >> 3] & (0x80 >> (
x & 7))) ? 0xff : 0x00);
1290 src += slot->bitmap.pitch;
1295 for (
int x = 0;
x <
int{
info.width};
x++)
1296 dd[
x] = ((
src[
x >> 3] & (0x80 >> (
x & 7))) ? 0xffffffff : 0x00000000);
1298 src += slot->bitmap.pitch;
1301 }
else if (slot->bitmap.pixel_mode == 7 ) {
1305 int h = slot->bitmap.rows;
1307#if Q_BYTE_ORDER == Q_BIG_ENDIAN
1310 for (
int x = 0; x < static_cast<int>(slot->bitmap.width);
x++, srcPixel++, dstPixel++) {
1311 const quint32 pixel = *srcPixel;
1312 *dstPixel =
qbswap(pixel);
1315 memcpy(
dst,
src, slot->bitmap.width * 4);
1317 dst += slot->bitmap.pitch;
1318 src += slot->bitmap.pitch;
1320 info.linearAdvance =
info.xOff = slot->bitmap.width;
1321 }
else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
1325 int h = slot->bitmap.rows;
1326 int bytes =
info.width;
1328 memcpy (
dst,
src, bytes);
1330 src += slot->bitmap.pitch;
1332 }
else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) {
1335 }
else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) {
1339 qWarning(
"QFontEngine: Glyph rendered in unknown pixel_mode=%d", slot->bitmap.pixel_mode);
1348 g->linearAdvance =
info.linearAdvance;
1349 g->width =
info.width;
1350 g->height =
info.height;
1353 g->advance =
info.xOff;
1356 g->data = glyph_buffer.release();
1359 set->setGlyph(glyph, subPixelPosition,
g);
1372 if (
p.postscriptName.isEmpty()) {
1412 if (scalableBitmapScaleFactor != 1) {
1413 m_ascent *= scalableBitmapScaleFactor;
1421 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(
freetype->
face, ft_sfnt_os2);
1422 if (os2 && os2->version >= 2) {
1433 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(
freetype->
face, ft_sfnt_os2);
1434 if (os2 && os2->sxHeight) {
1446 TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(
freetype->
face, ft_sfnt_os2);
1447 if (os2 && os2->xAvgCharWidth) {
1460 if (scalableBitmapScaleFactor != 1)
1461 max_advance *= scalableBitmapScaleFactor;
1462 return max_advance.
toReal();
1467 return line_thickness;
1472 return underline_position;
1477 if (!kerning_pairs_loaded) {
1478 kerning_pairs_loaded =
true;
1489 if (shouldUseDesignMetrics(
flags))
1492 flags &= ~DesignMetrics;
1501 m.xx = FT_Fixed(
matrix.m11() * 65536);
1502 m.xy = FT_Fixed(-
matrix.m21() * 65536);
1503 m.yx = FT_Fixed(-
matrix.m12() * 65536);
1504 m.yy = FT_Fixed(
matrix.m22() * 65536);
1514 for (;
i < nSets; ++
i) {
1515 QGlyphSet *
g = sets[
i];
1518 if (
g->transformationMatrix.xx ==
m.xx
1519 &&
g->transformationMatrix.xy ==
m.xy
1520 &&
g->transformationMatrix.yx ==
m.yx
1521 &&
g->transformationMatrix.yy ==
m.yy) {
1533 moveToFront(nSets - 1);
1535 sets[0] =
new QGlyphSet;
1536 QGlyphSet *gs = sets[0];
1538 gs->transformationMatrix =
m;
1545void QFontEngineFT::TransformedGlyphSets::moveToFront(
int i)
1547 QGlyphSet *
g = sets[
i];
1549 sets[
i] = sets[
i - 1];
1571 FT_Set_Transform(
face,
nullptr,
nullptr);
1572 FT_Load_Glyph(
face, glyph, FT_LOAD_NO_BITMAP);
1574 int left =
face->glyph->metrics.horiBearingX;
1575 int right =
face->glyph->metrics.horiBearingX +
face->glyph->metrics.width;
1576 int top =
face->glyph->metrics.horiBearingY;
1577 int bottom =
face->glyph->metrics.horiBearingY -
face->glyph->metrics.height;
1612 QVarLengthArray<glyph_t> positioned_glyphs;
1618 for (
int gl = 0; gl < glyphs.
numGlyphs; gl++) {
1619 FT_UInt glyph = positioned_glyphs[gl];
1620 FT_Load_Glyph(
face, glyph, FT_LOAD_TARGET_MONO);
1632 for (
int gl = 0; gl <
numGlyphs; gl++) {
1633 FT_UInt glyph = glyphs[gl];
1635 FT_Load_Glyph(
face, glyph, FT_LOAD_NO_BITMAP);
1637 FT_GlyphSlot
g =
face->glyph;
1638 if (
g->format != FT_GLYPH_FORMAT_OUTLINE)
1641 FT_GlyphSlot_Embolden(
g);
1643 FT_GlyphSlot_Oblique(
g);
1654 glyph = FT_Get_Char_Index(
face, ucs4);
1658 if (ucs4 == QChar::Nbsp || ucs4 == QChar::Tabulation) {
1659 glyph = FT_Get_Char_Index(
face, QChar::Space);
1668 glyph = FT_Get_Char_Index(
face, ucs4);
1670 if (!glyph &&
symbol && ucs4 < 0x100)
1671 glyph = FT_Get_Char_Index(
face, ucs4 + 0xf000);
1682 QFontEngine::ShaperFlags
flags)
const
1685 if (*nglyphs <
len) {
1690 int mappedGlyphs = 0;
1695 while (
it.hasNext()) {
1698 if ( !glyphs->
glyphs[glyph_pos] ) {
1708 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1710 glyph = FT_Get_Char_Index(
face, uc);
1714 glyph = FT_Get_Char_Index(
face, uc);
1716 if (!glyph &&
symbol && uc < 0x100)
1717 glyph = FT_Get_Char_Index(
face, uc + 0xf000);
1719 glyphs->
glyphs[glyph_pos] = glyph;
1730 while (
it.hasNext()) {
1733 if (!glyphs->
glyphs[glyph_pos]) {
1737 if (!glyph && (uc == 0xa0 || uc == 0x9)) {
1741 glyphs->
glyphs[glyph_pos] = glyph;
1752 *nglyphs = glyph_pos;
1758 return mappedGlyphs;
1761bool QFontEngineFT::shouldUseDesignMetrics(QFontEngine::ShaperFlags
flags)
const
1771 return m * scalableBitmapScaleFactor;
1778 t.m21(),
t.m22(),
t.m23(),
1780 const qreal scaleFactor = scalableBitmapScaleFactor.
toReal();
1781 trans.
scale(scaleFactor, scaleFactor);
1783 QRectF rect(
m.x.toReal(),
m.y.toReal(),
m.width.toReal(),
m.height.toReal());
1801 FT_Face
face =
nullptr;
1802 bool design = shouldUseDesignMetrics(
flags);
1807 if (
g &&
g->format == acceptableFormat) {
1826 if (scalableBitmapScaleFactor != 1)
1827 glyphs->
advances[
i] *= scalableBitmapScaleFactor;
1835 FT_Face
face =
nullptr;
1866 overall.x =
qMin(overall.x,
x);
1867 overall.y =
qMin(overall.y,
y);
1874 int right =
CEIL(
face->glyph->metrics.horiBearingX +
face->glyph->metrics.width);
1875 int top =
CEIL(
face->glyph->metrics.horiBearingY);
1880 overall.x =
qMin(overall.x,
x);
1881 overall.y =
qMin(overall.y,
y);
1887 overall.height =
qMax(overall.height, ymax - overall.y);
1888 overall.width = xmax - overall.x;
1894 overall = scaledBitmapMetrics(overall,
QTransform());
1900 FT_Face
face =
nullptr;
1914 overall.width =
g->width;
1915 overall.height =
g->height;
1916 overall.xoff =
g->advance;
1921 int right =
CEIL(
face->glyph->metrics.horiBearingX +
face->glyph->metrics.width);
1922 int top =
CEIL(
face->glyph->metrics.horiBearingY);
1935 overall = scaledBitmapMetrics(overall,
QTransform());
1953 const bool needsImageTransform = !FT_IS_SCALABLE(
freetype->
face)
1963 overall.width =
g->width;
1964 overall.height =
g->height;
1965 overall.xoff =
g->advance;
1971 int right =
CEIL(
face->glyph->metrics.horiBearingX +
face->glyph->metrics.width);
1972 int top =
CEIL(
face->glyph->metrics.horiBearingY);
1984 overall = scaledBitmapMetrics(overall,
matrix);
1990 if (glyph ==
nullptr || glyph->
height == 0 || glyph->
width == 0)
1994 int bytesPerLine = -1;
1998 bytesPerLine = ((glyph->
width + 31) & ~31) >> 3;
2002 bytesPerLine = (glyph->
width + 3) & ~3;
2006 bytesPerLine = glyph->
width * 4;
2028 neededFormat = defaultFormat;
2049 bool fetchBoundingBox,
2050 bool disableOutlineDrawing)
2053 if (glyphSet !=
nullptr && glyphSet->outline_drawing && !disableOutlineDrawing && !fetchBoundingBox)
2056 Glyph *glyph = glyphSet !=
nullptr ? glyphSet->getGlyph(
g, subPixelPosition) :
nullptr;
2057 if (!glyph || glyph->
format !=
format || (!fetchBoundingBox && !glyph->
data)) {
2063 FT_Matrix
m = this->matrix;
2064 FT_Matrix ftMatrix = glyphSet !=
nullptr ? glyphSet->transformationMatrix :
QTransformToFTMatrix(
t);
2065 FT_Matrix_Multiply(&ftMatrix, &
m);
2067 glyph =
loadGlyph(glyphSet,
g, subPixelPosition,
format,
false, disableOutlineDrawing);
2083 const bool needsImageTransform = !FT_IS_SCALABLE(
freetype->
face)
2090 if (needsImageTransform)
2132 if (glyph ==
nullptr)
2141 if (!
img.isNull() && (!
t.isIdentity() || scalableBitmapScaleFactor != 1)) {
2143 const qreal scaleFactor = scalableBitmapScaleFactor.
toReal();
2144 trans.
scale(scaleFactor, scaleFactor);
2175 if (FT_Set_Char_Size(
face,
face->units_per_EM << 6,
face->units_per_EM << 6, 0, 0) == 0) {
2180 FT_Set_Char_Size(
face, xsize, ysize, 0, 0);
2207 : outline_drawing(
false)
2213 memset(fast_glyph_data, 0,
sizeof(fast_glyph_data));
2214 fast_glyph_count = 0;
2224 if (fast_glyph_count > 0) {
2225 for (
int i = 0;
i < 256; ++
i) {
2226 if (fast_glyph_data[
i]) {
2227 delete fast_glyph_data[
i];
2228 fast_glyph_data[
i] =
nullptr;
2231 fast_glyph_count = 0;
2240 if (useFastGlyphData(
index, subPixelPosition)) {
2241 if (fast_glyph_data[
index]) {
2242 delete fast_glyph_data[
index];
2243 fast_glyph_data[
index] =
nullptr;
2244 if (fast_glyph_count > 0)
2256 if (useFastGlyphData(
index, subPixelPosition)) {
2257 if (!fast_glyph_data[
index])
2259 fast_glyph_data[
index] = glyph;
2268 bool hsubpixel =
true;
2270 int load_flags = loadFlags(
nullptr,
Format_A8,
flags, hsubpixel, vfactor);
2278 if (!
init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
2303 if (!fe->initFromFontEngine(
this)) {
T loadRelaxed() const noexcept
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
int toInt(bool *ok=nullptr, int base=10) const
Returns the byte array converted to an int using base base, which is ten by default.
bool startsWith(QByteArrayView bv) const
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
QByteArray & remove(qsizetype index, qsizetype len)
Removes len bytes from the array, starting at index position pos, and returns a reference to the arra...
The QColor class provides colors based on RGB, HSV or CMYK values.
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
static QString decodeName(const QByteArray &localFileName)
This does the reverse of QFile::encodeName() using localFileName.
bool expectsGammaCorrectedBlending() const override
glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override
int stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override
void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) override
void setDefaultHintStyle(HintStyle style) override
HintStyle default_hint_style
glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format) override
int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints) override
void initializeHeightMetrics() const override
QGlyphSet * loadGlyphSet(const QTransform &matrix)
QFixed underlinePosition() const override
QFixed lineThickness() const override
QFixed emSquareSize() const override
bool initFromFontEngine(const QFontEngineFT *fontEngine)
QFontEngine * cloneWithSize(qreal pixelSize) const override
void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) override
QImage alphaMapForGlyph(glyph_t g) override
QFontEngineFT(const QFontDef &fd)
bool isScalableBitmap() const
QFixed xHeight() const override
FT_Face non_locked_face() const
bool init(FaceId faceId, bool antiaalias, GlyphFormat defaultFormat=Format_None, const QByteArray &fontData=QByteArray())
void removeGlyphFromCache(glyph_t glyph) override
qreal maxCharWidth() const override
void doKerning(QGlyphLayout *, ShaperFlags) const override
void setQtDefaultHintStyle(QFont::HintingPreference hintingPreference)
Qt::HANDLE handle() const override
QFontEngine::Properties properties() const override
QFontEngine::FaceId faceId() const override
Glyph * loadGlyphFor(glyph_t g, const QFixedPoint &subPixelPosition, GlyphFormat format, const QTransform &t, bool fetchBoundingBox=false, bool disableOutlineDrawing=false)
Glyph * loadGlyph(uint glyph, const QFixedPoint &subPixelPosition, GlyphFormat format=Format_None, bool fetchMetricsOnly=false, bool disableOutlineDrawing=false) const
int glyphCount() const override
static QFontEngineFT * create(const QFontDef &fontDef, FaceId faceId, const QByteArray &fontData=QByteArray())
bool isBitmapFont() const
Glyph * glyphData(glyph_t glyph, const QFixedPoint &subPixelPosition, GlyphFormat neededFormat, const QTransform &t) override
glyph_t glyphIndex(uint ucs4) const override
void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags) override
int synthesized() const override
QFixed capHeight() const override
QImage alphaRGBMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t) override
QImage bitmapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t, const QColor &color) override
SubpixelAntialiasingType subpixelType
QFixed averageCharWidth() const override
bool getSfntTableData(uint tag, uchar *buffer, uint *length) const override
Returns true if the font table idetified by tag exists in the font; returns false otherwise.
bool supportsTransformation(const QTransform &transform) const override
FT_Face lockFace(Scaling scale=Scaled) const
void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags flags) const override
void * get() const noexcept
virtual QFixed descent() const
void loadKerningPairs(QFixed scalingFactor)
QFixed calculatedCapHeight() const
static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily)
int m_subPixelPositionCount
static bool isIgnorableChar(char32_t ucs4)
virtual QFixed ascent() const
struct QFontEngine::FaceData faceData
virtual QImage alphaRGBMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t)
virtual QFixed averageCharWidth() const
virtual void initializeHeightMetrics() const
virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags)
virtual void doKerning(QGlyphLayout *, ShaperFlags) const
void getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags, QVarLengthArray< glyph_t > &glyphs_out, QVarLengthArray< QFixedPoint > &positions)
virtual QFixed leading() const
void * harfbuzzFace() const
virtual QFixed xHeight() const
int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints)
static int getFaceIndexByStyleName(const QString &faceFileName, const QString &styleName)
static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path)
static void addGlyphToPath(FT_Face face, FT_GlyphSlot g, const QFixedPoint &point, QPainterPath *path, FT_Fixed x_scale, FT_Fixed y_scale)
bool isScalableBitmap() const
glyph_t cmapCache[cmapCacheSize]
static QFreetypeFace * getFace(const QFontEngine::FaceId &face_id, const QByteArray &fontData=QByteArray())
void release(const QFontEngine::FaceId &face_id)
QFontEngine::Properties properties() const
void computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing, QFixed *scalableBitmapScaleFactor)
bool getSfntTable(uint tag, uchar *buffer, uint *length) const
QScreen * primaryScreen
the primary (or default) screen of the application.
const_iterator cbegin() const noexcept
const_iterator cend() const noexcept
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
QImage copy(const QRect &rect=QRect()) const
Returns a sub-area of the image as a new image.
Format
The following image formats are available in Qt.
@ Format_ARGB32_Premultiplied
const_iterator constFind(const Key &key) const
const_iterator constEnd() const
\inmodule QtCore\reentrant
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
\inmodule QtCore\reentrant
The QScreen class is used to query screen properties. \inmodule QtGui.
QPlatformScreen * handle() const
Get the platform screen handle.
const_iterator constBegin() const noexcept
const_iterator constEnd() const noexcept
iterator erase(const_iterator i)
iterator find(const T &value)
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QByteArray toUtf8() const &
static QUuid createUuid()
On any platform other than Windows, this function returns a new UUID with variant QUuid::DCE and vers...
void * data()
Returns a pointer to the contained object as a generic void* that can be written to.
QHash< QFontEngine::FaceId, QFreetypeFace * > faces
QHash< FaceStyle, int > faceIndices
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
Combined button and popup list for selecting options.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
int qstrncmp(const char *str1, const char *str2, size_t len)
QList< QString > QStringList
Constructs a string list that contains the given string, str.
AudioChannelLayoutTag tag
static const QCssKnownValue positions[NumKnownPositionModes - 1]
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter * iter
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void * user_data
DBusConnection const char DBusError * error
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
constexpr T qbswap(T source)
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
int qRound(qfloat16 d) noexcept
static QFontEngineFT::Glyph emptyGlyph
void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path)
static QFontEngine::SubpixelAntialiasingType subpixelAntialiasingTypeHint()
static FT_Matrix QTransformToFTMatrix(const QTransform &matrix)
static void transformBoundingBox(int *left, int *top, int *right, int *bottom, FT_Matrix *matrix)
static void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr)
QtFreetypeData * qt_getFreetypeData()
static bool calculateActualItalic(QFreetypeFace *freetypeFace, FT_Face face, QFontEngine::FaceId faceId)
static bool is2dRotation(const QTransform &t)
static QImage alphaMapFromGlyphData(QFontEngineFT::Glyph *glyph, QFontEngine::GlyphFormat glyphFormat)
size_t qHash(const QtFreetypeData::FaceStyle &style, size_t seed)
static bool ft_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length)
static const QFontEngine::HintStyle ftInitialDefaultHintStyle
static int computeFaceIndex(const QString &faceFileName, const QString &styleName)
bool operator==(const QtFreetypeData::FaceStyle &style1, const QtFreetypeData::FaceStyle &style2)
FT_Library qt_getFreetype()
static FT_UShort calculateActualWeight(QFreetypeFace *freetypeFace, FT_Face face, QFontEngine::FaceId faceId)
QByteArray qt_fontdata_from_index(int)
static void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr)
static void scaleOutline(FT_Face face, FT_GlyphSlot g, FT_Fixed x_scale, FT_Fixed y_scale)
static void dont_delete(void *)
static bool areMetricsTooLarge(const QFontEngineFT::GlyphInfo &info)
Q_GUI_EXPORT FT_Library qt_getFreetype()
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
constexpr QtPrivate::QHashMultiReturnType< T... > qHashMulti(size_t seed, const T &... args) noexcept(std::conjunction_v< QtPrivate::QNothrowHashable< T >... >)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
constexpr T qAbs(const T &t)
GLboolean GLboolean GLboolean b
GLenum GLsizeiptr const void GLsizei faceIndex
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLenum GLuint GLenum GLsizei length
GLsizei const GLubyte GLsizei GLenum const void * coords
GLdouble GLdouble GLdouble GLdouble top
GLenum GLenum GLsizei count
GLenum const void GLbitfield GLsizei numGlyphs
GLsizei GLenum const void GLuint GLsizei GLfloat * metrics
GLenum GLuint GLintptr offset
GLint GLsizei GLsizei GLenum format
GLenum GLsizeiptr const void * fontData
GLuint GLfloat GLfloat y0
GLfloat GLfloat GLfloat GLfloat h
GLuint GLenum GLenum transform
GLsizei const GLchar *const * path
GLenum GLenum GLenum GLenum GLenum scale
#define QT_MAX_CACHED_GLYPH_SIZE
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
QVideoFrameFormat::PixelFormat fmt
QFuture< QSet< QChar > > set
[10]
constexpr QPointF toPointF() const
static constexpr QFixed fromReal(qreal r)
static constexpr QFixed fromFixed(int fixed)
constexpr int value() const
constexpr QFixed ceil() const
constexpr qreal toReal() const
QMap< QFont::Tag, float > variableAxisValues
void setGlyph(glyph_t index, const QFixedPoint &spp, Glyph *glyph)
FT_Matrix transformationMatrix
void removeGlyphFromCache(glyph_t index, const QFixedPoint &subPixelPosition)
Glyph * getGlyph(glyph_t index, const QFixedPoint &subPixelPositionX=QFixedPoint()) const
QMap< QFont::Tag, float > variableAxes
QByteArray postscriptName
The QFont::Tag type provides access to advanced font features.
constexpr quint32 value() const noexcept
Returns the numerical value of this tag.
QFixed effectiveAdvance(int item) const
QGlyphAttributes * attributes
FaceStyle(QString faceFileName, QString styleName)