1 /* 2 * Copyright (C) 2007 Google (Evan Stade) 3 * Copyright (C) 2003-2004,2007 Novell, Inc. http://www.novell.com (Ravindra (rkumar@novell.com)) 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #include <stdarg.h> 21 22 #include "windef.h" 23 #include "winbase.h" 24 #include "winuser.h" 25 #include "wingdi.h" 26 27 #define COBJMACROS 28 #include "objbase.h" 29 #include "olectl.h" 30 #include "ole2.h" 31 32 #include "gdiplus.h" 33 #include "gdiplus_private.h" 34 #include "wine/debug.h" 35 36 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus); 37 38 #ifdef __REACTOS__ 39 /* 40 Unix stuff 41 Code from http://www.johndcook.com/blog/2009/01/19/stand-alone-error-function-erf/ 42 */ 43 double erf(double x) 44 { 45 const float a1 = 0.254829592f; 46 const float a2 = -0.284496736f; 47 const float a3 = 1.421413741f; 48 const float a4 = -1.453152027f; 49 const float a5 = 1.061405429f; 50 const float p = 0.3275911f; 51 float t, y, sign; 52 53 /* Save the sign of x */ 54 sign = 1; 55 if (x < 0) 56 sign = -1; 57 x = abs(x); 58 59 /* A & S 7.1.26 */ 60 t = 1.0/(1.0 + p*x); 61 y = 1.0 - (((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*exp(-x*x); 62 63 return sign*y; 64 } 65 #endif 66 67 /****************************************************************************** 68 * GdipCloneBrush [GDIPLUS.@] 69 */ 70 GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone) 71 { 72 TRACE("(%p, %p)\n", brush, clone); 73 74 if(!brush || !clone) 75 return InvalidParameter; 76 77 switch(brush->bt){ 78 case BrushTypeSolidColor: 79 { 80 *clone = heap_alloc_zero(sizeof(GpSolidFill)); 81 if (!*clone) return OutOfMemory; 82 memcpy(*clone, brush, sizeof(GpSolidFill)); 83 break; 84 } 85 case BrushTypeHatchFill: 86 { 87 GpHatch *hatch = (GpHatch*)brush; 88 89 return GdipCreateHatchBrush(hatch->hatchstyle, hatch->forecol, hatch->backcol, (GpHatch**)clone); 90 } 91 case BrushTypePathGradient:{ 92 GpPathGradient *src, *dest; 93 INT count, pcount; 94 GpStatus stat; 95 96 *clone = heap_alloc_zero(sizeof(GpPathGradient)); 97 if (!*clone) return OutOfMemory; 98 99 src = (GpPathGradient*) brush, 100 dest = (GpPathGradient*) *clone; 101 102 memcpy(dest, src, sizeof(GpPathGradient)); 103 104 stat = GdipClonePath(src->path, &dest->path); 105 106 if(stat != Ok){ 107 heap_free(dest); 108 return stat; 109 } 110 111 dest->transform = src->transform; 112 113 /* blending */ 114 count = src->blendcount; 115 dest->blendcount = count; 116 dest->blendfac = heap_alloc_zero(count * sizeof(REAL)); 117 dest->blendpos = heap_alloc_zero(count * sizeof(REAL)); 118 dest->surroundcolors = heap_alloc_zero(dest->surroundcolorcount * sizeof(ARGB)); 119 pcount = dest->pblendcount; 120 if (pcount) 121 { 122 dest->pblendcolor = heap_alloc_zero(pcount * sizeof(ARGB)); 123 dest->pblendpos = heap_alloc_zero(pcount * sizeof(REAL)); 124 } 125 126 if(!dest->blendfac || !dest->blendpos || !dest->surroundcolors || 127 (pcount && (!dest->pblendcolor || !dest->pblendpos))){ 128 GdipDeletePath(dest->path); 129 heap_free(dest->blendfac); 130 heap_free(dest->blendpos); 131 heap_free(dest->surroundcolors); 132 heap_free(dest->pblendcolor); 133 heap_free(dest->pblendpos); 134 heap_free(dest); 135 return OutOfMemory; 136 } 137 138 memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL)); 139 memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL)); 140 memcpy(dest->surroundcolors, src->surroundcolors, dest->surroundcolorcount * sizeof(ARGB)); 141 142 if (pcount) 143 { 144 memcpy(dest->pblendcolor, src->pblendcolor, pcount * sizeof(ARGB)); 145 memcpy(dest->pblendpos, src->pblendpos, pcount * sizeof(REAL)); 146 } 147 148 break; 149 } 150 case BrushTypeLinearGradient:{ 151 GpLineGradient *dest, *src; 152 INT count, pcount; 153 154 dest = heap_alloc_zero(sizeof(GpLineGradient)); 155 if(!dest) return OutOfMemory; 156 157 src = (GpLineGradient*)brush; 158 159 memcpy(dest, src, sizeof(GpLineGradient)); 160 161 count = dest->blendcount; 162 dest->blendfac = heap_alloc_zero(count * sizeof(REAL)); 163 dest->blendpos = heap_alloc_zero(count * sizeof(REAL)); 164 pcount = dest->pblendcount; 165 if (pcount) 166 { 167 dest->pblendcolor = heap_alloc_zero(pcount * sizeof(ARGB)); 168 dest->pblendpos = heap_alloc_zero(pcount * sizeof(REAL)); 169 } 170 171 if (!dest->blendfac || !dest->blendpos || 172 (pcount && (!dest->pblendcolor || !dest->pblendpos))) 173 { 174 heap_free(dest->blendfac); 175 heap_free(dest->blendpos); 176 heap_free(dest->pblendcolor); 177 heap_free(dest->pblendpos); 178 heap_free(dest); 179 return OutOfMemory; 180 } 181 182 dest->transform = src->transform; 183 184 memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL)); 185 memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL)); 186 187 if (pcount) 188 { 189 memcpy(dest->pblendcolor, src->pblendcolor, pcount * sizeof(ARGB)); 190 memcpy(dest->pblendpos, src->pblendpos, pcount * sizeof(REAL)); 191 } 192 193 *clone = &dest->brush; 194 break; 195 } 196 case BrushTypeTextureFill: 197 { 198 GpStatus stat; 199 GpTexture *texture = (GpTexture*)brush; 200 GpTexture *new_texture; 201 UINT width, height; 202 203 stat = GdipGetImageWidth(texture->image, &width); 204 if (stat != Ok) return stat; 205 stat = GdipGetImageHeight(texture->image, &height); 206 if (stat != Ok) return stat; 207 208 stat = GdipCreateTextureIA(texture->image, texture->imageattributes, 0, 0, width, height, &new_texture); 209 210 if (stat == Ok) 211 { 212 new_texture->transform = texture->transform; 213 *clone = &new_texture->brush; 214 } 215 else 216 *clone = NULL; 217 218 return stat; 219 } 220 default: 221 ERR("not implemented for brush type %d\n", brush->bt); 222 return NotImplemented; 223 } 224 225 TRACE("<-- %p\n", *clone); 226 return Ok; 227 } 228 229 static const char HatchBrushes[][8] = { 230 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HatchStyleHorizontal */ 231 { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleVertical */ 232 { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HatchStyleForwardDiagonal */ 233 { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HatchStyleBackwardDiagonal */ 234 { 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleCross */ 235 { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }, /* HatchStyleDiagonalCross */ 236 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80 }, /* HatchStyle05Percent */ 237 { 0x00, 0x02, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88 }, /* HatchStyle10Percent */ 238 { 0x00, 0x22, 0x00, 0xcc, 0x00, 0x22, 0x00, 0xcc }, /* HatchStyle20Percent */ 239 { 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc }, /* HatchStyle25Percent */ 240 { 0x00, 0xcc, 0x04, 0xcc, 0x00, 0xcc, 0x40, 0xcc }, /* HatchStyle30Percent */ 241 { 0x44, 0xcc, 0x22, 0xcc, 0x44, 0xcc, 0x22, 0xcc }, /* HatchStyle40Percent */ 242 { 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc }, /* HatchStyle50Percent */ 243 { 0x55, 0xcd, 0x55, 0xee, 0x55, 0xdc, 0x55, 0xee }, /* HatchStyle60Percent */ 244 { 0x55, 0xdd, 0x55, 0xff, 0x55, 0xdd, 0x55, 0xff }, /* HatchStyle70Percent */ 245 { 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff }, /* HatchStyle75Percent */ 246 { 0x55, 0xff, 0x59, 0xff, 0x55, 0xff, 0x99, 0xff }, /* HatchStyle80Percent */ 247 { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xfd, 0xff }, /* HatchStyle90Percent */ 248 { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 }, /* HatchStyleLightDownwardDiagonal */ 249 { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 }, /* HatchStyleLightUpwardDiagonal */ 250 { 0x99, 0x33, 0x66, 0xcc, 0x99, 0x33, 0x66, 0xcc }, /* HatchStyleDarkDownwardDiagonal */ 251 { 0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33, 0x99 }, /* HatchStyleDarkUpwardDiagonal */ 252 { 0xc1, 0x83, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0 }, /* HatchStyleWideDownwardDiagonal */ 253 { 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x07, 0x83, 0xc1 }, /* HatchStyleWideUpwardDiagonal */ 254 { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 }, /* HatchStyleLightVertical */ 255 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff }, /* HatchStyleLightHorizontal */ 256 { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, /* HatchStyleNarrowVertical */ 257 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, /* HatchStyleNarrowHorizontal */ 258 { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }, /* HatchStyleDarkVertical */ 259 { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff }, /* HatchStyleDarkHorizontal */ 260 }; 261 262 GpStatus get_hatch_data(GpHatchStyle hatchstyle, const char **result) 263 { 264 if (hatchstyle < ARRAY_SIZE(HatchBrushes)) 265 { 266 *result = HatchBrushes[hatchstyle]; 267 return Ok; 268 } 269 else 270 return NotImplemented; 271 } 272 273 /****************************************************************************** 274 * GdipCreateHatchBrush [GDIPLUS.@] 275 */ 276 GpStatus WINGDIPAPI GdipCreateHatchBrush(GpHatchStyle hatchstyle, ARGB forecol, ARGB backcol, GpHatch **brush) 277 { 278 TRACE("(%d, %d, %d, %p)\n", hatchstyle, forecol, backcol, brush); 279 280 if(!brush) return InvalidParameter; 281 282 if(hatchstyle < HatchStyleMin || hatchstyle > HatchStyleMax) 283 return InvalidParameter; 284 285 *brush = heap_alloc_zero(sizeof(GpHatch)); 286 if (!*brush) return OutOfMemory; 287 288 (*brush)->brush.bt = BrushTypeHatchFill; 289 (*brush)->forecol = forecol; 290 (*brush)->backcol = backcol; 291 (*brush)->hatchstyle = hatchstyle; 292 TRACE("<-- %p\n", *brush); 293 294 return Ok; 295 } 296 297 static GpStatus create_line_brush(const GpRectF *rect, ARGB startcolor, ARGB endcolor, 298 GpWrapMode wrap, GpLineGradient **line) 299 { 300 *line = heap_alloc_zero(sizeof(GpLineGradient)); 301 if(!*line) return OutOfMemory; 302 303 (*line)->brush.bt = BrushTypeLinearGradient; 304 (*line)->startcolor = startcolor; 305 (*line)->endcolor = endcolor; 306 (*line)->wrap = wrap; 307 (*line)->gamma = FALSE; 308 (*line)->rect = *rect; 309 (*line)->blendcount = 1; 310 (*line)->blendfac = heap_alloc_zero(sizeof(REAL)); 311 (*line)->blendpos = heap_alloc_zero(sizeof(REAL)); 312 313 if (!(*line)->blendfac || !(*line)->blendpos) 314 { 315 heap_free((*line)->blendfac); 316 heap_free((*line)->blendpos); 317 heap_free(*line); 318 *line = NULL; 319 return OutOfMemory; 320 } 321 322 (*line)->blendfac[0] = 1.0f; 323 (*line)->blendpos[0] = 1.0f; 324 325 (*line)->pblendcolor = NULL; 326 (*line)->pblendpos = NULL; 327 (*line)->pblendcount = 0; 328 329 GdipSetMatrixElements(&(*line)->transform, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f); 330 331 return Ok; 332 } 333 334 static void linegradient_init_transform(const GpPointF *startpoint, const GpPointF *endpoint, GpLineGradient *line) 335 { 336 float trans_x = line->rect.X + (line->rect.Width / 2.f); 337 float trans_y = line->rect.Y + (line->rect.Height / 2.f); 338 float dx = endpoint->X - startpoint->X; 339 float dy = endpoint->Y - startpoint->Y; 340 float t_cos, t_sin, w_ratio, h_ratio; 341 float h; 342 GpMatrix rot; 343 344 h = sqrtf(dx * dx + dy * dy); 345 346 t_cos = dx / h; 347 t_sin = dy / h; 348 349 w_ratio = (fabs(t_cos) * line->rect.Width + fabs(t_sin) * line->rect.Height) / line->rect.Width; 350 h_ratio = (fabs(t_sin) * line->rect.Width + fabs(t_cos) * line->rect.Height) / line->rect.Height; 351 352 GdipSetMatrixElements(&line->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 353 354 GdipSetMatrixElements(&rot, t_cos, t_sin, -1.f * t_sin, t_cos, 0, 0); 355 356 /* center about the origin */ 357 GdipTranslateMatrix(&line->transform, -trans_x, -trans_y, MatrixOrderAppend); 358 359 /* scale to normalize gradient along gradient line (?) */ 360 GdipScaleMatrix(&line->transform, w_ratio, h_ratio, MatrixOrderAppend); 361 362 /* rotate so the gradient is horizontal */ 363 GdipMultiplyMatrix(&line->transform, &rot, MatrixOrderAppend); 364 365 /* restore original offset in new coords */ 366 GdipTranslateMatrix(&line->transform, trans_x, trans_y, MatrixOrderAppend); 367 } 368 369 /****************************************************************************** 370 * GdipCreateLineBrush [GDIPLUS.@] 371 */ 372 GpStatus WINGDIPAPI GdipCreateLineBrush(GDIPCONST GpPointF* startpoint, 373 GDIPCONST GpPointF* endpoint, ARGB startcolor, ARGB endcolor, 374 GpWrapMode wrap, GpLineGradient **line) 375 { 376 GpStatus stat; 377 GpRectF rect; 378 379 TRACE("(%s, %s, %x, %x, %d, %p)\n", debugstr_pointf(startpoint), 380 debugstr_pointf(endpoint), startcolor, endcolor, wrap, line); 381 382 if(!line || !startpoint || !endpoint || wrap == WrapModeClamp) 383 return InvalidParameter; 384 385 if (startpoint->X == endpoint->X && startpoint->Y == endpoint->Y) 386 return OutOfMemory; 387 388 rect.X = startpoint->X < endpoint->X ? startpoint->X : endpoint->X; 389 rect.Y = startpoint->Y < endpoint->Y ? startpoint->Y : endpoint->Y; 390 rect.Width = fabs(startpoint->X - endpoint->X); 391 rect.Height = fabs(startpoint->Y - endpoint->Y); 392 393 if (rect.Width == 0.0f) 394 { 395 rect.X -= rect.Height / 2.0f; 396 rect.Width = rect.Height; 397 } 398 else if (rect.Height == 0.0f) 399 { 400 rect.Y -= rect.Width / 2.0f; 401 rect.Height = rect.Width; 402 } 403 404 stat = create_line_brush(&rect, startcolor, endcolor, wrap, line); 405 if (stat != Ok) 406 return stat; 407 408 linegradient_init_transform(startpoint, endpoint, *line); 409 410 TRACE("<-- %p\n", *line); 411 412 return Ok; 413 } 414 415 GpStatus WINGDIPAPI GdipCreateLineBrushI(GDIPCONST GpPoint* startpoint, 416 GDIPCONST GpPoint* endpoint, ARGB startcolor, ARGB endcolor, 417 GpWrapMode wrap, GpLineGradient **line) 418 { 419 GpPointF stF; 420 GpPointF endF; 421 422 TRACE("(%p, %p, %x, %x, %d, %p)\n", startpoint, endpoint, 423 startcolor, endcolor, wrap, line); 424 425 if(!startpoint || !endpoint) 426 return InvalidParameter; 427 428 stF.X = (REAL)startpoint->X; 429 stF.Y = (REAL)startpoint->Y; 430 endF.X = (REAL)endpoint->X; 431 endF.Y = (REAL)endpoint->Y; 432 433 return GdipCreateLineBrush(&stF, &endF, startcolor, endcolor, wrap, line); 434 } 435 436 GpStatus WINGDIPAPI GdipCreateLineBrushFromRect(GDIPCONST GpRectF* rect, 437 ARGB startcolor, ARGB endcolor, LinearGradientMode mode, GpWrapMode wrap, 438 GpLineGradient **line) 439 { 440 float angle; 441 442 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect, startcolor, endcolor, mode, 443 wrap, line); 444 445 if(!line || !rect) 446 return InvalidParameter; 447 448 switch (mode) 449 { 450 case LinearGradientModeHorizontal: 451 angle = 0.0f; 452 break; 453 case LinearGradientModeVertical: 454 angle = 90.0f; 455 break; 456 case LinearGradientModeForwardDiagonal: 457 angle = 45.0f; 458 break; 459 case LinearGradientModeBackwardDiagonal: 460 angle = 135.0f; 461 break; 462 default: 463 return InvalidParameter; 464 } 465 466 return GdipCreateLineBrushFromRectWithAngle(rect, startcolor, endcolor, angle, TRUE, wrap, line); 467 } 468 469 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectI(GDIPCONST GpRect* rect, 470 ARGB startcolor, ARGB endcolor, LinearGradientMode mode, GpWrapMode wrap, 471 GpLineGradient **line) 472 { 473 GpRectF rectF; 474 475 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect, startcolor, endcolor, mode, 476 wrap, line); 477 478 rectF.X = (REAL) rect->X; 479 rectF.Y = (REAL) rect->Y; 480 rectF.Width = (REAL) rect->Width; 481 rectF.Height = (REAL) rect->Height; 482 483 return GdipCreateLineBrushFromRect(&rectF, startcolor, endcolor, mode, wrap, line); 484 } 485 486 /****************************************************************************** 487 * GdipCreateLineBrushFromRectWithAngle [GDIPLUS.@] 488 */ 489 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF* rect, 490 ARGB startcolor, ARGB endcolor, REAL angle, BOOL isAngleScalable, GpWrapMode wrap, 491 GpLineGradient **line) 492 { 493 GpStatus stat; 494 REAL exofs, eyofs, far_x, far_y; 495 REAL sin_angle, cos_angle, sin_cos_angle; 496 GpPointF start, end; 497 498 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect, startcolor, endcolor, angle, isAngleScalable, 499 wrap, line); 500 501 if (!rect || !line || wrap == WrapModeClamp) 502 return InvalidParameter; 503 504 if (!rect->Width || !rect->Height) 505 return OutOfMemory; 506 507 angle = fmodf(angle, 360); 508 if (angle < 0) 509 angle += 360; 510 511 if (isAngleScalable) 512 { 513 float add_angle = 0; 514 515 while(angle >= 90) { 516 angle -= 180; 517 add_angle += M_PI; 518 } 519 520 if (angle != 90 && angle != -90) 521 angle = atan((rect->Width / rect->Height) * tan(deg2rad(angle))); 522 else 523 angle = deg2rad(angle); 524 angle += add_angle; 525 } 526 else 527 { 528 angle = deg2rad(angle); 529 } 530 531 sin_angle = sinf(angle); 532 cos_angle = cosf(angle); 533 sin_cos_angle = sin_angle * cos_angle; 534 535 far_x = rect->X + rect->Width; 536 far_y = rect->Y + rect->Height; 537 538 if (angle == 0.0f) 539 { 540 start.X = min(rect->X, far_x); 541 start.Y = rect->Y; 542 end.X = max(rect->X, far_x); 543 end.Y = rect->Y; 544 } 545 else if (sin_cos_angle >= 0) 546 { 547 start.X = min(rect->X, far_x); 548 start.Y = min(rect->Y, far_y); 549 end.X = max(rect->X, far_x); 550 end.Y = max(rect->Y, far_y); 551 } 552 else 553 { 554 start.X = max(rect->X, far_x); 555 start.Y = min(rect->Y, far_y); 556 end.X = min(rect->X, far_x); 557 end.Y = max(rect->Y, far_y); 558 } 559 560 stat = create_line_brush(rect, startcolor, endcolor, wrap, line); 561 if (stat != Ok || angle == 0.0f) 562 return stat; 563 564 if (sin_cos_angle >= 0) 565 { 566 exofs = rect->Height * sin_cos_angle + rect->Width * cos_angle * cos_angle; 567 eyofs = rect->Height * sin_angle * sin_angle + rect->Width * sin_cos_angle; 568 } 569 else 570 { 571 exofs = rect->Width * sin_angle * sin_angle + rect->Height * sin_cos_angle; 572 eyofs = -rect->Width * sin_cos_angle + rect->Height * sin_angle * sin_angle; 573 } 574 575 if (sin_angle >= 0) 576 { 577 end.X = rect->X + exofs; 578 end.Y = rect->Y + eyofs; 579 } 580 else 581 { 582 end.X = start.X; 583 end.Y = start.Y; 584 start.X = rect->X + exofs; 585 start.Y = rect->Y + eyofs; 586 } 587 588 linegradient_init_transform(&start, &end, *line); 589 590 return stat; 591 } 592 593 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngleI(GDIPCONST GpRect* rect, 594 ARGB startcolor, ARGB endcolor, REAL angle, BOOL isAngleScalable, GpWrapMode wrap, 595 GpLineGradient **line) 596 { 597 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect, startcolor, endcolor, angle, isAngleScalable, 598 wrap, line); 599 600 return GdipCreateLineBrushFromRectI(rect, startcolor, endcolor, LinearGradientModeForwardDiagonal, 601 wrap, line); 602 } 603 604 static GpStatus create_path_gradient(GpPath *path, ARGB centercolor, GpPathGradient **grad) 605 { 606 GpRectF bounds; 607 608 if(!path || !grad) 609 return InvalidParameter; 610 611 if (path->pathdata.Count < 2) 612 return OutOfMemory; 613 614 GdipGetPathWorldBounds(path, &bounds, NULL, NULL); 615 616 *grad = heap_alloc_zero(sizeof(GpPathGradient)); 617 if (!*grad) 618 { 619 return OutOfMemory; 620 } 621 622 GdipSetMatrixElements(&(*grad)->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 623 624 (*grad)->blendfac = heap_alloc_zero(sizeof(REAL)); 625 (*grad)->blendpos = heap_alloc_zero(sizeof(REAL)); 626 (*grad)->surroundcolors = heap_alloc_zero(sizeof(ARGB)); 627 if(!(*grad)->blendfac || !(*grad)->blendpos || !(*grad)->surroundcolors){ 628 heap_free((*grad)->blendfac); 629 heap_free((*grad)->blendpos); 630 heap_free((*grad)->surroundcolors); 631 heap_free(*grad); 632 *grad = NULL; 633 return OutOfMemory; 634 } 635 (*grad)->blendfac[0] = 1.0; 636 (*grad)->blendpos[0] = 1.0; 637 (*grad)->blendcount = 1; 638 639 (*grad)->path = path; 640 641 (*grad)->brush.bt = BrushTypePathGradient; 642 (*grad)->centercolor = centercolor; 643 (*grad)->wrap = WrapModeClamp; 644 (*grad)->gamma = FALSE; 645 /* FIXME: this should be set to the "centroid" of the path by default */ 646 (*grad)->center.X = bounds.X + bounds.Width / 2; 647 (*grad)->center.Y = bounds.Y + bounds.Height / 2; 648 (*grad)->focus.X = 0.0; 649 (*grad)->focus.Y = 0.0; 650 (*grad)->surroundcolors[0] = 0xffffffff; 651 (*grad)->surroundcolorcount = 1; 652 653 TRACE("<-- %p\n", *grad); 654 655 return Ok; 656 } 657 658 GpStatus WINGDIPAPI GdipCreatePathGradient(GDIPCONST GpPointF* points, 659 INT count, GpWrapMode wrap, GpPathGradient **grad) 660 { 661 GpStatus stat; 662 GpPath *path; 663 664 TRACE("(%p, %d, %d, %p)\n", points, count, wrap, grad); 665 666 if(!grad) 667 return InvalidParameter; 668 669 if(!points || count <= 0) 670 return OutOfMemory; 671 672 stat = GdipCreatePath(FillModeAlternate, &path); 673 674 if (stat == Ok) 675 { 676 stat = GdipAddPathLine2(path, points, count); 677 678 if (stat == Ok) 679 stat = create_path_gradient(path, 0xff000000, grad); 680 681 if (stat != Ok) 682 GdipDeletePath(path); 683 } 684 685 if (stat == Ok) 686 (*grad)->wrap = wrap; 687 688 return stat; 689 } 690 691 GpStatus WINGDIPAPI GdipCreatePathGradientI(GDIPCONST GpPoint* points, 692 INT count, GpWrapMode wrap, GpPathGradient **grad) 693 { 694 GpStatus stat; 695 GpPath *path; 696 697 TRACE("(%p, %d, %d, %p)\n", points, count, wrap, grad); 698 699 if(!grad) 700 return InvalidParameter; 701 702 if(!points || count <= 0) 703 return OutOfMemory; 704 705 stat = GdipCreatePath(FillModeAlternate, &path); 706 707 if (stat == Ok) 708 { 709 stat = GdipAddPathLine2I(path, points, count); 710 711 if (stat == Ok) 712 stat = create_path_gradient(path, 0xff000000, grad); 713 714 if (stat != Ok) 715 GdipDeletePath(path); 716 } 717 718 if (stat == Ok) 719 (*grad)->wrap = wrap; 720 721 return stat; 722 } 723 724 /****************************************************************************** 725 * GdipCreatePathGradientFromPath [GDIPLUS.@] 726 */ 727 GpStatus WINGDIPAPI GdipCreatePathGradientFromPath(GDIPCONST GpPath* path, 728 GpPathGradient **grad) 729 { 730 GpStatus stat; 731 GpPath *new_path; 732 733 TRACE("(%p, %p)\n", path, grad); 734 735 if(!grad) 736 return InvalidParameter; 737 738 if (!path) 739 return OutOfMemory; 740 741 stat = GdipClonePath((GpPath*)path, &new_path); 742 743 if (stat == Ok) 744 { 745 stat = create_path_gradient(new_path, 0xffffffff, grad); 746 747 if (stat != Ok) 748 GdipDeletePath(new_path); 749 } 750 751 return stat; 752 } 753 754 /****************************************************************************** 755 * GdipCreateSolidFill [GDIPLUS.@] 756 */ 757 GpStatus WINGDIPAPI GdipCreateSolidFill(ARGB color, GpSolidFill **sf) 758 { 759 TRACE("(%x, %p)\n", color, sf); 760 761 if(!sf) return InvalidParameter; 762 763 *sf = heap_alloc_zero(sizeof(GpSolidFill)); 764 if (!*sf) return OutOfMemory; 765 766 (*sf)->brush.bt = BrushTypeSolidColor; 767 (*sf)->color = color; 768 769 TRACE("<-- %p\n", *sf); 770 771 return Ok; 772 } 773 774 /****************************************************************************** 775 * GdipCreateTexture [GDIPLUS.@] 776 * 777 * PARAMS 778 * image [I] image to use 779 * wrapmode [I] optional 780 * texture [O] pointer to the resulting texturebrush 781 * 782 * RETURNS 783 * SUCCESS: Ok 784 * FAILURE: element of GpStatus 785 */ 786 GpStatus WINGDIPAPI GdipCreateTexture(GpImage *image, GpWrapMode wrapmode, 787 GpTexture **texture) 788 { 789 UINT width, height; 790 GpImageAttributes *attributes; 791 GpStatus stat; 792 793 TRACE("%p, %d %p\n", image, wrapmode, texture); 794 795 if (!(image && texture)) 796 return InvalidParameter; 797 798 stat = GdipGetImageWidth(image, &width); 799 if (stat != Ok) return stat; 800 stat = GdipGetImageHeight(image, &height); 801 if (stat != Ok) return stat; 802 803 stat = GdipCreateImageAttributes(&attributes); 804 805 if (stat == Ok) 806 { 807 attributes->wrap = wrapmode; 808 809 stat = GdipCreateTextureIA(image, attributes, 0, 0, width, height, 810 texture); 811 812 GdipDisposeImageAttributes(attributes); 813 } 814 815 return stat; 816 } 817 818 /****************************************************************************** 819 * GdipCreateTexture2 [GDIPLUS.@] 820 */ 821 GpStatus WINGDIPAPI GdipCreateTexture2(GpImage *image, GpWrapMode wrapmode, 822 REAL x, REAL y, REAL width, REAL height, GpTexture **texture) 823 { 824 GpImageAttributes *attributes; 825 GpStatus stat; 826 827 TRACE("%p %d %f %f %f %f %p\n", image, wrapmode, 828 x, y, width, height, texture); 829 830 stat = GdipCreateImageAttributes(&attributes); 831 832 if (stat == Ok) 833 { 834 attributes->wrap = wrapmode; 835 836 stat = GdipCreateTextureIA(image, attributes, x, y, width, height, 837 texture); 838 839 GdipDisposeImageAttributes(attributes); 840 } 841 842 return stat; 843 } 844 845 /****************************************************************************** 846 * GdipCreateTextureIA [GDIPLUS.@] 847 */ 848 GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image, 849 GDIPCONST GpImageAttributes *imageattr, REAL x, REAL y, REAL width, 850 REAL height, GpTexture **texture) 851 { 852 GpStatus status; 853 GpImage *new_image=NULL; 854 855 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %p)\n", image, imageattr, x, y, width, height, 856 texture); 857 858 if(!image || !texture || x < 0.0 || y < 0.0 || width < 0.0 || height < 0.0) 859 return InvalidParameter; 860 861 *texture = NULL; 862 863 if(image->type != ImageTypeBitmap){ 864 FIXME("not implemented for image type %d\n", image->type); 865 return NotImplemented; 866 } 867 868 status = GdipCloneBitmapArea(x, y, width, height, PixelFormatDontCare, (GpBitmap*)image, (GpBitmap**)&new_image); 869 if (status != Ok) 870 return status; 871 872 *texture = heap_alloc_zero(sizeof(GpTexture)); 873 if (!*texture){ 874 status = OutOfMemory; 875 goto exit; 876 } 877 878 GdipSetMatrixElements(&(*texture)->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 879 880 if (imageattr) 881 { 882 status = GdipCloneImageAttributes(imageattr, &(*texture)->imageattributes); 883 } 884 else 885 { 886 status = GdipCreateImageAttributes(&(*texture)->imageattributes); 887 if (status == Ok) 888 (*texture)->imageattributes->wrap = WrapModeTile; 889 } 890 if (status == Ok) 891 { 892 (*texture)->brush.bt = BrushTypeTextureFill; 893 (*texture)->image = new_image; 894 } 895 896 exit: 897 if (status == Ok) 898 { 899 TRACE("<-- %p\n", *texture); 900 } 901 else 902 { 903 if (*texture) 904 { 905 GdipDisposeImageAttributes((*texture)->imageattributes); 906 heap_free(*texture); 907 *texture = NULL; 908 } 909 GdipDisposeImage(new_image); 910 TRACE("<-- error %u\n", status); 911 } 912 913 return status; 914 } 915 916 /****************************************************************************** 917 * GdipCreateTextureIAI [GDIPLUS.@] 918 */ 919 GpStatus WINGDIPAPI GdipCreateTextureIAI(GpImage *image, GDIPCONST GpImageAttributes *imageattr, 920 INT x, INT y, INT width, INT height, GpTexture **texture) 921 { 922 TRACE("(%p, %p, %d, %d, %d, %d, %p)\n", image, imageattr, x, y, width, height, 923 texture); 924 925 return GdipCreateTextureIA(image,imageattr,(REAL)x,(REAL)y,(REAL)width,(REAL)height,texture); 926 } 927 928 GpStatus WINGDIPAPI GdipCreateTexture2I(GpImage *image, GpWrapMode wrapmode, 929 INT x, INT y, INT width, INT height, GpTexture **texture) 930 { 931 GpImageAttributes *imageattr; 932 GpStatus stat; 933 934 TRACE("%p %d %d %d %d %d %p\n", image, wrapmode, x, y, width, height, 935 texture); 936 937 stat = GdipCreateImageAttributes(&imageattr); 938 939 if (stat == Ok) 940 { 941 imageattr->wrap = wrapmode; 942 943 stat = GdipCreateTextureIA(image, imageattr, x, y, width, height, texture); 944 GdipDisposeImageAttributes(imageattr); 945 } 946 947 return stat; 948 } 949 950 GpStatus WINGDIPAPI GdipGetBrushType(GpBrush *brush, GpBrushType *type) 951 { 952 TRACE("(%p, %p)\n", brush, type); 953 954 if(!brush || !type) return InvalidParameter; 955 956 *type = brush->bt; 957 958 return Ok; 959 } 960 961 GpStatus WINGDIPAPI GdipGetHatchBackgroundColor(GpHatch *brush, ARGB *backcol) 962 { 963 TRACE("(%p, %p)\n", brush, backcol); 964 965 if(!brush || !backcol) return InvalidParameter; 966 967 *backcol = brush->backcol; 968 969 return Ok; 970 } 971 972 GpStatus WINGDIPAPI GdipGetHatchForegroundColor(GpHatch *brush, ARGB *forecol) 973 { 974 TRACE("(%p, %p)\n", brush, forecol); 975 976 if(!brush || !forecol) return InvalidParameter; 977 978 *forecol = brush->forecol; 979 980 return Ok; 981 } 982 983 GpStatus WINGDIPAPI GdipGetHatchStyle(GpHatch *brush, GpHatchStyle *hatchstyle) 984 { 985 TRACE("(%p, %p)\n", brush, hatchstyle); 986 987 if(!brush || !hatchstyle) return InvalidParameter; 988 989 *hatchstyle = brush->hatchstyle; 990 991 return Ok; 992 } 993 994 GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush) 995 { 996 TRACE("(%p)\n", brush); 997 998 if(!brush) return InvalidParameter; 999 1000 switch(brush->bt) 1001 { 1002 case BrushTypePathGradient: 1003 GdipDeletePath(((GpPathGradient*) brush)->path); 1004 heap_free(((GpPathGradient*) brush)->blendfac); 1005 heap_free(((GpPathGradient*) brush)->blendpos); 1006 heap_free(((GpPathGradient*) brush)->surroundcolors); 1007 heap_free(((GpPathGradient*) brush)->pblendcolor); 1008 heap_free(((GpPathGradient*) brush)->pblendpos); 1009 break; 1010 case BrushTypeLinearGradient: 1011 heap_free(((GpLineGradient*)brush)->blendfac); 1012 heap_free(((GpLineGradient*)brush)->blendpos); 1013 heap_free(((GpLineGradient*)brush)->pblendcolor); 1014 heap_free(((GpLineGradient*)brush)->pblendpos); 1015 break; 1016 case BrushTypeTextureFill: 1017 GdipDisposeImage(((GpTexture*)brush)->image); 1018 GdipDisposeImageAttributes(((GpTexture*)brush)->imageattributes); 1019 heap_free(((GpTexture*)brush)->bitmap_bits); 1020 break; 1021 default: 1022 break; 1023 } 1024 1025 heap_free(brush); 1026 1027 return Ok; 1028 } 1029 1030 GpStatus WINGDIPAPI GdipGetLineGammaCorrection(GpLineGradient *line, 1031 BOOL *usinggamma) 1032 { 1033 TRACE("(%p, %p)\n", line, usinggamma); 1034 1035 if(!line || !usinggamma) 1036 return InvalidParameter; 1037 1038 *usinggamma = line->gamma; 1039 1040 return Ok; 1041 } 1042 1043 GpStatus WINGDIPAPI GdipGetLineWrapMode(GpLineGradient *brush, GpWrapMode *wrapmode) 1044 { 1045 TRACE("(%p, %p)\n", brush, wrapmode); 1046 1047 if(!brush || !wrapmode || brush->brush.bt != BrushTypeLinearGradient) 1048 return InvalidParameter; 1049 1050 *wrapmode = brush->wrap; 1051 1052 return Ok; 1053 } 1054 1055 GpStatus WINGDIPAPI GdipGetPathGradientBlend(GpPathGradient *brush, REAL *blend, 1056 REAL *positions, INT count) 1057 { 1058 TRACE("(%p, %p, %p, %d)\n", brush, blend, positions, count); 1059 1060 if(!brush || !blend || !positions || count <= 0 || brush->brush.bt != BrushTypePathGradient) 1061 return InvalidParameter; 1062 1063 if(count < brush->blendcount) 1064 return InsufficientBuffer; 1065 1066 memcpy(blend, brush->blendfac, count*sizeof(REAL)); 1067 if(brush->blendcount > 1){ 1068 memcpy(positions, brush->blendpos, count*sizeof(REAL)); 1069 } 1070 1071 return Ok; 1072 } 1073 1074 GpStatus WINGDIPAPI GdipGetPathGradientBlendCount(GpPathGradient *brush, INT *count) 1075 { 1076 TRACE("(%p, %p)\n", brush, count); 1077 1078 if(!brush || !count || brush->brush.bt != BrushTypePathGradient) 1079 return InvalidParameter; 1080 1081 *count = brush->blendcount; 1082 1083 return Ok; 1084 } 1085 1086 GpStatus WINGDIPAPI GdipGetPathGradientCenterPoint(GpPathGradient *grad, 1087 GpPointF *point) 1088 { 1089 TRACE("(%p, %p)\n", grad, point); 1090 1091 if(!grad || !point || grad->brush.bt != BrushTypePathGradient) 1092 return InvalidParameter; 1093 1094 point->X = grad->center.X; 1095 point->Y = grad->center.Y; 1096 1097 return Ok; 1098 } 1099 1100 GpStatus WINGDIPAPI GdipGetPathGradientCenterPointI(GpPathGradient *grad, 1101 GpPoint *point) 1102 { 1103 GpStatus ret; 1104 GpPointF ptf; 1105 1106 TRACE("(%p, %p)\n", grad, point); 1107 1108 if(!point) 1109 return InvalidParameter; 1110 1111 ret = GdipGetPathGradientCenterPoint(grad,&ptf); 1112 1113 if(ret == Ok){ 1114 point->X = gdip_round(ptf.X); 1115 point->Y = gdip_round(ptf.Y); 1116 } 1117 1118 return ret; 1119 } 1120 1121 GpStatus WINGDIPAPI GdipGetPathGradientCenterColor(GpPathGradient *grad, 1122 ARGB *colors) 1123 { 1124 TRACE("(%p,%p)\n", grad, colors); 1125 1126 if (!grad || !colors || grad->brush.bt != BrushTypePathGradient) 1127 return InvalidParameter; 1128 1129 *colors = grad->centercolor; 1130 1131 return Ok; 1132 } 1133 1134 GpStatus WINGDIPAPI GdipGetPathGradientFocusScales(GpPathGradient *grad, 1135 REAL *x, REAL *y) 1136 { 1137 TRACE("(%p, %p, %p)\n", grad, x, y); 1138 1139 if(!grad || !x || !y || grad->brush.bt != BrushTypePathGradient) 1140 return InvalidParameter; 1141 1142 *x = grad->focus.X; 1143 *y = grad->focus.Y; 1144 1145 return Ok; 1146 } 1147 1148 GpStatus WINGDIPAPI GdipGetPathGradientGammaCorrection(GpPathGradient *grad, 1149 BOOL *gamma) 1150 { 1151 TRACE("(%p, %p)\n", grad, gamma); 1152 1153 if(!grad || !gamma || grad->brush.bt != BrushTypePathGradient) 1154 return InvalidParameter; 1155 1156 *gamma = grad->gamma; 1157 1158 return Ok; 1159 } 1160 1161 GpStatus WINGDIPAPI GdipGetPathGradientPath(GpPathGradient *grad, GpPath *path) 1162 { 1163 static int calls; 1164 1165 TRACE("(%p, %p)\n", grad, path); 1166 1167 if (!(calls++)) 1168 FIXME("not implemented\n"); 1169 1170 return NotImplemented; 1171 } 1172 1173 GpStatus WINGDIPAPI GdipGetPathGradientPointCount(GpPathGradient *grad, 1174 INT *count) 1175 { 1176 TRACE("(%p, %p)\n", grad, count); 1177 1178 if(!grad || !count || grad->brush.bt != BrushTypePathGradient) 1179 return InvalidParameter; 1180 1181 *count = grad->path->pathdata.Count; 1182 1183 return Ok; 1184 } 1185 1186 GpStatus WINGDIPAPI GdipGetPathGradientRect(GpPathGradient *brush, GpRectF *rect) 1187 { 1188 GpStatus stat; 1189 1190 TRACE("(%p, %p)\n", brush, rect); 1191 1192 if(!brush || !rect || brush->brush.bt != BrushTypePathGradient) 1193 return InvalidParameter; 1194 1195 stat = GdipGetPathWorldBounds(brush->path, rect, NULL, NULL); 1196 1197 return stat; 1198 } 1199 1200 GpStatus WINGDIPAPI GdipGetPathGradientRectI(GpPathGradient *brush, GpRect *rect) 1201 { 1202 GpRectF rectf; 1203 GpStatus stat; 1204 1205 TRACE("(%p, %p)\n", brush, rect); 1206 1207 if(!brush || !rect) 1208 return InvalidParameter; 1209 1210 stat = GdipGetPathGradientRect(brush, &rectf); 1211 if(stat != Ok) return stat; 1212 1213 rect->X = gdip_round(rectf.X); 1214 rect->Y = gdip_round(rectf.Y); 1215 rect->Width = gdip_round(rectf.Width); 1216 rect->Height = gdip_round(rectf.Height); 1217 1218 return Ok; 1219 } 1220 1221 GpStatus WINGDIPAPI GdipGetPathGradientSurroundColorsWithCount(GpPathGradient 1222 *grad, ARGB *argb, INT *count) 1223 { 1224 INT i; 1225 1226 TRACE("(%p,%p,%p)\n", grad, argb, count); 1227 1228 if(!grad || !argb || !count || (*count < grad->path->pathdata.Count) || grad->brush.bt != BrushTypePathGradient) 1229 return InvalidParameter; 1230 1231 for (i=0; i<grad->path->pathdata.Count; i++) 1232 { 1233 if (i < grad->surroundcolorcount) 1234 argb[i] = grad->surroundcolors[i]; 1235 else 1236 argb[i] = grad->surroundcolors[grad->surroundcolorcount-1]; 1237 } 1238 1239 *count = grad->surroundcolorcount; 1240 1241 return Ok; 1242 } 1243 1244 GpStatus WINGDIPAPI GdipGetPathGradientSurroundColorCount(GpPathGradient *brush, INT *count) 1245 { 1246 TRACE("(%p, %p)\n", brush, count); 1247 1248 if (!brush || !count || brush->brush.bt != BrushTypePathGradient) 1249 return InvalidParameter; 1250 1251 /* Yes, this actually returns the number of points in the path (which is the 1252 * required size of a buffer to get the surround colors), rather than the 1253 * number of surround colors. The real count is returned when getting the 1254 * colors. */ 1255 *count = brush->path->pathdata.Count; 1256 1257 return Ok; 1258 } 1259 1260 GpStatus WINGDIPAPI GdipGetPathGradientWrapMode(GpPathGradient *brush, 1261 GpWrapMode *wrapmode) 1262 { 1263 TRACE("(%p, %p)\n", brush, wrapmode); 1264 1265 if(!brush || !wrapmode || brush->brush.bt != BrushTypePathGradient) 1266 return InvalidParameter; 1267 1268 *wrapmode = brush->wrap; 1269 1270 return Ok; 1271 } 1272 1273 GpStatus WINGDIPAPI GdipGetSolidFillColor(GpSolidFill *sf, ARGB *argb) 1274 { 1275 TRACE("(%p, %p)\n", sf, argb); 1276 1277 if(!sf || !argb) 1278 return InvalidParameter; 1279 1280 *argb = sf->color; 1281 1282 return Ok; 1283 } 1284 1285 /****************************************************************************** 1286 * GdipGetTextureImage [GDIPLUS.@] 1287 */ 1288 GpStatus WINGDIPAPI GdipGetTextureImage(GpTexture *brush, GpImage **image) 1289 { 1290 TRACE("(%p, %p)\n", brush, image); 1291 1292 if(!brush || !image) 1293 return InvalidParameter; 1294 1295 return GdipCloneImage(brush->image, image); 1296 } 1297 1298 /****************************************************************************** 1299 * GdipGetTextureTransform [GDIPLUS.@] 1300 */ 1301 GpStatus WINGDIPAPI GdipGetTextureTransform(GpTexture *brush, GpMatrix *matrix) 1302 { 1303 TRACE("(%p, %p)\n", brush, matrix); 1304 1305 if(!brush || !matrix) 1306 return InvalidParameter; 1307 1308 *matrix = brush->transform; 1309 1310 return Ok; 1311 } 1312 1313 /****************************************************************************** 1314 * GdipGetTextureWrapMode [GDIPLUS.@] 1315 */ 1316 GpStatus WINGDIPAPI GdipGetTextureWrapMode(GpTexture *brush, GpWrapMode *wrapmode) 1317 { 1318 TRACE("(%p, %p)\n", brush, wrapmode); 1319 1320 if(!brush || !wrapmode) 1321 return InvalidParameter; 1322 1323 *wrapmode = brush->imageattributes->wrap; 1324 1325 return Ok; 1326 } 1327 1328 /****************************************************************************** 1329 * GdipMultiplyTextureTransform [GDIPLUS.@] 1330 */ 1331 GpStatus WINGDIPAPI GdipMultiplyTextureTransform(GpTexture* brush, 1332 GDIPCONST GpMatrix *matrix, GpMatrixOrder order) 1333 { 1334 TRACE("(%p, %p, %d)\n", brush, matrix, order); 1335 1336 if(!brush || !matrix) 1337 return InvalidParameter; 1338 1339 return GdipMultiplyMatrix(&brush->transform, matrix, order); 1340 } 1341 1342 /****************************************************************************** 1343 * GdipResetTextureTransform [GDIPLUS.@] 1344 */ 1345 GpStatus WINGDIPAPI GdipResetTextureTransform(GpTexture* brush) 1346 { 1347 TRACE("(%p)\n", brush); 1348 1349 if(!brush) 1350 return InvalidParameter; 1351 1352 return GdipSetMatrixElements(&brush->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 1353 } 1354 1355 /****************************************************************************** 1356 * GdipScaleTextureTransform [GDIPLUS.@] 1357 */ 1358 GpStatus WINGDIPAPI GdipScaleTextureTransform(GpTexture* brush, 1359 REAL sx, REAL sy, GpMatrixOrder order) 1360 { 1361 TRACE("(%p, %.2f, %.2f, %d)\n", brush, sx, sy, order); 1362 1363 if(!brush) 1364 return InvalidParameter; 1365 1366 return GdipScaleMatrix(&brush->transform, sx, sy, order); 1367 } 1368 1369 GpStatus WINGDIPAPI GdipSetLineBlend(GpLineGradient *brush, 1370 GDIPCONST REAL *factors, GDIPCONST REAL* positions, INT count) 1371 { 1372 REAL *new_blendfac, *new_blendpos; 1373 1374 TRACE("(%p, %p, %p, %i)\n", brush, factors, positions, count); 1375 1376 if(!brush || !factors || !positions || count <= 0 || brush->brush.bt != BrushTypeLinearGradient || 1377 (count >= 2 && (positions[0] != 0.0f || positions[count-1] != 1.0f))) 1378 return InvalidParameter; 1379 1380 new_blendfac = heap_alloc_zero(count * sizeof(REAL)); 1381 new_blendpos = heap_alloc_zero(count * sizeof(REAL)); 1382 1383 if (!new_blendfac || !new_blendpos) 1384 { 1385 heap_free(new_blendfac); 1386 heap_free(new_blendpos); 1387 return OutOfMemory; 1388 } 1389 1390 memcpy(new_blendfac, factors, count * sizeof(REAL)); 1391 memcpy(new_blendpos, positions, count * sizeof(REAL)); 1392 1393 heap_free(brush->blendfac); 1394 heap_free(brush->blendpos); 1395 1396 brush->blendcount = count; 1397 brush->blendfac = new_blendfac; 1398 brush->blendpos = new_blendpos; 1399 1400 return Ok; 1401 } 1402 1403 GpStatus WINGDIPAPI GdipGetLineBlend(GpLineGradient *brush, REAL *factors, 1404 REAL *positions, INT count) 1405 { 1406 TRACE("(%p, %p, %p, %i)\n", brush, factors, positions, count); 1407 1408 if (!brush || !factors || !positions || count <= 0 || brush->brush.bt != BrushTypeLinearGradient) 1409 return InvalidParameter; 1410 1411 if (count < brush->blendcount) 1412 return InsufficientBuffer; 1413 1414 memcpy(factors, brush->blendfac, brush->blendcount * sizeof(REAL)); 1415 memcpy(positions, brush->blendpos, brush->blendcount * sizeof(REAL)); 1416 1417 return Ok; 1418 } 1419 1420 GpStatus WINGDIPAPI GdipGetLineBlendCount(GpLineGradient *brush, INT *count) 1421 { 1422 TRACE("(%p, %p)\n", brush, count); 1423 1424 if (!brush || !count || brush->brush.bt != BrushTypeLinearGradient) 1425 return InvalidParameter; 1426 1427 *count = brush->blendcount; 1428 1429 return Ok; 1430 } 1431 1432 GpStatus WINGDIPAPI GdipSetLineGammaCorrection(GpLineGradient *line, 1433 BOOL usegamma) 1434 { 1435 TRACE("(%p, %d)\n", line, usegamma); 1436 1437 if(!line || line->brush.bt != BrushTypeLinearGradient) 1438 return InvalidParameter; 1439 1440 line->gamma = usegamma; 1441 1442 return Ok; 1443 } 1444 1445 GpStatus WINGDIPAPI GdipSetLineSigmaBlend(GpLineGradient *line, REAL focus, 1446 REAL scale) 1447 { 1448 REAL factors[33]; 1449 REAL positions[33]; 1450 int num_points = 0; 1451 int i; 1452 const int precision = 16; 1453 REAL erf_range; /* we use values erf(-erf_range) through erf(+erf_range) */ 1454 REAL min_erf; 1455 REAL scale_erf; 1456 1457 TRACE("(%p, %0.2f, %0.2f)\n", line, focus, scale); 1458 1459 if(!line || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0 || line->brush.bt != BrushTypeLinearGradient) 1460 return InvalidParameter; 1461 1462 /* we want 2 standard deviations */ 1463 erf_range = 2.0 / sqrt(2); 1464 1465 /* calculate the constants we need to normalize the error function to be 1466 between 0.0 and scale over the range we need */ 1467 min_erf = erf(-erf_range); 1468 scale_erf = scale / (-2.0 * min_erf); 1469 1470 if (focus != 0.0) 1471 { 1472 positions[0] = 0.0; 1473 factors[0] = 0.0; 1474 for (i=1; i<precision; i++) 1475 { 1476 positions[i] = focus * i / precision; 1477 factors[i] = scale_erf * (erf(2 * erf_range * i / precision - erf_range) - min_erf); 1478 } 1479 num_points += precision; 1480 } 1481 1482 positions[num_points] = focus; 1483 factors[num_points] = scale; 1484 num_points += 1; 1485 1486 if (focus != 1.0) 1487 { 1488 for (i=1; i<precision; i++) 1489 { 1490 positions[i+num_points-1] = (focus + ((1.0-focus) * i / precision)); 1491 factors[i+num_points-1] = scale_erf * (erf(erf_range - 2 * erf_range * i / precision) - min_erf); 1492 } 1493 num_points += precision; 1494 positions[num_points-1] = 1.0; 1495 factors[num_points-1] = 0.0; 1496 } 1497 1498 return GdipSetLineBlend(line, factors, positions, num_points); 1499 } 1500 1501 GpStatus WINGDIPAPI GdipSetLineWrapMode(GpLineGradient *line, 1502 GpWrapMode wrap) 1503 { 1504 TRACE("(%p, %d)\n", line, wrap); 1505 1506 if(!line || wrap == WrapModeClamp || line->brush.bt != BrushTypeLinearGradient) 1507 return InvalidParameter; 1508 1509 line->wrap = wrap; 1510 1511 return Ok; 1512 } 1513 1514 GpStatus WINGDIPAPI GdipSetPathGradientBlend(GpPathGradient *brush, GDIPCONST REAL *blend, 1515 GDIPCONST REAL *pos, INT count) 1516 { 1517 REAL *new_blendfac, *new_blendpos; 1518 1519 TRACE("(%p,%p,%p,%i)\n", brush, blend, pos, count); 1520 1521 if(!brush || !blend || !pos || count <= 0 || brush->brush.bt != BrushTypePathGradient || 1522 (count >= 2 && (pos[0] != 0.0f || pos[count-1] != 1.0f))) 1523 return InvalidParameter; 1524 1525 new_blendfac = heap_alloc_zero(count * sizeof(REAL)); 1526 new_blendpos = heap_alloc_zero(count * sizeof(REAL)); 1527 1528 if (!new_blendfac || !new_blendpos) 1529 { 1530 heap_free(new_blendfac); 1531 heap_free(new_blendpos); 1532 return OutOfMemory; 1533 } 1534 1535 memcpy(new_blendfac, blend, count * sizeof(REAL)); 1536 memcpy(new_blendpos, pos, count * sizeof(REAL)); 1537 1538 heap_free(brush->blendfac); 1539 heap_free(brush->blendpos); 1540 1541 brush->blendcount = count; 1542 brush->blendfac = new_blendfac; 1543 brush->blendpos = new_blendpos; 1544 1545 return Ok; 1546 } 1547 1548 GpStatus WINGDIPAPI GdipSetPathGradientLinearBlend(GpPathGradient *brush, 1549 REAL focus, REAL scale) 1550 { 1551 REAL factors[3]; 1552 REAL positions[3]; 1553 int num_points = 0; 1554 1555 TRACE("(%p,%0.2f,%0.2f)\n", brush, focus, scale); 1556 1557 if (!brush || brush->brush.bt != BrushTypePathGradient) 1558 return InvalidParameter; 1559 1560 if (focus != 0.0) 1561 { 1562 factors[num_points] = 0.0; 1563 positions[num_points] = 0.0; 1564 num_points++; 1565 } 1566 1567 factors[num_points] = scale; 1568 positions[num_points] = focus; 1569 num_points++; 1570 1571 if (focus != 1.0) 1572 { 1573 factors[num_points] = 0.0; 1574 positions[num_points] = 1.0; 1575 num_points++; 1576 } 1577 1578 return GdipSetPathGradientBlend(brush, factors, positions, num_points); 1579 } 1580 1581 GpStatus WINGDIPAPI GdipSetPathGradientPresetBlend(GpPathGradient *brush, 1582 GDIPCONST ARGB *blend, GDIPCONST REAL *pos, INT count) 1583 { 1584 ARGB *new_color; 1585 REAL *new_pos; 1586 TRACE("(%p,%p,%p,%i)\n", brush, blend, pos, count); 1587 1588 if (!brush || !blend || !pos || count < 2 || brush->brush.bt != BrushTypePathGradient || 1589 pos[0] != 0.0f || pos[count-1] != 1.0f) 1590 { 1591 return InvalidParameter; 1592 } 1593 1594 new_color = heap_alloc_zero(count * sizeof(ARGB)); 1595 new_pos = heap_alloc_zero(count * sizeof(REAL)); 1596 if (!new_color || !new_pos) 1597 { 1598 heap_free(new_color); 1599 heap_free(new_pos); 1600 return OutOfMemory; 1601 } 1602 1603 memcpy(new_color, blend, sizeof(ARGB) * count); 1604 memcpy(new_pos, pos, sizeof(REAL) * count); 1605 1606 heap_free(brush->pblendcolor); 1607 heap_free(brush->pblendpos); 1608 1609 brush->pblendcolor = new_color; 1610 brush->pblendpos = new_pos; 1611 brush->pblendcount = count; 1612 1613 return Ok; 1614 } 1615 1616 GpStatus WINGDIPAPI GdipGetPathGradientPresetBlend(GpPathGradient *brush, 1617 ARGB *blend, REAL *pos, INT count) 1618 { 1619 TRACE("(%p,%p,%p,%i)\n", brush, blend, pos, count); 1620 1621 if (count < 0) 1622 return OutOfMemory; 1623 1624 if (!brush || !blend || !pos || count < 2 || brush->brush.bt != BrushTypePathGradient) 1625 return InvalidParameter; 1626 1627 if (brush->pblendcount == 0) 1628 return GenericError; 1629 1630 if (count != brush->pblendcount) 1631 { 1632 /* Native lines up the ends of each array, and copies the destination size. */ 1633 FIXME("Braindead behavior on wrong-sized buffer not implemented.\n"); 1634 return InvalidParameter; 1635 } 1636 1637 memcpy(blend, brush->pblendcolor, sizeof(ARGB) * brush->pblendcount); 1638 memcpy(pos, brush->pblendpos, sizeof(REAL) * brush->pblendcount); 1639 1640 return Ok; 1641 } 1642 1643 GpStatus WINGDIPAPI GdipGetPathGradientPresetBlendCount(GpPathGradient *brush, 1644 INT *count) 1645 { 1646 TRACE("(%p,%p)\n", brush, count); 1647 1648 if (!brush || !count || brush->brush.bt != BrushTypePathGradient) 1649 return InvalidParameter; 1650 1651 *count = brush->pblendcount; 1652 1653 return Ok; 1654 } 1655 1656 GpStatus WINGDIPAPI GdipSetPathGradientCenterColor(GpPathGradient *grad, 1657 ARGB argb) 1658 { 1659 TRACE("(%p, %x)\n", grad, argb); 1660 1661 if(!grad || grad->brush.bt != BrushTypePathGradient) 1662 return InvalidParameter; 1663 1664 grad->centercolor = argb; 1665 return Ok; 1666 } 1667 1668 GpStatus WINGDIPAPI GdipSetPathGradientCenterPoint(GpPathGradient *grad, 1669 GpPointF *point) 1670 { 1671 TRACE("(%p, %s)\n", grad, debugstr_pointf(point)); 1672 1673 if(!grad || !point || grad->brush.bt != BrushTypePathGradient) 1674 return InvalidParameter; 1675 1676 grad->center.X = point->X; 1677 grad->center.Y = point->Y; 1678 1679 return Ok; 1680 } 1681 1682 GpStatus WINGDIPAPI GdipSetPathGradientCenterPointI(GpPathGradient *grad, 1683 GpPoint *point) 1684 { 1685 GpPointF ptf; 1686 1687 TRACE("(%p, %p)\n", grad, point); 1688 1689 if(!point) 1690 return InvalidParameter; 1691 1692 ptf.X = (REAL)point->X; 1693 ptf.Y = (REAL)point->Y; 1694 1695 return GdipSetPathGradientCenterPoint(grad,&ptf); 1696 } 1697 1698 GpStatus WINGDIPAPI GdipSetPathGradientFocusScales(GpPathGradient *grad, 1699 REAL x, REAL y) 1700 { 1701 TRACE("(%p, %.2f, %.2f)\n", grad, x, y); 1702 1703 if(!grad || grad->brush.bt != BrushTypePathGradient) 1704 return InvalidParameter; 1705 1706 grad->focus.X = x; 1707 grad->focus.Y = y; 1708 1709 return Ok; 1710 } 1711 1712 GpStatus WINGDIPAPI GdipSetPathGradientGammaCorrection(GpPathGradient *grad, 1713 BOOL gamma) 1714 { 1715 TRACE("(%p, %d)\n", grad, gamma); 1716 1717 if(!grad || grad->brush.bt != BrushTypePathGradient) 1718 return InvalidParameter; 1719 1720 grad->gamma = gamma; 1721 1722 return Ok; 1723 } 1724 1725 GpStatus WINGDIPAPI GdipSetPathGradientPath(GpPathGradient *grad, GDIPCONST GpPath *path) 1726 { 1727 static int calls; 1728 1729 TRACE("(%p, %p)\n", grad, path); 1730 1731 if (!(calls++)) 1732 FIXME("not implemented\n"); 1733 1734 return NotImplemented; 1735 } 1736 1737 GpStatus WINGDIPAPI GdipSetPathGradientSigmaBlend(GpPathGradient *grad, 1738 REAL focus, REAL scale) 1739 { 1740 REAL factors[33]; 1741 REAL positions[33]; 1742 int num_points = 0; 1743 int i; 1744 const int precision = 16; 1745 REAL erf_range; /* we use values erf(-erf_range) through erf(+erf_range) */ 1746 REAL min_erf; 1747 REAL scale_erf; 1748 1749 TRACE("(%p,%0.2f,%0.2f)\n", grad, focus, scale); 1750 1751 if(!grad || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0 || grad->brush.bt != BrushTypePathGradient) 1752 return InvalidParameter; 1753 1754 /* we want 2 standard deviations */ 1755 erf_range = 2.0 / sqrt(2); 1756 1757 /* calculate the constants we need to normalize the error function to be 1758 between 0.0 and scale over the range we need */ 1759 min_erf = erf(-erf_range); 1760 scale_erf = scale / (-2.0 * min_erf); 1761 1762 if (focus != 0.0) 1763 { 1764 positions[0] = 0.0; 1765 factors[0] = 0.0; 1766 for (i=1; i<precision; i++) 1767 { 1768 positions[i] = focus * i / precision; 1769 factors[i] = scale_erf * (erf(2 * erf_range * i / precision - erf_range) - min_erf); 1770 } 1771 num_points += precision; 1772 } 1773 1774 positions[num_points] = focus; 1775 factors[num_points] = scale; 1776 num_points += 1; 1777 1778 if (focus != 1.0) 1779 { 1780 for (i=1; i<precision; i++) 1781 { 1782 positions[i+num_points-1] = (focus + ((1.0-focus) * i / precision)); 1783 factors[i+num_points-1] = scale_erf * (erf(erf_range - 2 * erf_range * i / precision) - min_erf); 1784 } 1785 num_points += precision; 1786 positions[num_points-1] = 1.0; 1787 factors[num_points-1] = 0.0; 1788 } 1789 1790 return GdipSetPathGradientBlend(grad, factors, positions, num_points); 1791 } 1792 1793 GpStatus WINGDIPAPI GdipSetPathGradientSurroundColorsWithCount(GpPathGradient 1794 *grad, GDIPCONST ARGB *argb, INT *count) 1795 { 1796 ARGB *new_surroundcolors; 1797 INT i, num_colors; 1798 1799 TRACE("(%p,%p,%p)\n", grad, argb, count); 1800 1801 if(!grad || !argb || !count || (*count <= 0) || grad->brush.bt != BrushTypePathGradient || 1802 (*count > grad->path->pathdata.Count)) 1803 return InvalidParameter; 1804 1805 num_colors = *count; 1806 1807 /* If all colors are the same, only store 1 color. */ 1808 if (*count > 1) 1809 { 1810 for (i=1; i < num_colors; i++) 1811 if (argb[i] != argb[i-1]) 1812 break; 1813 1814 if (i == num_colors) 1815 num_colors = 1; 1816 } 1817 1818 new_surroundcolors = heap_alloc_zero(num_colors * sizeof(ARGB)); 1819 if (!new_surroundcolors) 1820 return OutOfMemory; 1821 1822 memcpy(new_surroundcolors, argb, num_colors * sizeof(ARGB)); 1823 1824 heap_free(grad->surroundcolors); 1825 1826 grad->surroundcolors = new_surroundcolors; 1827 grad->surroundcolorcount = num_colors; 1828 1829 return Ok; 1830 } 1831 1832 GpStatus WINGDIPAPI GdipSetPathGradientWrapMode(GpPathGradient *grad, 1833 GpWrapMode wrap) 1834 { 1835 TRACE("(%p, %d)\n", grad, wrap); 1836 1837 if(!grad || grad->brush.bt != BrushTypePathGradient) 1838 return InvalidParameter; 1839 1840 grad->wrap = wrap; 1841 1842 return Ok; 1843 } 1844 1845 GpStatus WINGDIPAPI GdipSetPathGradientTransform(GpPathGradient *grad, 1846 GpMatrix *matrix) 1847 { 1848 TRACE("(%p,%p)\n", grad, matrix); 1849 1850 if (!grad || !matrix || grad->brush.bt != BrushTypePathGradient) 1851 return InvalidParameter; 1852 1853 grad->transform = *matrix; 1854 1855 return Ok; 1856 } 1857 1858 GpStatus WINGDIPAPI GdipGetPathGradientTransform(GpPathGradient *grad, 1859 GpMatrix *matrix) 1860 { 1861 TRACE("(%p,%p)\n", grad, matrix); 1862 1863 if (!grad || !matrix || grad->brush.bt != BrushTypePathGradient) 1864 return InvalidParameter; 1865 1866 *matrix = grad->transform; 1867 1868 return Ok; 1869 } 1870 1871 GpStatus WINGDIPAPI GdipMultiplyPathGradientTransform(GpPathGradient *grad, 1872 GDIPCONST GpMatrix *matrix, GpMatrixOrder order) 1873 { 1874 TRACE("(%p,%p,%i)\n", grad, matrix, order); 1875 1876 if (!grad || grad->brush.bt != BrushTypePathGradient) 1877 return InvalidParameter; 1878 1879 return GdipMultiplyMatrix(&grad->transform, matrix, order); 1880 } 1881 1882 GpStatus WINGDIPAPI GdipResetPathGradientTransform(GpPathGradient *grad) 1883 { 1884 TRACE("(%p)\n", grad); 1885 1886 if (!grad || grad->brush.bt != BrushTypePathGradient) 1887 return InvalidParameter; 1888 1889 return GdipSetMatrixElements(&grad->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 1890 } 1891 1892 GpStatus WINGDIPAPI GdipRotatePathGradientTransform(GpPathGradient *grad, 1893 REAL angle, GpMatrixOrder order) 1894 { 1895 TRACE("(%p,%0.2f,%i)\n", grad, angle, order); 1896 1897 if (!grad || grad->brush.bt != BrushTypePathGradient) 1898 return InvalidParameter; 1899 1900 return GdipRotateMatrix(&grad->transform, angle, order); 1901 } 1902 1903 GpStatus WINGDIPAPI GdipScalePathGradientTransform(GpPathGradient *grad, 1904 REAL sx, REAL sy, GpMatrixOrder order) 1905 { 1906 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad, sx, sy, order); 1907 1908 if (!grad || grad->brush.bt != BrushTypePathGradient) 1909 return InvalidParameter; 1910 1911 return GdipScaleMatrix(&grad->transform, sx, sy, order); 1912 } 1913 1914 GpStatus WINGDIPAPI GdipTranslatePathGradientTransform(GpPathGradient *grad, 1915 REAL dx, REAL dy, GpMatrixOrder order) 1916 { 1917 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad, dx, dy, order); 1918 1919 if (!grad || grad->brush.bt != BrushTypePathGradient) 1920 return InvalidParameter; 1921 1922 return GdipTranslateMatrix(&grad->transform, dx, dy, order); 1923 } 1924 1925 GpStatus WINGDIPAPI GdipSetSolidFillColor(GpSolidFill *sf, ARGB argb) 1926 { 1927 TRACE("(%p, %x)\n", sf, argb); 1928 1929 if(!sf) 1930 return InvalidParameter; 1931 1932 sf->color = argb; 1933 return Ok; 1934 } 1935 1936 /****************************************************************************** 1937 * GdipSetTextureTransform [GDIPLUS.@] 1938 */ 1939 GpStatus WINGDIPAPI GdipSetTextureTransform(GpTexture *texture, 1940 GDIPCONST GpMatrix *matrix) 1941 { 1942 TRACE("(%p, %p)\n", texture, matrix); 1943 1944 if(!texture || !matrix) 1945 return InvalidParameter; 1946 1947 texture->transform = *matrix; 1948 1949 return Ok; 1950 } 1951 1952 /****************************************************************************** 1953 * GdipSetTextureWrapMode [GDIPLUS.@] 1954 * 1955 * WrapMode not used, only stored 1956 */ 1957 GpStatus WINGDIPAPI GdipSetTextureWrapMode(GpTexture *brush, GpWrapMode wrapmode) 1958 { 1959 TRACE("(%p, %d)\n", brush, wrapmode); 1960 1961 if(!brush) 1962 return InvalidParameter; 1963 1964 brush->imageattributes->wrap = wrapmode; 1965 1966 return Ok; 1967 } 1968 1969 GpStatus WINGDIPAPI GdipSetLineColors(GpLineGradient *brush, ARGB color1, 1970 ARGB color2) 1971 { 1972 TRACE("(%p, %x, %x)\n", brush, color1, color2); 1973 1974 if(!brush || brush->brush.bt != BrushTypeLinearGradient) 1975 return InvalidParameter; 1976 1977 brush->startcolor = color1; 1978 brush->endcolor = color2; 1979 1980 return Ok; 1981 } 1982 1983 GpStatus WINGDIPAPI GdipGetLineColors(GpLineGradient *brush, ARGB *colors) 1984 { 1985 TRACE("(%p, %p)\n", brush, colors); 1986 1987 if(!brush || !colors || brush->brush.bt != BrushTypeLinearGradient) 1988 return InvalidParameter; 1989 1990 colors[0] = brush->startcolor; 1991 colors[1] = brush->endcolor; 1992 1993 return Ok; 1994 } 1995 1996 /****************************************************************************** 1997 * GdipRotateTextureTransform [GDIPLUS.@] 1998 */ 1999 GpStatus WINGDIPAPI GdipRotateTextureTransform(GpTexture* brush, REAL angle, 2000 GpMatrixOrder order) 2001 { 2002 TRACE("(%p, %.2f, %d)\n", brush, angle, order); 2003 2004 if(!brush) 2005 return InvalidParameter; 2006 2007 return GdipRotateMatrix(&brush->transform, angle, order); 2008 } 2009 2010 GpStatus WINGDIPAPI GdipSetLineLinearBlend(GpLineGradient *brush, REAL focus, 2011 REAL scale) 2012 { 2013 REAL factors[3]; 2014 REAL positions[3]; 2015 int num_points = 0; 2016 2017 TRACE("(%p,%.2f,%.2f)\n", brush, focus, scale); 2018 2019 if (!brush) return InvalidParameter; 2020 2021 if (focus != 0.0) 2022 { 2023 factors[num_points] = 0.0; 2024 positions[num_points] = 0.0; 2025 num_points++; 2026 } 2027 2028 factors[num_points] = scale; 2029 positions[num_points] = focus; 2030 num_points++; 2031 2032 if (focus != 1.0) 2033 { 2034 factors[num_points] = 0.0; 2035 positions[num_points] = 1.0; 2036 num_points++; 2037 } 2038 2039 return GdipSetLineBlend(brush, factors, positions, num_points); 2040 } 2041 2042 GpStatus WINGDIPAPI GdipSetLinePresetBlend(GpLineGradient *brush, 2043 GDIPCONST ARGB *blend, GDIPCONST REAL* positions, INT count) 2044 { 2045 ARGB *new_color; 2046 REAL *new_pos; 2047 TRACE("(%p,%p,%p,%i)\n", brush, blend, positions, count); 2048 2049 if (!brush || !blend || !positions || count < 2 || brush->brush.bt != BrushTypeLinearGradient || 2050 positions[0] != 0.0f || positions[count-1] != 1.0f) 2051 { 2052 return InvalidParameter; 2053 } 2054 2055 new_color = heap_alloc_zero(count * sizeof(ARGB)); 2056 new_pos = heap_alloc_zero(count * sizeof(REAL)); 2057 if (!new_color || !new_pos) 2058 { 2059 heap_free(new_color); 2060 heap_free(new_pos); 2061 return OutOfMemory; 2062 } 2063 2064 memcpy(new_color, blend, sizeof(ARGB) * count); 2065 memcpy(new_pos, positions, sizeof(REAL) * count); 2066 2067 heap_free(brush->pblendcolor); 2068 heap_free(brush->pblendpos); 2069 2070 brush->pblendcolor = new_color; 2071 brush->pblendpos = new_pos; 2072 brush->pblendcount = count; 2073 2074 return Ok; 2075 } 2076 2077 GpStatus WINGDIPAPI GdipGetLinePresetBlend(GpLineGradient *brush, 2078 ARGB *blend, REAL* positions, INT count) 2079 { 2080 if (!brush || !blend || !positions || count < 2 || brush->brush.bt != BrushTypeLinearGradient) 2081 return InvalidParameter; 2082 2083 if (brush->pblendcount == 0) 2084 return GenericError; 2085 2086 if (count < brush->pblendcount) 2087 return InsufficientBuffer; 2088 2089 memcpy(blend, brush->pblendcolor, sizeof(ARGB) * brush->pblendcount); 2090 memcpy(positions, brush->pblendpos, sizeof(REAL) * brush->pblendcount); 2091 2092 return Ok; 2093 } 2094 2095 GpStatus WINGDIPAPI GdipGetLinePresetBlendCount(GpLineGradient *brush, 2096 INT *count) 2097 { 2098 if (!brush || !count || brush->brush.bt != BrushTypeLinearGradient) 2099 return InvalidParameter; 2100 2101 *count = brush->pblendcount; 2102 2103 return Ok; 2104 } 2105 2106 GpStatus WINGDIPAPI GdipResetLineTransform(GpLineGradient *brush) 2107 { 2108 TRACE("(%p)\n", brush); 2109 2110 if(!brush) 2111 return InvalidParameter; 2112 2113 return GdipSetMatrixElements(&brush->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0); 2114 } 2115 2116 GpStatus WINGDIPAPI GdipSetLineTransform(GpLineGradient *brush, 2117 GDIPCONST GpMatrix *matrix) 2118 { 2119 TRACE("(%p,%p)\n", brush, matrix); 2120 2121 if(!brush || !matrix) 2122 return InvalidParameter; 2123 2124 brush->transform = *matrix; 2125 2126 return Ok; 2127 } 2128 2129 GpStatus WINGDIPAPI GdipGetLineTransform(GpLineGradient *brush, GpMatrix *matrix) 2130 { 2131 TRACE("(%p,%p)\n", brush, matrix); 2132 2133 if(!brush || !matrix) 2134 return InvalidParameter; 2135 2136 *matrix = brush->transform; 2137 2138 return Ok; 2139 } 2140 2141 GpStatus WINGDIPAPI GdipScaleLineTransform(GpLineGradient *brush, REAL sx, REAL sy, 2142 GpMatrixOrder order) 2143 { 2144 TRACE("(%p,%0.2f,%0.2f,%u)\n", brush, sx, sy, order); 2145 2146 if(!brush) 2147 return InvalidParameter; 2148 2149 return GdipScaleMatrix(&brush->transform, sx, sy, order); 2150 } 2151 2152 GpStatus WINGDIPAPI GdipMultiplyLineTransform(GpLineGradient *brush, 2153 GDIPCONST GpMatrix *matrix, GpMatrixOrder order) 2154 { 2155 TRACE("(%p,%p,%u)\n", brush, matrix, order); 2156 2157 if(!brush) 2158 return InvalidParameter; 2159 2160 if(!matrix) 2161 return Ok; 2162 2163 return GdipMultiplyMatrix(&brush->transform, matrix, order); 2164 } 2165 2166 GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient *brush, 2167 REAL dx, REAL dy, GpMatrixOrder order) 2168 { 2169 TRACE("(%p,%f,%f,%d)\n", brush, dx, dy, order); 2170 2171 if(!brush) 2172 return InvalidParameter; 2173 2174 return GdipTranslateMatrix(&brush->transform, dx, dy, order); 2175 } 2176 2177 /****************************************************************************** 2178 * GdipTranslateTextureTransform [GDIPLUS.@] 2179 */ 2180 GpStatus WINGDIPAPI GdipTranslateTextureTransform(GpTexture* brush, REAL dx, REAL dy, 2181 GpMatrixOrder order) 2182 { 2183 TRACE("(%p, %.2f, %.2f, %d)\n", brush, dx, dy, order); 2184 2185 if(!brush) 2186 return InvalidParameter; 2187 2188 return GdipTranslateMatrix(&brush->transform, dx, dy, order); 2189 } 2190 2191 GpStatus WINGDIPAPI GdipGetLineRect(GpLineGradient *brush, GpRectF *rect) 2192 { 2193 TRACE("(%p, %p)\n", brush, rect); 2194 2195 if(!brush || !rect || brush->brush.bt != BrushTypeLinearGradient) 2196 return InvalidParameter; 2197 2198 *rect = brush->rect; 2199 2200 return Ok; 2201 } 2202 2203 GpStatus WINGDIPAPI GdipGetLineRectI(GpLineGradient *brush, GpRect *rect) 2204 { 2205 GpRectF rectF; 2206 GpStatus ret; 2207 2208 TRACE("(%p, %p)\n", brush, rect); 2209 2210 if(!rect) 2211 return InvalidParameter; 2212 2213 ret = GdipGetLineRect(brush, &rectF); 2214 2215 if(ret == Ok){ 2216 rect->X = gdip_round(rectF.X); 2217 rect->Y = gdip_round(rectF.Y); 2218 rect->Width = gdip_round(rectF.Width); 2219 rect->Height = gdip_round(rectF.Height); 2220 } 2221 2222 return ret; 2223 } 2224 2225 GpStatus WINGDIPAPI GdipRotateLineTransform(GpLineGradient* brush, 2226 REAL angle, GpMatrixOrder order) 2227 { 2228 static int calls; 2229 2230 TRACE("(%p,%0.2f,%u)\n", brush, angle, order); 2231 2232 if(!brush || brush->brush.bt != BrushTypeLinearGradient) 2233 return InvalidParameter; 2234 2235 if(!(calls++)) 2236 FIXME("(%p, %.2f, %d) stub\n", brush, angle, order); 2237 2238 return NotImplemented; 2239 } 2240