diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index f23761271b2..2578f33b8cc 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -3326,9 +3326,19 @@ BOOL WINAPI GetCharWidthI(HDC hdc, UINT first, UINT count, LPWORD glyphs, LPINT /*********************************************************************** * GetFontUnicodeRanges (GDI32.@) + * + * Retrieve a list of supported Unicode characters in a font. + * + * PARAMS + * hdc [I] Handle to a device context. + * lpgs [O] GLYPHSET structure specifying supported character ranges. + * + * RETURNS + * Success: Number of bytes written to the buffer pointed to by lpgs. + * Failure: 0 + * */ DWORD WINAPI GetFontUnicodeRanges(HDC hdc, LPGLYPHSET lpgs) { - FIXME("(%p, %p): stub\n", hdc, lpgs); - return 0; + return WineEngGetFontUnicodeRanges(hdc, lpgs); } diff --git a/dlls/gdi32/freetype.c b/dlls/gdi32/freetype.c index abcc0e6768f..f3676afb414 100644 --- a/dlls/gdi32/freetype.c +++ b/dlls/gdi32/freetype.c @@ -4398,6 +4398,91 @@ BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph) return ret; } +/* Retrieve a list of supported Unicode ranges for a given font. + * Can be called with NULL gs to calculate the buffer size. Returns + * the number of ranges found. + */ +static DWORD get_font_unicode_ranges(FT_Face face, GLYPHSET *gs) +{ + DWORD num_ranges = 0; + + if (face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char) + { + FT_UInt glyph_code; + FT_ULong char_code, char_code_prev; + + glyph_code = 0; + char_code_prev = char_code = pFT_Get_First_Char(face, &glyph_code); + + TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n", + face->num_glyphs, glyph_code, char_code); + + if (!glyph_code) return 0; + + if (gs) + { + gs->ranges[0].wcLow = (USHORT)char_code; + gs->ranges[0].cGlyphs = 0; + gs->cGlyphsSupported = 0; + } + + num_ranges = 1; + while (glyph_code) + { + if (char_code < char_code_prev) + { + ERR("expected increasing char code from FT_Get_Next_Char\n"); + return 0; + } + if (char_code - char_code_prev > 1) + { + num_ranges++; + if (gs) + { + gs->ranges[num_ranges - 1].wcLow = (USHORT)char_code; + gs->ranges[num_ranges - 1].cGlyphs = 1; + gs->cGlyphsSupported++; + } + } + else if (gs) + { + gs->ranges[num_ranges - 1].cGlyphs++; + gs->cGlyphsSupported++; + } + char_code_prev = char_code; + char_code = pFT_Get_Next_Char(face, char_code, &glyph_code); + } + } + else + FIXME("encoding %u not supported\n", face->charmap->encoding); + + return num_ranges; +} + +DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset) +{ + DWORD size = 0; + DC *dc = DC_GetDCPtr(hdc); + + TRACE("(%p, %p)\n", hdc, glyphset); + + if (!dc) return 0; + + if (dc->gdiFont) + { + DWORD num_ranges = get_font_unicode_ranges(dc->gdiFont->ft_face, glyphset); + + size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1); + if (glyphset) + { + glyphset->cbThis = size; + glyphset->cRanges = num_ranges; + } + } + + GDI_ReleaseObj(hdc); + return size; +} /************************************************************* * FontIsLinked @@ -4813,6 +4898,12 @@ BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph) return FALSE; } +DWORD WineEngGetFontUnicodeRanges(HDC hdc, LPGLYPHSET glyphset) +{ + FIXME("(%p, %p): stub\n", hdc, glyphset); + return 0; +} + BOOL WINAPI FontIsLinked(HDC hdc) { return FALSE; diff --git a/dlls/gdi32/gdi_private.h b/dlls/gdi32/gdi_private.h index 07e9d4975b4..e43ac30712d 100644 --- a/dlls/gdi32/gdi_private.h +++ b/dlls/gdi32/gdi_private.h @@ -423,6 +423,7 @@ extern BOOL WineEngGetCharABCWidthsI(GdiFont *font, UINT firstChar, UINT count, LPWORD pgi, LPABC buffer); extern BOOL WineEngGetCharWidth(GdiFont*, UINT, UINT, LPINT); extern DWORD WineEngGetFontData(GdiFont*, DWORD, DWORD, LPVOID, DWORD); +extern DWORD WineEngGetFontUnicodeRanges(HDC, LPGLYPHSET); extern DWORD WineEngGetGlyphIndices(GdiFont *font, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags); extern DWORD WineEngGetGlyphOutline(GdiFont*, UINT glyph, UINT format, diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index 0a9f8d36a64..405d4bd61d6 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -1088,6 +1088,43 @@ static void test_font_charset(void) skip("Symbol or Wingdings is not installed\n"); } +static void test_GetFontUnicodeRanges(void) +{ + LOGFONTA lf; + HDC hdc; + HFONT hfont, hfont_old; + DWORD size, i; + GLYPHSET *gs; + + memset(&lf, 0, sizeof(lf)); + lstrcpyA(lf.lfFaceName, "Arial"); + hfont = create_font("Arial", &lf); + + hdc = GetDC(0); + hfont_old = SelectObject(hdc, hfont); + + size = GetFontUnicodeRanges(NULL, NULL); + ok(!size, "GetFontUnicodeRanges succeeded unexpectedly\n"); + + size = GetFontUnicodeRanges(hdc, NULL); + ok(size, "GetFontUnicodeRanges failed unexpectedly\n"); + + gs = HeapAlloc(GetProcessHeap(), 0, size); + + size = GetFontUnicodeRanges(hdc, gs); + ok(size, "GetFontUnicodeRanges failed\n"); + + for (i = 0; i < gs->cRanges; i++) + trace("%03d wcLow %04x cGlyphs %u\n", i, gs->ranges[i].wcLow, gs->ranges[i].cGlyphs); + trace("found %u ranges\n", gs->cRanges); + + HeapFree(GetProcessHeap(), 0, gs); + + SelectObject(hdc, hfont_old); + DeleteObject(hfont); + ReleaseDC(NULL, hdc); +} + START_TEST(font) { test_logfont(); @@ -1101,4 +1138,5 @@ START_TEST(font) test_GetOutlineTextMetrics(); test_SetTextJustification(); test_font_charset(); + test_GetFontUnicodeRanges(); }