1 /* 2 * Unit test suite for pens (and init) 3 * 4 * Copyright (C) 2007 Google (Evan Stade) 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <math.h> 22 23 #include "objbase.h" 24 #include "gdiplus.h" 25 #include "wine/test.h" 26 27 #define expect(expected, got) ok(got == expected, "Expected %.8x, got %.8x\n", expected, got) 28 #define expectf(expected, got) ok(fabs(got - expected) < 0.1, "Expected %.2f, got %.2f\n", expected, got) 29 30 static void test_startup(void) 31 { 32 GpPen *pen = NULL; 33 Status status; 34 struct GdiplusStartupInput gdiplusStartupInput; 35 ULONG_PTR gdiplusToken; 36 int gpversion; 37 38 gdiplusStartupInput.DebugEventCallback = NULL; 39 gdiplusStartupInput.SuppressBackgroundThread = 0; 40 gdiplusStartupInput.SuppressExternalCodecs = 0; 41 42 for (gpversion=1; gpversion<256; gpversion++) 43 { 44 gdiplusStartupInput.GdiplusVersion = gpversion; 45 status = GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 46 ok(status == Ok || status == UnsupportedGdiplusVersion, 47 "GdiplusStartup returned %x\n", status); 48 GdiplusShutdown(gdiplusToken); 49 if (status != Ok) 50 { 51 gpversion--; 52 break; 53 } 54 } 55 56 ok(gpversion > 0 && gpversion <= 2, "unexpected gdiplus version %i\n", gpversion); 57 trace("gdiplus version is %i\n", gpversion); 58 59 status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen); 60 61 todo_wine 62 expect(GdiplusNotInitialized, status); 63 64 GdipDeletePen(pen); 65 } 66 67 static void test_constructor_destructor(void) 68 { 69 GpStatus status; 70 GpPen *pen = NULL; 71 72 status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, NULL); 73 expect(InvalidParameter, status); 74 ok(pen == NULL, "Expected pen to be NULL\n"); 75 76 status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen); 77 expect(Ok, status); 78 ok(pen != NULL, "Expected pen to be initialized\n"); 79 80 status = GdipDeletePen(NULL); 81 expect(InvalidParameter, status); 82 83 status = GdipDeletePen(pen); 84 expect(Ok, status); 85 } 86 87 static void test_constructor_destructor2(void) 88 { 89 GpStatus status; 90 GpPen *pen = NULL; 91 GpBrush *brush = NULL; 92 GpPointF points[2]; 93 94 status = GdipCreatePen2(NULL, 10.0f, UnitPixel, &pen); 95 expect(InvalidParameter, status); 96 ok(pen == NULL, "Expected pen to be NULL\n"); 97 98 points[0].X = 7.0; 99 points[0].Y = 11.0; 100 points[1].X = 13.0; 101 points[1].Y = 17.0; 102 103 status = GdipCreateLineBrush(&points[0], &points[1], (ARGB)0xffff00ff, 104 (ARGB)0xff0000ff, WrapModeTile, (GpLineGradient **)&brush); 105 expect(Ok, status); 106 ok(brush != NULL, "Expected brush to be initialized\n"); 107 108 status = GdipCreatePen2(brush, 10.0f, UnitPixel, &pen); 109 expect(Ok, status); 110 ok(pen != NULL, "Expected pen to be initialized\n"); 111 112 status = GdipDeletePen(pen); 113 expect(Ok, status); 114 115 status = GdipDeleteBrush(brush); 116 expect(Ok, status); 117 } 118 119 static void test_brushfill(void) 120 { 121 GpStatus status; 122 GpPen *pen; 123 GpBrush *brush, *brush2; 124 GpBrushType type; 125 ARGB color = 0; 126 127 /* default solid */ 128 GdipCreatePen1(0xdeadbeef, 4.5, UnitWorld, &pen); 129 status = GdipGetPenBrushFill(pen, &brush); 130 expect(Ok, status); 131 GdipGetBrushType(brush, &type); 132 expect(BrushTypeSolidColor, type); 133 GdipGetPenColor(pen, &color); 134 expect(0xdeadbeef, color); 135 GdipDeleteBrush(brush); 136 137 /* color controlled by brush */ 138 GdipCreateSolidFill(0xabaddeed, (GpSolidFill**)&brush); 139 status = GdipSetPenBrushFill(pen, brush); 140 expect(Ok, status); 141 GdipGetPenColor(pen, &color); 142 expect(0xabaddeed, color); 143 GdipDeleteBrush(brush); 144 color = 0; 145 146 /* get returns a clone, not a reference */ 147 GdipGetPenBrushFill(pen, &brush); 148 GdipSetSolidFillColor((GpSolidFill*)brush, 0xbeadfeed); 149 GdipGetPenBrushFill(pen, &brush2); 150 ok(brush != brush2, "Expected to get a clone, not a copy of the reference\n"); 151 GdipGetSolidFillColor((GpSolidFill*)brush2, &color); 152 expect(0xabaddeed, color); 153 GdipDeleteBrush(brush); 154 GdipDeleteBrush(brush2); 155 156 /* brush cannot be NULL */ 157 status = GdipSetPenBrushFill(pen, NULL); 158 expect(InvalidParameter, status); 159 160 GdipDeletePen(pen); 161 } 162 163 static void test_dasharray(void) 164 { 165 GpPen *pen; 166 GpDashStyle style; 167 GpStatus status; 168 REAL dashes[12]; 169 170 GdipCreatePen1(0xdeadbeef, 10.0, UnitWorld, &pen); 171 dashes[0] = 10.0; 172 dashes[1] = 11.0; 173 dashes[2] = 12.0; 174 dashes[3] = 13.0; 175 dashes[4] = 14.0; 176 dashes[5] = -100.0; 177 dashes[6] = -100.0; 178 dashes[7] = dashes[8] = dashes[9] = dashes[10] = dashes[11] = 0.0; 179 180 /* setting the array sets the type to custom */ 181 GdipGetPenDashStyle(pen, &style); 182 expect(DashStyleSolid, style); 183 status = GdipSetPenDashArray(pen, dashes, 2); 184 expect(Ok, status); 185 GdipGetPenDashStyle(pen, &style); 186 expect(DashStyleCustom, style); 187 188 /* Getting the array on a non-custom pen returns invalid parameter (unless 189 * you are getting 0 elements).*/ 190 GdipSetPenDashStyle(pen, DashStyleSolid); 191 status = GdipGetPenDashArray(pen, &dashes[5], 2); 192 expect(InvalidParameter, status); 193 status = GdipGetPenDashArray(pen, &dashes[5], 0); 194 expect(Ok, status); 195 196 /* What does setting DashStyleCustom do to the array length? */ 197 GdipSetPenDashArray(pen, dashes, 2); 198 GdipSetPenDashStyle(pen, DashStyleCustom); 199 status = GdipGetPenDashArray(pen, &dashes[5], 2); 200 expect(Ok, status); 201 expectf(10.0, dashes[5]); 202 expectf(11.0, dashes[6]); 203 204 /* Set the array, then get with different sized buffers. */ 205 status = GdipSetPenDashArray(pen, dashes, 5); 206 expect(Ok, status); 207 dashes[5] = -100.0; 208 dashes[6] = -100.0; 209 status = GdipGetPenDashArray(pen, &dashes[5], 1); 210 expect(Ok, status); /* not InsufficientBuffer! */ 211 expectf(10.0, dashes[5]); 212 expectf(-100.0, dashes[6]); 213 dashes[5] = -100.0; 214 status = GdipGetPenDashArray(pen, &dashes[5], 6); 215 expect(InvalidParameter, status); /* not Ok! */ 216 expectf(-100.0, dashes[5]); 217 expectf(-100.0, dashes[6]); 218 219 /* Some invalid array values. */ 220 status = GdipSetPenDashArray(pen, &dashes[7], 5); 221 expect(InvalidParameter, status); 222 dashes[9] = -1.0; 223 status = GdipSetPenDashArray(pen, &dashes[7], 5); 224 expect(InvalidParameter, status); 225 226 /* Try to set with count = 0. */ 227 GdipSetPenDashStyle(pen, DashStyleDot); 228 if (0) /* corrupts stack on 64-bit Vista */ 229 { 230 status = GdipSetPenDashArray(pen, dashes, 0); 231 ok(status == OutOfMemory || status == InvalidParameter, 232 "Expected OutOfMemory or InvalidParameter, got %.8x\n", status); 233 } 234 status = GdipSetPenDashArray(pen, dashes, -1); 235 ok(status == OutOfMemory || status == InvalidParameter, 236 "Expected OutOfMemory or InvalidParameter, got %.8x\n", status); 237 GdipGetPenDashStyle(pen, &style); 238 expect(DashStyleDot, style); 239 240 GdipDeletePen(pen); 241 } 242 243 static void test_customcap(void) 244 { 245 GpPen *pen; 246 GpStatus status; 247 GpCustomLineCap *custom; 248 249 status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen); 250 expect(Ok, status); 251 252 /* NULL args */ 253 status = GdipGetPenCustomStartCap(NULL, NULL); 254 expect(InvalidParameter, status); 255 status = GdipGetPenCustomStartCap(pen, NULL); 256 expect(InvalidParameter, status); 257 status = GdipGetPenCustomStartCap(NULL, &custom); 258 expect(InvalidParameter, status); 259 260 status = GdipGetPenCustomEndCap(NULL, NULL); 261 expect(InvalidParameter, status); 262 status = GdipGetPenCustomEndCap(pen, NULL); 263 expect(InvalidParameter, status); 264 status = GdipGetPenCustomEndCap(NULL, &custom); 265 expect(InvalidParameter, status); 266 267 /* native crashes on pen == NULL, custom != NULL */ 268 status = GdipSetPenCustomStartCap(NULL, NULL); 269 expect(InvalidParameter, status); 270 status = GdipSetPenCustomStartCap(pen, NULL); 271 expect(InvalidParameter, status); 272 273 status = GdipSetPenCustomEndCap(NULL, NULL); 274 expect(InvalidParameter, status); 275 status = GdipSetPenCustomEndCap(pen, NULL); 276 expect(InvalidParameter, status); 277 278 /* get without setting previously */ 279 custom = (GpCustomLineCap*)0xdeadbeef; 280 status = GdipGetPenCustomEndCap(pen, &custom); 281 expect(Ok, status); 282 ok(custom == NULL,"Expect CustomCap == NULL\n"); 283 284 custom = (GpCustomLineCap*)0xdeadbeef; 285 status = GdipGetPenCustomStartCap(pen, &custom); 286 expect(Ok, status); 287 ok(custom == NULL,"Expect CustomCap == NULL\n"); 288 289 GdipDeletePen(pen); 290 } 291 292 static void test_penfilltype(void) 293 { 294 GpPen *pen; 295 GpSolidFill *solid; 296 GpLineGradient *line; 297 GpPointF a, b; 298 GpStatus status; 299 GpPenType type; 300 301 /* NULL */ 302 status = GdipGetPenFillType(NULL, NULL); 303 expect(InvalidParameter, status); 304 305 status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen); 306 expect(Ok, status); 307 status = GdipGetPenFillType(pen, NULL); 308 expect(InvalidParameter, status); 309 310 /* created with GdipCreatePen1() */ 311 status = GdipGetPenFillType(pen, &type); 312 expect(Ok, status); 313 expect(PenTypeSolidColor, type); 314 GdipDeletePen(pen); 315 316 /* based on SolidBrush */ 317 status = GdipCreateSolidFill((ARGB)0xffff00ff, &solid); 318 expect(Ok, status); 319 status = GdipCreatePen2((GpBrush*)solid, 10.0f, UnitPixel, &pen); 320 expect(Ok, status); 321 status = GdipGetPenFillType(pen, &type); 322 expect(Ok, status); 323 expect(PenTypeSolidColor, type); 324 GdipDeletePen(pen); 325 GdipDeleteBrush((GpBrush*)solid); 326 327 /* based on LinearGradientBrush */ 328 a.X = a.Y = 0.0; 329 b.X = b.Y = 10.0; 330 status = GdipCreateLineBrush(&a, &b, (ARGB)0xffff00ff, (ARGB)0xffff0000, 331 WrapModeTile, &line); 332 expect(Ok, status); 333 status = GdipCreatePen2((GpBrush*)line, 10.0f, UnitPixel, &pen); 334 expect(Ok, status); 335 status = GdipGetPenFillType(pen, &type); 336 expect(Ok, status); 337 expect(PenTypeLinearGradient, type); 338 GdipDeletePen(pen); 339 GdipDeleteBrush((GpBrush*)line); 340 } 341 342 static void test_compoundarray(void) 343 { 344 GpStatus status; 345 GpPen *pen; 346 static const REAL testvalues[] = {0.2, 0.4, 0.6, 0.8}; 347 INT count; 348 349 status = GdipSetPenCompoundArray(NULL, testvalues, 4); 350 expect(InvalidParameter, status); 351 352 status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen); 353 expect(Ok, status); 354 355 status = GdipGetPenCompoundCount(NULL, NULL); 356 expect(InvalidParameter, status); 357 358 status = GdipGetPenCompoundCount(pen, NULL); 359 expect(InvalidParameter, status); 360 361 count = 10; 362 status = GdipGetPenCompoundCount(pen, &count); 363 todo_wine { 364 expect(Ok, status); 365 ok(count == 0, "Unexpected compound count %d\n", count); 366 } 367 status = GdipSetPenCompoundArray(pen, NULL, 0); 368 expect(InvalidParameter, status); 369 status = GdipSetPenCompoundArray(pen, NULL, 4); 370 expect(InvalidParameter, status); 371 status = GdipSetPenCompoundArray(pen, testvalues, 3); 372 expect(InvalidParameter, status); 373 status = GdipSetPenCompoundArray(pen, testvalues, 0); 374 expect(InvalidParameter, status); 375 status = GdipSetPenCompoundArray(pen, testvalues, -2); 376 expect(InvalidParameter, status); 377 378 status = GdipSetPenCompoundArray(pen, testvalues, 4); 379 todo_wine expect(Ok, status); 380 status = GdipSetPenCompoundArray(pen, NULL, 0); 381 expect(InvalidParameter, status); 382 383 count = 0; 384 status = GdipGetPenCompoundCount(pen, &count); 385 todo_wine { 386 expect(Ok, status); 387 ok(count == 4, "Unexpected compound count %d\n", count); 388 } 389 GdipDeletePen(pen); 390 } 391 392 static void test_transform(void) 393 { 394 GpStatus status; 395 GpPen *pen; 396 GpMatrix *matrix, *matrix2; 397 REAL values[6]; 398 399 status = GdipCreatePen1((ARGB)0xffff00ff, 10.0f, UnitPixel, &pen); 400 expect(Ok, status); 401 402 status = GdipCreateMatrix(&matrix); 403 expect(Ok, status); 404 405 status = GdipGetPenTransform(pen, matrix); 406 expect(Ok, status); 407 408 status = GdipGetMatrixElements(matrix, values); 409 expect(Ok, status); 410 411 expectf(1.0, values[0]); 412 expectf(0.0, values[1]); 413 expectf(0.0, values[2]); 414 expectf(1.0, values[3]); 415 expectf(0.0, values[4]); 416 expectf(0.0, values[5]); 417 418 GdipCreateMatrix2(3.0, -2.0, 5.0, 2.0, 6.0, 3.0, &matrix2); 419 status = GdipSetPenTransform(pen, matrix2); 420 expect(Ok, status); 421 GdipDeleteMatrix(matrix2); 422 423 status = GdipGetPenTransform(pen, matrix); 424 expect(Ok, status); 425 status = GdipGetMatrixElements(matrix, values); 426 expect(Ok, status); 427 expectf(3.0, values[0]); 428 expectf(-2.0, values[1]); 429 expectf(5.0, values[2]); 430 expectf(2.0, values[3]); 431 expectf(6.0, values[4]); 432 expectf(3.0, values[5]); 433 434 /* Translate */ 435 status = GdipTranslatePenTransform(NULL, 1.0, -2.0, MatrixOrderAppend); 436 expect(InvalidParameter, status); 437 438 status = GdipTranslatePenTransform(pen, 1.0, -2.0, MatrixOrderAppend); 439 expect(Ok, status); 440 441 status = GdipGetPenTransform(pen, matrix); 442 expect(Ok, status); 443 status = GdipGetMatrixElements(matrix, values); 444 expect(Ok, status); 445 expectf(3.0, values[0]); 446 expectf(-2.0, values[1]); 447 expectf(5.0, values[2]); 448 expectf(2.0, values[3]); 449 expectf(7.0, values[4]); 450 expectf(1.0, values[5]); 451 452 status = GdipTranslatePenTransform(pen, -3.0, 5.0, MatrixOrderPrepend); 453 expect(Ok, status); 454 455 status = GdipGetPenTransform(pen, matrix); 456 expect(Ok, status); 457 status = GdipGetMatrixElements(matrix, values); 458 expect(Ok, status); 459 expectf(3.0, values[0]); 460 expectf(-2.0, values[1]); 461 expectf(5.0, values[2]); 462 expectf(2.0, values[3]); 463 expectf(23.0, values[4]); 464 expectf(17.0, values[5]); 465 466 status = GdipResetPenTransform(pen); 467 expect(Ok, status); 468 469 status = GdipGetPenTransform(pen, matrix); 470 expect(Ok, status); 471 status = GdipGetMatrixElements(matrix, values); 472 expect(Ok, status); 473 474 expectf(1.0, values[0]); 475 expectf(0.0, values[1]); 476 expectf(0.0, values[2]); 477 expectf(1.0, values[3]); 478 expectf(0.0, values[4]); 479 expectf(0.0, values[5]); 480 481 GdipDeletePen(pen); 482 483 GdipDeleteMatrix(matrix); 484 } 485 486 START_TEST(pen) 487 { 488 struct GdiplusStartupInput gdiplusStartupInput; 489 ULONG_PTR gdiplusToken; 490 HMODULE hmsvcrt; 491 int (CDECL * _controlfp_s)(unsigned int *cur, unsigned int newval, unsigned int mask); 492 493 /* Enable all FP exceptions except _EM_INEXACT, which gdi32 can trigger */ 494 hmsvcrt = LoadLibraryA("msvcrt"); 495 _controlfp_s = (void*)GetProcAddress(hmsvcrt, "_controlfp_s"); 496 if (_controlfp_s) _controlfp_s(0, 0, 0x0008001e); 497 498 test_startup(); 499 500 gdiplusStartupInput.GdiplusVersion = 1; 501 gdiplusStartupInput.DebugEventCallback = NULL; 502 gdiplusStartupInput.SuppressBackgroundThread = 0; 503 gdiplusStartupInput.SuppressExternalCodecs = 0; 504 505 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 506 507 test_constructor_destructor(); 508 test_constructor_destructor2(); 509 test_brushfill(); 510 test_dasharray(); 511 test_customcap(); 512 test_penfilltype(); 513 test_compoundarray(); 514 test_transform(); 515 516 GdiplusShutdown(gdiplusToken); 517 } 518