[PATCH 7/7] gdi32: Reimplement GetCharacterPlacement on top of Uniscribe.
Sven Baars
sbaars at codeweavers.com
Mon Nov 9 05:03:31 CST 2020
Signed-off-by: Sven Baars <sbaars at codeweavers.com>
---
An implementation that also returns the correct lpOrder would require
an implementation of SCRIPT_STATE.fGcpClusters. But this implementation already
seems to be less broken than the previous one.
dlls/gdi32/font.c | 218 +++++++++++++++++++++++++++++-----------
dlls/gdi32/tests/font.c | 8 +-
2 files changed, 167 insertions(+), 59 deletions(-)
diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c
index f0616b6f908..4f4e485220b 100644
--- a/dlls/gdi32/font.c
+++ b/dlls/gdi32/font.c
@@ -31,6 +31,7 @@
#include "winnls.h"
#include "winternl.h"
#include "winreg.h"
+#include "usp10.h"
#include "gdi_private.h"
#include "resource.h"
#include "wine/exception.h"
@@ -4046,6 +4047,89 @@ static void FONT_NewTextMetricExWToA(const NEWTEXTMETRICEXW *ptmW, NEWTEXTMETRIC
memcpy(&ptmA->ntmFontSig, &ptmW->ntmFontSig, sizeof(FONTSIGNATURE));
}
+/* Compute glyph positions using Uniscribe */
+static BOOL get_glyph_positions( HDC hdc, const WCHAR *string, int str_len, WORD *glyphs_in,
+ int *advance_in, unsigned int *max_num_glyphs )
+{
+ unsigned int i, glyph_pos = 0, max_num_items = *max_num_glyphs + 1;
+ int num_items = 0, num_glyphs, num_chars;
+ WORD *glyphs = NULL, *log_clust = NULL;
+ SCRIPT_VISATTR *psva = NULL;
+ SCRIPT_ITEM *items = NULL;
+ GOFFSET *goffset = NULL;
+ SCRIPT_CACHE sc = NULL;
+ int *advance = NULL;
+ BOOL ret = FALSE;
+ HRESULT res;
+
+ items = heap_alloc( sizeof(*items) * (max_num_items + 1) );
+ if (!items)
+ goto cleanup;
+
+ res = ScriptItemize( string, str_len, max_num_items, NULL, NULL, items, &num_items );
+ if (res)
+ WARN( "ScriptItemize failed with %x.\n", res );
+
+ if (glyphs_in)
+ glyphs = glyphs_in;
+ else
+ glyphs = heap_alloc( *max_num_glyphs * sizeof(*glyphs) );
+ if (!glyphs)
+ goto cleanup;
+
+ if (advance_in)
+ advance = advance_in;
+ else
+ advance = heap_alloc( *max_num_glyphs * sizeof(*advance) );
+ if (!advance)
+ goto cleanup;
+
+ log_clust = heap_alloc( str_len * sizeof(*log_clust) );
+ if (!log_clust)
+ goto cleanup;
+
+ goffset = heap_alloc( *max_num_glyphs * sizeof(*goffset) );
+ if (!goffset)
+ goto cleanup;
+
+ psva = heap_alloc( *max_num_glyphs * sizeof(*psva) );
+ if (!psva)
+ goto cleanup;
+
+ for (i = 0; i < num_items; ++i)
+ {
+ num_glyphs = *max_num_glyphs - glyph_pos;
+ num_chars = items[i+1].iCharPos - items[i].iCharPos;
+
+ res = ScriptShape( hdc, &sc, string + items[i].iCharPos, num_chars, num_glyphs,
+ &items[i].a, glyphs + glyph_pos, log_clust + glyph_pos, psva, &num_glyphs );
+ if (res)
+ WARN( "ScriptShape failed with %x.\n", res );
+
+ res = ScriptPlace( hdc, &sc, glyphs + glyph_pos, num_glyphs, psva, &items[i].a,
+ advance + glyph_pos, goffset, NULL );
+ if (res)
+ WARN( "ScriptPlace failed with %x.\n", res );
+
+ glyph_pos += num_glyphs;
+ }
+
+ *max_num_glyphs = glyph_pos;
+ ret = TRUE;
+
+cleanup:
+ heap_free( items );
+ if (!glyphs_in)
+ heap_free( glyphs );
+ if (!advance_in)
+ heap_free( advance );
+ heap_free( log_clust );
+ heap_free( goffset );
+ heap_free( psva );
+
+ return ret;
+}
+
/* compute positions for text rendering, in device coords */
static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size )
{
@@ -7252,32 +7336,32 @@ GetCharacterPlacementW(
DWORD dwFlags /* [in] Flags specifying how to process the string */
)
{
- DWORD ret=0;
+ int *kern = NULL, *advance = NULL, kern_total = 0;
+ unsigned int i, nSet, pos = 0;
+ 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);
+ TRACE( "%s, %d, %d, 0x%08x\n",
+ debugstr_wn( lpString, uCount ), uCount, nMaxExtent, dwFlags );
if (!uCount)
return 0;
if (!lpResults)
- return GetTextExtentPoint32W(hdc, lpString, uCount, &size) ? MAKELONG(size.cx, size.cy) : 0;
+ return GetTextExtentPoint32W( hdc, lpString, uCount, &size ) ? MAKELONG( size.cx, size.cy ) : 0;
- TRACE("lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
- "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
- lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
- lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
- lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit);
+ TRACE( "lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
+ "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
+ lpResults->lStructSize, lpResults->lpOutString, lpResults->lpOrder,
+ lpResults->lpDx, lpResults->lpCaretPos, lpResults->lpClass,
+ lpResults->lpGlyphs, lpResults->nGlyphs, lpResults->nMaxFit );
if (dwFlags & ~(GCP_REORDER | GCP_USEKERNING))
- FIXME("flags 0x%08x ignored\n", dwFlags);
+ FIXME( "flags 0x%08x ignored\n", dwFlags );
if (lpResults->lpClass)
- FIXME("classes not implemented\n");
+ FIXME( "classes not implemented\n" );
if (lpResults->lpCaretPos && (dwFlags & GCP_REORDER))
- FIXME("Caret positions for complex scripts not implemented\n");
+ FIXME( "Caret positions for complex scripts not implemented\n" );
nSet = (UINT)uCount;
if (nSet > lpResults->nGlyphs)
@@ -7286,72 +7370,94 @@ GetCharacterPlacementW(
/* return number of initialized fields */
lpResults->nGlyphs = nSet;
- if (!(dwFlags & GCP_REORDER))
+ if (dwFlags & GCP_USEKERNING)
{
- /* 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)
- memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR));
-
- if (lpResults->lpOrder)
+ kern = kern_string( hdc, lpString, nSet, &kern_total );
+ if (!kern)
{
- for (i = 0; i < nSet; i++)
- lpResults->lpOrder[i] = i;
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ return 0;
}
}
- else
- {
- BIDI_Reorder(NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
- nSet, lpResults->lpOrder, NULL, NULL );
- }
- if (dwFlags & GCP_USEKERNING)
+ if (!(dwFlags & GCP_REORDER))
{
- kern = kern_string(hdc, lpString, nSet, &kern_total);
- if (!kern)
+ if (lpResults->lpDx)
+ advance = lpResults->lpDx;
+ else if (lpResults->lpCaretPos)
+ advance = heap_alloc( lpResults->nGlyphs * sizeof(*advance) );
+
+ if (!get_glyph_positions( hdc, lpString, nSet, lpResults->lpGlyphs, advance, &lpResults->nGlyphs ))
{
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ if (!lpResults->lpDx)
+ heap_free( advance );
return 0;
}
- }
- /* FIXME: Will use the placement chars */
- if (lpResults->lpDx)
- {
- int c;
- for (i = 0; i < nSet; i++)
+ if (lpResults->lpOutString)
+ memcpy( lpResults->lpOutString, lpString, nSet * sizeof(WCHAR) );
+
+ if (lpResults->lpCaretPos)
{
- if (GetCharWidth32W(hdc, lpString[i], lpString[i], &c))
+ for (i = 0; i < lpResults->nGlyphs; i++)
{
- lpResults->lpDx[i] = c;
+
+ lpResults->lpCaretPos[i] = pos;
+ pos += advance[i];
+
if (dwFlags & GCP_USEKERNING)
- lpResults->lpDx[i] += kern[i];
+ pos += kern[i];
}
}
- }
- if (lpResults->lpCaretPos && !(dwFlags & GCP_REORDER))
+ if (lpResults->lpOrder)
+ {
+ if (lpResults->lpGlyphs)
+ for(i = 0; i < lpResults->nGlyphs; i++)
+ lpResults->lpOrder[i] = i;
+ else
+ for(i = 0; i < nSet; i++)
+ lpResults->lpOrder[i] = i;
+ }
+
+ if (!lpResults->lpDx)
+ heap_free( advance );
+ }
+ else
{
- int pos = 0;
+ BIDI_Reorder( NULL, lpString, uCount, dwFlags, WINE_GCPW_FORCE_LTR, lpResults->lpOutString,
+ nSet, lpResults->lpOrder, NULL, NULL );
- lpResults->lpCaretPos[0] = 0;
- for (i = 0; i < nSet - 1; i++)
+ if (lpResults->lpDx)
{
- if (dwFlags & GCP_USEKERNING)
- pos += kern[i];
-
- if (GetTextExtentPoint32W(hdc, &lpString[i], 1, &size))
- lpResults->lpCaretPos[i + 1] = (pos += size.cx);
+ int c;
+ for (i = 0; i < nSet; i++)
+ {
+ if (GetCharWidth32W( hdc, lpString[i], lpString[i], &c ))
+ lpResults->lpDx[i] = c;
+ }
}
+
+ if(lpResults->lpGlyphs)
+ GetGlyphIndicesW( hdc, lpString, nSet, lpResults->lpGlyphs, 0 );
+
}
- if (lpResults->lpGlyphs)
- GetGlyphIndicesW(hdc, lpString, nSet, lpResults->lpGlyphs, 0);
+ if (lpResults->lpDx && (dwFlags & GCP_USEKERNING))
+ {
+ if (lpResults->nGlyphs != nSet)
+ FIXME( "Kerning not supported with the number of glyphs unequal to the number of input characters\n" );
+ else
+ {
+ for (i = 0; i < lpResults->nGlyphs; i++)
+ lpResults->lpDx[i] += kern[i];
+ }
+ }
- if (GetTextExtentPoint32W(hdc, lpString, uCount, &size))
- ret = MAKELONG(size.cx + kern_total, size.cy);
+ if (GetTextExtentPoint32W( hdc, lpString, uCount, &size ))
+ ret = MAKELONG( size.cx + kern_total, size.cy );
- heap_free(kern);
+ heap_free( kern );
return ret;
}
diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c
index 62eaab8639c..ea2ae4c523f 100644
--- a/dlls/gdi32/tests/font.c
+++ b/dlls/gdi32/tests/font.c
@@ -5022,7 +5022,8 @@ static inline void _test_character_placement_ok(int valid, HDC hdc, const WCHAR
size = GetCharacterPlacementW(hdc, string, str_len, 0, &result, 0);
winetest_ok(size, "GetCharacterPlacementW failed.\n");
if (valid > 0)
- winetest_ok(result.nGlyphs == expected_len, "Expected %d, got %d.\n", expected_len, result.nGlyphs);
+ todo_wine_if(expected[expected_len - 1].order != expected_len - 1)
+ winetest_ok(result.nGlyphs == expected_len, "Expected %d, got %d.\n", expected_len, result.nGlyphs);
else if (result.nGlyphs != expected_len)
winetest_trace("Expected %d, got %d.\n", expected_len, result.nGlyphs);
for (i = 0; i < result.nGlyphs; ++i)
@@ -5053,7 +5054,8 @@ static inline void _test_character_placement_ok(int valid, HDC hdc, const WCHAR
size = GetCharacterPlacementW(hdc, string, str_len, 0, &result, GCP_REORDER);
winetest_ok(size, "GetCharacterPlacementW failed with GCP_REORDER.\n");
if (valid > 0)
- winetest_ok(result.nGlyphs == expected_len, "Expected %d with GCP_REORDER, got %d.\n", expected_len, result.nGlyphs);
+ todo_wine_if(expected[expected_len - 1].order != expected_len - 1)
+ winetest_ok(result.nGlyphs == expected_len, "Expected %d with GCP_REORDER, got %d.\n", expected_len, result.nGlyphs);
else if (result.nGlyphs != expected_len)
winetest_trace("Expected %d with GCP_REORDER, got %d.\n", expected_len, result.nGlyphs);
for (i = 0; i < result.nGlyphs; ++i)
@@ -8164,7 +8166,7 @@ static void test_zero_width_control(void)
size = GetCharacterPlacementW(hdc, test, 10, 0, &result, 0);
ok(size, "Test %d: GetCharacterPlacementA failed.\n", i);
ok(result.nGlyphs == 10, "Test %d: unexpected number of glyphs %u.\n", i, result.nGlyphs);
- todo_wine ok(glyphs[5] == glyphs[4], "Test %d: unexpected glyphs %s.\n", i, wine_dbgstr_wn(glyphs, result.nGlyphs));
+ ok(glyphs[5] == glyphs[4], "Test %d: unexpected glyphs %s.\n", i, wine_dbgstr_wn(glyphs, result.nGlyphs));
if (i < 15)
ok(pos[6] - pos[5] == 0, "Test %d: unexpected width %d.\n", i, pos[6] - pos[5]);
else
--
2.25.1
More information about the wine-devel
mailing list