summaryrefslogtreecommitdiffstats
path: root/src/platformsupport/fontdatabases
diff options
context:
space:
mode:
Diffstat (limited to 'src/platformsupport/fontdatabases')
-rw-r--r--src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp2
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp330
-rw-r--r--src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h2
-rw-r--r--src/platformsupport/fontdatabases/mac/coretext.pri6
-rw-r--r--src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm79
-rw-r--r--src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm375
-rw-r--r--src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h27
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp50
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp45
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h13
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp139
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h12
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp2
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h2
-rw-r--r--src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h2
-rw-r--r--src/platformsupport/fontdatabases/windows/windows.pri9
-rw-r--r--src/platformsupport/fontdatabases/winrt/winrt.pri4
17 files changed, 450 insertions, 649 deletions
diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
index aa8f9a892a..e545d54ec2 100644
--- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
+++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
@@ -908,7 +908,7 @@ QFont QFontconfigDatabase::defaultFont() const
void QFontconfigDatabase::setupFontEngine(QFontEngineFT *engine, const QFontDef &fontDef) const
{
bool antialias = !(fontDef.styleStrategy & QFont::NoAntialias);
- bool forcedAntialiasSetting = !antialias;
+ bool forcedAntialiasSetting = !antialias || QHighDpiScaling::isActive();
const QPlatformServices *services = QGuiApplicationPrivate::platformIntegration()->services();
bool useXftConf = false;
diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
index 7b4f6aa107..40db7dbac7 100644
--- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
+++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp
@@ -121,13 +121,12 @@ class QtFreetypeData
{
public:
QtFreetypeData()
- : library(0), hasPatentFreeLcdRendering(false)
+ : library(0)
{ }
~QtFreetypeData();
FT_Library library;
QHash<QFontEngine::FaceId, QFreetypeFace *> faces;
- bool hasPatentFreeLcdRendering;
};
QtFreetypeData::~QtFreetypeData()
@@ -153,11 +152,6 @@ QtFreetypeData *qt_getFreetypeData()
FT_Bool no_darkening = false;
FT_Property_Set(freetypeData->library, "cff", "no-stem-darkening", &no_darkening);
#endif
- // FreeType has since 2.8.1 a patent free alternative to LCD-filtering.
- FT_Int amajor, aminor = 0, apatch = 0;
- FT_Library_Version(freetypeData->library, &amajor, &aminor, &apatch);
- if (QT_VERSION_CHECK(amajor, aminor, apatch) >= QT_VERSION_CHECK(2, 8, 1))
- freetypeData->hasPatentFreeLcdRendering = true;
}
return freetypeData;
}
@@ -561,26 +555,7 @@ QFontEngineFT::Glyph::~Glyph()
delete [] data;
}
-struct LcdFilterDummy
-{
- static inline void filterPixel(uchar &, uchar &, uchar &)
- {}
-};
-
-struct LcdFilterLegacy
-{
- static inline void filterPixel(uchar &red, uchar &green, uchar &blue)
- {
- uint r = red, g = green, b = blue;
- // intra-pixel filter used by the legacy filter (adopted from _ft_lcd_filter_legacy)
- red = (r * uint(65538 * 9/13) + g * uint(65538 * 1/6) + b * uint(65538 * 1/13)) / 65536;
- green = (r * uint(65538 * 3/13) + g * uint(65538 * 4/6) + b * uint(65538 * 3/13)) / 65536;
- blue = (r * uint(65538 * 1/13) + g * uint(65538 * 1/6) + b * uint(65538 * 9/13)) / 65536;
- }
-};
-
-template <typename LcdFilter>
-static void convertRGBToARGB_helper(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr)
+static inline void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr)
{
const int offs = bgr ? -1 : 1;
const int w = width * 3;
@@ -590,24 +565,14 @@ static void convertRGBToARGB_helper(const uchar *src, uint *dst, int width, int
uchar red = src[x + 1 - offs];
uchar green = src[x + 1];
uchar blue = src[x + 1 + offs];
- LcdFilter::filterPixel(red, green, blue);
- *dd++ = (0xFF << 24) | (red << 16) | (green << 8) | blue;
+ *dd++ = (0xFFU << 24) | (red << 16) | (green << 8) | blue;
}
dst += width;
src += src_pitch;
}
}
-static inline void convertRGBToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
-{
- if (!legacyFilter)
- convertRGBToARGB_helper<LcdFilterDummy>(src, dst, width, height, src_pitch, bgr);
- else
- convertRGBToARGB_helper<LcdFilterLegacy>(src, dst, width, height, src_pitch, bgr);
-}
-
-template <typename LcdFilter>
-static void convertRGBToARGB_V_helper(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr)
+static inline void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr)
{
const int offs = bgr ? -src_pitch : src_pitch;
while (height--) {
@@ -615,54 +580,12 @@ static void convertRGBToARGB_V_helper(const uchar *src, uint *dst, int width, in
uchar red = src[x + src_pitch - offs];
uchar green = src[x + src_pitch];
uchar blue = src[x + src_pitch + offs];
- LcdFilter::filterPixel(red, green, blue);
- *dst++ = (0XFF << 24) | (red << 16) | (green << 8) | blue;
+ *dst++ = (0XFFU << 24) | (red << 16) | (green << 8) | blue;
}
src += 3*src_pitch;
}
}
-static inline void convertRGBToARGB_V(const uchar *src, uint *dst, int width, int height, int src_pitch, bool bgr, bool legacyFilter)
-{
- if (!legacyFilter)
- convertRGBToARGB_V_helper<LcdFilterDummy>(src, dst, width, height, src_pitch, bgr);
- else
- convertRGBToARGB_V_helper<LcdFilterLegacy>(src, dst, width, height, src_pitch, bgr);
-}
-
-static inline void convertGRAYToARGB(const uchar *src, uint *dst, int width, int height, int src_pitch)
-{
- while (height--) {
- const uchar *p = src;
- const uchar * const e = p + width;
- while (p < e) {
- uchar gray = *p++;
- *dst++ = (0xFF << 24) | (gray << 16) | (gray << 8) | gray;
- }
- src += src_pitch;
- }
-}
-
-static void convoluteBitmap(const uchar *src, uchar *dst, int width, int height, int pitch)
-{
- // convolute the bitmap with a triangle filter to get rid of color fringes
- // If we take account for a gamma value of 2, we end up with
- // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
- // as this nicely sums up to 16 :)
- int h = height;
- while (h--) {
- dst[0] = dst[1] = 0;
- //
- for (int x = 2; x < width - 2; ++x) {
- uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
- dst[x] = (uchar) (sum >> 4);
- }
- dst[width - 2] = dst[width - 1] = 0;
- src += pitch;
- dst += pitch;
- }
-}
-
static QFontEngine::SubpixelAntialiasingType subpixelAntialiasingTypeHint()
{
static int type = -1;
@@ -1153,196 +1076,97 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
int glyph_buffer_size = 0;
QScopedArrayPointer<uchar> glyph_buffer;
- bool useFreetypeRenderGlyph = false;
- if (slot->format == FT_GLYPH_FORMAT_OUTLINE && (hsubpixel || vfactor != 1)) {
- err = FT_Library_SetLcdFilter(slot->library, (FT_LcdFilter)lcdFilterType);
- // We use FT_Render_Glyph if freetype has support for lcd-filtering
- // or is version 2.8.1 or higher and can do without.
- if (err == FT_Err_Ok || qt_getFreetypeData()->hasPatentFreeLcdRendering)
- useFreetypeRenderGlyph = true;
+ FT_Render_Mode renderMode = (default_hint_style == HintLight) ? FT_RENDER_MODE_LIGHT : FT_RENDER_MODE_NORMAL;
+ switch (format) {
+ case Format_Mono:
+ renderMode = FT_RENDER_MODE_MONO;
+ break;
+ case Format_A32:
+ Q_ASSERT(hsubpixel || vfactor != 1);
+ renderMode = hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V;
+ break;
+ case Format_A8:
+ case Format_ARGB:
+ break;
+ default:
+ Q_UNREACHABLE();
}
- if (useFreetypeRenderGlyph) {
- err = FT_Render_Glyph(slot, hsubpixel ? FT_RENDER_MODE_LCD : FT_RENDER_MODE_LCD_V);
-
- if (err != FT_Err_Ok)
- qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
-
- FT_Library_SetLcdFilter(slot->library, FT_LCD_FILTER_NONE);
+ FT_Library_SetLcdFilter(slot->library, (FT_LcdFilter)lcdFilterType);
- info.height = slot->bitmap.rows / vfactor;
- info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
- info.x = slot->bitmap_left;
- info.y = slot->bitmap_top;
+ err = FT_Render_Glyph(slot, renderMode);
+ if (err != FT_Err_Ok)
+ qWarning("render glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
- glyph_buffer_size = info.width * info.height * 4;
- glyph_buffer.reset(new uchar[glyph_buffer_size]);
+ FT_Library_SetLcdFilter(slot->library, FT_LCD_FILTER_NONE);
- if (hsubpixel)
- convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, slot->bitmap.pitch, subpixelType != Subpixel_RGB, false);
- else if (vfactor != 1)
- convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, slot->bitmap.pitch, subpixelType != Subpixel_VRGB, false);
- } else {
- int left = slot->metrics.horiBearingX;
- int right = slot->metrics.horiBearingX + slot->metrics.width;
- int top = slot->metrics.horiBearingY;
- int bottom = slot->metrics.horiBearingY - slot->metrics.height;
- if (transform && slot->format != FT_GLYPH_FORMAT_BITMAP)
- transformBoundingBox(&left, &top, &right, &bottom, &matrix);
- left = FLOOR(left);
- right = CEIL(right);
- bottom = FLOOR(bottom);
- top = CEIL(top);
-
- int hpixels = TRUNC(right - left);
- // subpixel position requires one more pixel
- if (subPixelPosition > 0 && format != Format_Mono)
- hpixels++;
-
- if (hsubpixel)
- hpixels = hpixels*3 + 8;
- info.width = hpixels;
- info.height = TRUNC(top - bottom);
- info.x = TRUNC(left);
- info.y = TRUNC(top);
- if (hsubpixel) {
- info.width /= 3;
- info.x -= 1;
- }
-
- // If any of the metrics are too large to fit, don't cache them
- if (areMetricsTooLarge(info))
- return 0;
+ info.height = slot->bitmap.rows;
+ info.width = slot->bitmap.width;
+ info.x = slot->bitmap_left;
+ info.y = slot->bitmap_top;
+ if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD)
+ info.width = info.width / 3;
+ if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V)
+ info.height = info.height / vfactor;
int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
(format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
- if (glyph_buffer_size < pitch * info.height) {
- glyph_buffer_size = pitch * info.height;
- glyph_buffer.reset(new uchar[glyph_buffer_size]);
- memset(glyph_buffer.data(), 0, glyph_buffer_size);
- }
- if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
- FT_Bitmap bitmap;
- bitmap.rows = info.height*vfactor;
- bitmap.width = hpixels;
- bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
- int bitmap_buffer_size = bitmap.rows * bitmap.pitch;
- if (!hsubpixel && vfactor == 1 && format != Format_A32) {
- Q_ASSERT(glyph_buffer_size <= bitmap_buffer_size);
- bitmap.buffer = glyph_buffer.data();
- } else {
- bitmap.buffer = new uchar[bitmap_buffer_size];
- memset(bitmap.buffer, 0, bitmap_buffer_size);
- }
- bitmap.pixel_mode = format == Format_Mono ? FT_PIXEL_MODE_MONO : FT_PIXEL_MODE_GRAY;
- FT_Matrix matrix;
- matrix.xx = (hsubpixel ? 3 : 1) << 16;
- matrix.yy = vfactor << 16;
- matrix.yx = matrix.xy = 0;
-
- FT_Outline_Transform(&slot->outline, &matrix);
- FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
- FT_Outline_Get_Bitmap(slot->library, &slot->outline, &bitmap);
- if (hsubpixel) {
- Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
- Q_ASSERT(antialias);
- uchar *convoluted = new uchar[bitmap_buffer_size];
- bool useLegacyLcdFilter = false;
- useLegacyLcdFilter = (lcdFilterType == FT_LCD_FILTER_LEGACY);
- uchar *buffer = bitmap.buffer;
- if (!useLegacyLcdFilter) {
- convoluteBitmap(bitmap.buffer, convoluted, bitmap.width, info.height, bitmap.pitch);
- buffer = convoluted;
- }
- convertRGBToARGB(buffer + 1, (uint *)glyph_buffer.data(), info.width, info.height, bitmap.pitch, subpixelType != Subpixel_RGB, useLegacyLcdFilter);
- delete [] convoluted;
- } else if (vfactor != 1) {
- convertRGBToARGB_V(bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, bitmap.pitch, subpixelType != Subpixel_VRGB, true);
- } else if (format == Format_A32 && bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
- convertGRAYToARGB(bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, bitmap.pitch);
- }
+ glyph_buffer_size = info.height * pitch;
+ glyph_buffer.reset(new uchar[glyph_buffer_size]);
- if (bitmap.buffer != glyph_buffer.data())
- delete [] bitmap.buffer;
- } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
-#if ((FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100) >= 20500)
- Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO || slot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA);
-#else
- Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
-#endif
+ if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
+ Q_ASSERT(format == Format_Mono);
uchar *src = slot->bitmap.buffer;
uchar *dst = glyph_buffer.data();
int h = slot->bitmap.rows;
- if (format == Format_Mono) {
- int bytes = ((info.width + 7) & ~7) >> 3;
- while (h--) {
- memcpy (dst, src, bytes);
- dst += pitch;
- src += slot->bitmap.pitch;
- }
- } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) {
- if (hsubpixel) {
- while (h--) {
- uint *dd = (uint *)dst;
- *dd++ = 0;
- for (int x = 0; x < static_cast<int>(slot->bitmap.width); x++) {
- uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
- *dd++ = a;
- }
- *dd++ = 0;
- dst += pitch;
- src += slot->bitmap.pitch;
- }
- } else if (vfactor != 1) {
- while (h--) {
- uint *dd = (uint *)dst;
- for (int x = 0; x < static_cast<int>(slot->bitmap.width); x++) {
- uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
- *dd++ = a;
- }
- dst += pitch;
- src += slot->bitmap.pitch;
- }
- } else {
- while (h--) {
- for (int x = 0; x < static_cast<int>(slot->bitmap.width); x++) {
- unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
- dst[x] = a;
- }
- dst += pitch;
- src += slot->bitmap.pitch;
- }
- }
+
+ int bytes = ((info.width + 7) & ~7) >> 3;
+ while (h--) {
+ memcpy (dst, src, bytes);
+ dst += pitch;
+ src += slot->bitmap.pitch;
}
-#if ((FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100) >= 20500)
- else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA)
- {
- while (h--) {
+ } else if (slot->bitmap.pixel_mode == 7 /*FT_PIXEL_MODE_BGRA*/) {
+ Q_ASSERT(format == Format_ARGB);
+ uchar *src = slot->bitmap.buffer;
+ uchar *dst = glyph_buffer.data();
+ int h = slot->bitmap.rows;
+ while (h--) {
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- const quint32 *srcPixel = (const quint32 *)src;
- quint32 *dstPixel = (quint32 *)dst;
- for (int x = 0; x < static_cast<int>(slot->bitmap.width); x++, srcPixel++, dstPixel++) {
- const quint32 pixel = *srcPixel;
- *dstPixel = qbswap(pixel);
- }
+ const quint32 *srcPixel = (const quint32 *)src;
+ quint32 *dstPixel = (quint32 *)dst;
+ for (int x = 0; x < static_cast<int>(slot->bitmap.width); x++, srcPixel++, dstPixel++) {
+ const quint32 pixel = *srcPixel;
+ *dstPixel = qbswap(pixel);
+ }
#else
- memcpy(dst, src, slot->bitmap.width * 4);
+ memcpy(dst, src, slot->bitmap.width * 4);
#endif
- dst += slot->bitmap.pitch;
- src += slot->bitmap.pitch;
- }
- info.width = info.linearAdvance = info.xOff = slot->bitmap.width;
- info.height = slot->bitmap.rows;
- info.x = slot->bitmap_left;
- info.y = slot->bitmap_top;
+ dst += slot->bitmap.pitch;
+ src += slot->bitmap.pitch;
}
-#endif
+ info.linearAdvance = info.xOff = slot->bitmap.width;
+ } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
+ Q_ASSERT(format == Format_A8);
+ uchar *src = slot->bitmap.buffer;
+ uchar *dst = glyph_buffer.data();
+ int h = slot->bitmap.rows;
+ int bytes = info.width;
+ while (h--) {
+ memcpy (dst, src, bytes);
+ dst += pitch;
+ src += slot->bitmap.pitch;
+ }
+ } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) {
+ Q_ASSERT(format == Format_A32);
+ convertRGBToARGB(slot->bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, slot->bitmap.pitch, subpixelType != Subpixel_RGB);
+ } else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) {
+ Q_ASSERT(format == Format_A32);
+ convertRGBToARGB_V(slot->bitmap.buffer, (uint *)glyph_buffer.data(), info.width, info.height, slot->bitmap.pitch, subpixelType != Subpixel_VRGB);
} else {
- qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
+ qWarning("QFontEngine: Glyph rendered in unknown pixel_mode=%d", slot->bitmap.pixel_mode);
return 0;
}
- }
-
if (!g) {
g = new Glyph;
@@ -1556,7 +1380,7 @@ QFontEngineFT::QGlyphSet *QFontEngineFT::loadGlyphSet(const QTransform &matrix)
gs = &transformedGlyphSets[0];
gs->clear();
gs->transformationMatrix = m;
- gs->outline_drawing = fontDef.pixelSize * fontDef.pixelSize * qAbs(matrix.det()) >= QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE;
+ gs->outline_drawing = fontDef.pixelSize * fontDef.pixelSize * qAbs(matrix.determinant()) > QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE;
}
Q_ASSERT(gs != 0);
diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h
index d498b0ac8b..2d1d5e6572 100644
--- a/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h
+++ b/src/platformsupport/fontdatabases/freetype/qfontengine_ft_p.h
@@ -268,7 +268,7 @@ private:
inline bool isScalableBitmap() const { return freetype->isScalableBitmap(); }
inline Glyph *loadGlyph(uint glyph, QFixed subPixelPosition, GlyphFormat format = Format_None, bool fetchMetricsOnly = false, bool disableOutlineDrawing = false) const
- { return loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyph, subPixelPosition, format, fetchMetricsOnly, disableOutlineDrawing); }
+ { return loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr, glyph, subPixelPosition, format, fetchMetricsOnly, disableOutlineDrawing); }
Glyph *loadGlyph(QGlyphSet *set, uint glyph, QFixed subPixelPosition, GlyphFormat = Format_None, bool fetchMetricsOnly = false, bool disableOutlineDrawing = false) const;
Glyph *loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format, const QTransform &t, bool fetchBoundingBox = false, bool disableOutlineDrawing = false);
diff --git a/src/platformsupport/fontdatabases/mac/coretext.pri b/src/platformsupport/fontdatabases/mac/coretext.pri
index af75aa3281..95b9926e65 100644
--- a/src/platformsupport/fontdatabases/mac/coretext.pri
+++ b/src/platformsupport/fontdatabases/mac/coretext.pri
@@ -1,12 +1,6 @@
HEADERS += $$PWD/qcoretextfontdatabase_p.h $$PWD/qfontengine_coretext_p.h
OBJECTIVE_SOURCES += $$PWD/qfontengine_coretext.mm $$PWD/qcoretextfontdatabase.mm
-qtConfig(freetype) {
- QMAKE_USE_PRIVATE += freetype
- HEADERS += freetype/qfontengine_ft_p.h
- SOURCES += freetype/qfontengine_ft.cpp
-}
-
LIBS_PRIVATE += \
-framework CoreFoundation \
-framework CoreGraphics \
diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
index 5ac28ce798..047773d8e3 100644
--- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
+++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm
@@ -50,7 +50,9 @@
#include "qcoretextfontdatabase_p.h"
#include "qfontengine_coretext_p.h"
+#if QT_CONFIG(settings)
#include <QtCore/QSettings>
+#endif
#include <QtCore/QtEndian>
#ifndef QT_NO_FREETYPE
#include <QtFontDatabaseSupport/private/qfontengine_ft_p.h>
@@ -115,67 +117,6 @@ static NSInteger languageMapSort(id obj1, id obj2, void *context)
QCoreTextFontDatabase::QCoreTextFontDatabase()
: m_hasPopulatedAliases(false)
{
-#ifdef Q_OS_MACX
- QSettings appleSettings(QLatin1String("apple.com"));
- QVariant appleValue = appleSettings.value(QLatin1String("AppleAntiAliasingThreshold"));
- if (appleValue.isValid())
- QCoreTextFontEngine::antialiasingThreshold = appleValue.toInt();
-
- /*
- font_smoothing = 0 means no smoothing, while 1-3 means subpixel
- antialiasing with different hinting styles (but we don't care about the
- exact value, only if subpixel rendering is available or not)
- */
- int font_smoothing = 0;
- appleValue = appleSettings.value(QLatin1String("AppleFontSmoothing"));
- if (appleValue.isValid()) {
- font_smoothing = appleValue.toInt();
- } else {
- // non-Apple displays do not provide enough information about subpixel rendering so
- // draw text with cocoa and compare pixel colors to see if subpixel rendering is enabled
- int w = 10;
- int h = 10;
- NSRect rect = NSMakeRect(0.0, 0.0, w, h);
- NSImage *fontImage = [[NSImage alloc] initWithSize:NSMakeSize(w, h)];
-
- [fontImage lockFocus];
-
- [[NSColor whiteColor] setFill];
- NSRectFill(rect);
-
- NSString *str = @"X\\";
- NSFont *font = [NSFont fontWithName:@"Helvetica" size:10.0];
- NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
- [attrs setObject:font forKey:NSFontAttributeName];
- [attrs setObject:[NSColor blackColor] forKey:NSForegroundColorAttributeName];
-
- [str drawInRect:rect withAttributes:attrs];
-
- NSBitmapImageRep *nsBitmapImage = [[NSBitmapImageRep alloc] initWithFocusedViewRect:rect];
-
- [fontImage unlockFocus];
-
- float red, green, blue;
- for (int x = 0; x < w; x++) {
- for (int y = 0; y < h; y++) {
- NSColor *pixelColor = [nsBitmapImage colorAtX:x y:y];
- red = [pixelColor redComponent];
- green = [pixelColor greenComponent];
- blue = [pixelColor blueComponent];
- if (red != green || red != blue)
- font_smoothing = 1;
- }
- }
-
- [nsBitmapImage release];
- [fontImage release];
- }
- QCoreTextFontEngine::defaultGlyphFormat = (font_smoothing > 0
- ? QFontEngine::Format_A32
- : QFontEngine::Format_A8);
-#else
- QCoreTextFontEngine::defaultGlyphFormat = QFontEngine::Format_A8;
-#endif
}
QCoreTextFontDatabase::~QCoreTextFontDatabase()
@@ -253,7 +194,7 @@ struct FontDescription {
QFont::Weight weight;
QFont::Style style;
QFont::Stretch stretch;
- int pixelSize;
+ qreal pointSize;
bool fixedPitch;
QSupportedWritingSystems writingSystems;
};
@@ -269,7 +210,7 @@ Q_DECL_UNUSED static inline QDebug operator<<(QDebug debug, const FontDescriptio
<< ", weight=" << fd.weight
<< ", style=" << fd.style
<< ", stretch=" << fd.stretch
- << ", pixelSize=" << fd.pixelSize
+ << ", pointSize=" << fd.pointSize
<< ", fixedPitch=" << fd.fixedPitch
<< ", writingSystems=" << fd.writingSystems
<< ")";
@@ -345,9 +286,11 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
if (CFNumberIsFloatType(size)) {
double d;
CFNumberGetValue(size, kCFNumberDoubleType, &d);
- fd->pixelSize = d;
+ fd->pointSize = d;
} else {
- CFNumberGetValue(size, kCFNumberIntType, &fd->pixelSize);
+ int i;
+ CFNumberGetValue(size, kCFNumberIntType, &i);
+ fd->pointSize = i;
}
}
@@ -375,8 +318,8 @@ void QCoreTextFontDatabase::populateFromDescriptor(CTFontDescriptorRef font, con
CFRetain(font);
QPlatformFontDatabase::registerFont(family, fd.styleName, fd.foundryName, fd.weight, fd.style, fd.stretch,
- true /* antialiased */, true /* scalable */,
- fd.pixelSize, fd.fixedPitch, fd.writingSystems, (void *) font);
+ true /* antialiased */, true /* scalable */, 0 /* pixelSize, ignored as font is scalable */,
+ fd.fixedPitch, fd.writingSystems, (void *)font);
}
static NSString * const kQtFontDataAttribute = @"QtFontDataAttribute";
@@ -786,7 +729,7 @@ QFont *QCoreTextFontDatabase::themeFont(QPlatformTheme::Font f) const
else
CFRelease(fontDesc);
- QFont *font = new QFont(fd.familyName, fd.pixelSize, fd.weight, fd.style == QFont::StyleItalic);
+ QFont *font = new QFont(fd.familyName, fd.pointSize, fd.weight, fd.style == QFont::StyleItalic);
return font;
}
diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
index 6543759a3d..25e7c6df72 100644
--- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
+++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
@@ -41,9 +41,11 @@
#include <qpa/qplatformfontdatabase.h>
#include <QtCore/qendian.h>
+#if QT_CONFIG(settings)
#include <QtCore/qsettings.h>
+#endif
#include <QtCore/qoperatingsystemversion.h>
-
+#include <private/qcoregraphics_p.h>
#include <private/qimage_p.h>
#include <cmath>
@@ -83,6 +85,8 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts")
+
static float SYNTHETIC_ITALIC_SKEW = std::tan(14.f * std::acos(0.f) / 90.f);
bool QCoreTextFontEngine::ct_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length)
@@ -131,42 +135,6 @@ QFont::Weight QCoreTextFontEngine::qtWeightFromCFWeight(float value)
return ret;
}
-static void loadAdvancesForGlyphs(CTFontRef ctfont,
- QVarLengthArray<CGGlyph> &cgGlyphs,
- QGlyphLayout *glyphs, int len,
- QFontEngine::ShaperFlags flags,
- const QFontDef &fontDef)
-{
- Q_UNUSED(flags);
- QVarLengthArray<CGSize> advances(len);
- CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, cgGlyphs.data(), advances.data(), len);
-
- for (int i = 0; i < len; ++i) {
- if (glyphs->glyphs[i] & 0xff000000)
- continue;
- glyphs->advances[i] = QFixed::fromReal(advances[i].width);
- }
-
- if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
- for (int i = 0; i < len; ++i)
- glyphs->advances[i] = glyphs->advances[i].round();
- }
-}
-
-static float getTraitValue(CFDictionaryRef allTraits, CFStringRef trait)
-{
- if (CFDictionaryContainsKey(allTraits, trait)) {
- CFNumberRef traitNum = (CFNumberRef) CFDictionaryGetValue(allTraits, trait);
- float v = 0;
- CFNumberGetValue(traitNum, kCFNumberFloatType, &v);
- return v;
- }
- return 0;
-}
-
-int QCoreTextFontEngine::antialiasingThreshold = 0;
-QFontEngine::GlyphFormat QCoreTextFontEngine::defaultGlyphFormat = QFontEngine::Format_A32;
-
CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef)
{
CGAffineTransform transform = CGAffineTransformIdentity;
@@ -221,38 +189,36 @@ QCoreTextFontEngine *QCoreTextFontEngine::create(const QByteArray &fontData, qre
}
QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def)
- : QFontEngine(Mac)
+ : QCoreTextFontEngine(def)
{
- fontDef = def;
- transform = qt_transform_from_fontdef(fontDef);
- ctfont = font;
- CFRetain(ctfont);
- cgFont = CTFontCopyGraphicsFont(font, NULL);
+ ctfont = QCFType<CTFontRef>::constructFromGet(font);
+ cgFont = CTFontCopyGraphicsFont(font, nullptr);
init();
}
QCoreTextFontEngine::QCoreTextFontEngine(CGFontRef font, const QFontDef &def)
+ : QCoreTextFontEngine(def)
+{
+ cgFont = QCFType<CGFontRef>::constructFromGet(font);
+ ctfont = CTFontCreateWithGraphicsFont(font, fontDef.pixelSize, &transform, nullptr);
+ init();
+}
+
+QCoreTextFontEngine::QCoreTextFontEngine(const QFontDef &def)
: QFontEngine(Mac)
{
fontDef = def;
transform = qt_transform_from_fontdef(fontDef);
- cgFont = font;
- // Keep reference count balanced
- CFRetain(cgFont);
- ctfont = CTFontCreateWithGraphicsFont(font, fontDef.pixelSize, &transform, NULL);
- init();
}
QCoreTextFontEngine::~QCoreTextFontEngine()
{
- CFRelease(cgFont);
- CFRelease(ctfont);
}
void QCoreTextFontEngine::init()
{
- Q_ASSERT(ctfont != NULL);
- Q_ASSERT(cgFont != NULL);
+ Q_ASSERT(ctfont);
+ Q_ASSERT(cgFont);
face_id.index = 0;
QCFString name = CTFontCopyName(ctfont, kCTFontUniqueNameKey);
@@ -269,18 +235,29 @@ void QCoreTextFontEngine::init()
if (traits & kCTFontColorGlyphsTrait)
glyphFormat = QFontEngine::Format_ARGB;
+ else if (shouldSmoothFont() && fontSmoothing() == FontSmoothing::Subpixel)
+ glyphFormat = QFontEngine::Format_A32;
else
- glyphFormat = defaultGlyphFormat;
+ glyphFormat = QFontEngine::Format_A8;
if (traits & kCTFontItalicTrait)
fontDef.style = QFont::StyleItalic;
- CFDictionaryRef allTraits = CTFontCopyTraits(ctfont);
+ static const auto getTraitValue = [](CFDictionaryRef allTraits, CFStringRef trait) -> float {
+ if (CFDictionaryContainsKey(allTraits, trait)) {
+ CFNumberRef traitNum = (CFNumberRef) CFDictionaryGetValue(allTraits, trait);
+ float v = 0;
+ CFNumberGetValue(traitNum, kCFNumberFloatType, &v);
+ return v;
+ }
+ return 0;
+ };
+
+ QCFType<CFDictionaryRef> allTraits = CTFontCopyTraits(ctfont);
fontDef.weight = QCoreTextFontEngine::qtWeightFromCFWeight(getTraitValue(allTraits, kCTFontWeightTrait));
int slant = static_cast<int>(getTraitValue(allTraits, kCTFontSlantTrait) * 500 + 500);
if (slant > 500 && !(traits & kCTFontItalicTrait))
fontDef.style = QFont::StyleOblique;
- CFRelease(allTraits);
if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait))
synthesisFlags |= SynthesizedBold;
@@ -359,22 +336,9 @@ bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *
*nglyphs = glyph_pos;
glyphs->numGlyphs = glyph_pos;
- if (flags & GlyphIndicesOnly)
- return true;
-
- QVarLengthArray<CGSize> advances(glyph_pos);
- CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, cgGlyphs.data(), advances.data(), glyph_pos);
-
- for (int i = 0; i < glyph_pos; ++i) {
- if (glyphs->glyphs[i] & 0xff000000)
- continue;
- glyphs->advances[i] = QFixed::fromReal(advances[i].width);
- }
+ if (!(flags & GlyphIndicesOnly))
+ loadAdvancesForGlyphs(cgGlyphs, glyphs);
- if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
- for (int i = 0; i < glyph_pos; ++i)
- glyphs->advances[i] = glyphs->advances[i].round();
- }
return true;
}
@@ -469,6 +433,11 @@ qreal QCoreTextFontEngine::maxCharWidth() const
return bb.xoff.toReal();
}
+bool QCoreTextFontEngine::hasColorGlyphs() const
+{
+ return glyphFormat == QFontEngine::Format_ARGB;
+}
+
void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight)
{
QVarLengthArray<QFixedPoint> positions;
@@ -522,9 +491,11 @@ void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextIt
struct ConvertPathInfo
{
- ConvertPathInfo(QPainterPath *newPath, const QPointF &newPos) : path(newPath), pos(newPos) {}
+ ConvertPathInfo(QPainterPath *newPath, const QPointF &newPos, qreal newStretch = 1.0) :
+ path(newPath), pos(newPos), stretch(newStretch) {}
QPainterPath *path;
QPointF pos;
+ qreal stretch;
};
static void convertCGPathToQPainterPath(void *info, const CGPathElement *element)
@@ -532,32 +503,32 @@ static void convertCGPathToQPainterPath(void *info, const CGPathElement *element
ConvertPathInfo *myInfo = static_cast<ConvertPathInfo *>(info);
switch(element->type) {
case kCGPathElementMoveToPoint:
- myInfo->path->moveTo(element->points[0].x + myInfo->pos.x(),
+ myInfo->path->moveTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(),
element->points[0].y + myInfo->pos.y());
break;
case kCGPathElementAddLineToPoint:
- myInfo->path->lineTo(element->points[0].x + myInfo->pos.x(),
+ myInfo->path->lineTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(),
element->points[0].y + myInfo->pos.y());
break;
case kCGPathElementAddQuadCurveToPoint:
- myInfo->path->quadTo(element->points[0].x + myInfo->pos.x(),
+ myInfo->path->quadTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(),
element->points[0].y + myInfo->pos.y(),
- element->points[1].x + myInfo->pos.x(),
+ (element->points[1].x * myInfo->stretch) + myInfo->pos.x(),
element->points[1].y + myInfo->pos.y());
break;
case kCGPathElementAddCurveToPoint:
- myInfo->path->cubicTo(element->points[0].x + myInfo->pos.x(),
+ myInfo->path->cubicTo((element->points[0].x * myInfo->stretch) + myInfo->pos.x(),
element->points[0].y + myInfo->pos.y(),
- element->points[1].x + myInfo->pos.x(),
+ (element->points[1].x * myInfo->stretch) + myInfo->pos.x(),
element->points[1].y + myInfo->pos.y(),
- element->points[2].x + myInfo->pos.x(),
+ (element->points[2].x * myInfo->stretch) + myInfo->pos.x(),
element->points[2].y + myInfo->pos.y());
break;
case kCGPathElementCloseSubpath:
myInfo->path->closeSubpath();
break;
default:
- qDebug() << "Unhandled path transform type: " << element->type;
+ qCWarning(lcQpaFonts) << "Unhandled path transform type: " << element->type;
}
}
@@ -565,7 +536,7 @@ static void convertCGPathToQPainterPath(void *info, const CGPathElement *element
void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nGlyphs,
QPainterPath *path, QTextItem::RenderFlags)
{
- if (glyphFormat == QFontEngine::Format_ARGB)
+ if (hasColorGlyphs())
return; // We can't convert color-glyphs to path
CGAffineTransform cgMatrix = CGAffineTransformIdentity;
@@ -574,9 +545,10 @@ void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *position
if (synthesisFlags & QFontEngine::SynthesizedItalic)
cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -SYNTHETIC_ITALIC_SKEW, 1, 0, 0));
+ qreal stretch = fontDef.stretch ? qreal(fontDef.stretch) / 100 : 1.0;
for (int i = 0; i < nGlyphs; ++i) {
QCFType<CGPathRef> cgpath = CTFontCreatePathForGlyph(ctfont, glyphs[i], &cgMatrix);
- ConvertPathInfo info(path, positions[i].toPointF());
+ ConvertPathInfo info(path, positions[i].toPointF(), stretch);
CGPathApply(cgpath, &info, convertCGPathToQPainterPath);
}
}
@@ -645,66 +617,190 @@ glyph_metrics_t QCoreTextFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed s
return br;
}
+/*
+ Apple has gone through many iterations of its font smoothing algorithms,
+ and there are many ways to enable or disable certain aspects of it. As
+ keeping up with all the different toggles and behavior differences between
+ macOS versions is tricky, we resort to rendering a single glyph in a few
+ configurations, picking up the font smoothing algorithm from the observed
+ result.
+
+ The possible values are:
+
+ - Disabled: No font smoothing is applied.
+
+ Possibly triggered by the user unchecking the "Use font smoothing when
+ available" checkbox in the system preferences or setting AppleFontSmoothing
+ to 0. Also controlled by the CGContextSetAllowsFontSmoothing() API,
+ which gets its default from the settings above. This API overrides
+ the more granular CGContextSetShouldSmoothFonts(), which we use to
+ enable (request) or disable font smoothing.
+
+ Note that this does not exclude normal antialiasing, controlled by
+ the CGContextSetShouldAntialias() API.
+
+ - Subpixel: Font smoothing is applied, and affects subpixels.
+
+ This was the default mode on macOS versions prior to 10.14 (Mojave).
+ The font dilation (stem darkening) parameters were controlled by the
+ AppleFontSmoothing setting, ranging from 1 to 3 (light to strong).
+
+ On Mojave it is no longer supported, but can be triggered by a legacy
+ override (CGFontRenderingFontSmoothingDisabled=NO), so we need to
+ still account for it, otherwise users will have a bad time.
+
+ - Grayscale: Font smoothing is applied, but does not affect subpixels.
+
+ This is the default mode on macOS 10.14 (Mojave). The font dilation
+ (stem darkening) parameters are not affected by the AppleFontSmoothing
+ setting, but are instead computed based on the fill color used when
+ drawing the glyphs (white fill gives a lighter dilation than black
+ fill). This affects how we build our glyph cache, since we produce
+ alpha maps by drawing white on black.
+*/
+QCoreTextFontEngine::FontSmoothing QCoreTextFontEngine::fontSmoothing()
+{
+ static const FontSmoothing cachedFontSmoothing = [] {
+ static const int kSize = 10;
+ QCFType<CTFontRef> font = CTFontCreateWithName(CFSTR("Helvetica"), kSize, nullptr);
+
+ UniChar character('X'); CGGlyph glyph;
+ CTFontGetGlyphsForCharacters(font, &character, &glyph, 1);
+
+ auto drawGlyph = [&](bool smooth) -> QImage {
+ QImage image(kSize, kSize, QImage::Format_RGB32);
+ image.fill(0);
+
+ QMacCGContext ctx(&image);
+ CGContextSetTextDrawingMode(ctx, kCGTextFill);
+ CGContextSetGrayFillColor(ctx, 1, 1);
+
+ // Will be ignored if CGContextSetAllowsFontSmoothing() has been
+ // set to false by CoreGraphics based on user defaults.
+ CGContextSetShouldSmoothFonts(ctx, smooth);
+
+ CTFontDrawGlyphs(font, &glyph, &CGPointZero, 1, ctx);
+ return image;
+ };
+
+ QImage nonSmoothed = drawGlyph(false);
+ QImage smoothed = drawGlyph(true);
+
+ FontSmoothing fontSmoothing = FontSmoothing::Disabled;
+ [&] {
+ for (int x = 0; x < kSize; ++x) {
+ for (int y = 0; y < kSize; ++y) {
+ QRgb sp = smoothed.pixel(x, y);
+ if (qRed(sp) != qGreen(sp) || qRed(sp) != qBlue(sp)) {
+ fontSmoothing = FontSmoothing::Subpixel;
+ return;
+ }
+
+ if (sp != nonSmoothed.pixel(x, y))
+ fontSmoothing = FontSmoothing::Grayscale;
+ }
+ }
+ }();
+
+ auto defaults = [NSUserDefaults standardUserDefaults];
+ qCDebug(lcQpaFonts) << "Resolved font smoothing algorithm. Defaults ="
+ << [[defaults dictionaryRepresentation] dictionaryWithValuesForKeys:@[
+ @"AppleFontSmoothing",
+ @"CGFontRenderingFontSmoothingDisabled"
+ ]] << "Result =" << fontSmoothing;
+
+ return fontSmoothing;
+ }();
+
+ return cachedFontSmoothing;
+}
+
+bool QCoreTextFontEngine::shouldAntialias() const
+{
+ return !(fontDef.styleStrategy & QFont::NoAntialias);
+}
+
+bool QCoreTextFontEngine::shouldSmoothFont() const
+{
+ if (hasColorGlyphs())
+ return false;
+
+ if (!shouldAntialias())
+ return false;
+
+ switch (fontSmoothing()) {
+ case Disabled: return false;
+ case Subpixel: return !(fontDef.styleStrategy & QFont::NoSubpixelAntialias);
+ case Grayscale: return true;
+ }
+
+ Q_UNREACHABLE();
+}
+
bool QCoreTextFontEngine::expectsGammaCorrectedBlending() const
{
- // Only works well when font-smoothing is enabled
- return (glyphFormat == Format_A32) && !(fontDef.styleStrategy & (QFont::NoAntialias | QFont::NoSubpixelAntialias));
+ return shouldSmoothFont() && fontSmoothing() == Subpixel;
}
-QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, bool aa, const QTransform &matrix)
+qreal QCoreTextFontEngine::fontSmoothingGamma()
+{
+ return 2.0;
+}
+
+QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix)
{
glyph_metrics_t br = alphaMapBoundingBox(glyph, subPixelPosition, matrix, glyphFormat);
- bool isColorGlyph = glyphFormat == QFontEngine::Format_ARGB;
- QImage::Format imageFormat = isColorGlyph ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
+ QImage::Format imageFormat = hasColorGlyphs() ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
QImage im(br.width.ceil().toInt(), br.height.ceil().toInt(), imageFormat);
if (!im.width() || !im.height())
return im;
+ QCFType<CGColorSpaceRef> colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
+ QCFType<CGContextRef> ctx = CGBitmapContextCreate(im.bits(), im.width(), im.height(),
+ 8, im.bytesPerLine(), colorspace,
+ qt_mac_bitmapInfoForImage(im));
+ Q_ASSERT(ctx);
+
+ CGContextSetShouldAntialias(ctx, shouldAntialias());
+
+ const bool shouldSmooth = shouldSmoothFont();
+ CGContextSetShouldSmoothFonts(ctx, shouldSmooth);
+
#if defined(Q_OS_MACOS)
- CGColorRef glyphColor = CGColorGetConstantColor(kCGColorWhite);
- if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) {
- // macOS 10.14 uses a new font smoothing algorithm that takes the fill color into
- // account. This means our default approach of drawing white on black to produce
- // the alpha map will result in non-native looking text when then drawn as black
- // on white during the final blit. As a workaround we use the application's current
- // appearance to decide whether to draw with white or black fill, and then invert
- // the glyph image in the latter case, producing an alpha map. This covers the
- // most common use-cases, but longer term we should propagate the fill color all
- // the way from the paint engine, and include it in the key for the glyph cache.
- if (!qt_mac_applicationIsInDarkMode())
- glyphColor = CGColorGetConstantColor(kCGColorBlack);
- }
- const bool blackOnWhiteGlyphs = !isColorGlyph
- && CGColorEqualToColor(glyphColor, CGColorGetConstantColor(kCGColorBlack));
+ auto glyphColor = [&] {
+ if (shouldSmooth && fontSmoothing() == Grayscale) {
+ // The grayscale font smoothing algorithm introduced in macOS Mojave (10.14) adjusts
+ // its dilation (stem darkening) parameters based on the fill color. This means our
+ // default approach of drawing white on black to produce the alpha map will result
+ // in non-native looking text when then drawn as black on white during the final blit.
+ // As a workaround we use the application's current appearance to decide whether to
+ // draw with white or black fill, and then invert the glyph image in the latter case,
+ // producing an alpha map. This covers the most common use-cases, but longer term we
+ // should propagate the fill color all the way from the paint engine, and include it
+ //in the key for the glyph cache.
+
+ if (!qt_mac_applicationIsInDarkMode())
+ return kCGColorBlack;
+ }
+ return kCGColorWhite;
+ }();
+
+ const bool blackOnWhiteGlyphs = glyphColor == kCGColorBlack;
if (blackOnWhiteGlyphs)
im.fill(Qt::white);
else
#endif
- im.fill(0); // Faster than Qt::black
-
- CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
- uint cgflags = isColorGlyph ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
-#ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version
- cgflags |= kCGBitmapByteOrder32Host;
-#endif
+ im.fill(0);
- CGContextRef ctx = CGBitmapContextCreate(im.bits(), im.width(), im.height(),
- 8, im.bytesPerLine(), colorspace,
- cgflags);
- Q_ASSERT(ctx);
CGContextSetFontSize(ctx, fontDef.pixelSize);
- const bool antialias = (aa || fontDef.pointSize > antialiasingThreshold) && !(fontDef.styleStrategy & QFont::NoAntialias);
- CGContextSetShouldAntialias(ctx, antialias);
- const bool smoothing = antialias && !(fontDef.styleStrategy & QFont::NoSubpixelAntialias);
- CGContextSetShouldSmoothFonts(ctx, smoothing);
CGAffineTransform cgMatrix = CGAffineTransformIdentity;
if (synthesisFlags & QFontEngine::SynthesizedItalic)
cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, SYNTHETIC_ITALIC_SKEW, 1, 0, 0));
- if (!isColorGlyph) // CTFontDrawGlyphs incorporates the font's matrix already
+ if (!hasColorGlyphs()) // CTFontDrawGlyphs incorporates the font's matrix already
cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
if (matrix.isScaling())
@@ -714,10 +810,10 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
qreal pos_x = -br.x.truncate() + subPixelPosition.toReal();
qreal pos_y = im.height() + br.y.toReal();
- if (!isColorGlyph) {
+ if (!hasColorGlyphs()) {
CGContextSetTextMatrix(ctx, cgMatrix);
#if defined(Q_OS_MACOS)
- CGContextSetFillColorWithColor(ctx, glyphColor);
+ CGContextSetFillColorWithColor(ctx, CGColorGetConstantColor(glyphColor));
#else
CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
#endif
@@ -742,8 +838,8 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
CTFontDrawGlyphs(ctfont, &cgGlyph, &CGPointZero, 1, ctx);
}
- CGContextRelease(ctx);
- CGColorSpaceRelease(colorspace);
+ if (expectsGammaCorrectedBlending())
+ qGamma_correct_back_to_linear_cs(&im);
#if defined(Q_OS_MACOS)
if (blackOnWhiteGlyphs)
@@ -763,7 +859,7 @@ QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosit
if (x.type() > QTransform::TxScale)
return QFontEngine::alphaMapForGlyph(glyph, subPixelPosition, x);
- QImage im = imageForGlyph(glyph, subPixelPosition, false, x);
+ QImage im = imageForGlyph(glyph, subPixelPosition, x);
QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8);
@@ -785,9 +881,7 @@ QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPo
if (x.type() > QTransform::TxScale)
return QFontEngine::alphaRGBMapForGlyph(glyph, subPixelPosition, x);
- QImage im = imageForGlyph(glyph, subPixelPosition, true, x);
- qGamma_correct_back_to_linear_cs(&im);
- return im;
+ return imageForGlyph(glyph, subPixelPosition, x);
}
QImage QCoreTextFontEngine::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
@@ -795,22 +889,35 @@ QImage QCoreTextFontEngine::bitmapForGlyph(glyph_t glyph, QFixed subPixelPositio
if (t.type() > QTransform::TxScale)
return QFontEngine::bitmapForGlyph(glyph, subPixelPosition, t);
- return imageForGlyph(glyph, subPixelPosition, true, t);
+ return imageForGlyph(glyph, subPixelPosition, t);
}
void QCoreTextFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
{
- int i, numGlyphs = glyphs->numGlyphs;
+ Q_UNUSED(flags);
+
+ const int numGlyphs = glyphs->numGlyphs;
QVarLengthArray<CGGlyph> cgGlyphs(numGlyphs);
- for (i = 0; i < numGlyphs; ++i) {
- if (glyphs->glyphs[i] & 0xff000000)
- cgGlyphs[i] = 0;
- else
- cgGlyphs[i] = glyphs->glyphs[i];
+ for (int i = 0; i < numGlyphs; ++i) {
+ Q_ASSERT(!QFontEngineMulti::highByte(glyphs->glyphs[i]));
+ cgGlyphs[i] = glyphs->glyphs[i];
}
- loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, numGlyphs, flags, fontDef);
+ loadAdvancesForGlyphs(cgGlyphs, glyphs);
+}
+
+void QCoreTextFontEngine::loadAdvancesForGlyphs(QVarLengthArray<CGGlyph> &cgGlyphs, QGlyphLayout *glyphs) const
+{
+ const int numGlyphs = glyphs->numGlyphs;
+ QVarLengthArray<CGSize> advances(numGlyphs);
+ CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, cgGlyphs.data(), advances.data(), numGlyphs);
+
+ for (int i = 0; i < numGlyphs; ++i) {
+ QFixed advance = QFixed::fromReal(advances[i].width);
+ glyphs->advances[i] = fontDef.styleStrategy & QFont::ForceIntegerMetrics
+ ? advance.round() : advance;
+ }
}
QFontEngine::FaceId QCoreTextFontEngine::faceId() const
@@ -867,7 +974,7 @@ QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const
Qt::HANDLE QCoreTextFontEngine::handle() const
{
- return (Qt::HANDLE)ctfont;
+ return (Qt::HANDLE)(static_cast<CTFontRef>(ctfont));
}
bool QCoreTextFontEngine::supportsTransformation(const QTransform &transform) const
diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h
index b77aaa27c1..4064507058 100644
--- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h
+++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h
@@ -53,6 +53,7 @@
#include <private/qfontengine_p.h>
#include <private/qcore_mac_p.h>
+#include <QtCore/qloggingcategory.h>
#ifdef Q_OS_OSX
#include <ApplicationServices/ApplicationServices.h>
@@ -63,8 +64,12 @@
QT_BEGIN_NAMESPACE
+Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts)
+
class QCoreTextFontEngine : public QFontEngine
{
+ Q_GADGET
+
public:
QCoreTextFontEngine(CTFontRef font, const QFontDef &def);
QCoreTextFontEngine(CGFontRef font, const QFontDef &def);
@@ -118,18 +123,28 @@ public:
QFontEngine::Properties properties() const override;
+ enum FontSmoothing { Disabled, Subpixel, Grayscale };
+ Q_ENUM(FontSmoothing);
+
+ static FontSmoothing fontSmoothing();
+ static qreal fontSmoothingGamma();
+
static bool ct_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length);
static QFont::Weight qtWeightFromCFWeight(float value);
- static int antialiasingThreshold;
- static QFontEngine::GlyphFormat defaultGlyphFormat;
-
static QCoreTextFontEngine *create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
+
protected:
+ QCoreTextFontEngine(const QFontDef &def);
void init();
- QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, bool colorful, const QTransform &m);
- CTFontRef ctfont;
- CGFontRef cgFont;
+ QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &m);
+ void loadAdvancesForGlyphs(QVarLengthArray<CGGlyph> &cgGlyphs, QGlyphLayout *glyphs) const;
+ bool hasColorGlyphs() const;
+ bool shouldAntialias() const;
+ bool shouldSmoothFont() const;
+
+ QCFType<CTFontRef> ctfont;
+ QCFType<CGFontRef> cgFont;
int synthesisFlags;
CGAffineTransform transform;
QFixed avgCharWidth;
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
index 00a0643dd1..b1ba84fe14 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp
@@ -1264,11 +1264,6 @@ QWindowsFontDatabase::~QWindowsFontDatabase()
removeApplicationFonts();
}
-QFontEngineMulti *QWindowsFontDatabase::fontEngineMulti(QFontEngine *fontEngine, QChar::Script script)
-{
- return new QWindowsMultiFontEngine(fontEngine, script);
-}
-
QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
{
const QString faceName(static_cast<const QChar*>(handle));
@@ -1434,8 +1429,8 @@ QT_WARNING_POP
reinterpret_cast<const OS2Table *>(fontData.constData()
+ qFromBigEndian<quint32>(os2TableEntry->offset));
- bool italic = qFromBigEndian<quint16>(os2Table->selection) & 1;
- bool oblique = qFromBigEndian<quint16>(os2Table->selection) & 128;
+ bool italic = qFromBigEndian<quint16>(os2Table->selection) & (1 << 0);
+ bool oblique = qFromBigEndian<quint16>(os2Table->selection) & (1 << 9);
if (italic)
fontEngine->fontDef.style = QFont::StyleItalic;
@@ -1490,7 +1485,8 @@ static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag,
static void getFamiliesAndSignatures(const QByteArray &fontData,
QList<QFontNames> *families,
- QVector<FONTSIGNATURE> *signatures)
+ QVector<FONTSIGNATURE> *signatures,
+ QVector<QFontValues> *values)
{
const uchar *data = reinterpret_cast<const uchar *>(fontData.constData());
@@ -1509,11 +1505,27 @@ static void getFamiliesAndSignatures(const QByteArray &fontData,
if (names.name.isEmpty())
continue;
- families->append(qMove(names));
+ families->append(std::move(names));
+
+ if (values || signatures)
+ getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
+
+ if (values) {
+ QFontValues fontValues;
+ if (table && length >= 64) {
+ // Read in some details about the font, offset calculated based on the specification
+ fontValues.weight = qFromBigEndian<quint16>(table + 4);
+
+ quint16 fsSelection = qFromBigEndian<quint16>(table + 62);
+ fontValues.isItalic = (fsSelection & 1) != 0;
+ fontValues.isUnderlined = (fsSelection & (1 << 1)) != 0;
+ fontValues.isOverstruck = (fsSelection & (1 << 4)) != 0;
+ }
+ values->append(std::move(fontValues));
+ }
if (signatures) {
FONTSIGNATURE signature;
- getFontTable(data, font, MAKE_TAG('O', 'S', '/', '2'), &table, &length);
if (table && length >= 86) {
// Offsets taken from OS/2 table in the TrueType spec
signature.fsUsb[0] = qFromBigEndian<quint32>(table + 42);
@@ -1536,11 +1548,12 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData,
WinApplicationFont font;
font.fileName = fileName;
QVector<FONTSIGNATURE> signatures;
+ QVector<QFontValues> fontValues;
QList<QFontNames> families;
QStringList familyNames;
if (!fontData.isEmpty()) {
- getFamiliesAndSignatures(fontData, &families, &signatures);
+ getFamiliesAndSignatures(fontData, &families, &signatures, &fontValues);
if (families.isEmpty())
return familyNames;
@@ -1553,14 +1566,23 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData,
// Memory fonts won't show up in enumeration, so do add them the hard way.
for (int j = 0; j < families.count(); ++j) {
- const QString familyName = families.at(j).name;
- const QString styleName = families.at(j).style;
+ const auto &family = families.at(j);
+ const QString &familyName = family.name;
+ const QString &styleName = family.style;
familyNames << familyName;
HDC hdc = GetDC(0);
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
memcpy(lf.lfFaceName, familyName.utf16(), sizeof(wchar_t) * qMin(LF_FACESIZE - 1, familyName.size()));
lf.lfCharSet = DEFAULT_CHARSET;
+ const QFontValues &values = fontValues.at(j);
+ lf.lfWeight = values.weight;
+ if (values.isItalic)
+ lf.lfItalic = TRUE;
+ if (values.isOverstruck)
+ lf.lfStrikeOut = TRUE;
+ if (values.isUnderlined)
+ lf.lfUnderline = TRUE;
HFONT hfont = CreateFontIndirect(&lf);
HGDIOBJ oldobj = SelectObject(hdc, hfont);
@@ -1581,7 +1603,7 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData,
QByteArray data = f.readAll();
f.close();
- getFamiliesAndSignatures(data, &families, 0);
+ getFamiliesAndSignatures(data, &families, nullptr, nullptr);
if (families.isEmpty())
return QStringList();
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp
index f68ea54dcf..db2186644b 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp
@@ -115,30 +115,33 @@ static FontKeys &fontKeys()
{
static FontKeys result;
if (result.isEmpty()) {
- const QSettings fontRegistry(QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"),
- QSettings::NativeFormat);
- const QStringList allKeys = fontRegistry.allKeys();
- const QString trueType = QStringLiteral("(TrueType)");
+ const QStringList keys = { QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"),
+ QStringLiteral("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts") };
+ for (const auto key : keys) {
+ const QSettings fontRegistry(key, QSettings::NativeFormat);
+ const QStringList allKeys = fontRegistry.allKeys();
+ const QString trueType = QStringLiteral("(TrueType)");
#if QT_CONFIG(regularexpression)
- const QRegularExpression sizeListMatch(QStringLiteral("\\s(\\d+,)+\\d+"));
+ const QRegularExpression sizeListMatch(QStringLiteral("\\s(\\d+,)+\\d+"));
#else
- const QRegExp sizeListMatch(QLatin1String("\\s(\\d+,)+\\d+"));
+ const QRegExp sizeListMatch(QLatin1String("\\s(\\d+,)+\\d+"));
#endif
- Q_ASSERT(sizeListMatch.isValid());
- const int size = allKeys.size();
- result.reserve(size);
- for (int i = 0; i < size; ++i) {
- FontKey fontKey;
- const QString &registryFontKey = allKeys.at(i);
- fontKey.fileName = fontRegistry.value(registryFontKey).toString();
- QString realKey = registryFontKey;
- realKey.remove(trueType);
- realKey.remove(sizeListMatch);
- const auto fontNames = QStringRef(&realKey).trimmed().split(QLatin1Char('&'));
- fontKey.fontNames.reserve(fontNames.size());
- for (const QStringRef &fontName : fontNames)
- fontKey.fontNames.append(fontName.trimmed().toString());
- result.append(fontKey);
+ Q_ASSERT(sizeListMatch.isValid());
+ const int size = allKeys.size();
+ result.reserve(result.size() + size);
+ for (int i = 0; i < size; ++i) {
+ FontKey fontKey;
+ const QString &registryFontKey = allKeys.at(i);
+ fontKey.fileName = fontRegistry.value(registryFontKey).toString();
+ QString realKey = registryFontKey;
+ realKey.remove(trueType);
+ realKey.remove(sizeListMatch);
+ const auto fontNames = QStringRef(&realKey).trimmed().split(QLatin1Char('&'));
+ fontKey.fontNames.reserve(fontNames.size());
+ for (const QStringRef &fontName : fontNames)
+ fontKey.fontNames.append(fontName.trimmed().toString());
+ result.append(fontKey);
+ }
}
}
return result;
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h
index ab6d6307c7..b85a2dceee 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h
@@ -67,7 +67,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaFonts)
class QWindowsFontEngineData
{
- Q_DISABLE_COPY(QWindowsFontEngineData)
+ Q_DISABLE_COPY_MOVE(QWindowsFontEngineData)
public:
QWindowsFontEngineData();
~QWindowsFontEngineData();
@@ -85,7 +85,7 @@ public:
class QWindowsFontDatabase : public QPlatformFontDatabase
{
- Q_DISABLE_COPY(QWindowsFontDatabase)
+ Q_DISABLE_COPY_MOVE(QWindowsFontDatabase)
public:
enum FontOptions {
// Relevant bits from QWindowsIntegration::Options
@@ -98,7 +98,6 @@ public:
void populateFontDatabase() override;
void populateFamily(const QString &familyName) override;
- QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script) override;
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) override;
QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) override;
QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const override;
@@ -177,6 +176,14 @@ struct QFontNames
QString preferredStyle; // e.g. "Condensed Italic"
};
+struct QFontValues
+{
+ quint16 weight = 0;
+ bool isItalic = false;
+ bool isOverstruck = false;
+ bool isUnderlined = false;
+};
+
bool qt_localizedName(const QString &name);
QString qt_getEnglishName(const QString &familyName, bool includeStyle = false);
QFontNames qt_getCanonicalFontNames(const LOGFONT &lf);
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp
index 2a41209225..2ae378c558 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontengine.cpp
@@ -702,8 +702,8 @@ static inline double qt_fixed_to_double(const FIXED &p) {
return ((p.value << 16) + p.fract) / 65536.0;
}
-static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale) {
- return QPointF(qt_fixed_to_double(pt.x) * scale, -qt_fixed_to_double(pt.y) * scale);
+static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale, qreal stretch) {
+ return QPointF(qt_fixed_to_double(pt.x) * scale * stretch, -qt_fixed_to_double(pt.y) * scale);
}
#ifndef GGO_UNHINTED
@@ -711,7 +711,8 @@ static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale) {
#endif
static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
- QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0, qreal scale = 1)
+ QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0,
+ qreal scale = 1.0, qreal stretch = 1.0)
{
MAT2 mat;
mat.eM11.value = mat.eM22.value = 1;
@@ -761,7 +762,7 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
while (headerOffset < bufferSize) {
const TTPOLYGONHEADER *ttph = reinterpret_cast<const TTPOLYGONHEADER *>(dataBuffer + headerOffset);
- QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale));
+ QPointF lastPoint(qt_to_qpointf(ttph->pfxStart, scale, stretch));
path->moveTo(lastPoint + oset);
offset += sizeof(TTPOLYGONHEADER);
while (offset < headerOffset + ttph->cb) {
@@ -769,7 +770,7 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
switch (curve->wType) {
case TT_PRIM_LINE: {
for (int i=0; i<curve->cpfx; ++i) {
- QPointF p = qt_to_qpointf(curve->apfx[i], scale) + oset;
+ QPointF p = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset;
path->lineTo(p);
}
break;
@@ -779,8 +780,8 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
QPointF prev(elm.x, elm.y);
QPointF endPoint;
for (int i=0; i<curve->cpfx - 1; ++i) {
- QPointF p1 = qt_to_qpointf(curve->apfx[i], scale) + oset;
- QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale) + oset;
+ QPointF p1 = qt_to_qpointf(curve->apfx[i], scale, stretch) + oset;
+ QPointF p2 = qt_to_qpointf(curve->apfx[i+1], scale, stretch) + oset;
if (i < curve->cpfx - 2) {
endPoint = QPointF((p1.x() + p2.x()) / 2, (p1.y() + p2.y()) / 2);
} else {
@@ -795,9 +796,9 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
}
case TT_PRIM_CSPLINE: {
for (int i=0; i<curve->cpfx; ) {
- QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
- QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
- QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale) + oset;
+ QPointF p2 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
+ QPointF p3 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
+ QPointF p4 = qt_to_qpointf(curve->apfx[i++], scale, stretch) + oset;
path->cubicTo(p2, p3, p4);
}
break;
@@ -829,9 +830,11 @@ void QWindowsFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions
HDC hdc = m_fontEngineData->hdc;
HGDIOBJ oldfont = SelectObject(hdc, hf);
+ qreal scale = qreal(fontDef.pixelSize) / unitsPerEm;
+ qreal stretch = fontDef.stretch ? qreal(fontDef.stretch) / 100 : 1.0;
for(int i = 0; i < nglyphs; ++i) {
if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0,
- qreal(fontDef.pixelSize) / unitsPerEm)) {
+ scale, stretch)) {
// Some windows fonts, like "Modern", are vector stroke
// fonts, which are reported as TMPF_VECTOR but do not
// support GetGlyphOutline, and thus we set this bit so
@@ -1199,120 +1202,6 @@ void QWindowsFontEngine::initFontInfo(const QFontDef &request,
}
}
-/*!
- \class QWindowsMultiFontEngine
- \brief Standard Windows Multi font engine.
- \internal
- \ingroup qt-lighthouse-win
-
- "Merges" several font engines that have gaps in the
- supported writing systems.
-
- Will probably be superseded by a common Free Type font engine in Qt 5.X.
-*/
-QWindowsMultiFontEngine::QWindowsMultiFontEngine(QFontEngine *fe, int script)
- : QFontEngineMulti(fe, script)
-{
-}
-
-#ifndef QT_NO_DIRECTWRITE
-static QString msgDirectWriteFunctionFailed(HRESULT hr, const char *function,
- const QString &fam, const QString &substitute)
-{
- _com_error error(hr);
- QString result;
- QTextStream str(&result);
- str << function << " failed for \"" << fam << '"';
- if (substitute != fam)
- str << " (substitute: \"" << substitute << "\")";
- str << ": error " << hex << showbase << ulong(hr) << ' ' << noshowbase << dec
- << ": " << QString::fromWCharArray(error.ErrorMessage());
- return result;
-}
-#endif // !QT_NO_DIRECTWRITE
-
-QFontEngine *QWindowsMultiFontEngine::loadEngine(int at)
-{
- QFontEngine *fontEngine = engine(0);
- QSharedPointer<QWindowsFontEngineData> data;
- LOGFONT lf;
-
-#ifndef QT_NO_DIRECTWRITE
- if (fontEngine->type() == QFontEngine::DirectWrite) {
- QWindowsFontEngineDirectWrite *fe = static_cast<QWindowsFontEngineDirectWrite *>(fontEngine);
- lf = QWindowsFontDatabase::fontDefToLOGFONT(fe->fontDef, QString());
-
- data = fe->fontEngineData();
- } else
-#endif
- {
- QWindowsFontEngine *fe = static_cast<QWindowsFontEngine*>(fontEngine);
- lf = fe->m_logfont;
-
- data = fe->fontEngineData();
- }
-
- const QString fam = fallbackFamilyAt(at - 1);
- const int faceNameLength = qMin(fam.length(), LF_FACESIZE - 1);
- memcpy(lf.lfFaceName, fam.utf16(), faceNameLength * sizeof(wchar_t));
- lf.lfFaceName[faceNameLength] = 0;
-
-#ifndef QT_NO_DIRECTWRITE
- if (fontEngine->type() == QFontEngine::DirectWrite) {
- const QString nameSubstitute = QWindowsFontEngineDirectWrite::fontNameSubstitute(fam);
- if (nameSubstitute != fam) {
- const int nameSubstituteLength = qMin(nameSubstitute.length(), LF_FACESIZE - 1);
- memcpy(lf.lfFaceName, nameSubstitute.utf16(), nameSubstituteLength * sizeof(wchar_t));
- lf.lfFaceName[nameSubstituteLength] = 0;
- }
-
- HFONT hfont = CreateFontIndirect(&lf);
- if (hfont == nullptr) {
- qErrnoWarning("%s: CreateFontIndirect failed", __FUNCTION__);
- } else {
- HGDIOBJ oldFont = SelectObject(data->hdc, hfont);
-
- IDWriteFontFace *directWriteFontFace = nullptr;
- QWindowsFontEngineDirectWrite *fedw = nullptr;
- HRESULT hr = data->directWriteGdiInterop->CreateFontFaceFromHdc(data->hdc, &directWriteFontFace);
- if (SUCCEEDED(hr)) {
- Q_ASSERT(directWriteFontFace);
- fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace,
- fontEngine->fontDef.pixelSize,
- data);
- fedw->fontDef.weight = fontEngine->fontDef.weight;
- if (fontEngine->fontDef.style > QFont::StyleNormal)
- fedw->fontDef.style = fontEngine->fontDef.style;
- fedw->fontDef.family = fam;
- fedw->fontDef.hintingPreference = fontEngine->fontDef.hintingPreference;
- fedw->fontDef.stretch = fontEngine->fontDef.stretch;
- } else {
- qWarning("%s: %s", __FUNCTION__,
- qPrintable(msgDirectWriteFunctionFailed(hr, "CreateFontFace", fam, nameSubstitute)));
- }
-
- SelectObject(data->hdc, oldFont);
- DeleteObject(hfont);
-
- if (fedw != nullptr)
- return fedw;
- }
- }
-#endif
-
- // Get here if original font is not DirectWrite or DirectWrite creation failed for some
- // reason
-
- QFontEngine *fe = new QWindowsFontEngine(fam, lf, data);
- fe->fontDef.weight = fontEngine->fontDef.weight;
- if (fontEngine->fontDef.style > QFont::StyleNormal)
- fe->fontDef.style = fontEngine->fontDef.style;
- fe->fontDef.family = fam;
- fe->fontDef.hintingPreference = fontEngine->fontDef.hintingPreference;
- fe->fontDef.stretch = fontEngine->fontDef.stretch;
- return fe;
-}
-
bool QWindowsFontEngine::supportsTransformation(const QTransform &transform) const
{
// Support all transformations for ttf files, and translations for raster fonts
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h
index a151cf7343..b1b9d828ac 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontengine_p.h
@@ -66,9 +66,7 @@ class QWindowsFontEngineData;
class QWindowsFontEngine : public QFontEngine
{
- Q_DISABLE_COPY(QWindowsFontEngine)
- friend class QWindowsMultiFontEngine;
-
+ Q_DISABLE_COPY_MOVE(QWindowsFontEngine)
public:
QWindowsFontEngine(const QString &name, LOGFONT lf,
const QSharedPointer<QWindowsFontEngineData> &fontEngineData);
@@ -169,14 +167,6 @@ private:
mutable int designAdvancesSize = 0;
};
-class QWindowsMultiFontEngine : public QFontEngineMulti
-{
-public:
- explicit QWindowsMultiFontEngine(QFontEngine *fe, int script);
-
- QFontEngine *loadEngine(int at) override;
-};
-
QT_END_NAMESPACE
Q_DECLARE_METATYPE(HFONT)
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp
index 57c41938bc..60a5896e7b 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite.cpp
@@ -69,7 +69,7 @@ namespace {
class GeometrySink: public IDWriteGeometrySink
{
- Q_DISABLE_COPY(GeometrySink)
+ Q_DISABLE_COPY_MOVE(GeometrySink)
public:
GeometrySink(QPainterPath *path)
: m_refCount(0), m_path(path)
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h
index 9326f5aece..3eaf8cf3d8 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h
+++ b/src/platformsupport/fontdatabases/windows/qwindowsfontenginedirectwrite_p.h
@@ -72,7 +72,7 @@ class QWindowsFontEngineData;
class QWindowsFontEngineDirectWrite : public QFontEngine
{
- Q_DISABLE_COPY(QWindowsFontEngineDirectWrite)
+ Q_DISABLE_COPY_MOVE(QWindowsFontEngineDirectWrite)
public:
explicit QWindowsFontEngineDirectWrite(IDWriteFontFace *directWriteFontFace,
qreal pixelSize,
diff --git a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h
index 6c47a527d2..ed68ac2644 100644
--- a/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h
+++ b/src/platformsupport/fontdatabases/windows/qwindowsnativeimage_p.h
@@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE
class QWindowsNativeImage
{
- Q_DISABLE_COPY(QWindowsNativeImage)
+ Q_DISABLE_COPY_MOVE(QWindowsNativeImage)
public:
QWindowsNativeImage(int width, int height,
QImage::Format format);
diff --git a/src/platformsupport/fontdatabases/windows/windows.pri b/src/platformsupport/fontdatabases/windows/windows.pri
index 0e64084cf1..9c529f55ea 100644
--- a/src/platformsupport/fontdatabases/windows/windows.pri
+++ b/src/platformsupport/fontdatabases/windows/windows.pri
@@ -15,9 +15,14 @@ qtConfig(freetype) {
HEADERS += $$PWD/qwindowsfontdatabase_ft_p.h
}
-qtConfig(directwrite) {
- qtConfig(directwrite2): \
+qtConfig(directwrite):qtConfig(direct2d) {
+ qtConfig(directwrite2) {
+ QMAKE_USE_PRIVATE += dwrite_2
DEFINES *= QT_USE_DIRECTWRITE2
+ } else {
+ QMAKE_USE_PRIVATE += dwrite
+ }
+ QMAKE_USE_PRIVATE += d2d1
SOURCES += $$PWD/qwindowsfontenginedirectwrite.cpp
HEADERS += $$PWD/qwindowsfontenginedirectwrite_p.h
diff --git a/src/platformsupport/fontdatabases/winrt/winrt.pri b/src/platformsupport/fontdatabases/winrt/winrt.pri
index 291ada220f..7617df2e7a 100644
--- a/src/platformsupport/fontdatabases/winrt/winrt.pri
+++ b/src/platformsupport/fontdatabases/winrt/winrt.pri
@@ -8,4 +8,6 @@ HEADERS += \
DEFINES += __WRL_NO_DEFAULT_LIB__
-LIBS += -lws2_32 -ldwrite
+LIBS += -lws2_32
+
+QMAKE_USE_PRIVATE += dwrite_1