gdi32: Implement GetKerningPairs for TrueType fonts.
This commit is contained in:
parent
84a6330690
commit
ce6d4c72ac
|
@ -2514,11 +2514,68 @@ BOOL WINAPI CreateScalableFontResourceW( DWORD fHidden,
|
|||
* GetKerningPairsA (GDI32.@)
|
||||
*/
|
||||
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.@)
|
||||
|
@ -2526,15 +2583,18 @@ DWORD WINAPI GetKerningPairsA( HDC hDC, DWORD cPairs,
|
|||
DWORD WINAPI GetKerningPairsW( HDC hDC, DWORD cPairs,
|
||||
LPKERNINGPAIR lpKerningPairs )
|
||||
{
|
||||
unsigned int i;
|
||||
FIXME("(%p,%ld,%p): almost empty stub!\n", hDC, cPairs, lpKerningPairs);
|
||||
DC *dc = DC_GetDCPtr(hDC);
|
||||
DWORD ret = 0;
|
||||
|
||||
if(!lpKerningPairs) /* return the number of kerning pairs */
|
||||
return 0;
|
||||
TRACE("(%p,%ld,%p)\n", hDC, cPairs, lpKerningPairs);
|
||||
|
||||
for (i = 0; i < cPairs; i++)
|
||||
lpKerningPairs[i].iKernAmount = 0;
|
||||
return 0;
|
||||
if (!dc) return 0;
|
||||
|
||||
if (dc->gdiFont)
|
||||
ret = WineEngGetKerningPairs(dc->gdiFont, cPairs, lpKerningPairs);
|
||||
|
||||
GDI_ReleaseObj(hDC);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* FreeType font engine interface
|
||||
*
|
||||
* Copyright 2001 Huw D M Davies for CodeWeavers.
|
||||
* Copyright 2006 Dmitry Timoshkov for CodeWeavers.
|
||||
*
|
||||
* 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 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_Next_Char)(FT_Face,FT_ULong,FT_UInt*);
|
||||
static FT_TrueTypeEngineType (*pFT_Get_TrueType_Engine_Type)(FT_Library);
|
||||
#ifdef HAVE_FREETYPE_FTWINFNT_H
|
||||
MAKE_FUNCPTR(FT_Get_WinFNT_Header);
|
||||
|
@ -268,6 +270,8 @@ struct tagGdiFont {
|
|||
SHORT yMax;
|
||||
SHORT yMin;
|
||||
OUTLINETEXTMETRICW *potm;
|
||||
DWORD total_kern_pairs;
|
||||
KERNINGPAIR *kern_pairs;
|
||||
FONTSIGNATURE fs;
|
||||
GdiFont base_font;
|
||||
struct list child_fonts;
|
||||
|
@ -1652,6 +1656,7 @@ BOOL WineEngInit(void)
|
|||
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_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);
|
||||
#ifdef HAVE_FREETYPE_FTWINFNT_H
|
||||
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->potm = NULL;
|
||||
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->child_fonts);
|
||||
return ret;
|
||||
|
@ -1966,6 +1973,7 @@ static void free_font(GdiFont font)
|
|||
}
|
||||
|
||||
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->name);
|
||||
HeapFree(GetProcessHeap(), 0, font->gm);
|
||||
|
@ -4096,6 +4104,228 @@ BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
|
|||
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 */
|
||||
|
||||
|
@ -4233,4 +4463,10 @@ BOOL WINAPI GetRasterizerCaps( LPRASTERIZER_STATUS lprs, UINT cbNumBytes)
|
|||
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 */
|
||||
|
|
|
@ -376,6 +376,7 @@ extern DWORD WineEngGetGlyphIndices(GdiFont font, LPCWSTR lpstr, INT count,
|
|||
extern DWORD WineEngGetGlyphOutline(GdiFont, UINT glyph, UINT format,
|
||||
LPGLYPHMETRICS, DWORD buflen, LPVOID buf,
|
||||
const MAT2*);
|
||||
extern DWORD WineEngGetKerningPairs(GdiFont, DWORD, KERNINGPAIR *);
|
||||
extern BOOL WineEngGetLinkedHFont(DC *dc, WCHAR c, HFONT *new_hfont, UINT *glyph);
|
||||
extern UINT WineEngGetOutlineTextMetrics(GdiFont, UINT, LPOUTLINETEXTMETRICW);
|
||||
extern UINT WineEngGetTextCharsetInfo(GdiFont font, LPFONTSIGNATURE fs, DWORD flags);
|
||||
|
|
Loading…
Reference in New Issue