Signed-off-by: Dmitry Timoshkov dmitry@baikal.ru --- dlls/gdi32/font.c | 77 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-)
diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index 8788426a2c..0ad6502a9c 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -3278,6 +3278,55 @@ GetCharacterPlacementA(HDC hdc, LPCSTR lpString, INT uCount, return ret; }
+static int kern_pair(const KERNINGPAIR *kern, int count, WCHAR c1, WCHAR c2) +{ + int i; + + for (i = 0; i < count; i++) + { + if (kern[i].wFirst == c1 && kern[i].wSecond == c2) + return kern[i].iKernAmount; + } + + return 0; +} + +static int *kern_string(HDC hdc, const WCHAR *str, int len, int *kern_total) +{ + int i, count; + KERNINGPAIR *kern = NULL; + int *ret; + + *kern_total = 0; + + ret = heap_alloc(len * sizeof(*ret)); + if (!ret) return NULL; + + count = GetKerningPairsW(hdc, 0, NULL); + if (count) + { + kern = heap_alloc(count * sizeof(*kern)); + if (!kern) + { + heap_free(ret); + return NULL; + } + + GetKerningPairsW(hdc, count, kern); + } + + for (i = 0; i < len - 1; i++) + { + ret[i] = kern_pair(kern, count, str[i], str[i + 1]); + *kern_total += ret[i]; + } + + ret[len - 1] = 0; /* no kerning for last element */ + + heap_free(kern); + return ret; +} + /************************************************************************* * GetCharacterPlacementW [GDI32.@] * @@ -3309,6 +3358,7 @@ GetCharacterPlacementW( DWORD ret=0; SIZE size; UINT i, nSet; + int *kern = NULL, kern_total = 0;
TRACE("%s, %d, %d, 0x%08x\n", debugstr_wn(lpString, uCount), uCount, nMaxExtent, dwFlags); @@ -3325,7 +3375,7 @@ GetCharacterPlacementW( lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass, lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
- if(dwFlags&(~GCP_REORDER)) + if (dwFlags & ~(GCP_REORDER | GCP_USEKERNING)) FIXME("flags 0x%08x ignored\n", dwFlags); if(lpResults->lpClass) FIXME("classes not implemented\n"); @@ -3358,6 +3408,16 @@ GetCharacterPlacementW( nSet, lpResults->lpOrder, NULL, NULL ); }
+ if (dwFlags & GCP_USEKERNING) + { + kern = kern_string(hdc, lpString, nSet, &kern_total); + if (!kern) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + } + /* FIXME: Will use the placement chars */ if (lpResults->lpDx) { @@ -3365,7 +3425,11 @@ GetCharacterPlacementW( for (i = 0; i < nSet; i++) { if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c)) - lpResults->lpDx[i]= c; + { + lpResults->lpDx[i] = c; + if (dwFlags & GCP_USEKERNING) + lpResults->lpDx[i] += kern[i]; + } } }
@@ -3375,15 +3439,22 @@ GetCharacterPlacementW(
lpResults->lpCaretPos[0] = 0; for (i = 1; i < nSet; i++) + { + if (dwFlags & GCP_USEKERNING) + pos += kern[i]; + if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size)) lpResults->lpCaretPos[i] = (pos += size.cx); + } }
if(lpResults->lpGlyphs) GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
if (GetTextExtentPoint32W(hdc, lpString, uCount, &size)) - ret = MAKELONG(size.cx, size.cy); + ret = MAKELONG(size.cx + kern_total, size.cy); + + heap_free(kern);
return ret; }
Hi Dmitry,
On Fri, Jun 19, 2020 at 11:13:02AM +0800, Dmitry Timoshkov wrote:
@@ -3325,7 +3375,7 @@ GetCharacterPlacementW( lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass, lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
- if(dwFlags&(~GCP_REORDER))
- if (dwFlags & ~(GCP_REORDER | GCP_USEKERNING)) FIXME("flags 0x%08x ignored\n", dwFlags); if(lpResults->lpClass)
Not an issue, but could you sneak in a space after "if" here too?
FIXME("classes not implemented\n");
@@ -3375,15 +3439,22 @@ GetCharacterPlacementW(
lpResults->lpCaretPos[0] = 0; for (i = 1; i < nSet; i++)
{
if (dwFlags & GCP_USEKERNING)
pos += kern[i];
This should be kern[i - 1], right? It might be clearer to rewrite the loop to start at 0 and run for i < nSet - 1 --- up to you.
Also, and I should have asked this yesterday, could you add some tests? One possible way is to call GetKerningPairs() first, generate a string from the pairs (perhaps a two letter word for each pair). Then call GetCharacterPlacement() with and without GCP_USEKERNING and use the kerning pairs to compare them.
Huw.