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 */
erf(double x)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 */
GdipCloneBrush(GpBrush * brush,GpBrush ** clone)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
get_hatch_data(GpHatchStyle hatchstyle,const char ** result)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 */
GdipCreateHatchBrush(GpHatchStyle hatchstyle,ARGB forecol,ARGB backcol,GpHatch ** brush)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
create_line_brush(const GpRectF * rect,ARGB startcolor,ARGB endcolor,GpWrapMode wrap,GpLineGradient ** line)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
linegradient_init_transform(const GpPointF * startpoint,const GpPointF * endpoint,GpLineGradient * line)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 */
GdipCreateLineBrush(GDIPCONST GpPointF * startpoint,GDIPCONST GpPointF * endpoint,ARGB startcolor,ARGB endcolor,GpWrapMode wrap,GpLineGradient ** line)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
GdipCreateLineBrushI(GDIPCONST GpPoint * startpoint,GDIPCONST GpPoint * endpoint,ARGB startcolor,ARGB endcolor,GpWrapMode wrap,GpLineGradient ** line)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
GdipCreateLineBrushFromRect(GDIPCONST GpRectF * rect,ARGB startcolor,ARGB endcolor,LinearGradientMode mode,GpWrapMode wrap,GpLineGradient ** line)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
GdipCreateLineBrushFromRectI(GDIPCONST GpRect * rect,ARGB startcolor,ARGB endcolor,LinearGradientMode mode,GpWrapMode wrap,GpLineGradient ** line)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 */
GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF * rect,ARGB startcolor,ARGB endcolor,REAL angle,BOOL isAngleScalable,GpWrapMode wrap,GpLineGradient ** line)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
GdipCreateLineBrushFromRectWithAngleI(GDIPCONST GpRect * rect,ARGB startcolor,ARGB endcolor,REAL angle,BOOL isAngleScalable,GpWrapMode wrap,GpLineGradient ** line)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
create_path_gradient(GpPath * path,ARGB centercolor,GpPathGradient ** grad)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
GdipCreatePathGradient(GDIPCONST GpPointF * points,INT count,GpWrapMode wrap,GpPathGradient ** grad)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
GdipCreatePathGradientI(GDIPCONST GpPoint * points,INT count,GpWrapMode wrap,GpPathGradient ** grad)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 */
GdipCreatePathGradientFromPath(GDIPCONST GpPath * path,GpPathGradient ** grad)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 */
GdipCreateSolidFill(ARGB color,GpSolidFill ** sf)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 */
GdipCreateTexture(GpImage * image,GpWrapMode wrapmode,GpTexture ** texture)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 */
GdipCreateTexture2(GpImage * image,GpWrapMode wrapmode,REAL x,REAL y,REAL width,REAL height,GpTexture ** texture)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 */
GdipCreateTextureIA(GpImage * image,GDIPCONST GpImageAttributes * imageattr,REAL x,REAL y,REAL width,REAL height,GpTexture ** texture)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 */
GdipCreateTextureIAI(GpImage * image,GDIPCONST GpImageAttributes * imageattr,INT x,INT y,INT width,INT height,GpTexture ** texture)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
GdipCreateTexture2I(GpImage * image,GpWrapMode wrapmode,INT x,INT y,INT width,INT height,GpTexture ** texture)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
GdipGetBrushType(GpBrush * brush,GpBrushType * type)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
GdipGetHatchBackgroundColor(GpHatch * brush,ARGB * backcol)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
GdipGetHatchForegroundColor(GpHatch * brush,ARGB * forecol)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
GdipGetHatchStyle(GpHatch * brush,GpHatchStyle * hatchstyle)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
GdipDeleteBrush(GpBrush * brush)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
GdipGetLineGammaCorrection(GpLineGradient * line,BOOL * usinggamma)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
GdipGetLineWrapMode(GpLineGradient * brush,GpWrapMode * wrapmode)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
GdipGetPathGradientBlend(GpPathGradient * brush,REAL * blend,REAL * positions,INT count)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
GdipGetPathGradientBlendCount(GpPathGradient * brush,INT * count)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
GdipGetPathGradientCenterPoint(GpPathGradient * grad,GpPointF * point)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
GdipGetPathGradientCenterPointI(GpPathGradient * grad,GpPoint * point)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
GdipGetPathGradientCenterColor(GpPathGradient * grad,ARGB * colors)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
GdipGetPathGradientFocusScales(GpPathGradient * grad,REAL * x,REAL * y)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
GdipGetPathGradientGammaCorrection(GpPathGradient * grad,BOOL * gamma)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
GdipGetPathGradientPath(GpPathGradient * grad,GpPath * path)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
GdipGetPathGradientPointCount(GpPathGradient * grad,INT * count)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
GdipGetPathGradientRect(GpPathGradient * brush,GpRectF * rect)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
GdipGetPathGradientRectI(GpPathGradient * brush,GpRect * rect)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
GdipGetPathGradientSurroundColorsWithCount(GpPathGradient * grad,ARGB * argb,INT * count)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
GdipGetPathGradientSurroundColorCount(GpPathGradient * brush,INT * count)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
GdipGetPathGradientWrapMode(GpPathGradient * brush,GpWrapMode * wrapmode)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
GdipGetSolidFillColor(GpSolidFill * sf,ARGB * argb)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 */
GdipGetTextureImage(GpTexture * brush,GpImage ** image)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 */
GdipGetTextureTransform(GpTexture * brush,GpMatrix * matrix)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 */
GdipGetTextureWrapMode(GpTexture * brush,GpWrapMode * wrapmode)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 */
GdipMultiplyTextureTransform(GpTexture * brush,GDIPCONST GpMatrix * matrix,GpMatrixOrder order)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 */
GdipResetTextureTransform(GpTexture * brush)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 */
GdipScaleTextureTransform(GpTexture * brush,REAL sx,REAL sy,GpMatrixOrder order)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
GdipSetLineBlend(GpLineGradient * brush,GDIPCONST REAL * factors,GDIPCONST REAL * positions,INT count)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
GdipGetLineBlend(GpLineGradient * brush,REAL * factors,REAL * positions,INT count)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
GdipGetLineBlendCount(GpLineGradient * brush,INT * count)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
GdipSetLineGammaCorrection(GpLineGradient * line,BOOL usegamma)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
GdipSetLineSigmaBlend(GpLineGradient * line,REAL focus,REAL scale)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
GdipSetLineWrapMode(GpLineGradient * line,GpWrapMode wrap)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
GdipSetPathGradientBlend(GpPathGradient * brush,GDIPCONST REAL * blend,GDIPCONST REAL * pos,INT count)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
GdipSetPathGradientLinearBlend(GpPathGradient * brush,REAL focus,REAL scale)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
GdipSetPathGradientPresetBlend(GpPathGradient * brush,GDIPCONST ARGB * blend,GDIPCONST REAL * pos,INT count)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
GdipGetPathGradientPresetBlend(GpPathGradient * brush,ARGB * blend,REAL * pos,INT count)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
GdipGetPathGradientPresetBlendCount(GpPathGradient * brush,INT * count)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
GdipSetPathGradientCenterColor(GpPathGradient * grad,ARGB argb)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
GdipSetPathGradientCenterPoint(GpPathGradient * grad,GpPointF * point)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
GdipSetPathGradientCenterPointI(GpPathGradient * grad,GpPoint * point)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
GdipSetPathGradientFocusScales(GpPathGradient * grad,REAL x,REAL y)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
GdipSetPathGradientGammaCorrection(GpPathGradient * grad,BOOL gamma)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
GdipSetPathGradientPath(GpPathGradient * grad,GDIPCONST GpPath * path)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
GdipSetPathGradientSigmaBlend(GpPathGradient * grad,REAL focus,REAL scale)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
GdipSetPathGradientSurroundColorsWithCount(GpPathGradient * grad,GDIPCONST ARGB * argb,INT * count)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
GdipSetPathGradientWrapMode(GpPathGradient * grad,GpWrapMode wrap)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
GdipSetPathGradientTransform(GpPathGradient * grad,GpMatrix * matrix)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
GdipGetPathGradientTransform(GpPathGradient * grad,GpMatrix * matrix)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
GdipMultiplyPathGradientTransform(GpPathGradient * grad,GDIPCONST GpMatrix * matrix,GpMatrixOrder order)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
GdipResetPathGradientTransform(GpPathGradient * grad)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
GdipRotatePathGradientTransform(GpPathGradient * grad,REAL angle,GpMatrixOrder order)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
GdipScalePathGradientTransform(GpPathGradient * grad,REAL sx,REAL sy,GpMatrixOrder order)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
GdipTranslatePathGradientTransform(GpPathGradient * grad,REAL dx,REAL dy,GpMatrixOrder order)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
GdipSetSolidFillColor(GpSolidFill * sf,ARGB argb)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 */
GdipSetTextureTransform(GpTexture * texture,GDIPCONST GpMatrix * matrix)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 */
GdipSetTextureWrapMode(GpTexture * brush,GpWrapMode wrapmode)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
GdipSetLineColors(GpLineGradient * brush,ARGB color1,ARGB color2)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
GdipGetLineColors(GpLineGradient * brush,ARGB * colors)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 */
GdipRotateTextureTransform(GpTexture * brush,REAL angle,GpMatrixOrder order)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
GdipSetLineLinearBlend(GpLineGradient * brush,REAL focus,REAL scale)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
GdipSetLinePresetBlend(GpLineGradient * brush,GDIPCONST ARGB * blend,GDIPCONST REAL * positions,INT count)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
GdipGetLinePresetBlend(GpLineGradient * brush,ARGB * blend,REAL * positions,INT count)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
GdipGetLinePresetBlendCount(GpLineGradient * brush,INT * count)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
GdipResetLineTransform(GpLineGradient * brush)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
GdipSetLineTransform(GpLineGradient * brush,GDIPCONST GpMatrix * matrix)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
GdipGetLineTransform(GpLineGradient * brush,GpMatrix * matrix)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
GdipScaleLineTransform(GpLineGradient * brush,REAL sx,REAL sy,GpMatrixOrder order)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
GdipMultiplyLineTransform(GpLineGradient * brush,GDIPCONST GpMatrix * matrix,GpMatrixOrder order)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
GdipTranslateLineTransform(GpLineGradient * brush,REAL dx,REAL dy,GpMatrixOrder order)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 */
GdipTranslateTextureTransform(GpTexture * brush,REAL dx,REAL dy,GpMatrixOrder order)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
GdipGetLineRect(GpLineGradient * brush,GpRectF * rect)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
GdipGetLineRectI(GpLineGradient * brush,GpRect * rect)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
GdipRotateLineTransform(GpLineGradient * brush,REAL angle,GpMatrixOrder order)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