diff --git a/dlls/gdi32/font.c b/dlls/gdi32/font.c index 6574761999c..3c609a23d4a 100644 --- a/dlls/gdi32/font.c +++ b/dlls/gdi32/font.c @@ -308,6 +308,83 @@ static UINT get_default_smoothing( HKEY key ) return GGO_GRAY4_BITMAP; } +/* compute positions for text rendering, in device coords */ +static BOOL get_char_positions( DC *dc, const WCHAR *str, INT count, INT *dx, SIZE *size ) +{ + TEXTMETRICW tm; + PHYSDEV dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint ); + + size->cx = size->cy = 0; + if (!count) return TRUE; + + dev = GET_DC_PHYSDEV( dc, pGetTextMetrics ); + dev->funcs->pGetTextMetrics( dev, &tm ); + + if (!dev->funcs->pGetTextExtentExPoint( dev, str, count, 0, NULL, dx, size )) return FALSE; + + if (dc->breakExtra || dc->breakRem) + { + int i, space = 0, rem = dc->breakRem; + + for (i = 0; i < count; i++) + { + if (str[i] == tm.tmBreakChar) + { + space += dc->breakExtra; + if (rem > 0) + { + space++; + rem--; + } + } + dx[i] += space; + } + } + size->cx = dx[count - 1]; + size->cy = tm.tmHeight; + return TRUE; +} + +/* compute positions for text rendering, in device coords */ +static BOOL get_char_positions_indices( DC *dc, const WORD *indices, INT count, INT *dx, SIZE *size ) +{ + TEXTMETRICW tm; + PHYSDEV dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint ); + + size->cx = size->cy = 0; + if (!count) return TRUE; + + dev = GET_DC_PHYSDEV( dc, pGetTextMetrics ); + dev->funcs->pGetTextMetrics( dev, &tm ); + + if (!dev->funcs->pGetTextExtentExPointI( dev, indices, count, 0, NULL, dx, size )) return FALSE; + + if (dc->breakExtra || dc->breakRem) + { + WORD space_index; + int i, space = 0, rem = dc->breakRem; + + dev = GET_DC_PHYSDEV( dc, pGetGlyphIndices ); + dev->funcs->pGetGlyphIndices( dev, &tm.tmBreakChar, 1, &space_index, 0 ); + + for (i = 0; i < count; i++) + { + if (indices[i] == space_index) + { + space += dc->breakExtra; + if (rem > 0) + { + space++; + rem--; + } + } + dx[i] += space; + } + } + size->cx = dx[count - 1]; + size->cy = tm.tmHeight; + return TRUE; +} /*********************************************************************** * GdiGetCodePage (GDI32.@) @@ -1015,20 +1092,45 @@ BOOL WINAPI GetTextExtentPoint32W( BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext, LPINT nfit, LPINT dxs, LPSIZE size ) { - PHYSDEV dev; - BOOL ret; DC *dc; + int i; + BOOL ret; + INT buffer[256], *pos = dxs; if (count < 0) return FALSE; dc = get_dc_ptr( hdc ); if (!dc) return FALSE; - dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPointI ); - ret = dev->funcs->pGetTextExtentExPointI( dev, indices, count, max_ext, nfit, dxs, size ); - size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx)); - size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy)); - size->cx += count * dc->charExtra; + if (!dxs) + { + pos = buffer; + if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) ))) + { + release_dc_ptr( dc ); + return FALSE; + } + } + + ret = get_char_positions_indices( dc, indices, count, pos, size ); + if (ret) + { + if (dxs || nfit) + { + for (i = 0; i < count; i++) + { + unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra; + if (dx > (unsigned int)max_ext) break; + if (dxs) dxs[i] = dx; + } + if (nfit) *nfit = i; + } + + size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra; + size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy )); + } + + if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos ); release_dc_ptr( dc ); TRACE("(%p %p %d %p): returning %d x %d\n", @@ -1091,6 +1193,7 @@ BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count, LPWSTR p = NULL; if (count < 0) return FALSE; + if (maxExt < -1) return FALSE; if (alpDx) { @@ -1122,126 +1225,52 @@ BOOL WINAPI GetTextExtentExPointA( HDC hdc, LPCSTR str, INT count, * * Return the size of the string as it would be if it was output properly by * e.g. TextOut. - * - * This should include - * - Intercharacter spacing - * - justification spacing (not yet done) - * - kerning? see below - * - * Kerning. Since kerning would be carried out by the rendering code it should - * be done by the driver. However they don't support it yet. Also I am not - * yet persuaded that (certainly under Win95) any kerning is actually done. - * - * str: According to MSDN this should be null-terminated. That is not true; a - * null will not terminate it early. - * size: Certainly under Win95 this appears buggy or weird if *lpnFit is less - * than count. I have seen it be either the size of the full string or - * 1 less than the size of the full string. I have not seen it bear any - * resemblance to the portion that would fit. - * lpnFit: What exactly is fitting? Stupidly, in my opinion, it includes the - * trailing intercharacter spacing and any trailing justification. - * - * FIXME - * Currently we do this by measuring each character etc. We should do it by - * passing the request to the driver, perhaps by extending the - * pGetTextExtentPoint function to take the alpDx argument. That would avoid - * thinking about kerning issues and rounding issues in the justification. */ - -BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, - INT maxExt, LPINT lpnFit, - LPINT alpDx, LPSIZE size ) +BOOL WINAPI GetTextExtentExPointW( HDC hdc, LPCWSTR str, INT count, INT max_ext, + LPINT nfit, LPINT dxs, LPSIZE size ) { - INT nFit = 0; - LPINT dxs = NULL; DC *dc; - BOOL ret = FALSE; - TEXTMETRICW tm; - PHYSDEV dev; - - TRACE("(%p, %s, %d)\n",hdc,debugstr_wn(str,count),maxExt); + int i; + BOOL ret; + INT buffer[256], *pos = dxs; if (count < 0) return FALSE; dc = get_dc_ptr(hdc); if (!dc) return FALSE; - GetTextMetricsW(hdc, &tm); - - /* If we need to calculate nFit, then we need the partial extents even if - the user hasn't provided us with an array. */ - if (lpnFit) + if (!dxs) { - dxs = alpDx ? alpDx : HeapAlloc(GetProcessHeap(), 0, count * sizeof alpDx[0]); - if (! dxs) - { - release_dc_ptr(dc); - SetLastError(ERROR_OUTOFMEMORY); - return FALSE; - } + pos = buffer; + if (count > 256 && !(pos = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pos) ))) + { + release_dc_ptr( dc ); + return FALSE; + } } - else - dxs = alpDx; - dev = GET_DC_PHYSDEV( dc, pGetTextExtentExPoint ); - ret = dev->funcs->pGetTextExtentExPoint(dev, str, count, 0, NULL, dxs, size); - - /* Perform device size to world size transformations. */ + ret = get_char_positions( dc, str, count, pos, size ); if (ret) { - INT extra = abs(INTERNAL_XWSTODS(dc, dc->charExtra)), - breakExtra = dc->breakExtra, - breakRem = dc->breakRem, - i; - - if (dxs) - { - for (i = 0; i < count; ++i) - { - dxs[i] += (i+1) * extra; - if (count > 1 && (breakExtra || breakRem) && str[i] == tm.tmBreakChar) - { - dxs[i] += breakExtra; - if (breakRem > 0) - { - breakRem--; - dxs[i]++; - } - } - dxs[i] = abs(INTERNAL_XDSTOWS(dc, dxs[i])); - if (dxs[i] <= maxExt) - ++nFit; - } - } - else if (count > 1 && (breakExtra || breakRem)) + if (dxs || nfit) { for (i = 0; i < count; i++) { - if (str[i] == tm.tmBreakChar) - { - size->cx += breakExtra; - if (breakRem > 0) - { - breakRem--; - (size->cx)++; - } - } + unsigned int dx = abs( INTERNAL_XDSTOWS( dc, pos[i] )) + (i + 1) * dc->charExtra; + if (dx > (unsigned int)max_ext) break; + if (dxs) dxs[i] = dx; } + if (nfit) *nfit = i; } - size->cx += count * extra; - size->cx = abs(INTERNAL_XDSTOWS(dc, size->cx)); - size->cy = abs(INTERNAL_YDSTOWS(dc, size->cy)); + + size->cx = abs( INTERNAL_XDSTOWS( dc, size->cx )) + count * dc->charExtra; + size->cy = abs( INTERNAL_YDSTOWS( dc, size->cy )); } - if (lpnFit) - *lpnFit = nFit; - - if (! alpDx) - HeapFree(GetProcessHeap(), 0, dxs); - + if (pos != buffer && pos != dxs) HeapFree( GetProcessHeap(), 0, pos ); release_dc_ptr( dc ); - TRACE("returning %d %d x %d\n",nFit,size->cx,size->cy); + TRACE("(%p, %s, %d) returning %dx%d\n", hdc, debugstr_wn(str,count), max_ext, size->cx, size->cy ); return ret; } diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c index 8508d70ab6f..337a6b965a1 100644 --- a/dlls/gdi32/tests/font.c +++ b/dlls/gdi32/tests/font.c @@ -45,6 +45,8 @@ static BOOL (WINAPI *pGetCharABCWidthsFloatW)(HDC hdc, UINT first, UINT last, L static DWORD (WINAPI *pGetFontUnicodeRanges)(HDC hdc, LPGLYPHSET lpgs); static DWORD (WINAPI *pGetGlyphIndicesA)(HDC hdc, LPCSTR lpstr, INT count, LPWORD pgi, DWORD flags); static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWORD pgi, DWORD flags); +static BOOL (WINAPI *pGetTextExtentExPointI)(HDC hdc, const WORD *indices, INT count, INT max_ext, + LPINT nfit, LPINT dxs, LPSIZE size ); static BOOL (WINAPI *pGdiRealizationInfo)(HDC hdc, DWORD *); static HFONT (WINAPI *pCreateFontIndirectExA)(const ENUMLOGFONTEXDV *); static HANDLE (WINAPI *pAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *); @@ -69,6 +71,7 @@ static void init(void) pGetFontUnicodeRanges = (void *)GetProcAddress(hgdi32, "GetFontUnicodeRanges"); pGetGlyphIndicesA = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesA"); pGetGlyphIndicesW = (void *)GetProcAddress(hgdi32, "GetGlyphIndicesW"); + pGetTextExtentExPointI = (void *)GetProcAddress(hgdi32, "GetTextExtentExPointI"); pGdiRealizationInfo = (void *)GetProcAddress(hgdi32, "GdiRealizationInfo"); pCreateFontIndirectExA = (void *)GetProcAddress(hgdi32, "CreateFontIndirectExA"); pAddFontMemResourceEx = (void *)GetProcAddress(hgdi32, "AddFontMemResourceEx"); @@ -1294,20 +1297,20 @@ static void test_text_extents(void) fit1 = fit2 = -215; ret = GetTextExtentExPointA(hdc, "One", 3, -1, &fit1, NULL, &sz); ok(ret == TRUE, "got %d\n", ret); - todo_wine ok(fit1 == 3, "fit = %d\n", fit1); + ok(fit1 == 3, "fit = %d\n", fit1); ret = GetTextExtentExPointW(hdc, wt, 3, -1, &fit2, NULL, &sz); ok(ret == TRUE, "got %d\n", ret); - todo_wine ok(fit2 == 3, "fit = %d\n", fit2); + ok(fit2 == 3, "fit = %d\n", fit2); /* max_extent = -2 is interpreted similarly, but the Ansi version * rejects it while the Unicode one accepts it */ fit1 = fit2 = -215; ret = GetTextExtentExPointA(hdc, "One", 3, -2, &fit1, NULL, &sz); - todo_wine ok(ret == FALSE, "got %d\n", ret); - todo_wine ok(fit1 == -215, "fit = %d\n", fit1); + ok(ret == FALSE, "got %d\n", ret); + ok(fit1 == -215, "fit = %d\n", fit1); ret = GetTextExtentExPointW(hdc, wt, 3, -2, &fit2, NULL, &sz); ok(ret == TRUE, "got %d\n", ret); - todo_wine ok(fit2 == 3, "fit = %d\n", fit2); + ok(fit2 == 3, "fit = %d\n", fit2); hfont = SelectObject(hdc, hfont); DeleteObject(hfont); @@ -1834,6 +1837,9 @@ static void test_SetTextJustification(void) LOGFONTA lf; HFONT hfont; HWND hwnd; + SIZE size, expect; + int i; + WORD indices[2]; static char testText[] = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do " "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut " @@ -1859,17 +1865,74 @@ static void test_SetTextJustification(void) testJustification(hdc, testText, &clientArea); + if (!pGetGlyphIndicesA || !pGetTextExtentExPointI) goto done; + pGetGlyphIndicesA( hdc, "A ", 2, indices, 0 ); + + SetTextJustification(hdc, 0, 0); + GetTextExtentPoint32(hdc, " ", 1, &expect); + GetTextExtentPoint32(hdc, " ", 3, &size); + ok( size.cx == 3 * expect.cx, "wrong size %d/%d\n", size.cx, expect.cx ); + SetTextJustification(hdc, 4, 1); + GetTextExtentPoint32(hdc, " ", 1, &size); + ok( size.cx == expect.cx + 4, "wrong size %d/%d\n", size.cx, expect.cx ); + SetTextJustification(hdc, 9, 2); + GetTextExtentPoint32(hdc, " ", 2, &size); + ok( size.cx == 2 * expect.cx + 9, "wrong size %d/%d\n", size.cx, expect.cx ); + SetTextJustification(hdc, 7, 3); + GetTextExtentPoint32(hdc, " ", 3, &size); + ok( size.cx == 3 * expect.cx + 7, "wrong size %d/%d\n", size.cx, expect.cx ); + SetTextJustification(hdc, 7, 3); + SetTextCharacterExtra(hdc, 2 ); + GetTextExtentPoint32(hdc, " ", 3, &size); + ok( size.cx == 3 * (expect.cx + 2) + 7, "wrong size %d/%d\n", size.cx, expect.cx ); + SetTextJustification(hdc, 0, 0); + SetTextCharacterExtra(hdc, 0); + size.cx = size.cy = 1234; + GetTextExtentPoint32(hdc, " ", 0, &size); + ok( size.cx == 0 && size.cy == 0, "wrong size %d,%d\n", size.cx, size.cy ); + pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &expect); + SetTextJustification(hdc, 5, 1); + pGetTextExtentExPointI(hdc, indices, 2, -1, NULL, NULL, &size); + ok( size.cx == expect.cx + 5, "wrong size %d/%d\n", size.cx, expect.cx ); + SetTextJustification(hdc, 0, 0); + SetMapMode( hdc, MM_ANISOTROPIC ); SetWindowExtEx( hdc, 2, 2, NULL ); GetClientRect( hwnd, &clientArea ); DPtoLP( hdc, (POINT *)&clientArea, 2 ); testJustification(hdc, testText, &clientArea); + GetTextExtentPoint32(hdc, "A", 1, &expect); + for (i = 0; i < 10; i++) + { + SetTextCharacterExtra(hdc, i); + GetTextExtentPoint32(hdc, "A", 1, &size); + ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i ); + } + SetTextCharacterExtra(hdc, 0); + pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &expect); + for (i = 0; i < 10; i++) + { + SetTextCharacterExtra(hdc, i); + pGetTextExtentExPointI(hdc, indices, 1, -1, NULL, NULL, &size); + ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i ); + } + SetTextCharacterExtra(hdc, 0); + SetViewportExtEx( hdc, 3, 3, NULL ); GetClientRect( hwnd, &clientArea ); DPtoLP( hdc, (POINT *)&clientArea, 2 ); testJustification(hdc, testText, &clientArea); + GetTextExtentPoint32(hdc, "A", 1, &expect); + for (i = 0; i < 10; i++) + { + SetTextCharacterExtra(hdc, i); + GetTextExtentPoint32(hdc, "A", 1, &size); + ok( size.cx == expect.cx + i, "wrong size %d/%d+%d\n", size.cx, expect.cx, i ); + } + +done: DeleteObject(hfont); ReleaseDC(hwnd, hdc); DestroyWindow(hwnd); diff --git a/dlls/gdiplus/tests/graphics.c b/dlls/gdiplus/tests/graphics.c index fdea646c7b4..c37d33f87a2 100644 --- a/dlls/gdiplus/tests/graphics.c +++ b/dlls/gdiplus/tests/graphics.c @@ -3074,7 +3074,7 @@ static void test_string_functions(void) expectf(0.0, bounds.X); expectf(0.0, bounds.Y); expectf_(char_bounds.Width, bounds.Width, 0.01); - todo_wine expectf_(char_bounds.Height + char_height * 3, bounds.Height, 0.05); + expectf_(char_bounds.Height + char_height * 3, bounds.Height, 0.05); expect(6, codepointsfitted); todo_wine expect(4, linesfilled);