gdi32: Implement GetKerningPairs for TrueType fonts.

This commit is contained in:
Dmitry Timoshkov 2006-09-21 00:18:51 +09:00 committed by Alexandre Julliard
parent 84a6330690
commit ce6d4c72ac
3 changed files with 307 additions and 10 deletions

View File

@ -2514,11 +2514,68 @@ BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden,
* GetKerningPairsA (GDI32.@) * GetKerningPairsA (GDI32.@)
*/ */
DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs, DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
LPKERNINGPAIR lpKerningPairs ) LPKERNINGPAIR kern_pairA )
{ {
return GetKerningPairsW( hDC, cPairs, lpKerningPairs ); INT charset;
} CHARSETINFO csi;
CPINFO cpi;
DWORD i, total_kern_pairs, kern_pairs_copied = 0;
KERNINGPAIR *kern_pairW;
if (!cPairs && kern_pairA)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
charset = GetTextCharset(hDC);
if (!TranslateCharsetInfo((DWORD *)charset, &csi, TCI_SRCCHARSET))
{
FIXME("Can't find codepage for charset %d\n", charset);
return 0;
}
if (!GetCPInfo(csi.ciACP, &cpi))
{
FIXME("Can't find codepage %u info\n", csi.ciACP);
return 0;
}
TRACE("charset %d => codepage %u\n", charset, csi.ciACP);
total_kern_pairs = GetKerningPairsW(hDC, 0, NULL);
if (!total_kern_pairs) return 0;
kern_pairW = HeapAlloc(GetProcessHeap(), 0, total_kern_pairs * sizeof(*kern_pairW));
GetKerningPairsW(hDC, total_kern_pairs, kern_pairW);
for (i = 0; i < total_kern_pairs; i++)
{
char first, second;
if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wFirst, 1, &first, 1, NULL, NULL))
continue;
if (!WideCharToMultiByte(csi.ciACP, 0, &kern_pairW[i].wSecond, 1, &second, 1, NULL, NULL))
continue;
if (first == cpi.DefaultChar[0] || second == cpi.DefaultChar[0])
continue;
if (kern_pairA)
{
if (kern_pairs_copied >= cPairs) break;
kern_pairA->wFirst = (BYTE)first;
kern_pairA->wSecond = (BYTE)second;
kern_pairA->iKernAmount = kern_pairW[i].iKernAmount;
kern_pairA++;
}
kern_pairs_copied++;
}
HeapFree(GetProcessHeap(), 0, kern_pairW);
return kern_pairs_copied;
}
/************************************************************************* /*************************************************************************
* GetKerningPairsW (GDI32.@) * GetKerningPairsW (GDI32.@)
@ -2526,15 +2583,18 @@ DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs, DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
LPKERNINGPAIR lpKerningPairs ) LPKERNINGPAIR lpKerningPairs )
{ {
unsigned int i; DC *dc = DC_GetDCPtr(hDC);
FIXME("(%p,%ld,%p): almost empty stub!\n", hDC, cPairs, lpKerningPairs); DWORD ret = 0;
if(!lpKerningPairs) /* return the number of kerning pairs */ TRACE("(%p,%ld,%p)\n", hDC, cPairs, lpKerningPairs);
return 0;
for (i = 0; i < cPairs; i++) if (!dc) return 0;
lpKerningPairs[i].iKernAmount = 0;
return 0; if (dc->gdiFont)
ret = WineEngGetKerningPairs(dc->gdiFont, cPairs, lpKerningPairs);
GDI_ReleaseObj(hDC);
return ret;
} }
/************************************************************************* /*************************************************************************

View File

@ -2,6 +2,7 @@
* FreeType font engine interface * FreeType font engine interface
* *
* Copyright 2001 Huw D M Davies for CodeWeavers. * Copyright 2001 Huw D M Davies for CodeWeavers.
* Copyright 2006 Dmitry Timoshkov for CodeWeavers.
* *
* This file contains the WineEng* functions. * This file contains the WineEng* functions.
* *
@ -134,6 +135,7 @@ MAKE_FUNCPTR(FT_Vector_Transform);
static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*); static void (*pFT_Library_Version)(FT_Library,FT_Int*,FT_Int*,FT_Int*);
static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*); static FT_Error (*pFT_Load_Sfnt_Table)(FT_Face,FT_ULong,FT_Long,FT_Byte*,FT_ULong*);
static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*); static FT_ULong (*pFT_Get_First_Char)(FT_Face,FT_UInt*);
static FT_ULong (*pFT_Get_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library); static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
#ifdef HAVE_FREETYPE_FTWINFNT_H #ifdef HAVE_FREETYPE_FTWINFNT_H
MAKE_FUNCPTR(FT_Get_WinFNT_Header); MAKE_FUNCPTR(FT_Get_WinFNT_Header);
@ -268,6 +270,8 @@ struct tagGdiFont {
SHORT yMax; SHORT yMax;
SHORT yMin; SHORT yMin;
OUTLINETEXTMETRICW *potm; OUTLINETEXTMETRICW *potm;
DWORD total_kern_pairs;
KERNINGPAIR *kern_pairs;
FONTSIGNATURE fs; FONTSIGNATURE fs;
GdiFont base_font; GdiFont base_font;
struct list child_fonts; struct list child_fonts;
@ -1652,6 +1656,7 @@ BOOL WineEngInit(void)
pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0); pFT_Library_Version = wine_dlsym(ft_handle, "FT_Library_Version", NULL, 0);
pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0); pFT_Load_Sfnt_Table = wine_dlsym(ft_handle, "FT_Load_Sfnt_Table", NULL, 0);
pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0); pFT_Get_First_Char = wine_dlsym(ft_handle, "FT_Get_First_Char", NULL, 0);
pFT_Get_Next_Char = wine_dlsym(ft_handle, "FT_Get_Next_Char", NULL, 0);
pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0); pFT_Get_TrueType_Engine_Type = wine_dlsym(ft_handle, "FT_Get_TrueType_Engine_Type", NULL, 0);
#ifdef HAVE_FREETYPE_FTWINFNT_H #ifdef HAVE_FREETYPE_FTWINFNT_H
pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0); pFT_Get_WinFNT_Header = wine_dlsym(ft_handle, "FT_Get_WinFNT_Header", NULL, 0);
@ -1938,6 +1943,8 @@ static GdiFont alloc_font(void)
ret->gmsize * sizeof(*ret->gm)); ret->gmsize * sizeof(*ret->gm));
ret->potm = NULL; ret->potm = NULL;
ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0; ret->font_desc.matrix.eM11 = ret->font_desc.matrix.eM22 = 1.0;
ret->total_kern_pairs = (DWORD)-1;
ret->kern_pairs = NULL;
list_init(&ret->hfontlist); list_init(&ret->hfontlist);
list_init(&ret->child_fonts); list_init(&ret->child_fonts);
return ret; return ret;
@ -1966,6 +1973,7 @@ static void free_font(GdiFont font)
} }
if (font->ft_face) pFT_Done_Face(font->ft_face); if (font->ft_face) pFT_Done_Face(font->ft_face);
HeapFree(GetProcessHeap(), 0, font->kern_pairs);
HeapFree(GetProcessHeap(), 0, font->potm); HeapFree(GetProcessHeap(), 0, font->potm);
HeapFree(GetProcessHeap(), 0, font->name); HeapFree(GetProcessHeap(), 0, font->name);
HeapFree(GetProcessHeap(), 0, font->gm); HeapFree(GetProcessHeap(), 0, font->gm);
@ -4096,6 +4104,228 @@ BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
return TRUE; return TRUE;
} }
/*************************************************************************
* Kerning support for TrueType fonts
*/
#define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n')
struct TT_kern_table
{
USHORT version;
USHORT nTables;
};
struct TT_kern_subtable
{
USHORT version;
USHORT length;
union
{
USHORT word;
struct
{
USHORT horizontal : 1;
USHORT minimum : 1;
USHORT cross_stream: 1;
USHORT override : 1;
USHORT reserved1 : 4;
USHORT format : 8;
} bits;
} coverage;
};
struct TT_format0_kern_subtable
{
USHORT nPairs;
USHORT searchRange;
USHORT entrySelector;
USHORT rangeShift;
};
struct TT_kern_pair
{
USHORT left;
USHORT right;
short value;
};
static DWORD parse_format0_kern_subtable(GdiFont font,
const struct TT_format0_kern_subtable *tt_f0_ks,
const USHORT *glyph_to_char,
KERNINGPAIR *kern_pair, DWORD cPairs)
{
USHORT i, nPairs;
const struct TT_kern_pair *tt_kern_pair;
TRACE("font height %ld, units_per_EM %d\n", font->ppem, font->ft_face->units_per_EM);
nPairs = GET_BE_WORD(tt_f0_ks->nPairs);
TRACE("nPairs %u, searchRange %u, entrySelector %u, rangeShift %u\n",
nPairs, GET_BE_WORD(tt_f0_ks->searchRange),
GET_BE_WORD(tt_f0_ks->entrySelector), GET_BE_WORD(tt_f0_ks->rangeShift));
if (!kern_pair || !cPairs)
return nPairs;
tt_kern_pair = (const struct TT_kern_pair *)(tt_f0_ks + 1);
nPairs = min(nPairs, cPairs);
for (i = 0; i < nPairs; i++)
{
kern_pair->wFirst = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].left)];
kern_pair->wSecond = glyph_to_char[GET_BE_WORD(tt_kern_pair[i].right)];
kern_pair->iKernAmount = MulDiv((short)GET_BE_WORD(tt_kern_pair[i].value), font->ppem, font->ft_face->units_per_EM);
TRACE("left %u right %u value %d\n",
kern_pair->wFirst, kern_pair->wSecond, kern_pair->iKernAmount);
kern_pair++;
}
TRACE("copied %u entries\n", nPairs);
return nPairs;
}
DWORD WineEngGetKerningPairs(GdiFont font, DWORD cPairs, KERNINGPAIR *kern_pair)
{
DWORD length;
void *buf;
const struct TT_kern_table *tt_kern_table;
const struct TT_kern_subtable *tt_kern_subtable;
USHORT i, nTables;
USHORT *glyph_to_char;
if (font->total_kern_pairs != (DWORD)-1)
{
if (cPairs && kern_pair)
{
cPairs = min(cPairs, font->total_kern_pairs);
memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
return cPairs;
}
return font->total_kern_pairs;
}
font->total_kern_pairs = 0;
length = WineEngGetFontData(font, MS_KERN_TAG, 0, NULL, 0);
if (length == GDI_ERROR)
{
TRACE("no kerning data in the font\n");
return 0;
}
buf = HeapAlloc(GetProcessHeap(), 0, length);
if (!buf)
{
WARN("Out of memory\n");
return 0;
}
WineEngGetFontData(font, MS_KERN_TAG, 0, buf, length);
/* build a glyph index to char code map */
glyph_to_char = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(USHORT) * 65536);
if (!glyph_to_char)
{
WARN("Out of memory allocating a glyph index to char code map\n");
HeapFree(GetProcessHeap(), 0, buf);
return 0;
}
if (font->ft_face->charmap->encoding == FT_ENCODING_UNICODE && pFT_Get_First_Char)
{
FT_UInt glyph_code;
FT_ULong char_code;
glyph_code = 0;
char_code = pFT_Get_First_Char(font->ft_face, &glyph_code);
TRACE("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %lu\n",
font->ft_face->num_glyphs, glyph_code, char_code);
while (glyph_code)
{
/*TRACE("Char %04lX -> Index %u%s\n", char_code, glyph_code, glyph_to_char[glyph_code] ? " !" : "" );*/
/* FIXME: This doesn't match what Windows does: it does some fancy
* things with duplicate glyph index to char code mappings, while
* we just avoid overriding existing entries.
*/
if (glyph_code <= 65535 && !glyph_to_char[glyph_code])
glyph_to_char[glyph_code] = (USHORT)char_code;
char_code = pFT_Get_Next_Char(font->ft_face, char_code, &glyph_code);
}
}
else
{
ULONG n;
FIXME("encoding %u not supported\n", font->ft_face->charmap->encoding);
for (n = 0; n <= 65535; n++)
glyph_to_char[n] = (USHORT)n;
}
tt_kern_table = buf;
nTables = GET_BE_WORD(tt_kern_table->nTables);
TRACE("version %u, nTables %u\n",
GET_BE_WORD(tt_kern_table->version), nTables);
tt_kern_subtable = (const struct TT_kern_subtable *)(tt_kern_table + 1);
for (i = 0; i < nTables; i++)
{
struct TT_kern_subtable tt_kern_subtable_copy;
tt_kern_subtable_copy.version = GET_BE_WORD(tt_kern_subtable->version);
tt_kern_subtable_copy.length = GET_BE_WORD(tt_kern_subtable->length);
tt_kern_subtable_copy.coverage.word = GET_BE_WORD(tt_kern_subtable->coverage.word);
TRACE("version %u, length %u, coverage %u, subtable format %u\n",
tt_kern_subtable_copy.version, tt_kern_subtable_copy.length,
tt_kern_subtable_copy.coverage.word, tt_kern_subtable_copy.coverage.bits.format);
/* According to the TrueType specification this is the only format
* that will be properly interpreted by Windows and OS/2
*/
if (tt_kern_subtable_copy.coverage.bits.format == 0)
{
DWORD new_chunk, old_total = font->total_kern_pairs;
new_chunk = parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
glyph_to_char, NULL, 0);
font->total_kern_pairs += new_chunk;
if (!font->kern_pairs)
font->kern_pairs = HeapAlloc(GetProcessHeap(), 0,
font->total_kern_pairs * sizeof(*font->kern_pairs));
else
font->kern_pairs = HeapReAlloc(GetProcessHeap(), 0, font->kern_pairs,
font->total_kern_pairs * sizeof(*font->kern_pairs));
parse_format0_kern_subtable(font, (const struct TT_format0_kern_subtable *)(tt_kern_subtable + 1),
glyph_to_char, font->kern_pairs + old_total, new_chunk);
}
else
TRACE("skipping kerning table format %u\n", tt_kern_subtable_copy.coverage.bits.format);
tt_kern_subtable = (const struct TT_kern_subtable *)((const char *)tt_kern_subtable + tt_kern_subtable_copy.length);
}
HeapFree(GetProcessHeap(), 0, glyph_to_char);
HeapFree(GetProcessHeap(), 0, buf);
if (cPairs && kern_pair)
{
cPairs = min(cPairs, font->total_kern_pairs);
memcpy(kern_pair, font->kern_pairs, cPairs * sizeof(*kern_pair));
return cPairs;
}
return font->total_kern_pairs;
}
#else /* HAVE_FREETYPE */ #else /* HAVE_FREETYPE */
@ -4233,4 +4463,10 @@ BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
return TRUE; return TRUE;
} }
DWORD WineEngGetKerningPairs(GdiFont font, DWORD cPairs, KERNINGPAIR *kern_pair)
{
ERR("called but we don't have FreeType\n");
return 0;
}
#endif /* HAVE_FREETYPE */ #endif /* HAVE_FREETYPE */

View File

@ -376,6 +376,7 @@ extern DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
extern DWORD WineEngGetGlyphOutline(GdiFont, UINT glyph, UINT format, extern DWORD WineEngGetGlyphOutline(GdiFont, UINT glyph, UINT format,
LPGLYPHMETRICS, DWORD buflen, LPVOID buf, LPGLYPHMETRICS, DWORD buflen, LPVOID buf,
const MAT2*); const MAT2*);
extern DWORD WineEngGetKerningPairs(GdiFont, DWORD, KERNINGPAIR *);
extern BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph); extern BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph);
extern UINT WineEngGetOutlineTextMetrics(GdiFont, UINT, LPOUTLINETEXTMETRICW); extern UINT WineEngGetOutlineTextMetrics(GdiFont, UINT, LPOUTLINETEXTMETRICW);
extern UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags); extern UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags);