diff options
Diffstat (limited to 'src/platformsupport/fontdatabases')
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 ®istryFontKey = 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 ®istryFontKey = 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 |