ddraw: Separate IDirectDrawSurface4 vtable.
[wine] / dlls / user32 / tests / text.c
1 /*
2  * DrawText tests
3  *
4  * Copyright (c) 2004 Zach Gorman
5  * Copyright 2007 Dmitry Timoshkov
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <assert.h>
23
24 #include "wine/test.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winerror.h"
29
30 #define MODIFIED(rect) (rect.left == 10 && rect.right != 100 && rect.top == 10 && rect.bottom != 100)
31 #define EMPTY(rect) (rect.left == rect.right && rect.bottom == rect.top)
32
33 static void test_DrawTextCalcRect(void)
34 {
35     HWND hwnd;
36     HDC hdc;
37     HFONT hFont, hOldFont;
38     LOGFONTA lf;
39     static CHAR text[] = "Example text for testing DrawText in "
40       "MM_HIENGLISH mode";
41     static WCHAR textW[] = {'W','i','d','e',' ','c','h','a','r',' ',
42         's','t','r','i','n','g','\0'};
43     static CHAR emptystring[] = "";
44     static WCHAR emptystringW[] = { 0 };
45     INT textlen, textheight, heightcheck;
46     RECT rect = { 0, 0, 100, 0 };
47     BOOL ret;
48     DRAWTEXTPARAMS dtp;
49     BOOL conform_xp = TRUE;
50
51     /* Initialization */
52     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP,
53                            0, 0, 200, 200, 0, 0, 0, NULL);
54     ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
55     hdc = GetDC(hwnd);
56     ok(hdc != 0, "GetDC error %u\n", GetLastError());
57     trace("hdc %p\n", hdc);
58     textlen = lstrlenA(text);
59
60     /* LOGFONT initialization */
61     memset(&lf, 0, sizeof(lf));
62     lf.lfCharSet = ANSI_CHARSET;
63     lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
64     lf.lfWeight = FW_DONTCARE;
65     lf.lfHeight = 0; /* mapping mode dependent */
66     lf.lfQuality = DEFAULT_QUALITY;
67     lstrcpyA(lf.lfFaceName, "Arial");
68
69     /* DrawText in MM_HIENGLISH with DT_CALCRECT */
70     SetMapMode(hdc, MM_HIENGLISH);
71     lf.lfHeight = 100 * 9 / 72; /* 9 point */
72     hFont = CreateFontIndirectA(&lf);
73     ok(hFont != 0, "CreateFontIndirectA error %u\n",
74        GetLastError());
75     hOldFont = SelectObject(hdc, hFont);
76
77     textheight = DrawTextA(hdc, text, textlen, &rect, DT_CALCRECT |
78        DT_EXTERNALLEADING | DT_WORDBREAK | DT_NOCLIP | DT_LEFT |
79        DT_NOPREFIX);
80     ok( textheight, "DrawTextA error %u\n", GetLastError());
81
82     trace("MM_HIENGLISH rect.bottom %d\n", rect.bottom);
83     ok(rect.bottom < 0, "In MM_HIENGLISH, DrawText with "
84        "DT_CALCRECT should return a negative rectangle bottom. "
85        "(bot=%d)\n", rect.bottom);
86
87     SelectObject(hdc, hOldFont);
88     ret = DeleteObject(hFont);
89     ok( ret, "DeleteObject error %u\n", GetLastError());
90
91
92     /* DrawText in MM_TEXT with DT_CALCRECT */
93     SetMapMode(hdc, MM_TEXT);
94     lf.lfHeight = -MulDiv(9, GetDeviceCaps(hdc,
95        LOGPIXELSY), 72); /* 9 point */
96     hFont = CreateFontIndirectA(&lf);
97     ok(hFont != 0, "CreateFontIndirectA error %u\n",
98        GetLastError());
99     hOldFont = SelectObject(hdc, hFont);
100
101     textheight = DrawTextA(hdc, text, textlen, &rect, DT_CALCRECT |
102        DT_EXTERNALLEADING | DT_WORDBREAK | DT_NOCLIP | DT_LEFT |
103        DT_NOPREFIX);
104     ok( textheight, "DrawTextA error %u\n", GetLastError());
105
106     trace("MM_TEXT rect.bottom %d\n", rect.bottom);
107     ok(rect.bottom > 0, "In MM_TEXT, DrawText with DT_CALCRECT "
108        "should return a positive rectangle bottom. (bot=%d)\n",
109        rect.bottom);
110
111     /* empty or null text should in some cases calc an empty rectangle */
112
113     SetRect( &rect, 10,10, 100, 100);
114     heightcheck = textheight = DrawTextExA(hdc, text, 0, &rect, DT_CALCRECT, NULL );
115     ok( !EMPTY(rect) && !MODIFIED(rect),
116         "rectangle should NOT be empty got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
117     if (textheight != 0)  /* Windows 98 */
118     {
119         win_skip("XP conformity failed, skipping XP tests. Probably win9x\n");
120         conform_xp = FALSE;
121     }
122     else
123         ok(textheight==0,"Got textheight from DrawTextExA\n");
124
125     SetRect( &rect, 10,10, 100, 100);
126     textheight = DrawTextA(hdc, text, 0, &rect, DT_CALCRECT);
127     ok( !EMPTY(rect) && !MODIFIED(rect),
128         "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
129         rect.left, rect.top, rect.right, rect.bottom );
130     if (conform_xp)
131         ok(textheight==0,"Got textheight from DrawTextA\n");
132     ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
133
134     SetRect( &rect, 10,10, 100, 100);
135     SetLastError( 0);
136     heightcheck = textheight = DrawTextExA(hdc, emptystring, -1, &rect, DT_CALCRECT, NULL );
137     ok( EMPTY(rect),
138         "rectangle should be empty got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
139     ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
140
141     SetRect( &rect, 10,10, 100, 100);
142     textheight = DrawTextA(hdc, emptystring, -1, &rect, DT_CALCRECT);
143     ok( EMPTY(rect),
144         "rectangle should be empty got %d,%d-%d,%d\n",
145         rect.left, rect.top, rect.right, rect.bottom );
146     ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
147     ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
148
149     SetRect( &rect, 10,10, 100, 100);
150     SetLastError( 0);
151     heightcheck = textheight = DrawTextExA(hdc, NULL, -1, &rect, DT_CALCRECT, NULL );
152     ok( EMPTY(rect) || !MODIFIED(rect),
153         "rectangle should be empty or not modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
154     if (!textheight) /* Windows NT 4 */
155     {
156         if (conform_xp)
157             win_skip("XP conformity failed, skipping XP tests. Probably winNT\n");
158         conform_xp = FALSE;
159     }
160     else
161         ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
162
163     SetRect( &rect, 10,10, 100, 100);
164     textheight = DrawTextA(hdc, NULL, -1, &rect, DT_CALCRECT);
165     ok( EMPTY(rect) || !MODIFIED(rect),
166         "rectangle should be empty or NOT modified got %d,%d-%d,%d\n",
167         rect.left, rect.top, rect.right, rect.bottom );
168     if (conform_xp)
169         ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
170     ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
171
172     SetRect( &rect, 10,10, 100, 100);
173     heightcheck = textheight = DrawTextExA(hdc, NULL, 0, &rect, DT_CALCRECT, NULL );
174     ok( !EMPTY(rect) && !MODIFIED(rect),
175         "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
176     if (conform_xp)
177         ok(textheight==0,"Got textheight from DrawTextExA\n");
178
179     SetRect( &rect, 10,10, 100, 100);
180     textheight = DrawTextA(hdc, NULL, 0, &rect, DT_CALCRECT);
181     ok( !EMPTY(rect) && !MODIFIED(rect),
182         "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
183         rect.left, rect.top, rect.right, rect.bottom );
184     if (conform_xp)
185         ok(textheight==0,"Got textheight from DrawTextA\n");
186     ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
187
188     /* DT_SINGLELINE tests */
189
190     SetRect( &rect, 10,10, 100, 100);
191     heightcheck = textheight = DrawTextExA(hdc, text, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
192     ok( !EMPTY(rect) && !MODIFIED(rect),
193         "rectangle should NOT be empty got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
194     if (conform_xp)
195         ok(textheight==0,"Got textheight from DrawTextExA\n");
196
197     SetRect( &rect, 10,10, 100, 100);
198     textheight = DrawTextA(hdc, text, 0, &rect, DT_CALCRECT|DT_SINGLELINE);
199     ok( !EMPTY(rect) && !MODIFIED(rect),
200         "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
201         rect.left, rect.top, rect.right, rect.bottom );
202     if (conform_xp)
203         ok(textheight==0,"Got textheight from DrawTextA\n");
204     ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
205
206     SetRect( &rect, 10,10, 100, 100);
207     SetLastError( 0);
208     heightcheck = textheight = DrawTextExA(hdc, emptystring, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
209     ok( !EMPTY(rect) && MODIFIED(rect),
210         "rectangle should be modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
211     ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
212
213     SetRect( &rect, 10,10, 100, 100);
214     textheight = DrawTextA(hdc, emptystring, -1, &rect, DT_CALCRECT|DT_SINGLELINE);
215     ok( !EMPTY(rect) && MODIFIED (rect),
216         "rectangle should be modified got %d,%d-%d,%d\n",
217         rect.left, rect.top, rect.right, rect.bottom );
218     ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
219     ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
220
221     SetRect( &rect, 10,10, 100, 100);
222     SetLastError( 0);
223     heightcheck = textheight = DrawTextExA(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
224     ok( (!EMPTY(rect) && MODIFIED(rect)) || !MODIFIED(rect),
225         "rectangle should be modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
226     if (conform_xp)
227         ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
228
229     SetRect( &rect, 10,10, 100, 100);
230     textheight = DrawTextA(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE);
231     ok( (!EMPTY(rect) && MODIFIED(rect)) || !MODIFIED(rect),
232         "rectangle should be modified got %d,%d-%d,%d\n",
233         rect.left, rect.top, rect.right, rect.bottom );
234     if (conform_xp)
235         ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
236     ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
237
238     SetRect( &rect, 10,10, 100, 100);
239     heightcheck = textheight = DrawTextExA(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
240     ok( !EMPTY(rect) && !MODIFIED(rect),
241         "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
242     if (conform_xp)
243         ok(textheight==0,"Got textheight from DrawTextExA\n");
244
245     SetRect( &rect, 10,10, 100, 100);
246     textheight = DrawTextA(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE);
247     ok( !EMPTY(rect) && !MODIFIED(rect),
248         "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
249         rect.left, rect.top, rect.right, rect.bottom );
250     if (conform_xp)
251         ok(textheight==0,"Got textheight from DrawTextA\n");
252     ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
253
254     /* further tests with  0 count, NULL and empty strings */
255     heightcheck = textheight = DrawTextA(hdc, text, 0, &rect, 0);
256     if (conform_xp)
257         ok(textheight==0,"Got textheight from DrawTextA\n");
258     textheight = DrawTextExA(hdc, text, 0, &rect, 0, NULL );
259     if (conform_xp)
260         ok(textheight==0,"Got textheight from DrawTextExA\n");
261     ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
262     heightcheck = textheight = DrawTextA(hdc, emptystring, 0, &rect, 0);
263     if (conform_xp)
264         ok(textheight==0,"Got textheight from DrawTextA\n");
265     textheight = DrawTextExA(hdc, emptystring, 0, &rect, 0, NULL );
266     if (conform_xp)
267         ok(textheight==0,"Got textheight from DrawTextExA\n");
268     ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
269     heightcheck = textheight = DrawTextA(hdc, NULL, 0, &rect, 0);
270     if (conform_xp)
271         ok(textheight==0,"Got textheight from DrawTextA\n");
272     textheight = DrawTextExA(hdc, NULL, 0, &rect, 0, NULL );
273     if (conform_xp)
274         ok(textheight==0,"Got textheight from DrawTextExA\n");
275     ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
276     heightcheck = textheight = DrawTextA(hdc, emptystring, -1, &rect, 0);
277     ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
278     textheight = DrawTextExA(hdc, emptystring, -1, &rect, 0, NULL );
279     ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
280     ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
281     heightcheck = textheight = DrawTextA(hdc, NULL, -1, &rect, 0);
282     if (conform_xp)
283         ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
284     textheight = DrawTextExA(hdc, NULL, -1, &rect, 0, NULL );
285     if (conform_xp)
286         ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
287     ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
288     heightcheck = textheight = DrawTextA(hdc, NULL, 10, &rect, 0);
289     ok(textheight==0,"Got textheight from DrawTextA\n");
290     textheight = DrawTextExA(hdc, NULL, 10, &rect, 0, NULL );
291     ok(textheight==0,"Got textheight from DrawTextA\n");
292     ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
293
294
295     /* invalid dtp size test */
296     dtp.cbSize = -1; /* Invalid */
297     dtp.uiLengthDrawn = 1337;
298     textheight = DrawTextExA(hdc, text, 0, &rect, 0, &dtp);
299     ok(textheight==0,"Got textheight from DrawTextExA\n");
300     ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
301     dtp.uiLengthDrawn = 1337;
302     textheight = DrawTextExA(hdc, emptystring, 0, &rect, 0, &dtp);
303     ok(textheight==0,"Got textheight from DrawTextExA\n");
304     ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
305     dtp.uiLengthDrawn = 1337;
306     textheight = DrawTextExA(hdc, NULL, 0, &rect, 0, &dtp);
307     ok(textheight==0,"Got textheight from DrawTextExA\n");
308     ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
309     dtp.uiLengthDrawn = 1337;
310     textheight = DrawTextExA(hdc, emptystring, -1, &rect, 0, &dtp);
311     ok(textheight==0,"Got textheight from DrawTextExA\n");
312     ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
313     dtp.uiLengthDrawn = 1337;
314     textheight = DrawTextExA(hdc, NULL, -1, &rect, 0, &dtp);
315     ok(textheight==0,"Got textheight from DrawTextExA\n");
316     ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
317
318     /* Margin calculations */
319     dtp.cbSize = sizeof(dtp);
320     dtp.iLeftMargin = 0;
321     dtp.iRightMargin = 0;
322     SetRect( &rect, 0, 0, 0, 0);
323     DrawTextExA(hdc, text, -1, &rect, DT_CALCRECT, &dtp);
324     textlen = rect.right; /* Width without margin */
325     dtp.iLeftMargin = 8;
326     SetRect( &rect, 0, 0, 0, 0);
327     DrawTextExA(hdc, text, -1, &rect, DT_CALCRECT, &dtp);
328     ok(rect.right==dtp.iLeftMargin+textlen  ,"Incorrect left margin calculated  rc(%d,%d)\n", rect.left, rect.right);
329     dtp.iLeftMargin = 0;
330     dtp.iRightMargin = 8;
331     SetRect( &rect, 0, 0, 0, 0);
332     DrawTextExA(hdc, text, -1, &rect, DT_CALCRECT, &dtp);
333     ok(rect.right==dtp.iRightMargin+textlen  ,"Incorrect right margin calculated rc(%d,%d)\n", rect.left, rect.right);
334
335     /* Wide char versions */
336     SetRect( &rect, 10,10, 100, 100);
337     SetLastError( 0);
338     heightcheck = textheight = DrawTextExW(hdc, textW, 0, &rect, DT_CALCRECT, NULL );
339     if( GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) {
340         ok( !EMPTY(rect) && !MODIFIED(rect),
341             "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
342             rect.left, rect.top, rect.right, rect.bottom );
343         ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
344
345         SetRect( &rect, 10,10, 100, 100);
346         textheight = DrawTextW(hdc, textW, 0, &rect, DT_CALCRECT);
347         ok( !EMPTY(rect) && !MODIFIED(rect),
348             "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
349             rect.left, rect.top, rect.right, rect.bottom );
350         ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
351         ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
352
353         SetRect( &rect, 10,10, 100, 100);
354         heightcheck = textheight = DrawTextExW(hdc, emptystringW, -1, &rect, DT_CALCRECT, NULL );
355         ok( EMPTY(rect),
356             "rectangle should be empty got %d,%d-%d,%d\n",
357             rect.left, rect.top, rect.right, rect.bottom );
358         ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
359
360         SetRect( &rect, 10,10, 100, 100);
361         textheight = DrawTextW(hdc, emptystringW, -1, &rect, DT_CALCRECT);
362         ok( EMPTY(rect),
363             "rectangle should be empty got %d,%d-%d,%d\n",
364             rect.left, rect.top, rect.right, rect.bottom );
365         ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
366         ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
367
368         SetRect( &rect, 10,10, 100, 100);
369         heightcheck = textheight = DrawTextExW(hdc, NULL, 0, &rect, DT_CALCRECT, NULL );
370         ok( !EMPTY(rect) && !MODIFIED(rect),
371             "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
372             rect.left, rect.top, rect.right, rect.bottom );
373         if (textheight) /* windows 2000 */
374         {
375             if (conform_xp)
376                 win_skip("XP conformity failed, skipping XP tests. Probably win 2000\n");
377             conform_xp = FALSE;
378         }
379         else
380             ok(textheight==0,"Got textheight from DrawTextExW\n");
381
382         SetRect( &rect, 10,10, 100, 100);
383         textheight = DrawTextW(hdc, NULL, 0, &rect, DT_CALCRECT);
384         ok( !EMPTY(rect) && !MODIFIED(rect),
385             "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
386             rect.left, rect.top, rect.right, rect.bottom );
387         if (conform_xp)
388             ok(textheight==0,"Got textheight from DrawTextW\n");
389         ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
390
391         if (conform_xp) {
392             /* Crashes on NT4 */
393             SetRect( &rect, 10,10, 100, 100);
394             heightcheck = textheight = DrawTextExW(hdc, NULL, -1, &rect, DT_CALCRECT, NULL );
395             ok( !EMPTY(rect) && !MODIFIED(rect),
396                 "rectangle should NOT be empty  and NOT modified got %d,%d-%d,%d\n",
397                 rect.left, rect.top, rect.right, rect.bottom );
398             ok(textheight==0,"Got textheight from DrawTextExW\n");
399
400             SetRect( &rect, 10,10, 100, 100);
401             textheight = DrawTextW(hdc, NULL, -1, &rect, DT_CALCRECT);
402             ok( !EMPTY(rect) && !MODIFIED(rect),
403                 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
404                 rect.left, rect.top, rect.right, rect.bottom );
405             ok(textheight==0,"Got textheight from DrawTextW\n");
406             ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
407         }
408
409
410         /* DT_SINGLELINE tests */
411
412         heightcheck = textheight = DrawTextExW(hdc, textW, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
413         ok( !EMPTY(rect) && !MODIFIED(rect),
414             "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
415             rect.left, rect.top, rect.right, rect.bottom );
416         ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
417
418         SetRect( &rect, 10,10, 100, 100);
419         textheight = DrawTextW(hdc, textW, 0, &rect, DT_CALCRECT|DT_SINGLELINE);
420         ok( !EMPTY(rect) && !MODIFIED(rect),
421             "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
422             rect.left, rect.top, rect.right, rect.bottom );
423         ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
424         ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
425
426         SetRect( &rect, 10,10, 100, 100);
427         heightcheck = textheight = DrawTextExW(hdc, emptystringW, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
428         ok( !EMPTY(rect) && MODIFIED(rect),
429             "rectangle should be modified got %d,%d-%d,%d\n",
430             rect.left, rect.top, rect.right, rect.bottom );
431         ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
432
433         SetRect( &rect, 10,10, 100, 100);
434         textheight = DrawTextW(hdc, emptystringW, -1, &rect, DT_CALCRECT|DT_SINGLELINE);
435         ok( !EMPTY(rect) && MODIFIED(rect),
436             "rectangle should be modified got %d,%d-%d,%d\n",
437             rect.left, rect.top, rect.right, rect.bottom );
438         ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
439         ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
440
441         if (conform_xp) {
442             /* Crashes on NT4 */
443             SetRect( &rect, 10,10, 100, 100);
444             heightcheck = textheight = DrawTextExW(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
445             ok( !EMPTY(rect) && !MODIFIED(rect),
446                 "rectangle should NOT be empty  and NOT modified got %d,%d-%d,%d\n",
447                 rect.left, rect.top, rect.right, rect.bottom );
448             ok(textheight==0,"Got textheight from DrawTextExW\n");
449
450             SetRect( &rect, 10,10, 100, 100);
451             textheight = DrawTextW(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE);
452             ok( !EMPTY(rect) && !MODIFIED(rect),
453                 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
454                 rect.left, rect.top, rect.right, rect.bottom );
455             ok(textheight==0,"Got textheight from DrawTextW\n");
456             ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
457         }
458
459         SetRect( &rect, 10,10, 100, 100);
460         heightcheck = textheight = DrawTextExW(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
461         ok( !EMPTY(rect) && !MODIFIED(rect),
462             "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
463             rect.left, rect.top, rect.right, rect.bottom );
464         if (conform_xp)
465             ok(textheight==0,"Got textheight from DrawTextExW\n");
466
467         SetRect( &rect, 10,10, 100, 100);
468         textheight = DrawTextW(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE);
469         ok( !EMPTY(rect) && !MODIFIED(rect),
470             "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
471             rect.left, rect.top, rect.right, rect.bottom );
472         if (conform_xp)
473             ok(textheight==0,"Got textheight from DrawTextW\n");
474         ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
475
476         /* further tests with NULL and empty strings */
477         heightcheck = textheight = DrawTextW(hdc, textW, 0, &rect, 0);
478         ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
479         textheight = DrawTextExW(hdc, textW, 0, &rect, 0, NULL );
480         ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
481         ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
482         heightcheck = textheight = DrawTextW(hdc, emptystringW, 0, &rect, 0);
483         ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
484         textheight = DrawTextExW(hdc, emptystringW, 0, &rect, 0, NULL );
485         ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
486         ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
487         heightcheck = textheight = DrawTextW(hdc, NULL, 0, &rect, 0);
488         if (conform_xp)
489             ok(textheight==0,"Got textheight from DrawTextW\n");
490         textheight = DrawTextExW(hdc, NULL, 0, &rect, 0, NULL );
491         if (conform_xp)
492             ok(textheight==0,"Got textheight from DrawTextExW\n");
493         ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
494         heightcheck = textheight = DrawTextW(hdc, emptystringW, -1, &rect, 0);
495         ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
496         textheight = DrawTextExW(hdc, emptystringW, -1, &rect, 0, NULL );
497         ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
498         ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
499         if (conform_xp) {
500             /* Crashes on NT4 */
501             heightcheck = textheight = DrawTextW(hdc, NULL, -1, &rect, 0);
502             ok(textheight==0,"Got textheight from DrawTextW\n");
503             textheight = DrawTextExW(hdc, NULL, -1, &rect, 0, NULL );
504             ok(textheight==0,"Got textheight from DrawTextExW\n");
505             ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
506             heightcheck = textheight = DrawTextW(hdc, NULL, 10, &rect, 0);
507             ok(textheight==0,"Got textheight from DrawTextW\n");
508             textheight = DrawTextExW(hdc, NULL, 10, &rect, 0, NULL );
509             ok(textheight==0,"Got textheight from DrawTextW\n");
510             ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
511         }
512
513         dtp.cbSize = -1; /* Invalid */
514         dtp.uiLengthDrawn = 1337;
515         textheight = DrawTextExW(hdc, textW, 0, &rect, 0, &dtp);
516         ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
517         ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
518         dtp.uiLengthDrawn = 1337;
519         textheight = DrawTextExW(hdc, emptystringW, 0, &rect, 0, &dtp);
520         if (conform_xp)
521             ok(textheight==0,"Got textheight from DrawTextExW\n");
522         ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
523         dtp.uiLengthDrawn = 1337;
524         textheight = DrawTextExW(hdc, NULL, 0, &rect, 0, &dtp);
525         if (conform_xp)
526             ok(textheight==0,"Got textheight from DrawTextExW\n");
527         ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
528         dtp.uiLengthDrawn = 1337;
529         textheight = DrawTextExW(hdc, emptystringW, -1, &rect, 0, &dtp);
530         ok(textheight==0,"Got textheight from DrawTextExW\n");
531         ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
532         if (conform_xp) {
533             /* Crashes on NT4 */
534             dtp.uiLengthDrawn = 1337;
535             textheight = DrawTextExW(hdc, NULL, -1, &rect, 0, &dtp);
536             ok(textheight==0,"Got textheight from DrawTextExW\n");
537             ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
538         }
539     }
540
541     /* More test cases from bug 12226 */
542     SetRect(&rect, 0, 0, 0, 0);
543     textheight = DrawTextA(hdc, emptystring, -1, &rect, DT_CALCRECT | DT_LEFT | DT_SINGLELINE);
544     ok(textheight, "DrawTextA error %u\n", GetLastError());
545     ok(0 == rect.left, "expected 0, got %d\n", rect.left);
546     ok(0 == rect.right, "expected 0, got %d\n", rect.right);
547     ok(0 == rect.top, "expected 0, got %d\n", rect.top);
548     ok(rect.bottom, "rect.bottom should not be 0\n");
549
550     SetRect(&rect, 0, 0, 0, 0);
551     textheight = DrawTextW(hdc, emptystringW, -1, &rect, DT_CALCRECT | DT_LEFT | DT_SINGLELINE);
552     if (!textheight && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
553     {
554         win_skip( "DrawTextW not implemented\n" );
555     }
556     else
557     {
558         ok(textheight, "DrawTextW error %u\n", GetLastError());
559         ok(0 == rect.left, "expected 0, got %d\n", rect.left);
560         ok(0 == rect.right, "expected 0, got %d\n", rect.right);
561         ok(0 == rect.top, "expected 0, got %d\n", rect.top);
562         ok(rect.bottom, "rect.bottom should not be 0\n");
563     }
564
565     SelectObject(hdc, hOldFont);
566     ret = DeleteObject(hFont);
567     ok( ret, "DeleteObject error %u\n", GetLastError());
568
569     /* Clean up */
570     ret = ReleaseDC(hwnd, hdc);
571     ok( ret, "ReleaseDC error %u\n", GetLastError());
572     ret = DestroyWindow(hwnd);
573     ok( ret, "DestroyWindow error %u\n", GetLastError());
574 }
575
576 /* replace tabs by \t */
577 static void strfmt( const char *str, char *strout)
578 {
579     unsigned int i,j ;
580     for(i=0,j=0;i<=strlen(str);i++,j++)
581         if((strout[j]=str[i])=='\t') {
582             strout[j++]='\\';
583             strout[j]='t';
584         }
585 }
586
587
588 #define TABTEST( tabval, tabcount, string, _exp) \
589 { int i,x_act, x_exp; char strdisp[64];\
590     for(i=0;i<8;i++) tabs[i]=(i+1)*(tabval); \
591     extent = GetTabbedTextExtentA( hdc, string, strlen( string), (tabcount), tabs); \
592     strfmt( string, strdisp); \
593  /*   trace( "Extent is %08lx\n", extent); */\
594     x_act = LOWORD( extent); \
595     x_exp = (_exp); \
596     ok( x_act == x_exp, "Test case \"%s\". Text extent is %d, expected %d tab %d tabcount %d\n", \
597         strdisp, x_act, x_exp, tabval, tabcount); \
598 } \
599
600
601 static void test_TabbedText(void)
602 {
603     HWND hwnd;
604     HDC hdc;
605     BOOL ret;
606     TEXTMETRICA tm;
607     DWORD extent;
608     INT tabs[8], cx, cy, tab, tabcount,t,align;
609
610     /* Initialization */
611     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP,
612                            0, 0, 200, 200, 0, 0, 0, NULL);
613     ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
614     hdc = GetDC(hwnd);
615     ok(hdc != 0, "GetDC error %u\n", GetLastError());
616
617     ret = GetTextMetricsA( hdc, &tm);
618     ok( ret, "GetTextMetrics error %u\n", GetLastError());
619
620     extent = GetTabbedTextExtentA( hdc, "x", 0, 1, tabs);
621     ok( extent == 0, "GetTabbedTextExtentA returned non-zero on nCount == 0\n");
622
623     extent = GetTabbedTextExtentA( hdc, "x", 1, 1, tabs);
624     cx = LOWORD( extent);
625     cy = HIWORD( extent);
626     trace( "cx is %d cy is %d\n", cx, cy);
627
628     align=1;
629     for( t=-1; t<=1; t++) { /* slightly adjust the 4 char tabstop, to 
630                                catch the one off errors */
631         tab =  (cx *4 + t);
632         /* test the special case tabcount =1 and the general array (80 of tabs */
633         for( tabcount = 1; tabcount <= 8; tabcount +=7) { 
634             TABTEST( align * tab, tabcount, "\t", tab)
635             TABTEST( align * tab, tabcount, "xxx\t", tab)
636             TABTEST( align * tab, tabcount, "\tx", tab+cx)
637             TABTEST( align * tab, tabcount, "\t\t", tab*2)
638             TABTEST( align * tab, tabcount, "\tx\t", tab*2)
639             TABTEST( align * tab, tabcount, "x\tx", tab+cx)
640             TABTEST( align * tab, tabcount, "xx\tx", tab+cx)
641             TABTEST( align * tab, tabcount, "xxx\tx", tab+cx)
642             TABTEST( align * tab, tabcount, "xxxx\tx", t>0 ? tab + cx : 2*tab+cx)
643             TABTEST( align * tab, tabcount, "xxxxx\tx", 2*tab+cx)
644         }
645     }
646     align=-1;
647     for( t=-1; t<=1; t++) { /* slightly adjust the 4 char tabstop, to 
648                                catch the one off errors */
649         tab =  (cx *4 + t);
650         /* test the special case tabcount =1 and the general array (8) of tabs */
651         for( tabcount = 1; tabcount <= 8; tabcount +=7) { 
652             TABTEST( align * tab, tabcount, "\t", tab)
653             TABTEST( align * tab, tabcount, "xxx\t", tab)
654             TABTEST( align * tab, tabcount, "\tx", tab)
655             TABTEST( align * tab, tabcount, "\t\t", tab*2)
656             TABTEST( align * tab, tabcount, "\tx\t", tab*2)
657             TABTEST( align * tab, tabcount, "x\tx", tab)
658             TABTEST( align * tab, tabcount, "xx\tx", tab)
659             TABTEST( align * tab, tabcount, "xxx\tx", 4 * cx >= tab ? 2*tab :tab)
660             TABTEST( align * tab, tabcount, "xxxx\tx", 2*tab)
661             TABTEST( align * tab, tabcount, "xxxxx\tx", 2*tab)
662         }
663     }
664
665     ReleaseDC( hwnd, hdc );
666     DestroyWindow( hwnd );
667 }
668
669 static void test_DrawState(void)
670 {
671     static const char text[] = "Sample text string";
672     HWND hwnd;
673     HDC hdc;
674     BOOL ret;
675
676     hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP,
677                            0, 0, 200, 200, 0, 0, 0, NULL);
678     assert(hwnd);
679
680     hdc = GetDC(hwnd);
681     assert(hdc);
682
683     SetLastError(0xdeadbeef);
684     ret = DrawState(hdc, GetStockObject(DKGRAY_BRUSH), NULL, (LPARAM)text, strlen(text),
685                     0, 0, 10, 10, DST_TEXT);
686     ok(ret, "DrawState error %u\n", GetLastError());
687
688     SetLastError(0xdeadbeef);
689     ret = DrawState(hdc, GetStockObject(DKGRAY_BRUSH), NULL, (LPARAM)text, 0,
690                     0, 0, 10, 10, DST_TEXT);
691     ok(ret, "DrawState error %u\n", GetLastError());
692
693     SetLastError(0xdeadbeef);
694     ret = DrawState(hdc, GetStockObject(DKGRAY_BRUSH), NULL, 0, strlen(text),
695                     0, 0, 10, 10, DST_TEXT);
696     ok(!ret || broken(ret) /* win98 */, "DrawState succeeded\n");
697     ok(GetLastError() == 0xdeadbeef, "not expected error %u\n", GetLastError());
698
699     SetLastError(0xdeadbeef);
700     ret = DrawState(hdc, GetStockObject(DKGRAY_BRUSH), NULL, 0, 0,
701                     0, 0, 10, 10, DST_TEXT);
702     ok(!ret || broken(ret) /* win98 */, "DrawState succeeded\n");
703     ok(GetLastError() == 0xdeadbeef, "not expected error %u\n", GetLastError());
704
705     ReleaseDC(hwnd, hdc);
706     DestroyWindow(hwnd);
707 }
708
709 START_TEST(text)
710 {
711     test_TabbedText();
712     test_DrawTextCalcRect();
713     test_DrawState();
714 }