diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 36df1aad22d..4eed73c1f0e 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -286,7 +286,7 @@ extern INT32 freetype_get_kerning_pair_adjustment(IDWriteFontFace4*,UINT16,UINT1 extern void freetype_get_glyph_bbox(struct dwrite_glyphbitmap*) DECLSPEC_HIDDEN; extern BOOL freetype_get_glyph_bitmap(struct dwrite_glyphbitmap*) DECLSPEC_HIDDEN; extern INT freetype_get_charmap_index(IDWriteFontFace4*,BOOL*) DECLSPEC_HIDDEN; -extern INT32 freetype_get_glyph_advance(IDWriteFontFace4*,FLOAT,UINT16,DWRITE_MEASURING_MODE) DECLSPEC_HIDDEN; +extern INT32 freetype_get_glyph_advance(IDWriteFontFace4*,FLOAT,UINT16,DWRITE_MEASURING_MODE,BOOL*) DECLSPEC_HIDDEN; extern void freetype_get_design_glyph_bbox(IDWriteFontFace4*,UINT16,UINT16,RECT*) DECLSPEC_HIDDEN; /* Glyph shaping */ diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index 01719a3dca6..cf9ca3f8541 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -739,11 +739,20 @@ static inline int round_metric(FLOAT metric) return (int)floorf(metric + 0.5f); } +static UINT32 fontface_get_horz_metric_adjustment(const struct dwrite_fontface *fontface) +{ + if (!(fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD)) + return 0; + + return (fontface->metrics.designUnitsPerEm + 49) / 50; +} + static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFace4 *iface, FLOAT emSize, FLOAT ppdip, DWRITE_MATRIX const *m, BOOL use_gdi_natural, UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *metrics, BOOL is_sideways) { struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface); + UINT32 adjustment = fontface_get_horz_metric_adjustment(This); DWRITE_MEASURING_MODE mode; FLOAT scale, size; HRESULT hr; @@ -762,13 +771,17 @@ static HRESULT WINAPI dwritefontface_GetGdiCompatibleGlyphMetrics(IDWriteFontFac for (i = 0; i < glyph_count; i++) { DWRITE_GLYPH_METRICS *ret = metrics + i; DWRITE_GLYPH_METRICS design; + BOOL has_contours; hr = IDWriteFontFace4_GetDesignGlyphMetrics(iface, glyphs + i, 1, &design, is_sideways); if (FAILED(hr)) return hr; - ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode); - ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size); + ret->advanceWidth = freetype_get_glyph_advance(iface, size, glyphs[i], mode, &has_contours); + if (has_contours) + ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size + adjustment); + else + ret->advanceWidth = round_metric(ret->advanceWidth * This->metrics.designUnitsPerEm / size); #define SCALE_METRIC(x) ret->x = round_metric(round_metric((design.x) * scale) / scale) SCALE_METRIC(leftSideBearing); @@ -878,6 +891,7 @@ static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace4 *i UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances, BOOL is_sideways) { struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface); + UINT32 adjustment = fontface_get_horz_metric_adjustment(This); UINT32 i; TRACE("(%p)->(%u %p %p %d)\n", This, glyph_count, glyphs, advances, is_sideways); @@ -885,8 +899,14 @@ static HRESULT WINAPI dwritefontface1_GetDesignGlyphAdvances(IDWriteFontFace4 *i if (is_sideways) FIXME("sideways mode not supported\n"); - for (i = 0; i < glyph_count; i++) - advances[i] = freetype_get_glyph_advance(iface, This->metrics.designUnitsPerEm, glyphs[i], DWRITE_MEASURING_MODE_NATURAL); + for (i = 0; i < glyph_count; i++) { + BOOL has_contours; + + advances[i] = freetype_get_glyph_advance(iface, This->metrics.designUnitsPerEm, glyphs[i], + DWRITE_MEASURING_MODE_NATURAL, &has_contours); + if (has_contours) + advances[i] += adjustment; + } return S_OK; } @@ -896,6 +916,7 @@ static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontF BOOL is_sideways, UINT32 glyph_count, UINT16 const *glyphs, INT32 *advances) { struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface); + UINT32 adjustment = fontface_get_horz_metric_adjustment(This); DWRITE_MEASURING_MODE mode; UINT32 i; @@ -918,8 +939,13 @@ static HRESULT WINAPI dwritefontface1_GetGdiCompatibleGlyphAdvances(IDWriteFontF mode = use_gdi_natural ? DWRITE_MEASURING_MODE_GDI_NATURAL : DWRITE_MEASURING_MODE_GDI_CLASSIC; for (i = 0; i < glyph_count; i++) { - advances[i] = freetype_get_glyph_advance(iface, em_size, glyphs[i], mode); - advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size); + BOOL has_contours; + + advances[i] = freetype_get_glyph_advance(iface, em_size, glyphs[i], mode, &has_contours); + if (has_contours) + advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size + adjustment); + else + advances[i] = round_metric(advances[i] * This->metrics.designUnitsPerEm / em_size); } return S_OK; diff --git a/dlls/dwrite/freetype.c b/dlls/dwrite/freetype.c index 35a7ebfd892..2c348515430 100644 --- a/dlls/dwrite/freetype.c +++ b/dlls/dwrite/freetype.c @@ -1,7 +1,7 @@ /* * FreeType integration * - * Copyright 2014-2015 Nikolay Sivov for CodeWeavers + * Copyright 2014-2017 Nikolay Sivov for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -79,6 +79,7 @@ MAKE_FUNCPTR(FT_New_Memory_Face); MAKE_FUNCPTR(FT_Outline_Copy); MAKE_FUNCPTR(FT_Outline_Decompose); MAKE_FUNCPTR(FT_Outline_Done); +MAKE_FUNCPTR(FT_Outline_Embolden); MAKE_FUNCPTR(FT_Outline_Get_Bitmap); MAKE_FUNCPTR(FT_Outline_New); MAKE_FUNCPTR(FT_Outline_Transform); @@ -93,6 +94,7 @@ MAKE_FUNCPTR(FTC_Manager_LookupFace); MAKE_FUNCPTR(FTC_Manager_LookupSize); MAKE_FUNCPTR(FTC_Manager_RemoveFaceID); #undef MAKE_FUNCPTR +static FT_Error (*pFT_Outline_EmboldenXY)(FT_Outline *, FT_Pos, FT_Pos); struct face_finalizer_data { @@ -200,6 +202,7 @@ BOOL init_freetype(void) LOAD_FUNCPTR(FT_Outline_Copy) LOAD_FUNCPTR(FT_Outline_Decompose) LOAD_FUNCPTR(FT_Outline_Done) + LOAD_FUNCPTR(FT_Outline_Embolden) LOAD_FUNCPTR(FT_Outline_Get_Bitmap) LOAD_FUNCPTR(FT_Outline_New) LOAD_FUNCPTR(FT_Outline_Transform) @@ -214,6 +217,7 @@ BOOL init_freetype(void) LOAD_FUNCPTR(FTC_Manager_LookupSize) LOAD_FUNCPTR(FTC_Manager_RemoveFaceID) #undef LOAD_FUNCPTR + pFT_Outline_EmboldenXY = wine_dlsym(ft_handle, "FT_Outline_EmboldenXY", NULL, 0); if (pFT_Init_FreeType(&library) != 0) { ERR("Can't init FreeType library\n"); @@ -274,6 +278,7 @@ HRESULT freetype_get_design_glyph_metrics(IDWriteFontFace4 *fontface, UINT16 uni EnterCriticalSection(&freetype_cs); if (pFTC_Manager_LookupSize(cache_manager, &scaler, &size) == 0) { if (pFT_Load_Glyph(size->face, glyph, FT_LOAD_NO_SCALE) == 0) { + USHORT simulations = IDWriteFontFace4_GetSimulations(fontface); FT_Glyph_Metrics *metrics = &size->face->glyph->metrics; ret->leftSideBearing = metrics->horiBearingX; @@ -283,6 +288,13 @@ HRESULT freetype_get_design_glyph_metrics(IDWriteFontFace4 *fontface, UINT16 uni ret->advanceHeight = metrics->vertAdvance; ret->bottomSideBearing = metrics->vertAdvance - metrics->vertBearingY - metrics->height; ret->verticalOriginY = metrics->height + metrics->vertBearingY; + + /* Adjust in case of bold simulation, glyphs without contours are ignored. */ + if (simulations & DWRITE_FONT_SIMULATIONS_BOLD && size->face->glyph->format == FT_GLYPH_FORMAT_OUTLINE && + size->face->glyph->outline.n_contours != 0) { + if (ret->advanceWidth) + ret->advanceWidth += (unitsperEm + 49) / 50; + } } } LeaveCriticalSection(&freetype_cs); @@ -447,8 +459,29 @@ static void decompose_outline(FT_Outline *outline, FLOAT xoffset, FLOAT yoffset, ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED); } -HRESULT freetype_get_glyphrun_outline(IDWriteFontFace4 *fontface, FLOAT emSize, UINT16 const *glyphs, FLOAT const *advances, - DWRITE_GLYPH_OFFSET const *offsets, UINT32 count, BOOL is_rtl, IDWriteGeometrySink *sink) +static void embolden_glyph_outline(FT_Outline *outline, FLOAT emsize) +{ + FT_Pos strength; + + strength = MulDiv(emsize, 1 << 6, 24); + if (pFT_Outline_EmboldenXY) + pFT_Outline_EmboldenXY(outline, strength, 0); + else + pFT_Outline_Embolden(outline, strength); +} + +static void embolden_glyph(FT_Glyph glyph, FLOAT emsize) +{ + FT_OutlineGlyph outline_glyph = (FT_OutlineGlyph)glyph; + + if (glyph->format != FT_GLYPH_FORMAT_OUTLINE) + return; + + embolden_glyph_outline(&outline_glyph->outline, emsize); +} + +HRESULT freetype_get_glyphrun_outline(IDWriteFontFace4 *fontface, FLOAT emSize, UINT16 const *glyphs, + FLOAT const *advances, DWRITE_GLYPH_OFFSET const *offsets, UINT32 count, BOOL is_rtl, IDWriteGeometrySink *sink) { FTC_ScalerRec scaler; USHORT simulations; @@ -481,6 +514,9 @@ HRESULT freetype_get_glyphrun_outline(IDWriteFontFace4 *fontface, FLOAT emSize, FLOAT xoffset = 0.0f, yoffset = 0.0f; FT_Matrix m; + if (simulations & DWRITE_FONT_SIMULATIONS_BOLD) + embolden_glyph_outline(outline, emSize); + m.xx = 1 << 16; m.xy = simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE ? (1 << 16) / 3 : 0; m.yx = 0; @@ -610,8 +646,7 @@ static BOOL get_glyph_transform(struct dwrite_glyphbitmap *bitmap, FT_Matrix *re /* Some fonts provide mostly bitmaps and very few outlines, for example for .notdef. Disable transform if that's the case. */ - if (!(is_face_scalable(bitmap->fontface) && (bitmap->m || - (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE)))) + if (!is_face_scalable(bitmap->fontface) || (!bitmap->m && simulations == 0)) return FALSE; if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) { @@ -632,6 +667,7 @@ static BOOL get_glyph_transform(struct dwrite_glyphbitmap *bitmap, FT_Matrix *re void freetype_get_glyph_bbox(struct dwrite_glyphbitmap *bitmap) { + USHORT simulations = IDWriteFontFace4_GetSimulations(bitmap->fontface); FTC_ImageTypeRec imagetype; FT_BBox bbox = { 0 }; BOOL needs_transform; @@ -652,7 +688,12 @@ void freetype_get_glyph_bbox(struct dwrite_glyphbitmap *bitmap) FT_Glyph glyph_copy; if (pFT_Glyph_Copy(glyph, &glyph_copy) == 0) { - pFT_Glyph_Transform(glyph_copy, &m, NULL); + if (simulations & DWRITE_FONT_SIMULATIONS_BOLD) + embolden_glyph(glyph_copy, bitmap->emsize); + + if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) + pFT_Glyph_Transform(glyph_copy, &m, NULL); + pFT_Glyph_Get_CBox(glyph_copy, FT_GLYPH_BBOX_PIXELS, &bbox); pFT_Done_Glyph(glyph_copy); } @@ -786,6 +827,7 @@ static BOOL freetype_get_aa_glyph_bitmap(struct dwrite_glyphbitmap *bitmap, FT_G BOOL freetype_get_glyph_bitmap(struct dwrite_glyphbitmap *bitmap) { + USHORT simulations = IDWriteFontFace4_GetSimulations(bitmap->fontface); FTC_ImageTypeRec imagetype; BOOL needs_transform; BOOL ret = FALSE; @@ -806,7 +848,11 @@ BOOL freetype_get_glyph_bitmap(struct dwrite_glyphbitmap *bitmap) if (needs_transform) { if (pFT_Glyph_Copy(glyph, &glyph_copy) == 0) { - pFT_Glyph_Transform(glyph_copy, &m, NULL); + if (simulations & DWRITE_FONT_SIMULATIONS_BOLD) + embolden_glyph(glyph_copy, bitmap->emsize); + + if (simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) + pFT_Glyph_Transform(glyph_copy, &m, NULL); glyph = glyph_copy; } } @@ -859,7 +905,8 @@ INT freetype_get_charmap_index(IDWriteFontFace4 *fontface, BOOL *is_symbol) return charmap_index; } -INT32 freetype_get_glyph_advance(IDWriteFontFace4 *fontface, FLOAT emSize, UINT16 index, DWRITE_MEASURING_MODE mode) +INT32 freetype_get_glyph_advance(IDWriteFontFace4 *fontface, FLOAT emSize, UINT16 index, DWRITE_MEASURING_MODE mode, + BOOL *has_contours) { FTC_ImageTypeRec imagetype; FT_Glyph glyph; @@ -873,10 +920,14 @@ INT32 freetype_get_glyph_advance(IDWriteFontFace4 *fontface, FLOAT emSize, UINT1 imagetype.flags |= FT_LOAD_NO_HINTING; EnterCriticalSection(&freetype_cs); - if (pFTC_ImageCache_Lookup(image_cache, &imagetype, index, &glyph, NULL) == 0) + if (pFTC_ImageCache_Lookup(image_cache, &imagetype, index, &glyph, NULL) == 0) { + *has_contours = glyph->format == FT_GLYPH_FORMAT_OUTLINE && ((FT_OutlineGlyph)glyph)->outline.n_contours; advance = glyph->advance.x >> 16; - else + } + else { + *has_contours = FALSE; advance = 0; + } LeaveCriticalSection(&freetype_cs); return advance; @@ -955,8 +1006,10 @@ INT freetype_get_charmap_index(IDWriteFontFace4 *fontface, BOOL *is_symbol) return -1; } -INT32 freetype_get_glyph_advance(IDWriteFontFace4 *fontface, FLOAT emSize, UINT16 index, DWRITE_MEASURING_MODE mode) +INT32 freetype_get_glyph_advance(IDWriteFontFace4 *fontface, FLOAT emSize, UINT16 index, DWRITE_MEASURING_MODE mode, + BOOL *has_contours) { + *has_contours = FALSE; return 0; }