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