diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-09-22 14:54:39 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-10 22:09:21 +0000 |
commit | e48b85408752725bd9e90f303354bcdd380b3448 (patch) | |
tree | aaebb2aaf18570f362a04990e170fffec6295c03 /src/platformsupport/fontdatabases/freetype | |
parent | b179abc33b7111e889ca45f48f0ddd5c0182fa2e (diff) |
Simplify freetype rendering
Switch to always using FT_Render_Glyph for all glyph types.
Change-Id: I9427bbffd30a8d1ca92d7ab9a92df8761f6b89c3
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/platformsupport/fontdatabases/freetype')
-rw-r--r-- | src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp | 324 |
1 files changed, 74 insertions, 250 deletions
diff --git a/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp b/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp index 381db1ed12..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,7 +565,6 @@ 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++ = (0xFFU << 24) | (red << 16) | (green << 8) | blue; } dst += width; @@ -598,16 +572,7 @@ static void convertRGBToARGB_helper(const uchar *src, uint *dst, int width, int } } -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++ = (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++ = (0xFFU << 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; |