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