2 * Copyright (C) 2007 Google (Evan Stade)
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "gdiplus_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus
);
39 Code from http://www.johndcook.com/blog/2009/01/19/stand-alone-error-function-erf/
43 const float a1
= 0.254829592;
44 const float a2
= -0.284496736;
45 const float a3
= 1.421413741;
46 const float a4
= -1.453152027;
47 const float a5
= 1.061405429;
48 const float p
= 0.3275911;
51 /* Save the sign of x */
59 y
= 1.0 - (((((a5
*t
+ a4
)*t
) + a3
)*t
+ a2
)*t
+ a1
)*t
*exp(-x
*x
);
64 /******************************************************************************
65 * GdipCloneBrush [GDIPLUS.@]
67 GpStatus WINGDIPAPI
GdipCloneBrush(GpBrush
*brush
, GpBrush
**clone
)
69 TRACE("(%p, %p)\n", brush
, clone
);
72 return InvalidParameter
;
75 case BrushTypeSolidColor
:
77 *clone
= GdipAlloc(sizeof(GpSolidFill
));
78 if (!*clone
) return OutOfMemory
;
79 memcpy(*clone
, brush
, sizeof(GpSolidFill
));
82 case BrushTypeHatchFill
:
84 GpHatch
*hatch
= (GpHatch
*)brush
;
86 return GdipCreateHatchBrush(hatch
->hatchstyle
, hatch
->forecol
, hatch
->backcol
, (GpHatch
**)clone
);
88 case BrushTypePathGradient
:{
89 GpPathGradient
*src
, *dest
;
93 *clone
= GdipAlloc(sizeof(GpPathGradient
));
94 if (!*clone
) return OutOfMemory
;
96 src
= (GpPathGradient
*) brush
,
97 dest
= (GpPathGradient
*) *clone
;
99 memcpy(dest
, src
, sizeof(GpPathGradient
));
101 stat
= GdipClonePath(src
->path
, &dest
->path
);
108 dest
->transform
= src
->transform
;
111 count
= src
->blendcount
;
112 dest
->blendcount
= count
;
113 dest
->blendfac
= GdipAlloc(count
* sizeof(REAL
));
114 dest
->blendpos
= GdipAlloc(count
* sizeof(REAL
));
115 dest
->surroundcolors
= GdipAlloc(dest
->surroundcolorcount
* sizeof(ARGB
));
116 pcount
= dest
->pblendcount
;
119 dest
->pblendcolor
= GdipAlloc(pcount
* sizeof(ARGB
));
120 dest
->pblendpos
= GdipAlloc(pcount
* sizeof(REAL
));
123 if(!dest
->blendfac
|| !dest
->blendpos
|| !dest
->surroundcolors
||
124 (pcount
&& (!dest
->pblendcolor
|| !dest
->pblendpos
))){
125 GdipDeletePath(dest
->path
);
126 GdipFree(dest
->blendfac
);
127 GdipFree(dest
->blendpos
);
128 GdipFree(dest
->surroundcolors
);
129 GdipFree(dest
->pblendcolor
);
130 GdipFree(dest
->pblendpos
);
135 memcpy(dest
->blendfac
, src
->blendfac
, count
* sizeof(REAL
));
136 memcpy(dest
->blendpos
, src
->blendpos
, count
* sizeof(REAL
));
137 memcpy(dest
->surroundcolors
, src
->surroundcolors
, dest
->surroundcolorcount
* sizeof(ARGB
));
141 memcpy(dest
->pblendcolor
, src
->pblendcolor
, pcount
* sizeof(ARGB
));
142 memcpy(dest
->pblendpos
, src
->pblendpos
, pcount
* sizeof(REAL
));
147 case BrushTypeLinearGradient
:{
148 GpLineGradient
*dest
, *src
;
151 dest
= GdipAlloc(sizeof(GpLineGradient
));
152 if(!dest
) return OutOfMemory
;
154 src
= (GpLineGradient
*)brush
;
156 memcpy(dest
, src
, sizeof(GpLineGradient
));
158 count
= dest
->blendcount
;
159 dest
->blendfac
= GdipAlloc(count
* sizeof(REAL
));
160 dest
->blendpos
= GdipAlloc(count
* sizeof(REAL
));
161 pcount
= dest
->pblendcount
;
164 dest
->pblendcolor
= GdipAlloc(pcount
* sizeof(ARGB
));
165 dest
->pblendpos
= GdipAlloc(pcount
* sizeof(REAL
));
168 if (!dest
->blendfac
|| !dest
->blendpos
||
169 (pcount
&& (!dest
->pblendcolor
|| !dest
->pblendpos
)))
171 GdipFree(dest
->blendfac
);
172 GdipFree(dest
->blendpos
);
173 GdipFree(dest
->pblendcolor
);
174 GdipFree(dest
->pblendpos
);
179 memcpy(dest
->blendfac
, src
->blendfac
, count
* sizeof(REAL
));
180 memcpy(dest
->blendpos
, src
->blendpos
, count
* sizeof(REAL
));
184 memcpy(dest
->pblendcolor
, src
->pblendcolor
, pcount
* sizeof(ARGB
));
185 memcpy(dest
->pblendpos
, src
->pblendpos
, pcount
* sizeof(REAL
));
188 *clone
= &dest
->brush
;
191 case BrushTypeTextureFill
:
194 GpTexture
*texture
= (GpTexture
*)brush
;
195 GpTexture
*new_texture
;
198 stat
= GdipGetImageWidth(texture
->image
, &width
);
199 if (stat
!= Ok
) return stat
;
200 stat
= GdipGetImageHeight(texture
->image
, &height
);
201 if (stat
!= Ok
) return stat
;
203 stat
= GdipCreateTextureIA(texture
->image
, texture
->imageattributes
, 0, 0, width
, height
, &new_texture
);
207 new_texture
->transform
= texture
->transform
;
208 *clone
= (GpBrush
*)new_texture
;
216 ERR("not implemented for brush type %d\n", brush
->bt
);
217 return NotImplemented
;
220 TRACE("<-- %p\n", *clone
);
224 static const char HatchBrushes
[][8] = {
225 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HatchStyleHorizontal */
226 { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleVertical */
227 { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HatchStyleForwardDiagonal */
228 { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HatchStyleBackwardDiagonal */
229 { 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleCross */
230 { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }, /* HatchStyleDiagonalCross */
231 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80 }, /* HatchStyle05Percent */
232 { 0x00, 0x02, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88 }, /* HatchStyle10Percent */
233 { 0x00, 0x22, 0x00, 0xcc, 0x00, 0x22, 0x00, 0xcc }, /* HatchStyle20Percent */
234 { 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc }, /* HatchStyle25Percent */
235 { 0x00, 0xcc, 0x04, 0xcc, 0x00, 0xcc, 0x40, 0xcc }, /* HatchStyle30Percent */
236 { 0x44, 0xcc, 0x22, 0xcc, 0x44, 0xcc, 0x22, 0xcc }, /* HatchStyle40Percent */
237 { 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc }, /* HatchStyle50Percent */
238 { 0x55, 0xcd, 0x55, 0xee, 0x55, 0xdc, 0x55, 0xee }, /* HatchStyle60Percent */
239 { 0x55, 0xdd, 0x55, 0xff, 0x55, 0xdd, 0x55, 0xff }, /* HatchStyle70Percent */
240 { 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff }, /* HatchStyle75Percent */
241 { 0x55, 0xff, 0x59, 0xff, 0x55, 0xff, 0x99, 0xff }, /* HatchStyle80Percent */
242 { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xfd, 0xff }, /* HatchStyle90Percent */
243 { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 }, /* HatchStyleLightDownwardDiagonal */
244 { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 }, /* HatchStyleLightUpwardDiagonal */
245 { 0x99, 0x33, 0x66, 0xcc, 0x99, 0x33, 0x66, 0xcc }, /* HatchStyleDarkDownwardDiagonal */
246 { 0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33, 0x99 }, /* HatchStyleDarkUpwardDiagonal */
247 { 0xc1, 0x83, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0 }, /* HatchStyleWideDownwardDiagonal */
248 { 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x07, 0x83, 0xc1 }, /* HatchStyleWideUpwardDiagonal */
249 { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 }, /* HatchStyleLightVertical */
250 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff }, /* HatchStyleLightHorizontal */
251 { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, /* HatchStyleNarrowVertical */
252 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, /* HatchStyleNarrowHorizontal */
253 { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }, /* HatchStyleDarkVertical */
254 { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff }, /* HatchStyleDarkHorizontal */
257 GpStatus
get_hatch_data(HatchStyle hatchstyle
, const char **result
)
259 if (hatchstyle
< sizeof(HatchBrushes
) / sizeof(HatchBrushes
[0]))
261 *result
= HatchBrushes
[hatchstyle
];
265 return NotImplemented
;
268 /******************************************************************************
269 * GdipCreateHatchBrush [GDIPLUS.@]
271 GpStatus WINGDIPAPI
GdipCreateHatchBrush(HatchStyle hatchstyle
, ARGB forecol
, ARGB backcol
, GpHatch
**brush
)
273 TRACE("(%d, %d, %d, %p)\n", hatchstyle
, forecol
, backcol
, brush
);
275 if(!brush
) return InvalidParameter
;
277 *brush
= GdipAlloc(sizeof(GpHatch
));
278 if (!*brush
) return OutOfMemory
;
280 (*brush
)->brush
.bt
= BrushTypeHatchFill
;
281 (*brush
)->forecol
= forecol
;
282 (*brush
)->backcol
= backcol
;
283 (*brush
)->hatchstyle
= hatchstyle
;
284 TRACE("<-- %p\n", *brush
);
289 /******************************************************************************
290 * GdipCreateLineBrush [GDIPLUS.@]
292 GpStatus WINGDIPAPI
GdipCreateLineBrush(GDIPCONST GpPointF
* startpoint
,
293 GDIPCONST GpPointF
* endpoint
, ARGB startcolor
, ARGB endcolor
,
294 GpWrapMode wrap
, GpLineGradient
**line
)
296 TRACE("(%s, %s, %x, %x, %d, %p)\n", debugstr_pointf(startpoint
),
297 debugstr_pointf(endpoint
), startcolor
, endcolor
, wrap
, line
);
299 if(!line
|| !startpoint
|| !endpoint
|| wrap
== WrapModeClamp
)
300 return InvalidParameter
;
302 if (startpoint
->X
== endpoint
->X
&& startpoint
->Y
== endpoint
->Y
)
305 *line
= GdipAlloc(sizeof(GpLineGradient
));
306 if(!*line
) return OutOfMemory
;
308 (*line
)->brush
.bt
= BrushTypeLinearGradient
;
310 (*line
)->startpoint
.X
= startpoint
->X
;
311 (*line
)->startpoint
.Y
= startpoint
->Y
;
312 (*line
)->endpoint
.X
= endpoint
->X
;
313 (*line
)->endpoint
.Y
= endpoint
->Y
;
314 (*line
)->startcolor
= startcolor
;
315 (*line
)->endcolor
= endcolor
;
316 (*line
)->wrap
= wrap
;
317 (*line
)->gamma
= FALSE
;
319 (*line
)->rect
.X
= (startpoint
->X
< endpoint
->X
? startpoint
->X
: endpoint
->X
);
320 (*line
)->rect
.Y
= (startpoint
->Y
< endpoint
->Y
? startpoint
->Y
: endpoint
->Y
);
321 (*line
)->rect
.Width
= fabs(startpoint
->X
- endpoint
->X
);
322 (*line
)->rect
.Height
= fabs(startpoint
->Y
- endpoint
->Y
);
324 if ((*line
)->rect
.Width
== 0)
326 (*line
)->rect
.X
-= (*line
)->rect
.Height
/ 2.0f
;
327 (*line
)->rect
.Width
= (*line
)->rect
.Height
;
329 else if ((*line
)->rect
.Height
== 0)
331 (*line
)->rect
.Y
-= (*line
)->rect
.Width
/ 2.0f
;
332 (*line
)->rect
.Height
= (*line
)->rect
.Width
;
335 (*line
)->blendcount
= 1;
336 (*line
)->blendfac
= GdipAlloc(sizeof(REAL
));
337 (*line
)->blendpos
= GdipAlloc(sizeof(REAL
));
339 if (!(*line
)->blendfac
|| !(*line
)->blendpos
)
341 GdipFree((*line
)->blendfac
);
342 GdipFree((*line
)->blendpos
);
348 (*line
)->blendfac
[0] = 1.0f
;
349 (*line
)->blendpos
[0] = 1.0f
;
351 (*line
)->pblendcolor
= NULL
;
352 (*line
)->pblendpos
= NULL
;
353 (*line
)->pblendcount
= 0;
355 TRACE("<-- %p\n", *line
);
360 GpStatus WINGDIPAPI
GdipCreateLineBrushI(GDIPCONST GpPoint
* startpoint
,
361 GDIPCONST GpPoint
* endpoint
, ARGB startcolor
, ARGB endcolor
,
362 GpWrapMode wrap
, GpLineGradient
**line
)
367 TRACE("(%p, %p, %x, %x, %d, %p)\n", startpoint
, endpoint
,
368 startcolor
, endcolor
, wrap
, line
);
370 if(!startpoint
|| !endpoint
)
371 return InvalidParameter
;
373 stF
.X
= (REAL
)startpoint
->X
;
374 stF
.Y
= (REAL
)startpoint
->Y
;
375 endF
.X
= (REAL
)endpoint
->X
;
376 endF
.Y
= (REAL
)endpoint
->Y
;
378 return GdipCreateLineBrush(&stF
, &endF
, startcolor
, endcolor
, wrap
, line
);
381 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRect(GDIPCONST GpRectF
* rect
,
382 ARGB startcolor
, ARGB endcolor
, LinearGradientMode mode
, GpWrapMode wrap
,
383 GpLineGradient
**line
)
388 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect
, startcolor
, endcolor
, mode
,
392 return InvalidParameter
;
396 case LinearGradientModeHorizontal
:
399 end
.X
= rect
->X
+ rect
->Width
;
402 case LinearGradientModeVertical
:
406 end
.Y
= rect
->Y
+ rect
->Height
;
408 case LinearGradientModeForwardDiagonal
:
411 end
.X
= rect
->X
+ rect
->Width
;
412 end
.Y
= rect
->Y
+ rect
->Height
;
414 case LinearGradientModeBackwardDiagonal
:
415 start
.X
= rect
->X
+ rect
->Width
;
418 end
.Y
= rect
->Y
+ rect
->Height
;
421 return InvalidParameter
;
424 stat
= GdipCreateLineBrush(&start
, &end
, startcolor
, endcolor
, wrap
, line
);
427 (*line
)->rect
= *rect
;
432 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectI(GDIPCONST GpRect
* rect
,
433 ARGB startcolor
, ARGB endcolor
, LinearGradientMode mode
, GpWrapMode wrap
,
434 GpLineGradient
**line
)
438 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect
, startcolor
, endcolor
, mode
,
441 rectF
.X
= (REAL
) rect
->X
;
442 rectF
.Y
= (REAL
) rect
->Y
;
443 rectF
.Width
= (REAL
) rect
->Width
;
444 rectF
.Height
= (REAL
) rect
->Height
;
446 return GdipCreateLineBrushFromRect(&rectF
, startcolor
, endcolor
, mode
, wrap
, line
);
449 /******************************************************************************
450 * GdipCreateLineBrushFromRectWithAngle [GDIPLUS.@]
452 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF
* rect
,
453 ARGB startcolor
, ARGB endcolor
, REAL angle
, BOOL isAngleScalable
, GpWrapMode wrap
,
454 GpLineGradient
**line
)
457 LinearGradientMode mode
;
458 REAL width
, height
, exofs
, eyofs
;
459 REAL sin_angle
, cos_angle
, sin_cos_angle
;
461 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect
, startcolor
, endcolor
, angle
, isAngleScalable
,
464 sin_angle
= sinf(deg2rad(angle
));
465 cos_angle
= cosf(deg2rad(angle
));
466 sin_cos_angle
= sin_angle
* cos_angle
;
470 width
= height
= 1.0;
475 height
= rect
->Height
;
478 if (sin_cos_angle
>= 0)
479 mode
= LinearGradientModeForwardDiagonal
;
481 mode
= LinearGradientModeBackwardDiagonal
;
483 stat
= GdipCreateLineBrushFromRect(rect
, startcolor
, endcolor
, mode
, wrap
, line
);
487 if (sin_cos_angle
>= 0)
489 exofs
= width
* sin_cos_angle
+ height
* cos_angle
* cos_angle
;
490 eyofs
= width
* sin_angle
* sin_angle
+ height
* sin_cos_angle
;
494 exofs
= width
* sin_angle
* sin_angle
+ height
* sin_cos_angle
;
495 eyofs
= -width
* sin_cos_angle
+ height
* sin_angle
* sin_angle
;
500 exofs
= exofs
* rect
->Width
;
501 eyofs
= eyofs
* rect
->Height
;
506 (*line
)->endpoint
.X
= rect
->X
+ exofs
;
507 (*line
)->endpoint
.Y
= rect
->Y
+ eyofs
;
511 (*line
)->endpoint
.X
= (*line
)->startpoint
.X
;
512 (*line
)->endpoint
.Y
= (*line
)->startpoint
.Y
;
513 (*line
)->startpoint
.X
= rect
->X
+ exofs
;
514 (*line
)->startpoint
.Y
= rect
->Y
+ eyofs
;
521 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectWithAngleI(GDIPCONST GpRect
* rect
,
522 ARGB startcolor
, ARGB endcolor
, REAL angle
, BOOL isAngleScalable
, GpWrapMode wrap
,
523 GpLineGradient
**line
)
525 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect
, startcolor
, endcolor
, angle
, isAngleScalable
,
528 return GdipCreateLineBrushFromRectI(rect
, startcolor
, endcolor
, LinearGradientModeForwardDiagonal
,
532 static GpStatus
create_path_gradient(GpPath
*path
, ARGB centercolor
, GpPathGradient
**grad
)
537 return InvalidParameter
;
539 if (path
->pathdata
.Count
< 2)
542 GdipGetPathWorldBounds(path
, &bounds
, NULL
, NULL
);
544 *grad
= GdipAlloc(sizeof(GpPathGradient
));
550 GdipSetMatrixElements(&(*grad
)->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
552 (*grad
)->blendfac
= GdipAlloc(sizeof(REAL
));
553 (*grad
)->blendpos
= GdipAlloc(sizeof(REAL
));
554 (*grad
)->surroundcolors
= GdipAlloc(sizeof(ARGB
));
555 if(!(*grad
)->blendfac
|| !(*grad
)->blendpos
|| !(*grad
)->surroundcolors
){
556 GdipFree((*grad
)->blendfac
);
557 GdipFree((*grad
)->blendpos
);
558 GdipFree((*grad
)->surroundcolors
);
563 (*grad
)->blendfac
[0] = 1.0;
564 (*grad
)->blendpos
[0] = 1.0;
565 (*grad
)->blendcount
= 1;
567 (*grad
)->path
= path
;
569 (*grad
)->brush
.bt
= BrushTypePathGradient
;
570 (*grad
)->centercolor
= centercolor
;
571 (*grad
)->wrap
= WrapModeClamp
;
572 (*grad
)->gamma
= FALSE
;
573 /* FIXME: this should be set to the "centroid" of the path by default */
574 (*grad
)->center
.X
= bounds
.X
+ bounds
.Width
/ 2;
575 (*grad
)->center
.Y
= bounds
.Y
+ bounds
.Height
/ 2;
576 (*grad
)->focus
.X
= 0.0;
577 (*grad
)->focus
.Y
= 0.0;
578 (*grad
)->surroundcolors
[0] = 0xffffffff;
579 (*grad
)->surroundcolorcount
= 1;
581 TRACE("<-- %p\n", *grad
);
586 GpStatus WINGDIPAPI
GdipCreatePathGradient(GDIPCONST GpPointF
* points
,
587 INT count
, GpWrapMode wrap
, GpPathGradient
**grad
)
592 TRACE("(%p, %d, %d, %p)\n", points
, count
, wrap
, grad
);
595 return InvalidParameter
;
597 if(!points
|| count
<= 0)
600 stat
= GdipCreatePath(FillModeAlternate
, &path
);
604 stat
= GdipAddPathLine2(path
, points
, count
);
607 stat
= create_path_gradient(path
, 0xff000000, grad
);
610 GdipDeletePath(path
);
614 (*grad
)->wrap
= wrap
;
619 GpStatus WINGDIPAPI
GdipCreatePathGradientI(GDIPCONST GpPoint
* points
,
620 INT count
, GpWrapMode wrap
, GpPathGradient
**grad
)
625 TRACE("(%p, %d, %d, %p)\n", points
, count
, wrap
, grad
);
628 return InvalidParameter
;
630 if(!points
|| count
<= 0)
633 stat
= GdipCreatePath(FillModeAlternate
, &path
);
637 stat
= GdipAddPathLine2I(path
, points
, count
);
640 stat
= create_path_gradient(path
, 0xff000000, grad
);
643 GdipDeletePath(path
);
647 (*grad
)->wrap
= wrap
;
652 /******************************************************************************
653 * GdipCreatePathGradientFromPath [GDIPLUS.@]
655 GpStatus WINGDIPAPI
GdipCreatePathGradientFromPath(GDIPCONST GpPath
* path
,
656 GpPathGradient
**grad
)
661 TRACE("(%p, %p)\n", path
, grad
);
664 return InvalidParameter
;
669 stat
= GdipClonePath((GpPath
*)path
, &new_path
);
673 stat
= create_path_gradient(new_path
, 0xffffffff, grad
);
676 GdipDeletePath(new_path
);
682 /******************************************************************************
683 * GdipCreateSolidFill [GDIPLUS.@]
685 GpStatus WINGDIPAPI
GdipCreateSolidFill(ARGB color
, GpSolidFill
**sf
)
687 TRACE("(%x, %p)\n", color
, sf
);
689 if(!sf
) return InvalidParameter
;
691 *sf
= GdipAlloc(sizeof(GpSolidFill
));
692 if (!*sf
) return OutOfMemory
;
694 (*sf
)->brush
.bt
= BrushTypeSolidColor
;
695 (*sf
)->color
= color
;
697 TRACE("<-- %p\n", *sf
);
702 /******************************************************************************
703 * GdipCreateTexture [GDIPLUS.@]
706 * image [I] image to use
707 * wrapmode [I] optional
708 * texture [O] pointer to the resulting texturebrush
712 * FAILURE: element of GpStatus
714 GpStatus WINGDIPAPI
GdipCreateTexture(GpImage
*image
, GpWrapMode wrapmode
,
718 GpImageAttributes
*attributes
;
721 TRACE("%p, %d %p\n", image
, wrapmode
, texture
);
723 if (!(image
&& texture
))
724 return InvalidParameter
;
726 stat
= GdipGetImageWidth(image
, &width
);
727 if (stat
!= Ok
) return stat
;
728 stat
= GdipGetImageHeight(image
, &height
);
729 if (stat
!= Ok
) return stat
;
731 stat
= GdipCreateImageAttributes(&attributes
);
735 attributes
->wrap
= wrapmode
;
737 stat
= GdipCreateTextureIA(image
, attributes
, 0, 0, width
, height
,
740 GdipDisposeImageAttributes(attributes
);
746 /******************************************************************************
747 * GdipCreateTexture2 [GDIPLUS.@]
749 GpStatus WINGDIPAPI
GdipCreateTexture2(GpImage
*image
, GpWrapMode wrapmode
,
750 REAL x
, REAL y
, REAL width
, REAL height
, GpTexture
**texture
)
752 GpImageAttributes
*attributes
;
755 TRACE("%p %d %f %f %f %f %p\n", image
, wrapmode
,
756 x
, y
, width
, height
, texture
);
758 stat
= GdipCreateImageAttributes(&attributes
);
762 attributes
->wrap
= wrapmode
;
764 stat
= GdipCreateTextureIA(image
, attributes
, x
, y
, width
, height
,
767 GdipDisposeImageAttributes(attributes
);
773 /******************************************************************************
774 * GdipCreateTextureIA [GDIPLUS.@]
776 * FIXME: imageattr ignored
778 GpStatus WINGDIPAPI
GdipCreateTextureIA(GpImage
*image
,
779 GDIPCONST GpImageAttributes
*imageattr
, REAL x
, REAL y
, REAL width
,
780 REAL height
, GpTexture
**texture
)
783 GpImage
*new_image
=NULL
;
785 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %p)\n", image
, imageattr
, x
, y
, width
, height
,
788 if(!image
|| !texture
|| x
< 0.0 || y
< 0.0 || width
< 0.0 || height
< 0.0)
789 return InvalidParameter
;
793 if(image
->type
!= ImageTypeBitmap
){
794 FIXME("not implemented for image type %d\n", image
->type
);
795 return NotImplemented
;
798 status
= GdipCloneBitmapArea(x
, y
, width
, height
, PixelFormatDontCare
, (GpBitmap
*)image
, (GpBitmap
**)&new_image
);
802 *texture
= GdipAlloc(sizeof(GpTexture
));
804 status
= OutOfMemory
;
808 GdipSetMatrixElements(&(*texture
)->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
812 status
= GdipCloneImageAttributes(imageattr
, &(*texture
)->imageattributes
);
816 status
= GdipCreateImageAttributes(&(*texture
)->imageattributes
);
818 (*texture
)->imageattributes
->wrap
= WrapModeTile
;
822 (*texture
)->brush
.bt
= BrushTypeTextureFill
;
823 (*texture
)->image
= new_image
;
829 TRACE("<-- %p\n", *texture
);
835 GdipDisposeImageAttributes((*texture
)->imageattributes
);
839 GdipDisposeImage(new_image
);
840 TRACE("<-- error %u\n", status
);
846 /******************************************************************************
847 * GdipCreateTextureIAI [GDIPLUS.@]
849 GpStatus WINGDIPAPI
GdipCreateTextureIAI(GpImage
*image
, GDIPCONST GpImageAttributes
*imageattr
,
850 INT x
, INT y
, INT width
, INT height
, GpTexture
**texture
)
852 TRACE("(%p, %p, %d, %d, %d, %d, %p)\n", image
, imageattr
, x
, y
, width
, height
,
855 return GdipCreateTextureIA(image
,imageattr
,(REAL
)x
,(REAL
)y
,(REAL
)width
,(REAL
)height
,texture
);
858 GpStatus WINGDIPAPI
GdipCreateTexture2I(GpImage
*image
, GpWrapMode wrapmode
,
859 INT x
, INT y
, INT width
, INT height
, GpTexture
**texture
)
861 GpImageAttributes
*imageattr
;
864 TRACE("%p %d %d %d %d %d %p\n", image
, wrapmode
, x
, y
, width
, height
,
867 stat
= GdipCreateImageAttributes(&imageattr
);
871 imageattr
->wrap
= wrapmode
;
873 stat
= GdipCreateTextureIA(image
, imageattr
, x
, y
, width
, height
, texture
);
879 GpStatus WINGDIPAPI
GdipGetBrushType(GpBrush
*brush
, GpBrushType
*type
)
881 TRACE("(%p, %p)\n", brush
, type
);
883 if(!brush
|| !type
) return InvalidParameter
;
890 GpStatus WINGDIPAPI
GdipGetHatchBackgroundColor(GpHatch
*brush
, ARGB
*backcol
)
892 TRACE("(%p, %p)\n", brush
, backcol
);
894 if(!brush
|| !backcol
) return InvalidParameter
;
896 *backcol
= brush
->backcol
;
901 GpStatus WINGDIPAPI
GdipGetHatchForegroundColor(GpHatch
*brush
, ARGB
*forecol
)
903 TRACE("(%p, %p)\n", brush
, forecol
);
905 if(!brush
|| !forecol
) return InvalidParameter
;
907 *forecol
= brush
->forecol
;
912 GpStatus WINGDIPAPI
GdipGetHatchStyle(GpHatch
*brush
, HatchStyle
*hatchstyle
)
914 TRACE("(%p, %p)\n", brush
, hatchstyle
);
916 if(!brush
|| !hatchstyle
) return InvalidParameter
;
918 *hatchstyle
= brush
->hatchstyle
;
923 GpStatus WINGDIPAPI
GdipDeleteBrush(GpBrush
*brush
)
925 TRACE("(%p)\n", brush
);
927 if(!brush
) return InvalidParameter
;
931 case BrushTypePathGradient
:
932 GdipDeletePath(((GpPathGradient
*) brush
)->path
);
933 GdipFree(((GpPathGradient
*) brush
)->blendfac
);
934 GdipFree(((GpPathGradient
*) brush
)->blendpos
);
935 GdipFree(((GpPathGradient
*) brush
)->surroundcolors
);
936 GdipFree(((GpPathGradient
*) brush
)->pblendcolor
);
937 GdipFree(((GpPathGradient
*) brush
)->pblendpos
);
939 case BrushTypeLinearGradient
:
940 GdipFree(((GpLineGradient
*)brush
)->blendfac
);
941 GdipFree(((GpLineGradient
*)brush
)->blendpos
);
942 GdipFree(((GpLineGradient
*)brush
)->pblendcolor
);
943 GdipFree(((GpLineGradient
*)brush
)->pblendpos
);
945 case BrushTypeTextureFill
:
946 GdipDisposeImage(((GpTexture
*)brush
)->image
);
947 GdipDisposeImageAttributes(((GpTexture
*)brush
)->imageattributes
);
948 GdipFree(((GpTexture
*)brush
)->bitmap_bits
);
959 GpStatus WINGDIPAPI
GdipGetLineGammaCorrection(GpLineGradient
*line
,
962 TRACE("(%p, %p)\n", line
, usinggamma
);
964 if(!line
|| !usinggamma
)
965 return InvalidParameter
;
967 *usinggamma
= line
->gamma
;
972 GpStatus WINGDIPAPI
GdipGetLineWrapMode(GpLineGradient
*brush
, GpWrapMode
*wrapmode
)
974 TRACE("(%p, %p)\n", brush
, wrapmode
);
976 if(!brush
|| !wrapmode
)
977 return InvalidParameter
;
979 *wrapmode
= brush
->wrap
;
984 GpStatus WINGDIPAPI
GdipGetPathGradientBlend(GpPathGradient
*brush
, REAL
*blend
,
985 REAL
*positions
, INT count
)
987 TRACE("(%p, %p, %p, %d)\n", brush
, blend
, positions
, count
);
989 if(!brush
|| !blend
|| !positions
|| count
<= 0)
990 return InvalidParameter
;
992 if(count
< brush
->blendcount
)
993 return InsufficientBuffer
;
995 memcpy(blend
, brush
->blendfac
, count
*sizeof(REAL
));
996 if(brush
->blendcount
> 1){
997 memcpy(positions
, brush
->blendpos
, count
*sizeof(REAL
));
1003 GpStatus WINGDIPAPI
GdipGetPathGradientBlendCount(GpPathGradient
*brush
, INT
*count
)
1005 TRACE("(%p, %p)\n", brush
, count
);
1007 if(!brush
|| !count
)
1008 return InvalidParameter
;
1010 *count
= brush
->blendcount
;
1015 GpStatus WINGDIPAPI
GdipGetPathGradientCenterPoint(GpPathGradient
*grad
,
1018 TRACE("(%p, %p)\n", grad
, point
);
1021 return InvalidParameter
;
1023 point
->X
= grad
->center
.X
;
1024 point
->Y
= grad
->center
.Y
;
1029 GpStatus WINGDIPAPI
GdipGetPathGradientCenterPointI(GpPathGradient
*grad
,
1035 TRACE("(%p, %p)\n", grad
, point
);
1038 return InvalidParameter
;
1040 ret
= GdipGetPathGradientCenterPoint(grad
,&ptf
);
1043 point
->X
= gdip_round(ptf
.X
);
1044 point
->Y
= gdip_round(ptf
.Y
);
1050 GpStatus WINGDIPAPI
GdipGetPathGradientCenterColor(GpPathGradient
*grad
,
1053 TRACE("(%p,%p)\n", grad
, colors
);
1055 if (!grad
|| !colors
)
1056 return InvalidParameter
;
1058 *colors
= grad
->centercolor
;
1063 GpStatus WINGDIPAPI
GdipGetPathGradientFocusScales(GpPathGradient
*grad
,
1066 TRACE("(%p, %p, %p)\n", grad
, x
, y
);
1068 if(!grad
|| !x
|| !y
)
1069 return InvalidParameter
;
1077 GpStatus WINGDIPAPI
GdipGetPathGradientGammaCorrection(GpPathGradient
*grad
,
1080 TRACE("(%p, %p)\n", grad
, gamma
);
1083 return InvalidParameter
;
1085 *gamma
= grad
->gamma
;
1090 GpStatus WINGDIPAPI
GdipGetPathGradientPath(GpPathGradient
*grad
, GpPath
*path
)
1094 TRACE("(%p, %p)\n", grad
, path
);
1097 FIXME("not implemented\n");
1099 return NotImplemented
;
1102 GpStatus WINGDIPAPI
GdipGetPathGradientPointCount(GpPathGradient
*grad
,
1105 TRACE("(%p, %p)\n", grad
, count
);
1108 return InvalidParameter
;
1110 *count
= grad
->path
->pathdata
.Count
;
1115 GpStatus WINGDIPAPI
GdipGetPathGradientRect(GpPathGradient
*brush
, GpRectF
*rect
)
1119 TRACE("(%p, %p)\n", brush
, rect
);
1122 return InvalidParameter
;
1124 stat
= GdipGetPathWorldBounds(brush
->path
, rect
, NULL
, NULL
);
1129 GpStatus WINGDIPAPI
GdipGetPathGradientRectI(GpPathGradient
*brush
, GpRect
*rect
)
1134 TRACE("(%p, %p)\n", brush
, rect
);
1137 return InvalidParameter
;
1139 stat
= GdipGetPathGradientRect(brush
, &rectf
);
1140 if(stat
!= Ok
) return stat
;
1142 rect
->X
= gdip_round(rectf
.X
);
1143 rect
->Y
= gdip_round(rectf
.Y
);
1144 rect
->Width
= gdip_round(rectf
.Width
);
1145 rect
->Height
= gdip_round(rectf
.Height
);
1150 GpStatus WINGDIPAPI
GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
1151 *grad
, ARGB
*argb
, INT
*count
)
1155 TRACE("(%p,%p,%p)\n", grad
, argb
, count
);
1157 if(!grad
|| !argb
|| !count
|| (*count
< grad
->path
->pathdata
.Count
))
1158 return InvalidParameter
;
1160 for (i
=0; i
<grad
->path
->pathdata
.Count
; i
++)
1162 if (i
< grad
->surroundcolorcount
)
1163 argb
[i
] = grad
->surroundcolors
[i
];
1165 argb
[i
] = grad
->surroundcolors
[grad
->surroundcolorcount
-1];
1168 *count
= grad
->surroundcolorcount
;
1173 GpStatus WINGDIPAPI
GdipGetPathGradientSurroundColorCount(GpPathGradient
*brush
, INT
*count
)
1175 TRACE("(%p, %p)\n", brush
, count
);
1177 if (!brush
|| !count
)
1178 return InvalidParameter
;
1180 /* Yes, this actually returns the number of points in the path (which is the
1181 * required size of a buffer to get the surround colors), rather than the
1182 * number of surround colors. The real count is returned when getting the
1184 *count
= brush
->path
->pathdata
.Count
;
1189 GpStatus WINGDIPAPI
GdipGetPathGradientWrapMode(GpPathGradient
*brush
,
1190 GpWrapMode
*wrapmode
)
1192 TRACE("(%p, %p)\n", brush
, wrapmode
);
1194 if(!brush
|| !wrapmode
)
1195 return InvalidParameter
;
1197 *wrapmode
= brush
->wrap
;
1202 GpStatus WINGDIPAPI
GdipGetSolidFillColor(GpSolidFill
*sf
, ARGB
*argb
)
1204 TRACE("(%p, %p)\n", sf
, argb
);
1207 return InvalidParameter
;
1214 /******************************************************************************
1215 * GdipGetTextureImage [GDIPLUS.@]
1217 GpStatus WINGDIPAPI
GdipGetTextureImage(GpTexture
*brush
, GpImage
**image
)
1219 TRACE("(%p, %p)\n", brush
, image
);
1221 if(!brush
|| !image
)
1222 return InvalidParameter
;
1224 return GdipCloneImage(brush
->image
, image
);
1227 /******************************************************************************
1228 * GdipGetTextureTransform [GDIPLUS.@]
1230 GpStatus WINGDIPAPI
GdipGetTextureTransform(GpTexture
*brush
, GpMatrix
*matrix
)
1232 TRACE("(%p, %p)\n", brush
, matrix
);
1234 if(!brush
|| !matrix
)
1235 return InvalidParameter
;
1237 *matrix
= brush
->transform
;
1242 /******************************************************************************
1243 * GdipGetTextureWrapMode [GDIPLUS.@]
1245 GpStatus WINGDIPAPI
GdipGetTextureWrapMode(GpTexture
*brush
, GpWrapMode
*wrapmode
)
1247 TRACE("(%p, %p)\n", brush
, wrapmode
);
1249 if(!brush
|| !wrapmode
)
1250 return InvalidParameter
;
1252 *wrapmode
= brush
->imageattributes
->wrap
;
1257 /******************************************************************************
1258 * GdipMultiplyTextureTransform [GDIPLUS.@]
1260 GpStatus WINGDIPAPI
GdipMultiplyTextureTransform(GpTexture
* brush
,
1261 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
1263 TRACE("(%p, %p, %d)\n", brush
, matrix
, order
);
1265 if(!brush
|| !matrix
)
1266 return InvalidParameter
;
1268 return GdipMultiplyMatrix(&brush
->transform
, matrix
, order
);
1271 /******************************************************************************
1272 * GdipResetTextureTransform [GDIPLUS.@]
1274 GpStatus WINGDIPAPI
GdipResetTextureTransform(GpTexture
* brush
)
1276 TRACE("(%p)\n", brush
);
1279 return InvalidParameter
;
1281 return GdipSetMatrixElements(&brush
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1284 /******************************************************************************
1285 * GdipScaleTextureTransform [GDIPLUS.@]
1287 GpStatus WINGDIPAPI
GdipScaleTextureTransform(GpTexture
* brush
,
1288 REAL sx
, REAL sy
, GpMatrixOrder order
)
1290 TRACE("(%p, %.2f, %.2f, %d)\n", brush
, sx
, sy
, order
);
1293 return InvalidParameter
;
1295 return GdipScaleMatrix(&brush
->transform
, sx
, sy
, order
);
1298 GpStatus WINGDIPAPI
GdipSetLineBlend(GpLineGradient
*brush
,
1299 GDIPCONST REAL
*factors
, GDIPCONST REAL
* positions
, INT count
)
1301 REAL
*new_blendfac
, *new_blendpos
;
1303 TRACE("(%p, %p, %p, %i)\n", brush
, factors
, positions
, count
);
1305 if(!brush
|| !factors
|| !positions
|| count
<= 0 ||
1306 (count
>= 2 && (positions
[0] != 0.0f
|| positions
[count
-1] != 1.0f
)))
1307 return InvalidParameter
;
1309 new_blendfac
= GdipAlloc(count
* sizeof(REAL
));
1310 new_blendpos
= GdipAlloc(count
* sizeof(REAL
));
1312 if (!new_blendfac
|| !new_blendpos
)
1314 GdipFree(new_blendfac
);
1315 GdipFree(new_blendpos
);
1319 memcpy(new_blendfac
, factors
, count
* sizeof(REAL
));
1320 memcpy(new_blendpos
, positions
, count
* sizeof(REAL
));
1322 GdipFree(brush
->blendfac
);
1323 GdipFree(brush
->blendpos
);
1325 brush
->blendcount
= count
;
1326 brush
->blendfac
= new_blendfac
;
1327 brush
->blendpos
= new_blendpos
;
1332 GpStatus WINGDIPAPI
GdipGetLineBlend(GpLineGradient
*brush
, REAL
*factors
,
1333 REAL
*positions
, INT count
)
1335 TRACE("(%p, %p, %p, %i)\n", brush
, factors
, positions
, count
);
1337 if (!brush
|| !factors
|| !positions
|| count
<= 0)
1338 return InvalidParameter
;
1340 if (count
< brush
->blendcount
)
1341 return InsufficientBuffer
;
1343 memcpy(factors
, brush
->blendfac
, brush
->blendcount
* sizeof(REAL
));
1344 memcpy(positions
, brush
->blendpos
, brush
->blendcount
* sizeof(REAL
));
1349 GpStatus WINGDIPAPI
GdipGetLineBlendCount(GpLineGradient
*brush
, INT
*count
)
1351 TRACE("(%p, %p)\n", brush
, count
);
1353 if (!brush
|| !count
)
1354 return InvalidParameter
;
1356 *count
= brush
->blendcount
;
1361 GpStatus WINGDIPAPI
GdipSetLineGammaCorrection(GpLineGradient
*line
,
1364 TRACE("(%p, %d)\n", line
, usegamma
);
1367 return InvalidParameter
;
1369 line
->gamma
= usegamma
;
1374 GpStatus WINGDIPAPI
GdipSetLineSigmaBlend(GpLineGradient
*line
, REAL focus
,
1381 const int precision
= 16;
1382 REAL erf_range
; /* we use values erf(-erf_range) through erf(+erf_range) */
1386 TRACE("(%p, %0.2f, %0.2f)\n", line
, focus
, scale
);
1388 if(!line
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0)
1389 return InvalidParameter
;
1391 /* we want 2 standard deviations */
1392 erf_range
= 2.0 / sqrt(2);
1394 /* calculate the constants we need to normalize the error function to be
1395 between 0.0 and scale over the range we need */
1396 min_erf
= erf(-erf_range
);
1397 scale_erf
= scale
/ (-2.0 * min_erf
);
1403 for (i
=1; i
<precision
; i
++)
1405 positions
[i
] = focus
* i
/ precision
;
1406 factors
[i
] = scale_erf
* (erf(2 * erf_range
* i
/ precision
- erf_range
) - min_erf
);
1408 num_points
+= precision
;
1411 positions
[num_points
] = focus
;
1412 factors
[num_points
] = scale
;
1417 for (i
=1; i
<precision
; i
++)
1419 positions
[i
+num_points
-1] = (focus
+ ((1.0-focus
) * i
/ precision
));
1420 factors
[i
+num_points
-1] = scale_erf
* (erf(erf_range
- 2 * erf_range
* i
/ precision
) - min_erf
);
1422 num_points
+= precision
;
1423 positions
[num_points
-1] = 1.0;
1424 factors
[num_points
-1] = 0.0;
1427 return GdipSetLineBlend(line
, factors
, positions
, num_points
);
1430 GpStatus WINGDIPAPI
GdipSetLineWrapMode(GpLineGradient
*line
,
1433 TRACE("(%p, %d)\n", line
, wrap
);
1435 if(!line
|| wrap
== WrapModeClamp
)
1436 return InvalidParameter
;
1443 GpStatus WINGDIPAPI
GdipSetPathGradientBlend(GpPathGradient
*brush
, GDIPCONST REAL
*blend
,
1444 GDIPCONST REAL
*pos
, INT count
)
1446 REAL
*new_blendfac
, *new_blendpos
;
1448 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1450 if(!brush
|| !blend
|| !pos
|| count
<= 0 ||
1451 (count
>= 2 && (pos
[0] != 0.0f
|| pos
[count
-1] != 1.0f
)))
1452 return InvalidParameter
;
1454 new_blendfac
= GdipAlloc(count
* sizeof(REAL
));
1455 new_blendpos
= GdipAlloc(count
* sizeof(REAL
));
1457 if (!new_blendfac
|| !new_blendpos
)
1459 GdipFree(new_blendfac
);
1460 GdipFree(new_blendpos
);
1464 memcpy(new_blendfac
, blend
, count
* sizeof(REAL
));
1465 memcpy(new_blendpos
, pos
, count
* sizeof(REAL
));
1467 GdipFree(brush
->blendfac
);
1468 GdipFree(brush
->blendpos
);
1470 brush
->blendcount
= count
;
1471 brush
->blendfac
= new_blendfac
;
1472 brush
->blendpos
= new_blendpos
;
1477 GpStatus WINGDIPAPI
GdipSetPathGradientLinearBlend(GpPathGradient
*brush
,
1478 REAL focus
, REAL scale
)
1484 TRACE("(%p,%0.2f,%0.2f)\n", brush
, focus
, scale
);
1486 if (!brush
) return InvalidParameter
;
1490 factors
[num_points
] = 0.0;
1491 positions
[num_points
] = 0.0;
1495 factors
[num_points
] = scale
;
1496 positions
[num_points
] = focus
;
1501 factors
[num_points
] = 0.0;
1502 positions
[num_points
] = 1.0;
1506 return GdipSetPathGradientBlend(brush
, factors
, positions
, num_points
);
1509 GpStatus WINGDIPAPI
GdipSetPathGradientPresetBlend(GpPathGradient
*brush
,
1510 GDIPCONST ARGB
*blend
, GDIPCONST REAL
*pos
, INT count
)
1514 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1516 if (!brush
|| !blend
|| !pos
|| count
< 2 ||
1517 pos
[0] != 0.0f
|| pos
[count
-1] != 1.0f
)
1519 return InvalidParameter
;
1522 new_color
= GdipAlloc(count
* sizeof(ARGB
));
1523 new_pos
= GdipAlloc(count
* sizeof(REAL
));
1524 if (!new_color
|| !new_pos
)
1526 GdipFree(new_color
);
1531 memcpy(new_color
, blend
, sizeof(ARGB
) * count
);
1532 memcpy(new_pos
, pos
, sizeof(REAL
) * count
);
1534 GdipFree(brush
->pblendcolor
);
1535 GdipFree(brush
->pblendpos
);
1537 brush
->pblendcolor
= new_color
;
1538 brush
->pblendpos
= new_pos
;
1539 brush
->pblendcount
= count
;
1544 GpStatus WINGDIPAPI
GdipGetPathGradientPresetBlend(GpPathGradient
*brush
,
1545 ARGB
*blend
, REAL
*pos
, INT count
)
1547 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1552 if (!brush
|| !blend
|| !pos
|| count
< 2)
1553 return InvalidParameter
;
1555 if (brush
->pblendcount
== 0)
1556 return GenericError
;
1558 if (count
!= brush
->pblendcount
)
1560 /* Native lines up the ends of each array, and copies the destination size. */
1561 FIXME("Braindead behavior on wrong-sized buffer not implemented.\n");
1562 return InvalidParameter
;
1565 memcpy(blend
, brush
->pblendcolor
, sizeof(ARGB
) * brush
->pblendcount
);
1566 memcpy(pos
, brush
->pblendpos
, sizeof(REAL
) * brush
->pblendcount
);
1571 GpStatus WINGDIPAPI
GdipGetPathGradientPresetBlendCount(GpPathGradient
*brush
,
1574 TRACE("(%p,%p)\n", brush
, count
);
1576 if (!brush
|| !count
)
1577 return InvalidParameter
;
1579 *count
= brush
->pblendcount
;
1584 GpStatus WINGDIPAPI
GdipSetPathGradientCenterColor(GpPathGradient
*grad
,
1587 TRACE("(%p, %x)\n", grad
, argb
);
1590 return InvalidParameter
;
1592 grad
->centercolor
= argb
;
1596 GpStatus WINGDIPAPI
GdipSetPathGradientCenterPoint(GpPathGradient
*grad
,
1599 TRACE("(%p, %s)\n", grad
, debugstr_pointf(point
));
1602 return InvalidParameter
;
1604 grad
->center
.X
= point
->X
;
1605 grad
->center
.Y
= point
->Y
;
1610 GpStatus WINGDIPAPI
GdipSetPathGradientCenterPointI(GpPathGradient
*grad
,
1615 TRACE("(%p, %p)\n", grad
, point
);
1618 return InvalidParameter
;
1620 ptf
.X
= (REAL
)point
->X
;
1621 ptf
.Y
= (REAL
)point
->Y
;
1623 return GdipSetPathGradientCenterPoint(grad
,&ptf
);
1626 GpStatus WINGDIPAPI
GdipSetPathGradientFocusScales(GpPathGradient
*grad
,
1629 TRACE("(%p, %.2f, %.2f)\n", grad
, x
, y
);
1632 return InvalidParameter
;
1640 GpStatus WINGDIPAPI
GdipSetPathGradientGammaCorrection(GpPathGradient
*grad
,
1643 TRACE("(%p, %d)\n", grad
, gamma
);
1646 return InvalidParameter
;
1648 grad
->gamma
= gamma
;
1653 GpStatus WINGDIPAPI
GdipSetPathGradientSigmaBlend(GpPathGradient
*grad
,
1654 REAL focus
, REAL scale
)
1660 const int precision
= 16;
1661 REAL erf_range
; /* we use values erf(-erf_range) through erf(+erf_range) */
1665 TRACE("(%p,%0.2f,%0.2f)\n", grad
, focus
, scale
);
1667 if(!grad
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0)
1668 return InvalidParameter
;
1670 /* we want 2 standard deviations */
1671 erf_range
= 2.0 / sqrt(2);
1673 /* calculate the constants we need to normalize the error function to be
1674 between 0.0 and scale over the range we need */
1675 min_erf
= erf(-erf_range
);
1676 scale_erf
= scale
/ (-2.0 * min_erf
);
1682 for (i
=1; i
<precision
; i
++)
1684 positions
[i
] = focus
* i
/ precision
;
1685 factors
[i
] = scale_erf
* (erf(2 * erf_range
* i
/ precision
- erf_range
) - min_erf
);
1687 num_points
+= precision
;
1690 positions
[num_points
] = focus
;
1691 factors
[num_points
] = scale
;
1696 for (i
=1; i
<precision
; i
++)
1698 positions
[i
+num_points
-1] = (focus
+ ((1.0-focus
) * i
/ precision
));
1699 factors
[i
+num_points
-1] = scale_erf
* (erf(erf_range
- 2 * erf_range
* i
/ precision
) - min_erf
);
1701 num_points
+= precision
;
1702 positions
[num_points
-1] = 1.0;
1703 factors
[num_points
-1] = 0.0;
1706 return GdipSetPathGradientBlend(grad
, factors
, positions
, num_points
);
1709 GpStatus WINGDIPAPI
GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
1710 *grad
, GDIPCONST ARGB
*argb
, INT
*count
)
1712 ARGB
*new_surroundcolors
;
1715 TRACE("(%p,%p,%p)\n", grad
, argb
, count
);
1717 if(!grad
|| !argb
|| !count
|| (*count
<= 0) ||
1718 (*count
> grad
->path
->pathdata
.Count
))
1719 return InvalidParameter
;
1721 num_colors
= *count
;
1723 /* If all colors are the same, only store 1 color. */
1726 for (i
=1; i
< num_colors
; i
++)
1727 if (argb
[i
] != argb
[i
-1])
1730 if (i
== num_colors
)
1734 new_surroundcolors
= GdipAlloc(num_colors
* sizeof(ARGB
));
1735 if (!new_surroundcolors
)
1738 memcpy(new_surroundcolors
, argb
, num_colors
* sizeof(ARGB
));
1740 GdipFree(grad
->surroundcolors
);
1742 grad
->surroundcolors
= new_surroundcolors
;
1743 grad
->surroundcolorcount
= num_colors
;
1748 GpStatus WINGDIPAPI
GdipSetPathGradientWrapMode(GpPathGradient
*grad
,
1751 TRACE("(%p, %d)\n", grad
, wrap
);
1754 return InvalidParameter
;
1761 GpStatus WINGDIPAPI
GdipSetPathGradientTransform(GpPathGradient
*grad
,
1764 TRACE("(%p,%p)\n", grad
, matrix
);
1766 if (!grad
|| !matrix
)
1767 return InvalidParameter
;
1769 grad
->transform
= *matrix
;
1774 GpStatus WINGDIPAPI
GdipGetPathGradientTransform(GpPathGradient
*grad
,
1777 TRACE("(%p,%p)\n", grad
, matrix
);
1779 if (!grad
|| !matrix
)
1780 return InvalidParameter
;
1782 *matrix
= grad
->transform
;
1787 GpStatus WINGDIPAPI
GdipMultiplyPathGradientTransform(GpPathGradient
*grad
,
1788 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
1790 TRACE("(%p,%p,%i)\n", grad
, matrix
, order
);
1793 return InvalidParameter
;
1795 return GdipMultiplyMatrix(&grad
->transform
, matrix
, order
);
1798 GpStatus WINGDIPAPI
GdipResetPathGradientTransform(GpPathGradient
*grad
)
1800 TRACE("(%p)\n", grad
);
1803 return InvalidParameter
;
1805 return GdipSetMatrixElements(&grad
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1808 GpStatus WINGDIPAPI
GdipRotatePathGradientTransform(GpPathGradient
*grad
,
1809 REAL angle
, GpMatrixOrder order
)
1811 TRACE("(%p,%0.2f,%i)\n", grad
, angle
, order
);
1814 return InvalidParameter
;
1816 return GdipRotateMatrix(&grad
->transform
, angle
, order
);
1819 GpStatus WINGDIPAPI
GdipScalePathGradientTransform(GpPathGradient
*grad
,
1820 REAL sx
, REAL sy
, GpMatrixOrder order
)
1822 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad
, sx
, sy
, order
);
1825 return InvalidParameter
;
1827 return GdipScaleMatrix(&grad
->transform
, sx
, sy
, order
);
1830 GpStatus WINGDIPAPI
GdipTranslatePathGradientTransform(GpPathGradient
*grad
,
1831 REAL dx
, REAL dy
, GpMatrixOrder order
)
1833 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad
, dx
, dy
, order
);
1836 return InvalidParameter
;
1838 return GdipTranslateMatrix(&grad
->transform
, dx
, dy
, order
);
1841 GpStatus WINGDIPAPI
GdipSetSolidFillColor(GpSolidFill
*sf
, ARGB argb
)
1843 TRACE("(%p, %x)\n", sf
, argb
);
1846 return InvalidParameter
;
1852 /******************************************************************************
1853 * GdipSetTextureTransform [GDIPLUS.@]
1855 GpStatus WINGDIPAPI
GdipSetTextureTransform(GpTexture
*texture
,
1856 GDIPCONST GpMatrix
*matrix
)
1858 TRACE("(%p, %p)\n", texture
, matrix
);
1860 if(!texture
|| !matrix
)
1861 return InvalidParameter
;
1863 texture
->transform
= *matrix
;
1868 /******************************************************************************
1869 * GdipSetTextureWrapMode [GDIPLUS.@]
1871 * WrapMode not used, only stored
1873 GpStatus WINGDIPAPI
GdipSetTextureWrapMode(GpTexture
*brush
, GpWrapMode wrapmode
)
1875 TRACE("(%p, %d)\n", brush
, wrapmode
);
1878 return InvalidParameter
;
1880 brush
->imageattributes
->wrap
= wrapmode
;
1885 GpStatus WINGDIPAPI
GdipSetLineColors(GpLineGradient
*brush
, ARGB color1
,
1888 TRACE("(%p, %x, %x)\n", brush
, color1
, color2
);
1891 return InvalidParameter
;
1893 brush
->startcolor
= color1
;
1894 brush
->endcolor
= color2
;
1899 GpStatus WINGDIPAPI
GdipGetLineColors(GpLineGradient
*brush
, ARGB
*colors
)
1901 TRACE("(%p, %p)\n", brush
, colors
);
1903 if(!brush
|| !colors
)
1904 return InvalidParameter
;
1906 colors
[0] = brush
->startcolor
;
1907 colors
[1] = brush
->endcolor
;
1912 /******************************************************************************
1913 * GdipRotateTextureTransform [GDIPLUS.@]
1915 GpStatus WINGDIPAPI
GdipRotateTextureTransform(GpTexture
* brush
, REAL angle
,
1916 GpMatrixOrder order
)
1918 TRACE("(%p, %.2f, %d)\n", brush
, angle
, order
);
1921 return InvalidParameter
;
1923 return GdipRotateMatrix(&brush
->transform
, angle
, order
);
1926 GpStatus WINGDIPAPI
GdipSetLineLinearBlend(GpLineGradient
*brush
, REAL focus
,
1933 TRACE("(%p,%.2f,%.2f)\n", brush
, focus
, scale
);
1935 if (!brush
) return InvalidParameter
;
1939 factors
[num_points
] = 0.0;
1940 positions
[num_points
] = 0.0;
1944 factors
[num_points
] = scale
;
1945 positions
[num_points
] = focus
;
1950 factors
[num_points
] = 0.0;
1951 positions
[num_points
] = 1.0;
1955 return GdipSetLineBlend(brush
, factors
, positions
, num_points
);
1958 GpStatus WINGDIPAPI
GdipSetLinePresetBlend(GpLineGradient
*brush
,
1959 GDIPCONST ARGB
*blend
, GDIPCONST REAL
* positions
, INT count
)
1963 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, positions
, count
);
1965 if (!brush
|| !blend
|| !positions
|| count
< 2 ||
1966 positions
[0] != 0.0f
|| positions
[count
-1] != 1.0f
)
1968 return InvalidParameter
;
1971 new_color
= GdipAlloc(count
* sizeof(ARGB
));
1972 new_pos
= GdipAlloc(count
* sizeof(REAL
));
1973 if (!new_color
|| !new_pos
)
1975 GdipFree(new_color
);
1980 memcpy(new_color
, blend
, sizeof(ARGB
) * count
);
1981 memcpy(new_pos
, positions
, sizeof(REAL
) * count
);
1983 GdipFree(brush
->pblendcolor
);
1984 GdipFree(brush
->pblendpos
);
1986 brush
->pblendcolor
= new_color
;
1987 brush
->pblendpos
= new_pos
;
1988 brush
->pblendcount
= count
;
1993 GpStatus WINGDIPAPI
GdipGetLinePresetBlend(GpLineGradient
*brush
,
1994 ARGB
*blend
, REAL
* positions
, INT count
)
1996 if (!brush
|| !blend
|| !positions
|| count
< 2)
1997 return InvalidParameter
;
1999 if (brush
->pblendcount
== 0)
2000 return GenericError
;
2002 if (count
< brush
->pblendcount
)
2003 return InsufficientBuffer
;
2005 memcpy(blend
, brush
->pblendcolor
, sizeof(ARGB
) * brush
->pblendcount
);
2006 memcpy(positions
, brush
->pblendpos
, sizeof(REAL
) * brush
->pblendcount
);
2011 GpStatus WINGDIPAPI
GdipGetLinePresetBlendCount(GpLineGradient
*brush
,
2014 if (!brush
|| !count
)
2015 return InvalidParameter
;
2017 *count
= brush
->pblendcount
;
2022 GpStatus WINGDIPAPI
GdipResetLineTransform(GpLineGradient
*brush
)
2026 TRACE("(%p)\n", brush
);
2029 FIXME("not implemented\n");
2031 return NotImplemented
;
2034 GpStatus WINGDIPAPI
GdipSetLineTransform(GpLineGradient
*brush
,
2035 GDIPCONST GpMatrix
*matrix
)
2039 TRACE("(%p,%p)\n", brush
, matrix
);
2042 FIXME("not implemented\n");
2044 return NotImplemented
;
2047 GpStatus WINGDIPAPI
GdipGetLineTransform(GpLineGradient
*brush
, GpMatrix
*matrix
)
2051 TRACE("(%p,%p)\n", brush
, matrix
);
2054 FIXME("not implemented\n");
2056 return NotImplemented
;
2059 GpStatus WINGDIPAPI
GdipScaleLineTransform(GpLineGradient
*brush
, REAL sx
, REAL sy
,
2060 GpMatrixOrder order
)
2064 TRACE("(%p,%0.2f,%0.2f,%u)\n", brush
, sx
, sy
, order
);
2067 FIXME("not implemented\n");
2069 return NotImplemented
;
2072 GpStatus WINGDIPAPI
GdipMultiplyLineTransform(GpLineGradient
*brush
,
2073 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
2077 TRACE("(%p,%p,%u)\n", brush
, matrix
, order
);
2080 FIXME("not implemented\n");
2082 return NotImplemented
;
2085 GpStatus WINGDIPAPI
GdipTranslateLineTransform(GpLineGradient
* brush
,
2086 REAL dx
, REAL dy
, GpMatrixOrder order
)
2090 TRACE("(%p,%f,%f,%d)\n", brush
, dx
, dy
, order
);
2093 FIXME("not implemented\n");
2098 /******************************************************************************
2099 * GdipTranslateTextureTransform [GDIPLUS.@]
2101 GpStatus WINGDIPAPI
GdipTranslateTextureTransform(GpTexture
* brush
, REAL dx
, REAL dy
,
2102 GpMatrixOrder order
)
2104 TRACE("(%p, %.2f, %.2f, %d)\n", brush
, dx
, dy
, order
);
2107 return InvalidParameter
;
2109 return GdipTranslateMatrix(&brush
->transform
, dx
, dy
, order
);
2112 GpStatus WINGDIPAPI
GdipGetLineRect(GpLineGradient
*brush
, GpRectF
*rect
)
2114 TRACE("(%p, %p)\n", brush
, rect
);
2117 return InvalidParameter
;
2119 *rect
= brush
->rect
;
2124 GpStatus WINGDIPAPI
GdipGetLineRectI(GpLineGradient
*brush
, GpRect
*rect
)
2129 TRACE("(%p, %p)\n", brush
, rect
);
2132 return InvalidParameter
;
2134 ret
= GdipGetLineRect(brush
, &rectF
);
2137 rect
->X
= gdip_round(rectF
.X
);
2138 rect
->Y
= gdip_round(rectF
.Y
);
2139 rect
->Width
= gdip_round(rectF
.Width
);
2140 rect
->Height
= gdip_round(rectF
.Height
);
2146 GpStatus WINGDIPAPI
GdipRotateLineTransform(GpLineGradient
* brush
,
2147 REAL angle
, GpMatrixOrder order
)
2151 TRACE("(%p,%0.2f,%u)\n", brush
, angle
, order
);
2154 return InvalidParameter
;
2157 FIXME("(%p, %.2f, %d) stub\n", brush
, angle
, order
);
2159 return NotImplemented
;