2 * Copyright (C) 2007 Google (Evan Stade)
3 * Copyright (C) 2003-2004,2007 Novell, Inc. http://www.novell.com (Ravindra (rkumar@novell.com))
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.
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.
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
20 #include "gdiplus_private.h"
25 Code from http://www.johndcook.com/blog/2009/01/19/stand-alone-error-function-erf/
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
;
37 /* Save the sign of x */
45 y
= 1.0 - (((((a5
*t
+ a4
)*t
) + a3
)*t
+ a2
)*t
+ a1
)*t
*exp(-x
*x
);
51 /******************************************************************************
52 * GdipCloneBrush [GDIPLUS.@]
54 GpStatus WINGDIPAPI
GdipCloneBrush(GpBrush
*brush
, GpBrush
**clone
)
56 TRACE("(%p, %p)\n", brush
, clone
);
59 return InvalidParameter
;
62 case BrushTypeSolidColor
:
64 *clone
= heap_alloc_zero(sizeof(GpSolidFill
));
65 if (!*clone
) return OutOfMemory
;
66 memcpy(*clone
, brush
, sizeof(GpSolidFill
));
69 case BrushTypeHatchFill
:
71 GpHatch
*hatch
= (GpHatch
*)brush
;
73 return GdipCreateHatchBrush(hatch
->hatchstyle
, hatch
->forecol
, hatch
->backcol
, (GpHatch
**)clone
);
75 case BrushTypePathGradient
:{
76 GpPathGradient
*src
, *dest
;
80 *clone
= heap_alloc_zero(sizeof(GpPathGradient
));
81 if (!*clone
) return OutOfMemory
;
83 src
= (GpPathGradient
*) brush
,
84 dest
= (GpPathGradient
*) *clone
;
86 memcpy(dest
, src
, sizeof(GpPathGradient
));
88 stat
= GdipClonePath(src
->path
, &dest
->path
);
95 dest
->transform
= src
->transform
;
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
;
106 dest
->pblendcolor
= heap_alloc_zero(pcount
* sizeof(ARGB
));
107 dest
->pblendpos
= heap_alloc_zero(pcount
* sizeof(REAL
));
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
);
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
));
128 memcpy(dest
->pblendcolor
, src
->pblendcolor
, pcount
* sizeof(ARGB
));
129 memcpy(dest
->pblendpos
, src
->pblendpos
, pcount
* sizeof(REAL
));
134 case BrushTypeLinearGradient
:{
135 GpLineGradient
*dest
, *src
;
138 dest
= heap_alloc_zero(sizeof(GpLineGradient
));
139 if(!dest
) return OutOfMemory
;
141 src
= (GpLineGradient
*)brush
;
143 memcpy(dest
, src
, sizeof(GpLineGradient
));
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
;
151 dest
->pblendcolor
= heap_alloc_zero(pcount
* sizeof(ARGB
));
152 dest
->pblendpos
= heap_alloc_zero(pcount
* sizeof(REAL
));
155 if (!dest
->blendfac
|| !dest
->blendpos
||
156 (pcount
&& (!dest
->pblendcolor
|| !dest
->pblendpos
)))
158 heap_free(dest
->blendfac
);
159 heap_free(dest
->blendpos
);
160 heap_free(dest
->pblendcolor
);
161 heap_free(dest
->pblendpos
);
166 dest
->transform
= src
->transform
;
168 memcpy(dest
->blendfac
, src
->blendfac
, count
* sizeof(REAL
));
169 memcpy(dest
->blendpos
, src
->blendpos
, count
* sizeof(REAL
));
173 memcpy(dest
->pblendcolor
, src
->pblendcolor
, pcount
* sizeof(ARGB
));
174 memcpy(dest
->pblendpos
, src
->pblendpos
, pcount
* sizeof(REAL
));
177 *clone
= &dest
->brush
;
180 case BrushTypeTextureFill
:
183 GpTexture
*texture
= (GpTexture
*)brush
;
184 GpTexture
*new_texture
;
187 stat
= GdipGetImageWidth(texture
->image
, &width
);
188 if (stat
!= Ok
) return stat
;
189 stat
= GdipGetImageHeight(texture
->image
, &height
);
190 if (stat
!= Ok
) return stat
;
192 stat
= GdipCreateTextureIA(texture
->image
, texture
->imageattributes
, 0, 0, width
, height
, &new_texture
);
196 new_texture
->transform
= texture
->transform
;
197 *clone
= &new_texture
->brush
;
205 ERR("not implemented for brush type %d\n", brush
->bt
);
206 return NotImplemented
;
209 TRACE("<-- %p\n", *clone
);
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 */
246 GpStatus
get_hatch_data(GpHatchStyle hatchstyle
, const char **result
)
248 if (hatchstyle
< sizeof(HatchBrushes
) / sizeof(HatchBrushes
[0]))
250 *result
= HatchBrushes
[hatchstyle
];
254 return NotImplemented
;
257 /******************************************************************************
258 * GdipCreateHatchBrush [GDIPLUS.@]
260 GpStatus WINGDIPAPI
GdipCreateHatchBrush(GpHatchStyle hatchstyle
, ARGB forecol
, ARGB backcol
, GpHatch
**brush
)
262 TRACE("(%d, %d, %d, %p)\n", hatchstyle
, forecol
, backcol
, brush
);
264 if(!brush
) return InvalidParameter
;
266 if(hatchstyle
< HatchStyleMin
|| hatchstyle
> HatchStyleMax
)
267 return InvalidParameter
;
269 *brush
= heap_alloc_zero(sizeof(GpHatch
));
270 if (!*brush
) return OutOfMemory
;
272 (*brush
)->brush
.bt
= BrushTypeHatchFill
;
273 (*brush
)->forecol
= forecol
;
274 (*brush
)->backcol
= backcol
;
275 (*brush
)->hatchstyle
= hatchstyle
;
276 TRACE("<-- %p\n", *brush
);
281 static void linegradient_init_transform(GpLineGradient
*line
)
283 float trans_x
= line
->rect
.X
+ (line
->rect
.Width
/ 2.f
);
284 float trans_y
= line
->rect
.Y
+ (line
->rect
.Height
/ 2.f
);
285 float dx
= line
->endpoint
.X
- line
->startpoint
.X
;
286 float dy
= line
->endpoint
.Y
- line
->startpoint
.Y
;
287 float t_cos
, t_sin
, w_ratio
, h_ratio
;
291 h
= sqrtf(dx
* dx
+ dy
* dy
);
296 w_ratio
= (fabs(t_cos
) * line
->rect
.Width
+ fabs(t_sin
) * line
->rect
.Height
) / line
->rect
.Width
;
297 h_ratio
= (fabs(t_sin
) * line
->rect
.Width
+ fabs(t_cos
) * line
->rect
.Height
) / line
->rect
.Height
;
299 GdipSetMatrixElements(&line
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
301 GdipSetMatrixElements(&rot
, t_cos
, t_sin
, -1.f
* t_sin
, t_cos
, 0, 0);
303 /* center about the origin */
304 GdipTranslateMatrix(&line
->transform
, -trans_x
, -trans_y
, MatrixOrderAppend
);
306 /* scale to normalize gradient along gradient line (?) */
307 GdipScaleMatrix(&line
->transform
, w_ratio
, h_ratio
, MatrixOrderAppend
);
309 /* rotate so the gradient is horizontal */
310 GdipMultiplyMatrix(&line
->transform
, &rot
, MatrixOrderAppend
);
312 /* restore original offset in new coords */
313 GdipTranslateMatrix(&line
->transform
, trans_x
, trans_y
, MatrixOrderAppend
);
316 /******************************************************************************
317 * GdipCreateLineBrush [GDIPLUS.@]
319 GpStatus WINGDIPAPI
GdipCreateLineBrush(GDIPCONST GpPointF
* startpoint
,
320 GDIPCONST GpPointF
* endpoint
, ARGB startcolor
, ARGB endcolor
,
321 GpWrapMode wrap
, GpLineGradient
**line
)
323 TRACE("(%s, %s, %x, %x, %d, %p)\n", debugstr_pointf(startpoint
),
324 debugstr_pointf(endpoint
), startcolor
, endcolor
, wrap
, line
);
326 if(!line
|| !startpoint
|| !endpoint
|| wrap
== WrapModeClamp
)
327 return InvalidParameter
;
329 if (startpoint
->X
== endpoint
->X
&& startpoint
->Y
== endpoint
->Y
)
332 *line
= heap_alloc_zero(sizeof(GpLineGradient
));
333 if(!*line
) return OutOfMemory
;
335 (*line
)->brush
.bt
= BrushTypeLinearGradient
;
337 (*line
)->startpoint
.X
= startpoint
->X
;
338 (*line
)->startpoint
.Y
= startpoint
->Y
;
339 (*line
)->endpoint
.X
= endpoint
->X
;
340 (*line
)->endpoint
.Y
= endpoint
->Y
;
341 (*line
)->startcolor
= startcolor
;
342 (*line
)->endcolor
= endcolor
;
343 (*line
)->wrap
= wrap
;
344 (*line
)->gamma
= FALSE
;
346 (*line
)->rect
.X
= (startpoint
->X
< endpoint
->X
? startpoint
->X
: endpoint
->X
);
347 (*line
)->rect
.Y
= (startpoint
->Y
< endpoint
->Y
? startpoint
->Y
: endpoint
->Y
);
348 (*line
)->rect
.Width
= fabs(startpoint
->X
- endpoint
->X
);
349 (*line
)->rect
.Height
= fabs(startpoint
->Y
- endpoint
->Y
);
351 if ((*line
)->rect
.Width
== 0)
353 (*line
)->rect
.X
-= (*line
)->rect
.Height
/ 2.0f
;
354 (*line
)->rect
.Width
= (*line
)->rect
.Height
;
356 else if ((*line
)->rect
.Height
== 0)
358 (*line
)->rect
.Y
-= (*line
)->rect
.Width
/ 2.0f
;
359 (*line
)->rect
.Height
= (*line
)->rect
.Width
;
362 (*line
)->blendcount
= 1;
363 (*line
)->blendfac
= heap_alloc_zero(sizeof(REAL
));
364 (*line
)->blendpos
= heap_alloc_zero(sizeof(REAL
));
366 if (!(*line
)->blendfac
|| !(*line
)->blendpos
)
368 heap_free((*line
)->blendfac
);
369 heap_free((*line
)->blendpos
);
375 (*line
)->blendfac
[0] = 1.0f
;
376 (*line
)->blendpos
[0] = 1.0f
;
378 (*line
)->pblendcolor
= NULL
;
379 (*line
)->pblendpos
= NULL
;
380 (*line
)->pblendcount
= 0;
382 linegradient_init_transform(*line
);
384 TRACE("<-- %p\n", *line
);
389 GpStatus WINGDIPAPI
GdipCreateLineBrushI(GDIPCONST GpPoint
* startpoint
,
390 GDIPCONST GpPoint
* endpoint
, ARGB startcolor
, ARGB endcolor
,
391 GpWrapMode wrap
, GpLineGradient
**line
)
396 TRACE("(%p, %p, %x, %x, %d, %p)\n", startpoint
, endpoint
,
397 startcolor
, endcolor
, wrap
, line
);
399 if(!startpoint
|| !endpoint
)
400 return InvalidParameter
;
402 stF
.X
= (REAL
)startpoint
->X
;
403 stF
.Y
= (REAL
)startpoint
->Y
;
404 endF
.X
= (REAL
)endpoint
->X
;
405 endF
.Y
= (REAL
)endpoint
->Y
;
407 return GdipCreateLineBrush(&stF
, &endF
, startcolor
, endcolor
, wrap
, line
);
410 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRect(GDIPCONST GpRectF
* rect
,
411 ARGB startcolor
, ARGB endcolor
, LinearGradientMode mode
, GpWrapMode wrap
,
412 GpLineGradient
**line
)
418 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect
, startcolor
, endcolor
, mode
,
422 return InvalidParameter
;
424 far_x
= rect
->X
+ rect
->Width
;
425 far_y
= rect
->Y
+ rect
->Height
;
429 case LinearGradientModeHorizontal
:
430 start
.X
= min(rect
->X
, far_x
);
432 end
.X
= max(rect
->X
, far_x
);
435 case LinearGradientModeVertical
:
437 start
.Y
= min(rect
->Y
, far_y
);
439 end
.Y
= max(rect
->Y
, far_y
);
441 case LinearGradientModeForwardDiagonal
:
442 start
.X
= min(rect
->X
, far_x
);
443 start
.Y
= min(rect
->Y
, far_y
);
444 end
.X
= max(rect
->X
, far_x
);
445 end
.Y
= max(rect
->Y
, far_y
);
447 case LinearGradientModeBackwardDiagonal
:
448 start
.X
= max(rect
->X
, far_x
);
449 start
.Y
= min(rect
->Y
, far_y
);
450 end
.X
= min(rect
->X
, far_x
);
451 end
.Y
= max(rect
->Y
, far_y
);
454 return InvalidParameter
;
457 stat
= GdipCreateLineBrush(&start
, &end
, startcolor
, endcolor
, wrap
, line
);
460 (*line
)->rect
= *rect
;
465 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectI(GDIPCONST GpRect
* rect
,
466 ARGB startcolor
, ARGB endcolor
, LinearGradientMode mode
, GpWrapMode wrap
,
467 GpLineGradient
**line
)
471 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect
, startcolor
, endcolor
, mode
,
474 rectF
.X
= (REAL
) rect
->X
;
475 rectF
.Y
= (REAL
) rect
->Y
;
476 rectF
.Width
= (REAL
) rect
->Width
;
477 rectF
.Height
= (REAL
) rect
->Height
;
479 return GdipCreateLineBrushFromRect(&rectF
, startcolor
, endcolor
, mode
, wrap
, line
);
482 /******************************************************************************
483 * GdipCreateLineBrushFromRectWithAngle [GDIPLUS.@]
485 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF
* rect
,
486 ARGB startcolor
, ARGB endcolor
, REAL angle
, BOOL isAngleScalable
, GpWrapMode wrap
,
487 GpLineGradient
**line
)
490 LinearGradientMode mode
;
492 REAL sin_angle
, cos_angle
, sin_cos_angle
;
494 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect
, startcolor
, endcolor
, angle
, isAngleScalable
,
497 if (!rect
|| !line
|| wrap
== WrapModeClamp
)
498 return InvalidParameter
;
500 if (!rect
->Width
|| !rect
->Height
)
503 angle
= fmodf(angle
, 360);
516 if (angle
!= 90 && angle
!= -90)
517 angle
= atan((rect
->Width
/ rect
->Height
) * tan(deg2rad(angle
)));
519 angle
= deg2rad(angle
);
524 angle
= deg2rad(angle
);
527 sin_angle
= sinf(angle
);
528 cos_angle
= cosf(angle
);
529 sin_cos_angle
= sin_angle
* cos_angle
;
531 if (sin_cos_angle
>= 0)
532 mode
= LinearGradientModeForwardDiagonal
;
534 mode
= LinearGradientModeBackwardDiagonal
;
536 stat
= GdipCreateLineBrushFromRect(rect
, startcolor
, endcolor
, mode
, wrap
, line
);
540 if (sin_cos_angle
>= 0)
542 exofs
= rect
->Height
* sin_cos_angle
+ rect
->Width
* cos_angle
* cos_angle
;
543 eyofs
= rect
->Height
* sin_angle
* sin_angle
+ rect
->Width
* sin_cos_angle
;
547 exofs
= rect
->Width
* sin_angle
* sin_angle
+ rect
->Height
* sin_cos_angle
;
548 eyofs
= -rect
->Width
* sin_cos_angle
+ rect
->Height
* sin_angle
* sin_angle
;
553 (*line
)->endpoint
.X
= rect
->X
+ exofs
;
554 (*line
)->endpoint
.Y
= rect
->Y
+ eyofs
;
558 (*line
)->endpoint
.X
= (*line
)->startpoint
.X
;
559 (*line
)->endpoint
.Y
= (*line
)->startpoint
.Y
;
560 (*line
)->startpoint
.X
= rect
->X
+ exofs
;
561 (*line
)->startpoint
.Y
= rect
->Y
+ eyofs
;
564 linegradient_init_transform(*line
);
570 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectWithAngleI(GDIPCONST GpRect
* rect
,
571 ARGB startcolor
, ARGB endcolor
, REAL angle
, BOOL isAngleScalable
, GpWrapMode wrap
,
572 GpLineGradient
**line
)
574 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect
, startcolor
, endcolor
, angle
, isAngleScalable
,
577 return GdipCreateLineBrushFromRectI(rect
, startcolor
, endcolor
, LinearGradientModeForwardDiagonal
,
581 static GpStatus
create_path_gradient(GpPath
*path
, ARGB centercolor
, GpPathGradient
**grad
)
586 return InvalidParameter
;
588 if (path
->pathdata
.Count
< 2)
591 GdipGetPathWorldBounds(path
, &bounds
, NULL
, NULL
);
593 *grad
= heap_alloc_zero(sizeof(GpPathGradient
));
599 GdipSetMatrixElements(&(*grad
)->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
601 (*grad
)->blendfac
= heap_alloc_zero(sizeof(REAL
));
602 (*grad
)->blendpos
= heap_alloc_zero(sizeof(REAL
));
603 (*grad
)->surroundcolors
= heap_alloc_zero(sizeof(ARGB
));
604 if(!(*grad
)->blendfac
|| !(*grad
)->blendpos
|| !(*grad
)->surroundcolors
){
605 heap_free((*grad
)->blendfac
);
606 heap_free((*grad
)->blendpos
);
607 heap_free((*grad
)->surroundcolors
);
612 (*grad
)->blendfac
[0] = 1.0;
613 (*grad
)->blendpos
[0] = 1.0;
614 (*grad
)->blendcount
= 1;
616 (*grad
)->path
= path
;
618 (*grad
)->brush
.bt
= BrushTypePathGradient
;
619 (*grad
)->centercolor
= centercolor
;
620 (*grad
)->wrap
= WrapModeClamp
;
621 (*grad
)->gamma
= FALSE
;
622 /* FIXME: this should be set to the "centroid" of the path by default */
623 (*grad
)->center
.X
= bounds
.X
+ bounds
.Width
/ 2;
624 (*grad
)->center
.Y
= bounds
.Y
+ bounds
.Height
/ 2;
625 (*grad
)->focus
.X
= 0.0;
626 (*grad
)->focus
.Y
= 0.0;
627 (*grad
)->surroundcolors
[0] = 0xffffffff;
628 (*grad
)->surroundcolorcount
= 1;
630 TRACE("<-- %p\n", *grad
);
635 GpStatus WINGDIPAPI
GdipCreatePathGradient(GDIPCONST GpPointF
* points
,
636 INT count
, GpWrapMode wrap
, GpPathGradient
**grad
)
641 TRACE("(%p, %d, %d, %p)\n", points
, count
, wrap
, grad
);
644 return InvalidParameter
;
646 if(!points
|| count
<= 0)
649 stat
= GdipCreatePath(FillModeAlternate
, &path
);
653 stat
= GdipAddPathLine2(path
, points
, count
);
656 stat
= create_path_gradient(path
, 0xff000000, grad
);
659 GdipDeletePath(path
);
663 (*grad
)->wrap
= wrap
;
668 GpStatus WINGDIPAPI
GdipCreatePathGradientI(GDIPCONST GpPoint
* points
,
669 INT count
, GpWrapMode wrap
, GpPathGradient
**grad
)
674 TRACE("(%p, %d, %d, %p)\n", points
, count
, wrap
, grad
);
677 return InvalidParameter
;
679 if(!points
|| count
<= 0)
682 stat
= GdipCreatePath(FillModeAlternate
, &path
);
686 stat
= GdipAddPathLine2I(path
, points
, count
);
689 stat
= create_path_gradient(path
, 0xff000000, grad
);
692 GdipDeletePath(path
);
696 (*grad
)->wrap
= wrap
;
701 /******************************************************************************
702 * GdipCreatePathGradientFromPath [GDIPLUS.@]
704 GpStatus WINGDIPAPI
GdipCreatePathGradientFromPath(GDIPCONST GpPath
* path
,
705 GpPathGradient
**grad
)
710 TRACE("(%p, %p)\n", path
, grad
);
713 return InvalidParameter
;
718 stat
= GdipClonePath((GpPath
*)path
, &new_path
);
722 stat
= create_path_gradient(new_path
, 0xffffffff, grad
);
725 GdipDeletePath(new_path
);
731 /******************************************************************************
732 * GdipCreateSolidFill [GDIPLUS.@]
734 GpStatus WINGDIPAPI
GdipCreateSolidFill(ARGB color
, GpSolidFill
**sf
)
736 TRACE("(%x, %p)\n", color
, sf
);
738 if(!sf
) return InvalidParameter
;
740 *sf
= heap_alloc_zero(sizeof(GpSolidFill
));
741 if (!*sf
) return OutOfMemory
;
743 (*sf
)->brush
.bt
= BrushTypeSolidColor
;
744 (*sf
)->color
= color
;
746 TRACE("<-- %p\n", *sf
);
751 /******************************************************************************
752 * GdipCreateTexture [GDIPLUS.@]
755 * image [I] image to use
756 * wrapmode [I] optional
757 * texture [O] pointer to the resulting texturebrush
761 * FAILURE: element of GpStatus
763 GpStatus WINGDIPAPI
GdipCreateTexture(GpImage
*image
, GpWrapMode wrapmode
,
767 GpImageAttributes
*attributes
;
770 TRACE("%p, %d %p\n", image
, wrapmode
, texture
);
772 if (!(image
&& texture
))
773 return InvalidParameter
;
775 stat
= GdipGetImageWidth(image
, &width
);
776 if (stat
!= Ok
) return stat
;
777 stat
= GdipGetImageHeight(image
, &height
);
778 if (stat
!= Ok
) return stat
;
780 stat
= GdipCreateImageAttributes(&attributes
);
784 attributes
->wrap
= wrapmode
;
786 stat
= GdipCreateTextureIA(image
, attributes
, 0, 0, width
, height
,
789 GdipDisposeImageAttributes(attributes
);
795 /******************************************************************************
796 * GdipCreateTexture2 [GDIPLUS.@]
798 GpStatus WINGDIPAPI
GdipCreateTexture2(GpImage
*image
, GpWrapMode wrapmode
,
799 REAL x
, REAL y
, REAL width
, REAL height
, GpTexture
**texture
)
801 GpImageAttributes
*attributes
;
804 TRACE("%p %d %f %f %f %f %p\n", image
, wrapmode
,
805 x
, y
, width
, height
, texture
);
807 stat
= GdipCreateImageAttributes(&attributes
);
811 attributes
->wrap
= wrapmode
;
813 stat
= GdipCreateTextureIA(image
, attributes
, x
, y
, width
, height
,
816 GdipDisposeImageAttributes(attributes
);
822 /******************************************************************************
823 * GdipCreateTextureIA [GDIPLUS.@]
825 GpStatus WINGDIPAPI
GdipCreateTextureIA(GpImage
*image
,
826 GDIPCONST GpImageAttributes
*imageattr
, REAL x
, REAL y
, REAL width
,
827 REAL height
, GpTexture
**texture
)
830 GpImage
*new_image
=NULL
;
832 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %p)\n", image
, imageattr
, x
, y
, width
, height
,
835 if(!image
|| !texture
|| x
< 0.0 || y
< 0.0 || width
< 0.0 || height
< 0.0)
836 return InvalidParameter
;
840 if(image
->type
!= ImageTypeBitmap
){
841 FIXME("not implemented for image type %d\n", image
->type
);
842 return NotImplemented
;
845 status
= GdipCloneBitmapArea(x
, y
, width
, height
, PixelFormatDontCare
, (GpBitmap
*)image
, (GpBitmap
**)&new_image
);
849 *texture
= heap_alloc_zero(sizeof(GpTexture
));
851 status
= OutOfMemory
;
855 GdipSetMatrixElements(&(*texture
)->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
859 status
= GdipCloneImageAttributes(imageattr
, &(*texture
)->imageattributes
);
863 status
= GdipCreateImageAttributes(&(*texture
)->imageattributes
);
865 (*texture
)->imageattributes
->wrap
= WrapModeTile
;
869 (*texture
)->brush
.bt
= BrushTypeTextureFill
;
870 (*texture
)->image
= new_image
;
876 TRACE("<-- %p\n", *texture
);
882 GdipDisposeImageAttributes((*texture
)->imageattributes
);
886 GdipDisposeImage(new_image
);
887 TRACE("<-- error %u\n", status
);
893 /******************************************************************************
894 * GdipCreateTextureIAI [GDIPLUS.@]
896 GpStatus WINGDIPAPI
GdipCreateTextureIAI(GpImage
*image
, GDIPCONST GpImageAttributes
*imageattr
,
897 INT x
, INT y
, INT width
, INT height
, GpTexture
**texture
)
899 TRACE("(%p, %p, %d, %d, %d, %d, %p)\n", image
, imageattr
, x
, y
, width
, height
,
902 return GdipCreateTextureIA(image
,imageattr
,(REAL
)x
,(REAL
)y
,(REAL
)width
,(REAL
)height
,texture
);
905 GpStatus WINGDIPAPI
GdipCreateTexture2I(GpImage
*image
, GpWrapMode wrapmode
,
906 INT x
, INT y
, INT width
, INT height
, GpTexture
**texture
)
908 GpImageAttributes
*imageattr
;
911 TRACE("%p %d %d %d %d %d %p\n", image
, wrapmode
, x
, y
, width
, height
,
914 stat
= GdipCreateImageAttributes(&imageattr
);
918 imageattr
->wrap
= wrapmode
;
920 stat
= GdipCreateTextureIA(image
, imageattr
, x
, y
, width
, height
, texture
);
921 GdipDisposeImageAttributes(imageattr
);
927 GpStatus WINGDIPAPI
GdipGetBrushType(GpBrush
*brush
, GpBrushType
*type
)
929 TRACE("(%p, %p)\n", brush
, type
);
931 if(!brush
|| !type
) return InvalidParameter
;
938 GpStatus WINGDIPAPI
GdipGetHatchBackgroundColor(GpHatch
*brush
, ARGB
*backcol
)
940 TRACE("(%p, %p)\n", brush
, backcol
);
942 if(!brush
|| !backcol
) return InvalidParameter
;
944 *backcol
= brush
->backcol
;
949 GpStatus WINGDIPAPI
GdipGetHatchForegroundColor(GpHatch
*brush
, ARGB
*forecol
)
951 TRACE("(%p, %p)\n", brush
, forecol
);
953 if(!brush
|| !forecol
) return InvalidParameter
;
955 *forecol
= brush
->forecol
;
960 GpStatus WINGDIPAPI
GdipGetHatchStyle(GpHatch
*brush
, GpHatchStyle
*hatchstyle
)
962 TRACE("(%p, %p)\n", brush
, hatchstyle
);
964 if(!brush
|| !hatchstyle
) return InvalidParameter
;
966 *hatchstyle
= brush
->hatchstyle
;
971 GpStatus WINGDIPAPI
GdipDeleteBrush(GpBrush
*brush
)
973 TRACE("(%p)\n", brush
);
975 if(!brush
) return InvalidParameter
;
979 case BrushTypePathGradient
:
980 GdipDeletePath(((GpPathGradient
*) brush
)->path
);
981 heap_free(((GpPathGradient
*) brush
)->blendfac
);
982 heap_free(((GpPathGradient
*) brush
)->blendpos
);
983 heap_free(((GpPathGradient
*) brush
)->surroundcolors
);
984 heap_free(((GpPathGradient
*) brush
)->pblendcolor
);
985 heap_free(((GpPathGradient
*) brush
)->pblendpos
);
987 case BrushTypeLinearGradient
:
988 heap_free(((GpLineGradient
*)brush
)->blendfac
);
989 heap_free(((GpLineGradient
*)brush
)->blendpos
);
990 heap_free(((GpLineGradient
*)brush
)->pblendcolor
);
991 heap_free(((GpLineGradient
*)brush
)->pblendpos
);
993 case BrushTypeTextureFill
:
994 GdipDisposeImage(((GpTexture
*)brush
)->image
);
995 GdipDisposeImageAttributes(((GpTexture
*)brush
)->imageattributes
);
996 heap_free(((GpTexture
*)brush
)->bitmap_bits
);
1007 GpStatus WINGDIPAPI
GdipGetLineGammaCorrection(GpLineGradient
*line
,
1010 TRACE("(%p, %p)\n", line
, usinggamma
);
1012 if(!line
|| !usinggamma
)
1013 return InvalidParameter
;
1015 *usinggamma
= line
->gamma
;
1020 GpStatus WINGDIPAPI
GdipGetLineWrapMode(GpLineGradient
*brush
, GpWrapMode
*wrapmode
)
1022 TRACE("(%p, %p)\n", brush
, wrapmode
);
1024 if(!brush
|| !wrapmode
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1025 return InvalidParameter
;
1027 *wrapmode
= brush
->wrap
;
1032 GpStatus WINGDIPAPI
GdipGetPathGradientBlend(GpPathGradient
*brush
, REAL
*blend
,
1033 REAL
*positions
, INT count
)
1035 TRACE("(%p, %p, %p, %d)\n", brush
, blend
, positions
, count
);
1037 if(!brush
|| !blend
|| !positions
|| count
<= 0 || brush
->brush
.bt
!= BrushTypePathGradient
)
1038 return InvalidParameter
;
1040 if(count
< brush
->blendcount
)
1041 return InsufficientBuffer
;
1043 memcpy(blend
, brush
->blendfac
, count
*sizeof(REAL
));
1044 if(brush
->blendcount
> 1){
1045 memcpy(positions
, brush
->blendpos
, count
*sizeof(REAL
));
1051 GpStatus WINGDIPAPI
GdipGetPathGradientBlendCount(GpPathGradient
*brush
, INT
*count
)
1053 TRACE("(%p, %p)\n", brush
, count
);
1055 if(!brush
|| !count
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1056 return InvalidParameter
;
1058 *count
= brush
->blendcount
;
1063 GpStatus WINGDIPAPI
GdipGetPathGradientCenterPoint(GpPathGradient
*grad
,
1066 TRACE("(%p, %p)\n", grad
, point
);
1068 if(!grad
|| !point
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1069 return InvalidParameter
;
1071 point
->X
= grad
->center
.X
;
1072 point
->Y
= grad
->center
.Y
;
1077 GpStatus WINGDIPAPI
GdipGetPathGradientCenterPointI(GpPathGradient
*grad
,
1083 TRACE("(%p, %p)\n", grad
, point
);
1086 return InvalidParameter
;
1088 ret
= GdipGetPathGradientCenterPoint(grad
,&ptf
);
1091 point
->X
= gdip_round(ptf
.X
);
1092 point
->Y
= gdip_round(ptf
.Y
);
1098 GpStatus WINGDIPAPI
GdipGetPathGradientCenterColor(GpPathGradient
*grad
,
1101 TRACE("(%p,%p)\n", grad
, colors
);
1103 if (!grad
|| !colors
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1104 return InvalidParameter
;
1106 *colors
= grad
->centercolor
;
1111 GpStatus WINGDIPAPI
GdipGetPathGradientFocusScales(GpPathGradient
*grad
,
1114 TRACE("(%p, %p, %p)\n", grad
, x
, y
);
1116 if(!grad
|| !x
|| !y
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1117 return InvalidParameter
;
1125 GpStatus WINGDIPAPI
GdipGetPathGradientGammaCorrection(GpPathGradient
*grad
,
1128 TRACE("(%p, %p)\n", grad
, gamma
);
1130 if(!grad
|| !gamma
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1131 return InvalidParameter
;
1133 *gamma
= grad
->gamma
;
1138 GpStatus WINGDIPAPI
GdipGetPathGradientPath(GpPathGradient
*grad
, GpPath
*path
)
1142 TRACE("(%p, %p)\n", grad
, path
);
1145 FIXME("not implemented\n");
1147 return NotImplemented
;
1150 GpStatus WINGDIPAPI
GdipGetPathGradientPointCount(GpPathGradient
*grad
,
1153 TRACE("(%p, %p)\n", grad
, count
);
1155 if(!grad
|| !count
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1156 return InvalidParameter
;
1158 *count
= grad
->path
->pathdata
.Count
;
1163 GpStatus WINGDIPAPI
GdipGetPathGradientRect(GpPathGradient
*brush
, GpRectF
*rect
)
1167 TRACE("(%p, %p)\n", brush
, rect
);
1169 if(!brush
|| !rect
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1170 return InvalidParameter
;
1172 stat
= GdipGetPathWorldBounds(brush
->path
, rect
, NULL
, NULL
);
1177 GpStatus WINGDIPAPI
GdipGetPathGradientRectI(GpPathGradient
*brush
, GpRect
*rect
)
1182 TRACE("(%p, %p)\n", brush
, rect
);
1185 return InvalidParameter
;
1187 stat
= GdipGetPathGradientRect(brush
, &rectf
);
1188 if(stat
!= Ok
) return stat
;
1190 rect
->X
= gdip_round(rectf
.X
);
1191 rect
->Y
= gdip_round(rectf
.Y
);
1192 rect
->Width
= gdip_round(rectf
.Width
);
1193 rect
->Height
= gdip_round(rectf
.Height
);
1198 GpStatus WINGDIPAPI
GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
1199 *grad
, ARGB
*argb
, INT
*count
)
1203 TRACE("(%p,%p,%p)\n", grad
, argb
, count
);
1205 if(!grad
|| !argb
|| !count
|| (*count
< grad
->path
->pathdata
.Count
) || grad
->brush
.bt
!= BrushTypePathGradient
)
1206 return InvalidParameter
;
1208 for (i
=0; i
<grad
->path
->pathdata
.Count
; i
++)
1210 if (i
< grad
->surroundcolorcount
)
1211 argb
[i
] = grad
->surroundcolors
[i
];
1213 argb
[i
] = grad
->surroundcolors
[grad
->surroundcolorcount
-1];
1216 *count
= grad
->surroundcolorcount
;
1221 GpStatus WINGDIPAPI
GdipGetPathGradientSurroundColorCount(GpPathGradient
*brush
, INT
*count
)
1223 TRACE("(%p, %p)\n", brush
, count
);
1225 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1226 return InvalidParameter
;
1228 /* Yes, this actually returns the number of points in the path (which is the
1229 * required size of a buffer to get the surround colors), rather than the
1230 * number of surround colors. The real count is returned when getting the
1232 *count
= brush
->path
->pathdata
.Count
;
1237 GpStatus WINGDIPAPI
GdipGetPathGradientWrapMode(GpPathGradient
*brush
,
1238 GpWrapMode
*wrapmode
)
1240 TRACE("(%p, %p)\n", brush
, wrapmode
);
1242 if(!brush
|| !wrapmode
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1243 return InvalidParameter
;
1245 *wrapmode
= brush
->wrap
;
1250 GpStatus WINGDIPAPI
GdipGetSolidFillColor(GpSolidFill
*sf
, ARGB
*argb
)
1252 TRACE("(%p, %p)\n", sf
, argb
);
1255 return InvalidParameter
;
1262 /******************************************************************************
1263 * GdipGetTextureImage [GDIPLUS.@]
1265 GpStatus WINGDIPAPI
GdipGetTextureImage(GpTexture
*brush
, GpImage
**image
)
1267 TRACE("(%p, %p)\n", brush
, image
);
1269 if(!brush
|| !image
)
1270 return InvalidParameter
;
1272 return GdipCloneImage(brush
->image
, image
);
1275 /******************************************************************************
1276 * GdipGetTextureTransform [GDIPLUS.@]
1278 GpStatus WINGDIPAPI
GdipGetTextureTransform(GpTexture
*brush
, GpMatrix
*matrix
)
1280 TRACE("(%p, %p)\n", brush
, matrix
);
1282 if(!brush
|| !matrix
)
1283 return InvalidParameter
;
1285 *matrix
= brush
->transform
;
1290 /******************************************************************************
1291 * GdipGetTextureWrapMode [GDIPLUS.@]
1293 GpStatus WINGDIPAPI
GdipGetTextureWrapMode(GpTexture
*brush
, GpWrapMode
*wrapmode
)
1295 TRACE("(%p, %p)\n", brush
, wrapmode
);
1297 if(!brush
|| !wrapmode
)
1298 return InvalidParameter
;
1300 *wrapmode
= brush
->imageattributes
->wrap
;
1305 /******************************************************************************
1306 * GdipMultiplyTextureTransform [GDIPLUS.@]
1308 GpStatus WINGDIPAPI
GdipMultiplyTextureTransform(GpTexture
* brush
,
1309 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
1311 TRACE("(%p, %p, %d)\n", brush
, matrix
, order
);
1313 if(!brush
|| !matrix
)
1314 return InvalidParameter
;
1316 return GdipMultiplyMatrix(&brush
->transform
, matrix
, order
);
1319 /******************************************************************************
1320 * GdipResetTextureTransform [GDIPLUS.@]
1322 GpStatus WINGDIPAPI
GdipResetTextureTransform(GpTexture
* brush
)
1324 TRACE("(%p)\n", brush
);
1327 return InvalidParameter
;
1329 return GdipSetMatrixElements(&brush
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1332 /******************************************************************************
1333 * GdipScaleTextureTransform [GDIPLUS.@]
1335 GpStatus WINGDIPAPI
GdipScaleTextureTransform(GpTexture
* brush
,
1336 REAL sx
, REAL sy
, GpMatrixOrder order
)
1338 TRACE("(%p, %.2f, %.2f, %d)\n", brush
, sx
, sy
, order
);
1341 return InvalidParameter
;
1343 return GdipScaleMatrix(&brush
->transform
, sx
, sy
, order
);
1346 GpStatus WINGDIPAPI
GdipSetLineBlend(GpLineGradient
*brush
,
1347 GDIPCONST REAL
*factors
, GDIPCONST REAL
* positions
, INT count
)
1349 REAL
*new_blendfac
, *new_blendpos
;
1351 TRACE("(%p, %p, %p, %i)\n", brush
, factors
, positions
, count
);
1353 if(!brush
|| !factors
|| !positions
|| count
<= 0 || brush
->brush
.bt
!= BrushTypeLinearGradient
||
1354 (count
>= 2 && (positions
[0] != 0.0f
|| positions
[count
-1] != 1.0f
)))
1355 return InvalidParameter
;
1357 new_blendfac
= heap_alloc_zero(count
* sizeof(REAL
));
1358 new_blendpos
= heap_alloc_zero(count
* sizeof(REAL
));
1360 if (!new_blendfac
|| !new_blendpos
)
1362 heap_free(new_blendfac
);
1363 heap_free(new_blendpos
);
1367 memcpy(new_blendfac
, factors
, count
* sizeof(REAL
));
1368 memcpy(new_blendpos
, positions
, count
* sizeof(REAL
));
1370 heap_free(brush
->blendfac
);
1371 heap_free(brush
->blendpos
);
1373 brush
->blendcount
= count
;
1374 brush
->blendfac
= new_blendfac
;
1375 brush
->blendpos
= new_blendpos
;
1380 GpStatus WINGDIPAPI
GdipGetLineBlend(GpLineGradient
*brush
, REAL
*factors
,
1381 REAL
*positions
, INT count
)
1383 TRACE("(%p, %p, %p, %i)\n", brush
, factors
, positions
, count
);
1385 if (!brush
|| !factors
|| !positions
|| count
<= 0 || brush
->brush
.bt
!= BrushTypeLinearGradient
)
1386 return InvalidParameter
;
1388 if (count
< brush
->blendcount
)
1389 return InsufficientBuffer
;
1391 memcpy(factors
, brush
->blendfac
, brush
->blendcount
* sizeof(REAL
));
1392 memcpy(positions
, brush
->blendpos
, brush
->blendcount
* sizeof(REAL
));
1397 GpStatus WINGDIPAPI
GdipGetLineBlendCount(GpLineGradient
*brush
, INT
*count
)
1399 TRACE("(%p, %p)\n", brush
, count
);
1401 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1402 return InvalidParameter
;
1404 *count
= brush
->blendcount
;
1409 GpStatus WINGDIPAPI
GdipSetLineGammaCorrection(GpLineGradient
*line
,
1412 TRACE("(%p, %d)\n", line
, usegamma
);
1414 if(!line
|| line
->brush
.bt
!= BrushTypeLinearGradient
)
1415 return InvalidParameter
;
1417 line
->gamma
= usegamma
;
1422 GpStatus WINGDIPAPI
GdipSetLineSigmaBlend(GpLineGradient
*line
, REAL focus
,
1429 const int precision
= 16;
1430 REAL erf_range
; /* we use values erf(-erf_range) through erf(+erf_range) */
1434 TRACE("(%p, %0.2f, %0.2f)\n", line
, focus
, scale
);
1436 if(!line
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0 || line
->brush
.bt
!= BrushTypeLinearGradient
)
1437 return InvalidParameter
;
1439 /* we want 2 standard deviations */
1440 erf_range
= 2.0 / sqrt(2);
1442 /* calculate the constants we need to normalize the error function to be
1443 between 0.0 and scale over the range we need */
1444 min_erf
= erf(-erf_range
);
1445 scale_erf
= scale
/ (-2.0 * min_erf
);
1451 for (i
=1; i
<precision
; i
++)
1453 positions
[i
] = focus
* i
/ precision
;
1454 factors
[i
] = scale_erf
* (erf(2 * erf_range
* i
/ precision
- erf_range
) - min_erf
);
1456 num_points
+= precision
;
1459 positions
[num_points
] = focus
;
1460 factors
[num_points
] = scale
;
1465 for (i
=1; i
<precision
; i
++)
1467 positions
[i
+num_points
-1] = (focus
+ ((1.0-focus
) * i
/ precision
));
1468 factors
[i
+num_points
-1] = scale_erf
* (erf(erf_range
- 2 * erf_range
* i
/ precision
) - min_erf
);
1470 num_points
+= precision
;
1471 positions
[num_points
-1] = 1.0;
1472 factors
[num_points
-1] = 0.0;
1475 return GdipSetLineBlend(line
, factors
, positions
, num_points
);
1478 GpStatus WINGDIPAPI
GdipSetLineWrapMode(GpLineGradient
*line
,
1481 TRACE("(%p, %d)\n", line
, wrap
);
1483 if(!line
|| wrap
== WrapModeClamp
|| line
->brush
.bt
!= BrushTypeLinearGradient
)
1484 return InvalidParameter
;
1491 GpStatus WINGDIPAPI
GdipSetPathGradientBlend(GpPathGradient
*brush
, GDIPCONST REAL
*blend
,
1492 GDIPCONST REAL
*pos
, INT count
)
1494 REAL
*new_blendfac
, *new_blendpos
;
1496 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1498 if(!brush
|| !blend
|| !pos
|| count
<= 0 || brush
->brush
.bt
!= BrushTypePathGradient
||
1499 (count
>= 2 && (pos
[0] != 0.0f
|| pos
[count
-1] != 1.0f
)))
1500 return InvalidParameter
;
1502 new_blendfac
= heap_alloc_zero(count
* sizeof(REAL
));
1503 new_blendpos
= heap_alloc_zero(count
* sizeof(REAL
));
1505 if (!new_blendfac
|| !new_blendpos
)
1507 heap_free(new_blendfac
);
1508 heap_free(new_blendpos
);
1512 memcpy(new_blendfac
, blend
, count
* sizeof(REAL
));
1513 memcpy(new_blendpos
, pos
, count
* sizeof(REAL
));
1515 heap_free(brush
->blendfac
);
1516 heap_free(brush
->blendpos
);
1518 brush
->blendcount
= count
;
1519 brush
->blendfac
= new_blendfac
;
1520 brush
->blendpos
= new_blendpos
;
1525 GpStatus WINGDIPAPI
GdipSetPathGradientLinearBlend(GpPathGradient
*brush
,
1526 REAL focus
, REAL scale
)
1532 TRACE("(%p,%0.2f,%0.2f)\n", brush
, focus
, scale
);
1534 if (!brush
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1535 return InvalidParameter
;
1539 factors
[num_points
] = 0.0;
1540 positions
[num_points
] = 0.0;
1544 factors
[num_points
] = scale
;
1545 positions
[num_points
] = focus
;
1550 factors
[num_points
] = 0.0;
1551 positions
[num_points
] = 1.0;
1555 return GdipSetPathGradientBlend(brush
, factors
, positions
, num_points
);
1558 GpStatus WINGDIPAPI
GdipSetPathGradientPresetBlend(GpPathGradient
*brush
,
1559 GDIPCONST ARGB
*blend
, GDIPCONST REAL
*pos
, INT count
)
1563 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1565 if (!brush
|| !blend
|| !pos
|| count
< 2 || brush
->brush
.bt
!= BrushTypePathGradient
||
1566 pos
[0] != 0.0f
|| pos
[count
-1] != 1.0f
)
1568 return InvalidParameter
;
1571 new_color
= heap_alloc_zero(count
* sizeof(ARGB
));
1572 new_pos
= heap_alloc_zero(count
* sizeof(REAL
));
1573 if (!new_color
|| !new_pos
)
1575 heap_free(new_color
);
1580 memcpy(new_color
, blend
, sizeof(ARGB
) * count
);
1581 memcpy(new_pos
, pos
, sizeof(REAL
) * count
);
1583 heap_free(brush
->pblendcolor
);
1584 heap_free(brush
->pblendpos
);
1586 brush
->pblendcolor
= new_color
;
1587 brush
->pblendpos
= new_pos
;
1588 brush
->pblendcount
= count
;
1593 GpStatus WINGDIPAPI
GdipGetPathGradientPresetBlend(GpPathGradient
*brush
,
1594 ARGB
*blend
, REAL
*pos
, INT count
)
1596 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1601 if (!brush
|| !blend
|| !pos
|| count
< 2 || brush
->brush
.bt
!= BrushTypePathGradient
)
1602 return InvalidParameter
;
1604 if (brush
->pblendcount
== 0)
1605 return GenericError
;
1607 if (count
!= brush
->pblendcount
)
1609 /* Native lines up the ends of each array, and copies the destination size. */
1610 FIXME("Braindead behavior on wrong-sized buffer not implemented.\n");
1611 return InvalidParameter
;
1614 memcpy(blend
, brush
->pblendcolor
, sizeof(ARGB
) * brush
->pblendcount
);
1615 memcpy(pos
, brush
->pblendpos
, sizeof(REAL
) * brush
->pblendcount
);
1620 GpStatus WINGDIPAPI
GdipGetPathGradientPresetBlendCount(GpPathGradient
*brush
,
1623 TRACE("(%p,%p)\n", brush
, count
);
1625 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1626 return InvalidParameter
;
1628 *count
= brush
->pblendcount
;
1633 GpStatus WINGDIPAPI
GdipSetPathGradientCenterColor(GpPathGradient
*grad
,
1636 TRACE("(%p, %x)\n", grad
, argb
);
1638 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1639 return InvalidParameter
;
1641 grad
->centercolor
= argb
;
1645 GpStatus WINGDIPAPI
GdipSetPathGradientCenterPoint(GpPathGradient
*grad
,
1648 TRACE("(%p, %s)\n", grad
, debugstr_pointf(point
));
1650 if(!grad
|| !point
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1651 return InvalidParameter
;
1653 grad
->center
.X
= point
->X
;
1654 grad
->center
.Y
= point
->Y
;
1659 GpStatus WINGDIPAPI
GdipSetPathGradientCenterPointI(GpPathGradient
*grad
,
1664 TRACE("(%p, %p)\n", grad
, point
);
1667 return InvalidParameter
;
1669 ptf
.X
= (REAL
)point
->X
;
1670 ptf
.Y
= (REAL
)point
->Y
;
1672 return GdipSetPathGradientCenterPoint(grad
,&ptf
);
1675 GpStatus WINGDIPAPI
GdipSetPathGradientFocusScales(GpPathGradient
*grad
,
1678 TRACE("(%p, %.2f, %.2f)\n", grad
, x
, y
);
1680 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1681 return InvalidParameter
;
1689 GpStatus WINGDIPAPI
GdipSetPathGradientGammaCorrection(GpPathGradient
*grad
,
1692 TRACE("(%p, %d)\n", grad
, gamma
);
1694 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1695 return InvalidParameter
;
1697 grad
->gamma
= gamma
;
1702 GpStatus WINGDIPAPI
GdipSetPathGradientSigmaBlend(GpPathGradient
*grad
,
1703 REAL focus
, REAL scale
)
1709 const int precision
= 16;
1710 REAL erf_range
; /* we use values erf(-erf_range) through erf(+erf_range) */
1714 TRACE("(%p,%0.2f,%0.2f)\n", grad
, focus
, scale
);
1716 if(!grad
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0 || grad
->brush
.bt
!= BrushTypePathGradient
)
1717 return InvalidParameter
;
1719 /* we want 2 standard deviations */
1720 erf_range
= 2.0 / sqrt(2);
1722 /* calculate the constants we need to normalize the error function to be
1723 between 0.0 and scale over the range we need */
1724 min_erf
= erf(-erf_range
);
1725 scale_erf
= scale
/ (-2.0 * min_erf
);
1731 for (i
=1; i
<precision
; i
++)
1733 positions
[i
] = focus
* i
/ precision
;
1734 factors
[i
] = scale_erf
* (erf(2 * erf_range
* i
/ precision
- erf_range
) - min_erf
);
1736 num_points
+= precision
;
1739 positions
[num_points
] = focus
;
1740 factors
[num_points
] = scale
;
1745 for (i
=1; i
<precision
; i
++)
1747 positions
[i
+num_points
-1] = (focus
+ ((1.0-focus
) * i
/ precision
));
1748 factors
[i
+num_points
-1] = scale_erf
* (erf(erf_range
- 2 * erf_range
* i
/ precision
) - min_erf
);
1750 num_points
+= precision
;
1751 positions
[num_points
-1] = 1.0;
1752 factors
[num_points
-1] = 0.0;
1755 return GdipSetPathGradientBlend(grad
, factors
, positions
, num_points
);
1758 GpStatus WINGDIPAPI
GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
1759 *grad
, GDIPCONST ARGB
*argb
, INT
*count
)
1761 ARGB
*new_surroundcolors
;
1764 TRACE("(%p,%p,%p)\n", grad
, argb
, count
);
1766 if(!grad
|| !argb
|| !count
|| (*count
<= 0) || grad
->brush
.bt
!= BrushTypePathGradient
||
1767 (*count
> grad
->path
->pathdata
.Count
))
1768 return InvalidParameter
;
1770 num_colors
= *count
;
1772 /* If all colors are the same, only store 1 color. */
1775 for (i
=1; i
< num_colors
; i
++)
1776 if (argb
[i
] != argb
[i
-1])
1779 if (i
== num_colors
)
1783 new_surroundcolors
= heap_alloc_zero(num_colors
* sizeof(ARGB
));
1784 if (!new_surroundcolors
)
1787 memcpy(new_surroundcolors
, argb
, num_colors
* sizeof(ARGB
));
1789 heap_free(grad
->surroundcolors
);
1791 grad
->surroundcolors
= new_surroundcolors
;
1792 grad
->surroundcolorcount
= num_colors
;
1797 GpStatus WINGDIPAPI
GdipSetPathGradientWrapMode(GpPathGradient
*grad
,
1800 TRACE("(%p, %d)\n", grad
, wrap
);
1802 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1803 return InvalidParameter
;
1810 GpStatus WINGDIPAPI
GdipSetPathGradientTransform(GpPathGradient
*grad
,
1813 TRACE("(%p,%p)\n", grad
, matrix
);
1815 if (!grad
|| !matrix
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1816 return InvalidParameter
;
1818 grad
->transform
= *matrix
;
1823 GpStatus WINGDIPAPI
GdipGetPathGradientTransform(GpPathGradient
*grad
,
1826 TRACE("(%p,%p)\n", grad
, matrix
);
1828 if (!grad
|| !matrix
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1829 return InvalidParameter
;
1831 *matrix
= grad
->transform
;
1836 GpStatus WINGDIPAPI
GdipMultiplyPathGradientTransform(GpPathGradient
*grad
,
1837 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
1839 TRACE("(%p,%p,%i)\n", grad
, matrix
, order
);
1841 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1842 return InvalidParameter
;
1844 return GdipMultiplyMatrix(&grad
->transform
, matrix
, order
);
1847 GpStatus WINGDIPAPI
GdipResetPathGradientTransform(GpPathGradient
*grad
)
1849 TRACE("(%p)\n", grad
);
1851 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1852 return InvalidParameter
;
1854 return GdipSetMatrixElements(&grad
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1857 GpStatus WINGDIPAPI
GdipRotatePathGradientTransform(GpPathGradient
*grad
,
1858 REAL angle
, GpMatrixOrder order
)
1860 TRACE("(%p,%0.2f,%i)\n", grad
, angle
, order
);
1862 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1863 return InvalidParameter
;
1865 return GdipRotateMatrix(&grad
->transform
, angle
, order
);
1868 GpStatus WINGDIPAPI
GdipScalePathGradientTransform(GpPathGradient
*grad
,
1869 REAL sx
, REAL sy
, GpMatrixOrder order
)
1871 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad
, sx
, sy
, order
);
1873 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1874 return InvalidParameter
;
1876 return GdipScaleMatrix(&grad
->transform
, sx
, sy
, order
);
1879 GpStatus WINGDIPAPI
GdipTranslatePathGradientTransform(GpPathGradient
*grad
,
1880 REAL dx
, REAL dy
, GpMatrixOrder order
)
1882 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad
, dx
, dy
, order
);
1884 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1885 return InvalidParameter
;
1887 return GdipTranslateMatrix(&grad
->transform
, dx
, dy
, order
);
1890 GpStatus WINGDIPAPI
GdipSetSolidFillColor(GpSolidFill
*sf
, ARGB argb
)
1892 TRACE("(%p, %x)\n", sf
, argb
);
1895 return InvalidParameter
;
1901 /******************************************************************************
1902 * GdipSetTextureTransform [GDIPLUS.@]
1904 GpStatus WINGDIPAPI
GdipSetTextureTransform(GpTexture
*texture
,
1905 GDIPCONST GpMatrix
*matrix
)
1907 TRACE("(%p, %p)\n", texture
, matrix
);
1909 if(!texture
|| !matrix
)
1910 return InvalidParameter
;
1912 texture
->transform
= *matrix
;
1917 /******************************************************************************
1918 * GdipSetTextureWrapMode [GDIPLUS.@]
1920 * WrapMode not used, only stored
1922 GpStatus WINGDIPAPI
GdipSetTextureWrapMode(GpTexture
*brush
, GpWrapMode wrapmode
)
1924 TRACE("(%p, %d)\n", brush
, wrapmode
);
1927 return InvalidParameter
;
1929 brush
->imageattributes
->wrap
= wrapmode
;
1934 GpStatus WINGDIPAPI
GdipSetLineColors(GpLineGradient
*brush
, ARGB color1
,
1937 TRACE("(%p, %x, %x)\n", brush
, color1
, color2
);
1939 if(!brush
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1940 return InvalidParameter
;
1942 brush
->startcolor
= color1
;
1943 brush
->endcolor
= color2
;
1948 GpStatus WINGDIPAPI
GdipGetLineColors(GpLineGradient
*brush
, ARGB
*colors
)
1950 TRACE("(%p, %p)\n", brush
, colors
);
1952 if(!brush
|| !colors
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1953 return InvalidParameter
;
1955 colors
[0] = brush
->startcolor
;
1956 colors
[1] = brush
->endcolor
;
1961 /******************************************************************************
1962 * GdipRotateTextureTransform [GDIPLUS.@]
1964 GpStatus WINGDIPAPI
GdipRotateTextureTransform(GpTexture
* brush
, REAL angle
,
1965 GpMatrixOrder order
)
1967 TRACE("(%p, %.2f, %d)\n", brush
, angle
, order
);
1970 return InvalidParameter
;
1972 return GdipRotateMatrix(&brush
->transform
, angle
, order
);
1975 GpStatus WINGDIPAPI
GdipSetLineLinearBlend(GpLineGradient
*brush
, REAL focus
,
1982 TRACE("(%p,%.2f,%.2f)\n", brush
, focus
, scale
);
1984 if (!brush
) return InvalidParameter
;
1988 factors
[num_points
] = 0.0;
1989 positions
[num_points
] = 0.0;
1993 factors
[num_points
] = scale
;
1994 positions
[num_points
] = focus
;
1999 factors
[num_points
] = 0.0;
2000 positions
[num_points
] = 1.0;
2004 return GdipSetLineBlend(brush
, factors
, positions
, num_points
);
2007 GpStatus WINGDIPAPI
GdipSetLinePresetBlend(GpLineGradient
*brush
,
2008 GDIPCONST ARGB
*blend
, GDIPCONST REAL
* positions
, INT count
)
2012 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, positions
, count
);
2014 if (!brush
|| !blend
|| !positions
|| count
< 2 || brush
->brush
.bt
!= BrushTypeLinearGradient
||
2015 positions
[0] != 0.0f
|| positions
[count
-1] != 1.0f
)
2017 return InvalidParameter
;
2020 new_color
= heap_alloc_zero(count
* sizeof(ARGB
));
2021 new_pos
= heap_alloc_zero(count
* sizeof(REAL
));
2022 if (!new_color
|| !new_pos
)
2024 heap_free(new_color
);
2029 memcpy(new_color
, blend
, sizeof(ARGB
) * count
);
2030 memcpy(new_pos
, positions
, sizeof(REAL
) * count
);
2032 heap_free(brush
->pblendcolor
);
2033 heap_free(brush
->pblendpos
);
2035 brush
->pblendcolor
= new_color
;
2036 brush
->pblendpos
= new_pos
;
2037 brush
->pblendcount
= count
;
2042 GpStatus WINGDIPAPI
GdipGetLinePresetBlend(GpLineGradient
*brush
,
2043 ARGB
*blend
, REAL
* positions
, INT count
)
2045 if (!brush
|| !blend
|| !positions
|| count
< 2 || brush
->brush
.bt
!= BrushTypeLinearGradient
)
2046 return InvalidParameter
;
2048 if (brush
->pblendcount
== 0)
2049 return GenericError
;
2051 if (count
< brush
->pblendcount
)
2052 return InsufficientBuffer
;
2054 memcpy(blend
, brush
->pblendcolor
, sizeof(ARGB
) * brush
->pblendcount
);
2055 memcpy(positions
, brush
->pblendpos
, sizeof(REAL
) * brush
->pblendcount
);
2060 GpStatus WINGDIPAPI
GdipGetLinePresetBlendCount(GpLineGradient
*brush
,
2063 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
2064 return InvalidParameter
;
2066 *count
= brush
->pblendcount
;
2071 GpStatus WINGDIPAPI
GdipResetLineTransform(GpLineGradient
*brush
)
2073 TRACE("(%p)\n", brush
);
2076 return InvalidParameter
;
2078 return GdipSetMatrixElements(&brush
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
2081 GpStatus WINGDIPAPI
GdipSetLineTransform(GpLineGradient
*brush
,
2082 GDIPCONST GpMatrix
*matrix
)
2084 TRACE("(%p,%p)\n", brush
, matrix
);
2086 if(!brush
|| !matrix
)
2087 return InvalidParameter
;
2089 brush
->transform
= *matrix
;
2094 GpStatus WINGDIPAPI
GdipGetLineTransform(GpLineGradient
*brush
, GpMatrix
*matrix
)
2096 TRACE("(%p,%p)\n", brush
, matrix
);
2098 if(!brush
|| !matrix
)
2099 return InvalidParameter
;
2101 *matrix
= brush
->transform
;
2106 GpStatus WINGDIPAPI
GdipScaleLineTransform(GpLineGradient
*brush
, REAL sx
, REAL sy
,
2107 GpMatrixOrder order
)
2109 TRACE("(%p,%0.2f,%0.2f,%u)\n", brush
, sx
, sy
, order
);
2112 return InvalidParameter
;
2114 return GdipScaleMatrix(&brush
->transform
, sx
, sy
, order
);
2117 GpStatus WINGDIPAPI
GdipMultiplyLineTransform(GpLineGradient
*brush
,
2118 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
2120 TRACE("(%p,%p,%u)\n", brush
, matrix
, order
);
2123 return InvalidParameter
;
2128 return GdipMultiplyMatrix(&brush
->transform
, matrix
, order
);
2131 GpStatus WINGDIPAPI
GdipTranslateLineTransform(GpLineGradient
*brush
,
2132 REAL dx
, REAL dy
, GpMatrixOrder order
)
2134 TRACE("(%p,%f,%f,%d)\n", brush
, dx
, dy
, order
);
2137 return InvalidParameter
;
2139 return GdipTranslateMatrix(&brush
->transform
, dx
, dy
, order
);
2142 /******************************************************************************
2143 * GdipTranslateTextureTransform [GDIPLUS.@]
2145 GpStatus WINGDIPAPI
GdipTranslateTextureTransform(GpTexture
* brush
, REAL dx
, REAL dy
,
2146 GpMatrixOrder order
)
2148 TRACE("(%p, %.2f, %.2f, %d)\n", brush
, dx
, dy
, order
);
2151 return InvalidParameter
;
2153 return GdipTranslateMatrix(&brush
->transform
, dx
, dy
, order
);
2156 GpStatus WINGDIPAPI
GdipGetLineRect(GpLineGradient
*brush
, GpRectF
*rect
)
2158 TRACE("(%p, %p)\n", brush
, rect
);
2160 if(!brush
|| !rect
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
2161 return InvalidParameter
;
2163 *rect
= brush
->rect
;
2168 GpStatus WINGDIPAPI
GdipGetLineRectI(GpLineGradient
*brush
, GpRect
*rect
)
2173 TRACE("(%p, %p)\n", brush
, rect
);
2176 return InvalidParameter
;
2178 ret
= GdipGetLineRect(brush
, &rectF
);
2181 rect
->X
= gdip_round(rectF
.X
);
2182 rect
->Y
= gdip_round(rectF
.Y
);
2183 rect
->Width
= gdip_round(rectF
.Width
);
2184 rect
->Height
= gdip_round(rectF
.Height
);
2190 GpStatus WINGDIPAPI
GdipRotateLineTransform(GpLineGradient
* brush
,
2191 REAL angle
, GpMatrixOrder order
)
2195 TRACE("(%p,%0.2f,%u)\n", brush
, angle
, order
);
2197 if(!brush
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
2198 return InvalidParameter
;
2201 FIXME("(%p, %.2f, %d) stub\n", brush
, angle
, order
);
2203 return NotImplemented
;