Commit cb511b82 authored by Dmitry Timoshkov's avatar Dmitry Timoshkov Committed by Alexandre Julliard

gdi32: Add support for GCP_USEKERNING to GetCharacterPlacement().

parent 53d54af8
......@@ -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,30 +3375,30 @@ 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)
if (lpResults->lpClass)
FIXME("classes not implemented\n");
if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
FIXME("Caret positions for complex scripts not implemented\n");
nSet = (UINT)uCount;
if(nSet > lpResults->nGlyphs)
if (nSet > lpResults->nGlyphs)
nSet = lpResults->nGlyphs;
/* return number of initialized fields */
lpResults->nGlyphs = nSet;
if((dwFlags&GCP_REORDER)==0 )
if (!(dwFlags & GCP_REORDER))
{
/* Treat the case where no special handling was requested in a fastpath way */
/* copy will do if the GCP_REORDER flag is not set */
if(lpResults->lpOutString)
if (lpResults->lpOutString)
memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
if(lpResults->lpOrder)
if (lpResults->lpOrder)
{
for(i = 0; i < nSet; i++)
for (i = 0; i < nSet; i++)
lpResults->lpOrder[i] = i;
}
}
......@@ -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];
}
}
}
......@@ -3374,16 +3438,23 @@ GetCharacterPlacementW(
int pos = 0;
lpResults->lpCaretPos[0] = 0;
for (i = 1; i < nSet; i++)
if (GetTextExtentPoint32W(hdc, &(lpString[i - 1]), 1, &size))
lpResults->lpCaretPos[i] = (pos += size.cx);
for (i = 0; i < nSet - 1; i++)
{
if (dwFlags & GCP_USEKERNING)
pos += kern[i];
if (GetTextExtentPoint32W(hdc, &lpString[i], 1, &size))
lpResults->lpCaretPos[i + 1] = (pos += size.cx);
}
}
if(lpResults->lpGlyphs)
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;
}
......
......@@ -7168,6 +7168,106 @@ static void test_char_width(void)
ReleaseDC(NULL, dc);
}
static void test_GetCharacterPlacement_kerning(void)
{
LOGFONTA lf;
HFONT hfont, hfont_old;
KERNINGPAIR *kp;
HDC hdc;
DWORD count, ret, i, size, width, width_kern, idx;
WCHAR str[30];
GCP_RESULTSW result;
int kern[30], pos[30], pos_kern[30], dx[30], dx_kern[30], kern_amount;
if (!is_font_installed("Arial"))
{
skip("Arial is not installed, skipping the test\n");
return;
}
hdc = GetDC(0);
memset(&lf, 0, sizeof(lf));
strcpy(lf.lfFaceName, "Arial");
lf.lfHeight = 120;
hfont = CreateFontIndirectA(&lf);
ok(hfont != NULL, "CreateFontIndirect failed\n");
hfont_old = SelectObject(hdc, hfont);
count = GetKerningPairsW(hdc, 0, NULL);
kp = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*kp));
ret = GetKerningPairsW(hdc, count, kp);
ok(ret == count, "got %u, expected %u\n", ret, count);
size = kern_amount = idx = 0;
for (i = 0; i < count; i++)
{
if (kp[i].wFirst >= 'A' && kp[i].wFirst <= 'z' &&
kp[i].wSecond >= 'A' && kp[i].wSecond <= 'z')
{
str[size++] = kp[i].wFirst;
str[size++] = kp[i].wSecond;
str[size++] = 0;
kern[idx] = kp[i].iKernAmount;
idx++;
kern_amount += kp[i].iKernAmount;
if (size >= ARRAY_SIZE(str)) break;
}
}
HeapFree(GetProcessHeap(), 0, kp);
count = size;
memset(&result, 0, sizeof(result));
result.lStructSize = sizeof(result);
result.lpCaretPos = pos;
result.lpDx = dx;
result.nGlyphs = count;
ret = GetCharacterPlacementW(hdc, str, count, 0, &result, 0);
ok(ret, "GetCharacterPlacement failed\n");
ok(result.nGlyphs == count, "got %u\n", result.nGlyphs);
width = LOWORD(ret);
memset(&result, 0, sizeof(result));
result.lStructSize = sizeof(result);
result.lpCaretPos = pos_kern;
result.lpDx = dx_kern;
result.nGlyphs = count;
ret = GetCharacterPlacementW(hdc, str, count, 0, &result, GCP_USEKERNING);
ok(ret, "GetCharacterPlacement failed\n");
ok(result.nGlyphs == count, "got %u\n", result.nGlyphs);
width_kern = LOWORD(ret);
if (width == width_kern)
{
win_skip("GCP_USEKERNING is broken on this platform\n");
goto done;
}
ok(width + kern_amount == width_kern, "%d + %d != %d\n", width, kern_amount, width_kern);
kern_amount = idx = 0;
for (i = 0; i < count; i += 3, idx++)
{
ok(pos[i] + kern_amount == pos_kern[i], "%d: %d + %d != %d\n", i, pos[i], kern_amount, pos_kern[i]);
kern_amount += kern[idx];
ok(pos[i+1] + kern_amount == pos_kern[i+1], "%d: %d + %d != %d\n", i, pos[i+1], kern_amount, pos_kern[i+1]);
ok(pos[i+2] + kern_amount == pos_kern[i+2], "%d: %d + %d != %d\n", i, pos[i+2], kern_amount, pos_kern[i+2]);
ok(dx[i] + kern[idx] == dx_kern[i], "%d: %d + %d != %d\n", i, dx[i], kern[idx], dx_kern[i]);
ok(dx[i+1] == dx_kern[i+1], "%d: %d != %d\n", i, dx[i+1], dx_kern[i+1]);
ok(dx[i+2] == dx_kern[i+2], "%d: %d != %d\n", i, dx[i+2], dx_kern[i+2]);
}
done:
SelectObject(hdc, hfont_old);
DeleteObject(hfont);
ReleaseDC(0, hdc);
}
START_TEST(font)
{
static const char *test_names[] =
......@@ -7236,6 +7336,7 @@ START_TEST(font)
test_GetTextMetrics2("Arial", -55);
test_GetTextMetrics2("Arial", -110);
test_GetCharacterPlacement();
test_GetCharacterPlacement_kerning();
test_GetCharWidthInfo();
test_CreateFontIndirect();
test_CreateFontIndirectEx();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment