[PATCH] gdi32: Add support for GCP_USEKERNING to GetCharacterPlacement.

Dmitry Timoshkov dmitry at baikal.ru
Thu Jun 18 22:13:02 CDT 2020


Signed-off-by: Dmitry Timoshkov <dmitry at 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;
 }
-- 
2.26.2




More information about the wine-devel mailing list