user32/tests: Use wine_dbgstr_rect() to print RECTs.
[wine.git] / dlls / user32 / tests / text.c
blob7166e69376286add4e26f27d95d788ea3f9df14c
1 /*
2 * DrawText tests
4 * Copyright (c) 2004 Zach Gorman
5 * Copyright 2007 Dmitry Timoshkov
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.
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.
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
22 #include <assert.h>
24 #include "wine/test.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winerror.h"
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)
33 static void test_DrawTextCalcRect(void)
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 static CHAR wordbreak_text[] = "line1 line2";
46 static WCHAR wordbreak_textW[] = {'l','i','n','e','1',' ','l','i','n','e','2',0};
47 static char tabstring[] = "one\ttwo";
48 INT textlen, textheight, heightcheck;
49 RECT rect = { 0, 0, 100, 0 }, rect2;
50 BOOL ret;
51 DRAWTEXTPARAMS dtp;
52 BOOL conform_xp = TRUE;
54 /* Initialization */
55 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP,
56 0, 0, 200, 200, 0, 0, 0, NULL);
57 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
58 hdc = GetDC(hwnd);
59 ok(hdc != 0, "GetDC error %u\n", GetLastError());
60 trace("hdc %p\n", hdc);
61 textlen = lstrlenA(text);
63 /* LOGFONT initialization */
64 memset(&lf, 0, sizeof(lf));
65 lf.lfCharSet = ANSI_CHARSET;
66 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
67 lf.lfWeight = FW_DONTCARE;
68 lf.lfHeight = 0; /* mapping mode dependent */
69 lf.lfQuality = DEFAULT_QUALITY;
70 lstrcpyA(lf.lfFaceName, "Arial");
72 /* DrawText in MM_HIENGLISH with DT_CALCRECT */
73 SetMapMode(hdc, MM_HIENGLISH);
74 lf.lfHeight = 100 * 9 / 72; /* 9 point */
75 hFont = CreateFontIndirectA(&lf);
76 ok(hFont != 0, "CreateFontIndirectA error %u\n",
77 GetLastError());
78 hOldFont = SelectObject(hdc, hFont);
80 textheight = DrawTextA(hdc, text, textlen, &rect, DT_CALCRECT |
81 DT_EXTERNALLEADING | DT_WORDBREAK | DT_NOCLIP | DT_LEFT |
82 DT_NOPREFIX);
83 ok( textheight, "DrawTextA error %u\n", GetLastError());
85 trace("MM_HIENGLISH rect.bottom %d\n", rect.bottom);
86 ok(rect.bottom < 0, "In MM_HIENGLISH, DrawText with "
87 "DT_CALCRECT should return a negative rectangle bottom. "
88 "(bot=%d)\n", rect.bottom);
90 SelectObject(hdc, hOldFont);
91 ret = DeleteObject(hFont);
92 ok( ret, "DeleteObject error %u\n", GetLastError());
95 /* DrawText in MM_TEXT with DT_CALCRECT */
96 SetMapMode(hdc, MM_TEXT);
97 lf.lfHeight = -MulDiv(9, GetDeviceCaps(hdc,
98 LOGPIXELSY), 72); /* 9 point */
99 hFont = CreateFontIndirectA(&lf);
100 ok(hFont != 0, "CreateFontIndirectA error %u\n",
101 GetLastError());
102 hOldFont = SelectObject(hdc, hFont);
104 textheight = DrawTextA(hdc, text, textlen, &rect, DT_CALCRECT |
105 DT_EXTERNALLEADING | DT_WORDBREAK | DT_NOCLIP | DT_LEFT |
106 DT_NOPREFIX);
107 ok( textheight, "DrawTextA error %u\n", GetLastError());
109 trace("MM_TEXT rect.bottom %d\n", rect.bottom);
110 ok(rect.bottom > 0, "In MM_TEXT, DrawText with DT_CALCRECT "
111 "should return a positive rectangle bottom. (bot=%d)\n",
112 rect.bottom);
114 /* empty or null text should in some cases calc an empty rectangle */
116 SetRect( &rect, 10,10, 100, 100);
117 heightcheck = textheight = DrawTextExA(hdc, text, 0, &rect, DT_CALCRECT, NULL );
118 ok( !EMPTY(rect) && !MODIFIED(rect),
119 "rectangle should NOT be empty got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
120 ok(textheight==0,"Got textheight from DrawTextExA\n");
122 SetRect( &rect, 10,10, 100, 100);
123 textheight = DrawTextA(hdc, text, 0, &rect, DT_CALCRECT);
124 ok( !EMPTY(rect) && !MODIFIED(rect),
125 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
126 rect.left, rect.top, rect.right, rect.bottom );
127 if (conform_xp)
128 ok(textheight==0,"Got textheight from DrawTextA\n");
129 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
131 SetRect( &rect, 10,10, 100, 100);
132 SetLastError( 0);
133 heightcheck = textheight = DrawTextExA(hdc, emptystring, -1, &rect, DT_CALCRECT, NULL );
134 ok( EMPTY(rect),
135 "rectangle should be empty got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
136 ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
138 SetRect( &rect, 10,10, 100, 100);
139 textheight = DrawTextA(hdc, emptystring, -1, &rect, DT_CALCRECT);
140 ok( EMPTY(rect),
141 "rectangle should be empty got %d,%d-%d,%d\n",
142 rect.left, rect.top, rect.right, rect.bottom );
143 ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
144 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
146 SetRect( &rect, 10,10, 100, 100);
147 SetLastError( 0);
148 heightcheck = textheight = DrawTextExA(hdc, NULL, -1, &rect, DT_CALCRECT, NULL );
149 ok( EMPTY(rect) || !MODIFIED(rect),
150 "rectangle should be empty or not modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
151 if (!textheight) /* Windows NT 4 */
153 if (conform_xp)
154 win_skip("XP conformity failed, skipping XP tests. Probably winNT\n");
155 conform_xp = FALSE;
157 else
158 ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
160 SetRect( &rect, 10,10, 100, 100);
161 textheight = DrawTextA(hdc, NULL, -1, &rect, DT_CALCRECT);
162 ok( EMPTY(rect) || !MODIFIED(rect),
163 "rectangle should be empty or NOT modified got %d,%d-%d,%d\n",
164 rect.left, rect.top, rect.right, rect.bottom );
165 if (conform_xp)
166 ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
167 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
169 SetRect( &rect, 10,10, 100, 100);
170 heightcheck = textheight = DrawTextExA(hdc, NULL, 0, &rect, DT_CALCRECT, NULL );
171 ok( !EMPTY(rect) && !MODIFIED(rect),
172 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
173 if (conform_xp)
174 ok(textheight==0,"Got textheight from DrawTextExA\n");
176 SetRect( &rect, 10,10, 100, 100);
177 textheight = DrawTextA(hdc, NULL, 0, &rect, DT_CALCRECT);
178 ok( !EMPTY(rect) && !MODIFIED(rect),
179 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
180 rect.left, rect.top, rect.right, rect.bottom );
181 if (conform_xp)
182 ok(textheight==0,"Got textheight from DrawTextA\n");
183 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
185 /* DT_SINGLELINE tests */
187 SetRect( &rect, 10,10, 100, 100);
188 heightcheck = textheight = DrawTextExA(hdc, text, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
189 ok( !EMPTY(rect) && !MODIFIED(rect),
190 "rectangle should NOT be empty got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
191 if (conform_xp)
192 ok(textheight==0,"Got textheight from DrawTextExA\n");
194 SetRect( &rect, 10,10, 100, 100);
195 textheight = DrawTextA(hdc, text, 0, &rect, DT_CALCRECT|DT_SINGLELINE);
196 ok( !EMPTY(rect) && !MODIFIED(rect),
197 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
198 rect.left, rect.top, rect.right, rect.bottom );
199 if (conform_xp)
200 ok(textheight==0,"Got textheight from DrawTextA\n");
201 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
203 SetRect( &rect, 10,10, 100, 100);
204 SetLastError( 0);
205 heightcheck = textheight = DrawTextExA(hdc, emptystring, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
206 ok( !EMPTY(rect) && MODIFIED(rect),
207 "rectangle should be modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
208 ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
210 SetRect( &rect, 10,10, 100, 100);
211 textheight = DrawTextA(hdc, emptystring, -1, &rect, DT_CALCRECT|DT_SINGLELINE);
212 ok( !EMPTY(rect) && MODIFIED (rect),
213 "rectangle should be modified got %d,%d-%d,%d\n",
214 rect.left, rect.top, rect.right, rect.bottom );
215 ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
216 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
218 SetRect( &rect, 10,10, 100, 100);
219 SetLastError( 0);
220 heightcheck = textheight = DrawTextExA(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
221 ok( (!EMPTY(rect) && MODIFIED(rect)) || !MODIFIED(rect),
222 "rectangle should be modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
223 if (conform_xp)
224 ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
226 SetRect( &rect, 10,10, 100, 100);
227 textheight = DrawTextA(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE);
228 ok( (!EMPTY(rect) && MODIFIED(rect)) || !MODIFIED(rect),
229 "rectangle should be modified got %d,%d-%d,%d\n",
230 rect.left, rect.top, rect.right, rect.bottom );
231 if (conform_xp)
232 ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
233 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
235 SetRect( &rect, 10,10, 100, 100);
236 heightcheck = textheight = DrawTextExA(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
237 ok( !EMPTY(rect) && !MODIFIED(rect),
238 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n", rect.left, rect.top, rect.right, rect.bottom );
239 if (conform_xp)
240 ok(textheight==0,"Got textheight from DrawTextExA\n");
242 SetRect( &rect, 10,10, 100, 100);
243 textheight = DrawTextA(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE);
244 ok( !EMPTY(rect) && !MODIFIED(rect),
245 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
246 rect.left, rect.top, rect.right, rect.bottom );
247 if (conform_xp)
248 ok(textheight==0,"Got textheight from DrawTextA\n");
249 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
251 /* further tests with 0 count, NULL and empty strings */
252 heightcheck = textheight = DrawTextA(hdc, text, 0, &rect, 0);
253 if (conform_xp)
254 ok(textheight==0,"Got textheight from DrawTextA\n");
255 textheight = DrawTextExA(hdc, text, 0, &rect, 0, NULL );
256 if (conform_xp)
257 ok(textheight==0,"Got textheight from DrawTextExA\n");
258 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
259 heightcheck = textheight = DrawTextA(hdc, emptystring, 0, &rect, 0);
260 if (conform_xp)
261 ok(textheight==0,"Got textheight from DrawTextA\n");
262 textheight = DrawTextExA(hdc, emptystring, 0, &rect, 0, NULL );
263 if (conform_xp)
264 ok(textheight==0,"Got textheight from DrawTextExA\n");
265 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
266 heightcheck = textheight = DrawTextA(hdc, NULL, 0, &rect, 0);
267 if (conform_xp)
268 ok(textheight==0,"Got textheight from DrawTextA\n");
269 textheight = DrawTextExA(hdc, NULL, 0, &rect, 0, NULL );
270 if (conform_xp)
271 ok(textheight==0,"Got textheight from DrawTextExA\n");
272 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
273 heightcheck = textheight = DrawTextA(hdc, emptystring, -1, &rect, 0);
274 ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
275 textheight = DrawTextExA(hdc, emptystring, -1, &rect, 0, NULL );
276 ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
277 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
278 heightcheck = textheight = DrawTextA(hdc, NULL, -1, &rect, 0);
279 if (conform_xp)
280 ok(textheight!=0,"Failed to get textheight from DrawTextA\n");
281 textheight = DrawTextExA(hdc, NULL, -1, &rect, 0, NULL );
282 if (conform_xp)
283 ok(textheight!=0,"Failed to get textheight from DrawTextExA\n");
284 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
285 heightcheck = textheight = DrawTextA(hdc, NULL, 10, &rect, 0);
286 ok(textheight==0,"Got textheight from DrawTextA\n");
287 textheight = DrawTextExA(hdc, NULL, 10, &rect, 0, NULL );
288 ok(textheight==0,"Got textheight from DrawTextA\n");
289 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
292 /* invalid dtp size test */
293 dtp.cbSize = -1; /* Invalid */
294 dtp.uiLengthDrawn = 1337;
295 textheight = DrawTextExA(hdc, text, 0, &rect, 0, &dtp);
296 ok(textheight==0,"Got textheight from DrawTextExA\n");
297 ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
298 dtp.uiLengthDrawn = 1337;
299 textheight = DrawTextExA(hdc, emptystring, 0, &rect, 0, &dtp);
300 ok(textheight==0,"Got textheight from DrawTextExA\n");
301 ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
302 dtp.uiLengthDrawn = 1337;
303 textheight = DrawTextExA(hdc, NULL, 0, &rect, 0, &dtp);
304 ok(textheight==0,"Got textheight from DrawTextExA\n");
305 ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
306 dtp.uiLengthDrawn = 1337;
307 textheight = DrawTextExA(hdc, emptystring, -1, &rect, 0, &dtp);
308 ok(textheight==0,"Got textheight from DrawTextExA\n");
309 ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
310 dtp.uiLengthDrawn = 1337;
311 textheight = DrawTextExA(hdc, NULL, -1, &rect, 0, &dtp);
312 ok(textheight==0,"Got textheight from DrawTextExA\n");
313 ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
315 /* Margin calculations */
316 dtp.cbSize = sizeof(dtp);
317 dtp.iLeftMargin = 0;
318 dtp.iRightMargin = 0;
319 SetRectEmpty(&rect);
320 DrawTextExA(hdc, text, -1, &rect, DT_CALCRECT, &dtp);
321 textlen = rect.right; /* Width without margin */
322 dtp.iLeftMargin = 8;
323 SetRectEmpty(&rect);
324 DrawTextExA(hdc, text, -1, &rect, DT_CALCRECT, &dtp);
325 ok(rect.right==dtp.iLeftMargin+textlen ,"Incorrect left margin calculated rc(%d,%d)\n", rect.left, rect.right);
326 dtp.iLeftMargin = 0;
327 dtp.iRightMargin = 8;
328 SetRectEmpty(&rect);
329 DrawTextExA(hdc, text, -1, &rect, DT_CALCRECT, &dtp);
330 ok(rect.right==dtp.iRightMargin+textlen ,"Incorrect right margin calculated rc(%d,%d)\n", rect.left, rect.right);
332 /* Wide char versions */
333 SetRect( &rect, 10,10, 100, 100);
334 SetLastError( 0);
335 heightcheck = textheight = DrawTextExW(hdc, textW, 0, &rect, DT_CALCRECT, NULL );
336 if( GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) {
337 ok( !EMPTY(rect) && !MODIFIED(rect),
338 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
339 rect.left, rect.top, rect.right, rect.bottom );
340 ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
342 SetRect( &rect, 10,10, 100, 100);
343 textheight = DrawTextW(hdc, textW, 0, &rect, DT_CALCRECT);
344 ok( !EMPTY(rect) && !MODIFIED(rect),
345 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
346 rect.left, rect.top, rect.right, rect.bottom );
347 ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
348 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
350 SetRect( &rect, 10,10, 100, 100);
351 heightcheck = textheight = DrawTextExW(hdc, emptystringW, -1, &rect, DT_CALCRECT, NULL );
352 ok( EMPTY(rect),
353 "rectangle should be empty got %d,%d-%d,%d\n",
354 rect.left, rect.top, rect.right, rect.bottom );
355 ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
357 SetRect( &rect, 10,10, 100, 100);
358 textheight = DrawTextW(hdc, emptystringW, -1, &rect, DT_CALCRECT);
359 ok( EMPTY(rect),
360 "rectangle should be empty got %d,%d-%d,%d\n",
361 rect.left, rect.top, rect.right, rect.bottom );
362 ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
363 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
365 SetRect( &rect, 10,10, 100, 100);
366 heightcheck = textheight = DrawTextExW(hdc, NULL, 0, &rect, DT_CALCRECT, NULL );
367 ok( !EMPTY(rect) && !MODIFIED(rect),
368 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
369 rect.left, rect.top, rect.right, rect.bottom );
370 if (textheight) /* windows 2000 */
372 if (conform_xp)
373 win_skip("XP conformity failed, skipping XP tests. Probably win 2000\n");
374 conform_xp = FALSE;
376 else
377 ok(textheight==0,"Got textheight from DrawTextExW\n");
379 SetRect( &rect, 10,10, 100, 100);
380 textheight = DrawTextW(hdc, NULL, 0, &rect, DT_CALCRECT);
381 ok( !EMPTY(rect) && !MODIFIED(rect),
382 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
383 rect.left, rect.top, rect.right, rect.bottom );
384 if (conform_xp)
385 ok(textheight==0,"Got textheight from DrawTextW\n");
386 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
388 if (conform_xp) {
389 /* Crashes on NT4 */
390 SetRect( &rect, 10,10, 100, 100);
391 heightcheck = textheight = DrawTextExW(hdc, NULL, -1, &rect, DT_CALCRECT, NULL );
392 ok( !EMPTY(rect) && !MODIFIED(rect),
393 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
394 rect.left, rect.top, rect.right, rect.bottom );
395 ok(textheight==0,"Got textheight from DrawTextExW\n");
397 SetRect( &rect, 10,10, 100, 100);
398 textheight = DrawTextW(hdc, NULL, -1, &rect, DT_CALCRECT);
399 ok( !EMPTY(rect) && !MODIFIED(rect),
400 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
401 rect.left, rect.top, rect.right, rect.bottom );
402 ok(textheight==0,"Got textheight from DrawTextW\n");
403 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
407 /* DT_SINGLELINE tests */
409 heightcheck = textheight = DrawTextExW(hdc, textW, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
410 ok( !EMPTY(rect) && !MODIFIED(rect),
411 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
412 rect.left, rect.top, rect.right, rect.bottom );
413 ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
415 SetRect( &rect, 10,10, 100, 100);
416 textheight = DrawTextW(hdc, textW, 0, &rect, DT_CALCRECT|DT_SINGLELINE);
417 ok( !EMPTY(rect) && !MODIFIED(rect),
418 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
419 rect.left, rect.top, rect.right, rect.bottom );
420 ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
421 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
423 SetRect( &rect, 10,10, 100, 100);
424 heightcheck = textheight = DrawTextExW(hdc, emptystringW, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
425 ok( !EMPTY(rect) && MODIFIED(rect),
426 "rectangle should be modified got %d,%d-%d,%d\n",
427 rect.left, rect.top, rect.right, rect.bottom );
428 ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
430 SetRect( &rect, 10,10, 100, 100);
431 textheight = DrawTextW(hdc, emptystringW, -1, &rect, DT_CALCRECT|DT_SINGLELINE);
432 ok( !EMPTY(rect) && MODIFIED(rect),
433 "rectangle should be modified got %d,%d-%d,%d\n",
434 rect.left, rect.top, rect.right, rect.bottom );
435 ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
436 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
438 if (conform_xp) {
439 /* Crashes on NT4 */
440 SetRect( &rect, 10,10, 100, 100);
441 heightcheck = textheight = DrawTextExW(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
442 ok( !EMPTY(rect) && !MODIFIED(rect),
443 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
444 rect.left, rect.top, rect.right, rect.bottom );
445 ok(textheight==0,"Got textheight from DrawTextExW\n");
447 SetRect( &rect, 10,10, 100, 100);
448 textheight = DrawTextW(hdc, NULL, -1, &rect, DT_CALCRECT|DT_SINGLELINE);
449 ok( !EMPTY(rect) && !MODIFIED(rect),
450 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
451 rect.left, rect.top, rect.right, rect.bottom );
452 ok(textheight==0,"Got textheight from DrawTextW\n");
453 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
456 SetRect( &rect, 10,10, 100, 100);
457 heightcheck = textheight = DrawTextExW(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE, NULL );
458 ok( !EMPTY(rect) && !MODIFIED(rect),
459 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
460 rect.left, rect.top, rect.right, rect.bottom );
461 if (conform_xp)
462 ok(textheight==0,"Got textheight from DrawTextExW\n");
464 SetRect( &rect, 10,10, 100, 100);
465 textheight = DrawTextW(hdc, NULL, 0, &rect, DT_CALCRECT|DT_SINGLELINE);
466 ok( !EMPTY(rect) && !MODIFIED(rect),
467 "rectangle should NOT be empty and NOT modified got %d,%d-%d,%d\n",
468 rect.left, rect.top, rect.right, rect.bottom );
469 if (conform_xp)
470 ok(textheight==0,"Got textheight from DrawTextW\n");
471 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
473 /* further tests with NULL and empty strings */
474 heightcheck = textheight = DrawTextW(hdc, textW, 0, &rect, 0);
475 ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
476 textheight = DrawTextExW(hdc, textW, 0, &rect, 0, NULL );
477 ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
478 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
479 heightcheck = textheight = DrawTextW(hdc, emptystringW, 0, &rect, 0);
480 ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
481 textheight = DrawTextExW(hdc, emptystringW, 0, &rect, 0, NULL );
482 ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
483 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
484 heightcheck = textheight = DrawTextW(hdc, NULL, 0, &rect, 0);
485 if (conform_xp)
486 ok(textheight==0,"Got textheight from DrawTextW\n");
487 textheight = DrawTextExW(hdc, NULL, 0, &rect, 0, NULL );
488 if (conform_xp)
489 ok(textheight==0,"Got textheight from DrawTextExW\n");
490 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
491 heightcheck = textheight = DrawTextW(hdc, emptystringW, -1, &rect, 0);
492 ok(textheight!=0,"Failed to get textheight from DrawTextW\n");
493 textheight = DrawTextExW(hdc, emptystringW, -1, &rect, 0, NULL );
494 ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
495 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
496 if (conform_xp) {
497 /* Crashes on NT4 */
498 heightcheck = textheight = DrawTextW(hdc, NULL, -1, &rect, 0);
499 ok(textheight==0,"Got textheight from DrawTextW\n");
500 textheight = DrawTextExW(hdc, NULL, -1, &rect, 0, NULL );
501 ok(textheight==0,"Got textheight from DrawTextExW\n");
502 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
503 heightcheck = textheight = DrawTextW(hdc, NULL, 10, &rect, 0);
504 ok(textheight==0,"Got textheight from DrawTextW\n");
505 textheight = DrawTextExW(hdc, NULL, 10, &rect, 0, NULL );
506 ok(textheight==0,"Got textheight from DrawTextW\n");
507 ok(textheight == heightcheck,"DrawTextEx and DrawText differ in return\n");
510 dtp.cbSize = -1; /* Invalid */
511 dtp.uiLengthDrawn = 1337;
512 textheight = DrawTextExW(hdc, textW, 0, &rect, 0, &dtp);
513 ok(textheight!=0,"Failed to get textheight from DrawTextExW\n");
514 ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
515 dtp.uiLengthDrawn = 1337;
516 textheight = DrawTextExW(hdc, emptystringW, 0, &rect, 0, &dtp);
517 if (conform_xp)
518 ok(textheight==0,"Got textheight from DrawTextExW\n");
519 ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
520 dtp.uiLengthDrawn = 1337;
521 textheight = DrawTextExW(hdc, NULL, 0, &rect, 0, &dtp);
522 if (conform_xp)
523 ok(textheight==0,"Got textheight from DrawTextExW\n");
524 ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
525 dtp.uiLengthDrawn = 1337;
526 textheight = DrawTextExW(hdc, emptystringW, -1, &rect, 0, &dtp);
527 ok(textheight==0,"Got textheight from DrawTextExW\n");
528 ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
529 if (conform_xp) {
530 /* Crashes on NT4 */
531 dtp.uiLengthDrawn = 1337;
532 textheight = DrawTextExW(hdc, NULL, -1, &rect, 0, &dtp);
533 ok(textheight==0,"Got textheight from DrawTextExW\n");
534 ok(dtp.uiLengthDrawn==1337, "invalid dtp.uiLengthDrawn = %i\n",dtp.uiLengthDrawn);
538 /* More test cases from bug 12226 */
539 SetRectEmpty(&rect);
540 textheight = DrawTextA(hdc, emptystring, -1, &rect, DT_CALCRECT | DT_LEFT | DT_SINGLELINE);
541 ok(textheight, "DrawTextA error %u\n", GetLastError());
542 ok(0 == rect.left, "expected 0, got %d\n", rect.left);
543 ok(0 == rect.right, "expected 0, got %d\n", rect.right);
544 ok(0 == rect.top, "expected 0, got %d\n", rect.top);
545 ok(rect.bottom, "rect.bottom should not be 0\n");
547 SetRectEmpty(&rect);
548 textheight = DrawTextW(hdc, emptystringW, -1, &rect, DT_CALCRECT | DT_LEFT | DT_SINGLELINE);
549 if (!textheight && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
551 win_skip( "DrawTextW not implemented\n" );
553 else
555 ok(textheight, "DrawTextW error %u\n", GetLastError());
556 ok(0 == rect.left, "expected 0, got %d\n", rect.left);
557 ok(0 == rect.right, "expected 0, got %d\n", rect.right);
558 ok(0 == rect.top, "expected 0, got %d\n", rect.top);
559 ok(rect.bottom, "rect.bottom should not be 0\n");
562 SetRect(&rect, 0, 0, 1, 1);
563 heightcheck = DrawTextA(hdc, wordbreak_text, -1, &rect, DT_CALCRECT);
564 SetRect(&rect, 0, 0, 1, 1);
565 textheight = DrawTextA(hdc, wordbreak_text, -1, &rect, DT_CALCRECT | DT_WORDBREAK);
566 ok(textheight == heightcheck * 2, "Got unexpected textheight %d, expected %d.\n",
567 textheight, heightcheck * 2);
568 SetRect(&rect, 0, 0, 1, 1);
569 textheight = DrawTextA(hdc, wordbreak_text, -1, &rect, DT_CALCRECT | DT_WORDBREAK | DT_EDITCONTROL);
570 ok(textheight >= heightcheck * 6, "Got unexpected textheight %d, expected at least %d.\n",
571 textheight, heightcheck * 6);
573 SetRect(&rect, 0, 0, 1, 1);
574 heightcheck = DrawTextW(hdc, wordbreak_textW, -1, &rect, DT_CALCRECT);
575 SetRect(&rect, 0, 0, 1, 1);
576 textheight = DrawTextW(hdc, wordbreak_textW, -1, &rect, DT_CALCRECT | DT_WORDBREAK);
577 ok(textheight == heightcheck * 2, "Got unexpected textheight %d, expected %d.\n",
578 textheight, heightcheck * 2);
579 SetRect(&rect, 0, 0, 1, 1);
580 textheight = DrawTextW(hdc, wordbreak_textW, -1, &rect, DT_CALCRECT | DT_WORDBREAK | DT_EDITCONTROL);
581 ok(textheight >= heightcheck * 6, "Got unexpected textheight %d, expected at least %d.\n",
582 textheight, heightcheck * 6);
584 /* DT_TABSTOP | DT_EXPANDTABS tests */
585 SetRect( &rect, 0,0, 10, 10);
586 textheight = DrawTextA(hdc, tabstring, -1, &rect, DT_TABSTOP | DT_EXPANDTABS );
587 ok(textheight >= heightcheck, "Got unexpected textheight %d\n", textheight);
589 SetRect( &rect, 0,0, 10, 10);
590 memset(&dtp, 0, sizeof(dtp));
591 dtp.cbSize = sizeof(dtp);
592 textheight = DrawTextExA(hdc, tabstring, -1, &rect, DT_CALCRECT, &dtp);
593 ok(textheight >= heightcheck, "Got unexpected textheight %d\n", textheight);
594 ok(dtp.iTabLength == 0, "invalid dtp.iTabLength = %i\n",dtp.iTabLength);
596 SetRect( &rect2, 0,0, 10, 10);
597 memset(&dtp, 0, sizeof(dtp));
598 dtp.cbSize = sizeof(dtp);
599 textheight = DrawTextExA(hdc, tabstring, -1, &rect2, DT_CALCRECT | DT_TABSTOP | DT_EXPANDTABS, &dtp);
600 ok(textheight >= heightcheck, "Got unexpected textheight %d\n", textheight);
601 ok(dtp.iTabLength == 0, "invalid dtp.iTabLength = %i\n",dtp.iTabLength);
602 ok(rect.left == rect2.left && rect.right != rect2.right && rect.top == rect2.top && rect.bottom == rect2.bottom,
603 "incorrect rect %s rect2 %s\n", wine_dbgstr_rect(&rect), wine_dbgstr_rect(&rect2));
605 SetRect( &rect, 0,0, 10, 10);
606 memset(&dtp, 0, sizeof(dtp));
607 dtp.cbSize = sizeof(dtp);
608 dtp.iTabLength = 8;
609 textheight = DrawTextExA(hdc, tabstring, -1, &rect, DT_CALCRECT | DT_TABSTOP | DT_EXPANDTABS, &dtp);
610 ok(textheight >= heightcheck, "Got unexpected textheight %d\n", textheight);
611 ok(dtp.iTabLength == 8, "invalid dtp.iTabLength = %i\n",dtp.iTabLength);
612 ok(rect.left == rect2.left, "unexpected value %d, got %d\n", rect.left, rect2.left);
613 /* XP, 2003 appear to not give the same values. */
614 ok(rect.right == rect2.right || broken(rect.right > rect2.right), "unexpected value %d, got %d\n",rect.right, rect2.right);
615 ok(rect.top == rect2.top, "unexpected value %d, got %d\n", rect.top, rect2.top);
616 ok(rect.bottom == rect2.bottom , "unexpected value %d, got %d\n", rect.bottom, rect2.bottom);
619 SelectObject(hdc, hOldFont);
620 ret = DeleteObject(hFont);
621 ok( ret, "DeleteObject error %u\n", GetLastError());
623 /* Clean up */
624 ret = ReleaseDC(hwnd, hdc);
625 ok( ret, "ReleaseDC error %u\n", GetLastError());
626 ret = DestroyWindow(hwnd);
627 ok( ret, "DestroyWindow error %u\n", GetLastError());
630 /* replace tabs by \t */
631 static void strfmt( const char *str, char *strout)
633 unsigned int i,j ;
634 for(i=0,j=0;i<=strlen(str);i++,j++)
635 if((strout[j]=str[i])=='\t') {
636 strout[j++]='\\';
637 strout[j]='t';
642 #define TABTEST( tabval, tabcount, string, _exp) \
643 { int i; char strdisp[64];\
644 for(i=0;i<8;i++) tabs[i]=(i+1)*(tabval); \
645 extent = GetTabbedTextExtentA( hdc, string, strlen( string), (tabcount), tabs); \
646 strfmt( string, strdisp); \
647 /* trace( "Extent is %08lx\n", extent); */\
648 ok( extent == _exp, "Test case \"%s\". Text extent is 0x%x, expected 0x%x tab %d tabcount %d\n", \
649 strdisp, extent, _exp, tabval, tabcount); \
653 static void test_TabbedText(void)
655 HWND hwnd;
656 HDC hdc;
657 BOOL ret;
658 TEXTMETRICA tm;
659 DWORD extent;
660 INT tabs[8], cx, cy, tab, tabcount,t,align;
662 /* Initialization */
663 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP,
664 0, 0, 200, 200, 0, 0, 0, NULL);
665 ok(hwnd != 0, "CreateWindowExA error %u\n", GetLastError());
666 hdc = GetDC(hwnd);
667 ok(hdc != 0, "GetDC error %u\n", GetLastError());
669 ret = GetTextMetricsA( hdc, &tm);
670 ok( ret, "GetTextMetrics error %u\n", GetLastError());
672 extent = GetTabbedTextExtentA( hdc, "x", 0, 1, tabs);
673 ok( extent == 0, "GetTabbedTextExtentA returned non-zero on nCount == 0\n");
675 extent = GetTabbedTextExtentA( hdc, "x", 1, 1, tabs);
676 cx = LOWORD( extent);
677 cy = HIWORD( extent);
678 trace( "cx is %d cy is %d\n", cx, cy);
680 align=1;
681 for( t=-1; t<=1; t++) { /* slightly adjust the 4 char tabstop, to
682 catch the one off errors */
683 tab = (cx *4 + t);
684 /* test the special case tabcount =1 and the general array (80 of tabs */
685 for( tabcount = 1; tabcount <= 8; tabcount +=7) {
686 TABTEST( align * tab, tabcount, "\t", MAKELONG(tab, cy))
687 TABTEST( align * tab, tabcount, "xxx\t", MAKELONG(tab, cy))
688 TABTEST( align * tab, tabcount, "\tx", MAKELONG(tab+cx, cy))
689 TABTEST( align * tab, tabcount, "\t\t", MAKELONG(tab*2, cy))
690 TABTEST( align * tab, tabcount, "\tx\t", MAKELONG(tab*2, cy))
691 TABTEST( align * tab, tabcount, "x\tx", MAKELONG(tab+cx, cy))
692 TABTEST( align * tab, tabcount, "xx\tx", MAKELONG(tab+cx, cy))
693 TABTEST( align * tab, tabcount, "xxx\tx", MAKELONG(tab+cx, cy))
694 TABTEST( align * tab, tabcount, "xxxx\tx", MAKELONG(t>0 ? tab + cx : 2*tab+cx, cy))
695 TABTEST( align * tab, tabcount, "xxxxx\tx", MAKELONG(2*tab+cx, cy))
698 align=-1;
699 for( t=-1; t<=1; t++) { /* slightly adjust the 4 char tabstop, to
700 catch the one off errors */
701 tab = (cx *4 + t);
702 /* test the special case tabcount =1 and the general array (8) of tabs */
703 for( tabcount = 1; tabcount <= 8; tabcount +=7) {
704 TABTEST( align * tab, tabcount, "\t", MAKELONG(tab, cy))
705 TABTEST( align * tab, tabcount, "xxx\t", MAKELONG(tab, cy))
706 TABTEST( align * tab, tabcount, "\tx", MAKELONG(tab, cy))
707 TABTEST( align * tab, tabcount, "\t\t", MAKELONG(tab*2, cy))
708 TABTEST( align * tab, tabcount, "\tx\t", MAKELONG(tab*2, cy))
709 TABTEST( align * tab, tabcount, "x\tx", MAKELONG(tab, cy))
710 TABTEST( align * tab, tabcount, "xx\tx", MAKELONG(tab, cy))
711 TABTEST( align * tab, tabcount, "xxx\tx", MAKELONG(4 * cx >= tab ? 2*tab :tab, cy))
712 TABTEST( align * tab, tabcount, "xxxx\tx", MAKELONG(2*tab, cy))
713 TABTEST( align * tab, tabcount, "xxxxx\tx", MAKELONG(2*tab, cy))
717 ReleaseDC( hwnd, hdc );
718 DestroyWindow( hwnd );
721 static void test_DrawState(void)
723 static const char text[] = "Sample text string";
724 HWND hwnd;
725 HDC hdc;
726 BOOL ret;
728 hwnd = CreateWindowExA(0, "static", NULL, WS_POPUP,
729 0, 0, 200, 200, 0, 0, 0, NULL);
730 assert(hwnd);
732 hdc = GetDC(hwnd);
733 assert(hdc);
735 SetLastError(0xdeadbeef);
736 ret = DrawStateA(hdc, GetStockObject(DKGRAY_BRUSH), NULL, (LPARAM)text, strlen(text),
737 0, 0, 10, 10, DST_TEXT);
738 ok(ret, "DrawState error %u\n", GetLastError());
740 SetLastError(0xdeadbeef);
741 ret = DrawStateA(hdc, GetStockObject(DKGRAY_BRUSH), NULL, (LPARAM)text, 0,
742 0, 0, 10, 10, DST_TEXT);
743 ok(ret, "DrawState error %u\n", GetLastError());
745 SetLastError(0xdeadbeef);
746 ret = DrawStateA(hdc, GetStockObject(DKGRAY_BRUSH), NULL, 0, strlen(text),
747 0, 0, 10, 10, DST_TEXT);
748 ok(!ret || broken(ret) /* win98 */, "DrawState succeeded\n");
749 ok(GetLastError() == 0xdeadbeef, "not expected error %u\n", GetLastError());
751 SetLastError(0xdeadbeef);
752 ret = DrawStateA(hdc, GetStockObject(DKGRAY_BRUSH), NULL, 0, 0,
753 0, 0, 10, 10, DST_TEXT);
754 ok(!ret || broken(ret) /* win98 */, "DrawState succeeded\n");
755 ok(GetLastError() == 0xdeadbeef, "not expected error %u\n", GetLastError());
757 ReleaseDC(hwnd, hdc);
758 DestroyWindow(hwnd);
761 START_TEST(text)
763 test_TabbedText();
764 test_DrawTextCalcRect();
765 test_DrawState();