From: Józef Kucia Subject: [PATCH] d3dx9: Correctly handle whitespace character in D3DXCreateText. Message-Id: <1438546679-15299-1-git-send-email-joseph.kucia@gmail.com> Date: Sun, 2 Aug 2015 22:17:59 +0200 Fixes bug 38976. --- dlls/d3dx9_36/mesh.c | 4 ++ dlls/d3dx9_36/tests/mesh.c | 173 +++++++++++++++++++++++++-------------------- 2 files changed, 99 insertions(+), 78 deletions(-) diff --git a/dlls/d3dx9_36/mesh.c b/dlls/d3dx9_36/mesh.c index d0459da..39d279d 100644 --- a/dlls/d3dx9_36/mesh.c +++ b/dlls/d3dx9_36/mesh.c @@ -5847,6 +5847,10 @@ static HRESULT triangulate(struct triangulation_array *triangulations) int i; struct point2d_index *idx_ptr; + /* Glyphs without outlines do not generate any vertices. */ + if (!glyph->outlines.count) + return D3D_OK; + for (i = 0; i < glyph->outlines.count; i++) nb_vertices += glyph->outlines.items[i].count; diff --git a/dlls/d3dx9_36/tests/mesh.c b/dlls/d3dx9_36/tests/mesh.c index 0243a61..14cefe8 100644 --- a/dlls/d3dx9_36/tests/mesh.c +++ b/dlls/d3dx9_36/tests/mesh.c @@ -3617,57 +3617,17 @@ static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int da return S_OK; } -static BOOL compute_text_mesh(struct mesh *mesh, HDC hdc, const char *text, - float deviation, float extrusion, float otmEMSquare) +static BOOL compute_text_mesh(struct mesh *mesh, const char *text, + float deviation, float extrusion, float otmEMSquare, const struct glyphinfo *glyphs) { - HRESULT hr = E_FAIL; DWORD nb_vertices, nb_faces; DWORD nb_corners, nb_outline_points; int textlen = 0; - float offset_x; - char *raw_outline = NULL; - struct glyphinfo *glyphs = NULL; - GLYPHMETRICS gm; int i; struct vertex *vertex_ptr; face *face_ptr; - if (deviation == 0.0f) - deviation = 1.0f / otmEMSquare; - textlen = strlen(text); - glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs)); - if (!glyphs) { - hr = E_OUTOFMEMORY; - goto error; - } - - offset_x = 0.0f; - for (i = 0; i < textlen; i++) - { - /* get outline points from data returned from GetGlyphOutline */ - const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; - int datasize; - - glyphs[i].offset_x = offset_x; - - datasize = GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity); - if (datasize < 0) { - hr = E_FAIL; - goto error; - } - HeapFree(GetProcessHeap(), 0, raw_outline); - raw_outline = HeapAlloc(GetProcessHeap(), 0, datasize); - if (!raw_outline) { - hr = E_OUTOFMEMORY; - goto error; - } - datasize = GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, datasize, raw_outline, &identity); - - create_outline(&glyphs[i], raw_outline, datasize, deviation, otmEMSquare); - - offset_x += gm.gmCellIncX / (float)otmEMSquare; - } /* corner points need an extra vertex for the different side faces normals */ nb_corners = 0; @@ -3691,7 +3651,7 @@ static BOOL compute_text_mesh(struct mesh *mesh, HDC hdc, const char *text, nb_faces = nb_outline_points * 2; if (!new_mesh(mesh, nb_vertices, nb_faces)) - goto error; + return FALSE; /* convert 2D vertices and faces into 3D mesh */ vertex_ptr = mesh->vertices; @@ -3801,24 +3761,11 @@ static BOOL compute_text_mesh(struct mesh *mesh, HDC hdc, const char *text, vertex_ptr++; } - hr = D3D_OK; -error: - if (glyphs) { - for (i = 0; i < textlen; i++) - { - int j; - for (j = 0; j < glyphs[i].outlines.count; j++) - HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items[j].items); - HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items); - } - HeapFree(GetProcessHeap(), 0, glyphs); - } - HeapFree(GetProcessHeap(), 0, raw_outline); - - return hr == D3D_OK; + return TRUE; } -static void compare_text_outline_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh, int textlen, float extrusion) +static void compare_text_outline_mesh(const char *name, ID3DXMesh *d3dxmesh, struct mesh *mesh, + size_t textlen, float extrusion, const struct glyphinfo *glyphs) { HRESULT hr; DWORD number_of_vertices, number_of_faces; @@ -3936,13 +3883,20 @@ static void compare_text_outline_mesh(const char *name, ID3DXMesh *d3dxmesh, str first_vtx1 = vtx_idx1; first_vtx2 = vtx_idx2; - for (; vtx_idx1 < number_of_vertices; vtx_idx1++) { - if (vertices[vtx_idx1].normal.z != 0) - break; - } - for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) { - if (mesh->vertices[vtx_idx2].normal.z != 0) - break; + /* Glyphs without outlines do not generate any vertices. */ + if (glyphs[i].outlines.count > 0) + { + for (; vtx_idx1 < number_of_vertices; vtx_idx1++) + { + if (vertices[vtx_idx1].normal.z != 0) + break; + } + + for (; vtx_idx2 < mesh->number_of_vertices; vtx_idx2++) + { + if (mesh->vertices[vtx_idx2].normal.z != 0) + break; + } } nb_outline_vertices1 = vtx_idx1 - first_vtx1; nb_outline_vertices2 = vtx_idx2 - first_vtx2; @@ -4124,15 +4078,19 @@ error: static void test_createtext(IDirect3DDevice9 *device, HDC hdc, const char *text, float deviation, float extrusion) { HRESULT hr; - ID3DXMesh *d3dxmesh; - struct mesh mesh; + ID3DXMesh *d3dxmesh = NULL; + struct mesh mesh = {0}; char name[256]; OUTLINETEXTMETRICA otm; GLYPHMETRICS gm; + struct glyphinfo *glyphs = NULL; GLYPHMETRICSFLOAT *glyphmetrics_float = HeapAlloc(GetProcessHeap(), 0, sizeof(GLYPHMETRICSFLOAT) * strlen(text)); int i; LOGFONTA lf; + float offset_x; + size_t textlen; HFONT font = NULL, oldfont = NULL; + char *raw_outline = NULL; sprintf(name, "text ('%s', %f, %f)", text, deviation, extrusion); @@ -4141,7 +4099,7 @@ static void test_createtext(IDirect3DDevice9 *device, HDC hdc, const char *text, if (hr != D3D_OK) { skip("Couldn't create text with D3DXCreateText\n"); - return; + goto error; } /* must select a modified font having lfHeight = otm.otmEMSquare before @@ -4149,21 +4107,28 @@ static void test_createtext(IDirect3DDevice9 *device, HDC hdc, const char *text, if (!GetObjectA(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf) || !GetOutlineTextMetricsA(hdc, sizeof(otm), &otm)) { - d3dxmesh->lpVtbl->Release(d3dxmesh); skip("Couldn't get text outline\n"); - return; + goto error; } lf.lfHeight = otm.otmEMSquare; lf.lfWidth = 0; if (!(font = CreateFontIndirectA(&lf))) { - d3dxmesh->lpVtbl->Release(d3dxmesh); skip("Couldn't create the modified font\n"); - return; + goto error; + } + + textlen = strlen(text); + glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs)); + if (!glyphs) + { + hr = E_OUTOFMEMORY; + goto error; } + oldfont = SelectObject(hdc, font); - for (i = 0; i < strlen(text); i++) + for (i = 0; i < textlen; i++) { const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity); @@ -4175,8 +4140,44 @@ static void test_createtext(IDirect3DDevice9 *device, HDC hdc, const char *text, compare_float(glyphmetrics_float[i].gmfCellIncY, gm.gmCellIncY / (float)otm.otmEMSquare); } + if (deviation == 0.0f) + deviation = 1.0f / otm.otmEMSquare; + + offset_x = 0.0f; + for (i = 0; i < textlen; i++) + { + /* get outline points from data returned from GetGlyphOutline */ + const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; + int datasize; + + glyphs[i].offset_x = offset_x; + + datasize = GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity); + if (datasize < 0) + { + hr = E_FAIL; + SelectObject(hdc, oldfont); + goto error; + } + HeapFree(GetProcessHeap(), 0, raw_outline); + raw_outline = HeapAlloc(GetProcessHeap(), 0, datasize); + if (!raw_outline) + { + hr = E_OUTOFMEMORY; + SelectObject(hdc, oldfont); + goto error; + } + datasize = GetGlyphOutlineA(hdc, text[i], GGO_NATIVE, &gm, datasize, raw_outline, &identity); + + create_outline(&glyphs[i], raw_outline, datasize, deviation, otm.otmEMSquare); + + offset_x += gm.gmCellIncX / (float)otm.otmEMSquare; + } + + SelectObject(hdc, oldfont); + ZeroMemory(&mesh, sizeof(mesh)); - if (!compute_text_mesh(&mesh, hdc, text, deviation, extrusion, otm.otmEMSquare)) + if (!compute_text_mesh(&mesh, text, deviation, extrusion, otm.otmEMSquare, glyphs)) { skip("Couldn't create mesh\n"); d3dxmesh->lpVtbl->Release(d3dxmesh); @@ -4184,13 +4185,26 @@ static void test_createtext(IDirect3DDevice9 *device, HDC hdc, const char *text, } mesh.fvf = D3DFVF_XYZ | D3DFVF_NORMAL; - compare_text_outline_mesh(name, d3dxmesh, &mesh, strlen(text), extrusion); + compare_text_outline_mesh(name, d3dxmesh, &mesh, textlen, extrusion, glyphs); +error: free_mesh(&mesh); - d3dxmesh->lpVtbl->Release(d3dxmesh); - SelectObject(hdc, oldfont); + if (d3dxmesh) d3dxmesh->lpVtbl->Release(d3dxmesh); HeapFree(GetProcessHeap(), 0, glyphmetrics_float); + + if (glyphs) + { + for (i = 0; i < textlen; i++) + { + int j; + for (j = 0; j < glyphs[i].outlines.count; j++) + HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items[j].items); + HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items); + } + HeapFree(GetProcessHeap(), 0, glyphs); + } + HeapFree(GetProcessHeap(), 0, raw_outline); } static void D3DXCreateTextTest(void) @@ -4281,6 +4295,9 @@ if (0) test_createtext(device, hdc, "wine", 0.001f, 0.0f); test_createtext(device, hdc, "wine", 0.001f, FLT_MAX); test_createtext(device, hdc, "wine", 0.0f, 1.0f); + test_createtext(device, hdc, " wine", 1.0f, 0.0f); + test_createtext(device, hdc, "wine ", 1.0f, 0.0f); + test_createtext(device, hdc, "wi ne", 1.0f, 0.0f); DeleteDC(hdc); -- 2.4.6