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
33 #include "gdiplus_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus
);
41 Code from http://www.johndcook.com/blog/2009/01/19/stand-alone-error-function-erf/
45 const float a1
= 0.254829592f
;
46 const float a2
= -0.284496736f
;
47 const float a3
= 1.421413741f
;
48 const float a4
= -1.453152027f
;
49 const float a5
= 1.061405429f
;
50 const float p
= 0.3275911f
;
53 /* Save the sign of x */
61 y
= 1.0 - (((((a5
*t
+ a4
)*t
) + a3
)*t
+ a2
)*t
+ a1
)*t
*exp(-x
*x
);
67 /******************************************************************************
68 * GdipCloneBrush [GDIPLUS.@]
70 GpStatus WINGDIPAPI
GdipCloneBrush(GpBrush
*brush
, GpBrush
**clone
)
72 TRACE("(%p, %p)\n", brush
, clone
);
75 return InvalidParameter
;
78 case BrushTypeSolidColor
:
80 *clone
= heap_alloc_zero(sizeof(GpSolidFill
));
81 if (!*clone
) return OutOfMemory
;
82 memcpy(*clone
, brush
, sizeof(GpSolidFill
));
85 case BrushTypeHatchFill
:
87 GpHatch
*hatch
= (GpHatch
*)brush
;
89 return GdipCreateHatchBrush(hatch
->hatchstyle
, hatch
->forecol
, hatch
->backcol
, (GpHatch
**)clone
);
91 case BrushTypePathGradient
:{
92 GpPathGradient
*src
, *dest
;
96 *clone
= heap_alloc_zero(sizeof(GpPathGradient
));
97 if (!*clone
) return OutOfMemory
;
99 src
= (GpPathGradient
*) brush
,
100 dest
= (GpPathGradient
*) *clone
;
102 memcpy(dest
, src
, sizeof(GpPathGradient
));
104 stat
= GdipClonePath(src
->path
, &dest
->path
);
111 dest
->transform
= src
->transform
;
114 count
= src
->blendcount
;
115 dest
->blendcount
= count
;
116 dest
->blendfac
= heap_alloc_zero(count
* sizeof(REAL
));
117 dest
->blendpos
= heap_alloc_zero(count
* sizeof(REAL
));
118 dest
->surroundcolors
= heap_alloc_zero(dest
->surroundcolorcount
* sizeof(ARGB
));
119 pcount
= dest
->pblendcount
;
122 dest
->pblendcolor
= heap_alloc_zero(pcount
* sizeof(ARGB
));
123 dest
->pblendpos
= heap_alloc_zero(pcount
* sizeof(REAL
));
126 if(!dest
->blendfac
|| !dest
->blendpos
|| !dest
->surroundcolors
||
127 (pcount
&& (!dest
->pblendcolor
|| !dest
->pblendpos
))){
128 GdipDeletePath(dest
->path
);
129 heap_free(dest
->blendfac
);
130 heap_free(dest
->blendpos
);
131 heap_free(dest
->surroundcolors
);
132 heap_free(dest
->pblendcolor
);
133 heap_free(dest
->pblendpos
);
138 memcpy(dest
->blendfac
, src
->blendfac
, count
* sizeof(REAL
));
139 memcpy(dest
->blendpos
, src
->blendpos
, count
* sizeof(REAL
));
140 memcpy(dest
->surroundcolors
, src
->surroundcolors
, dest
->surroundcolorcount
* sizeof(ARGB
));
144 memcpy(dest
->pblendcolor
, src
->pblendcolor
, pcount
* sizeof(ARGB
));
145 memcpy(dest
->pblendpos
, src
->pblendpos
, pcount
* sizeof(REAL
));
150 case BrushTypeLinearGradient
:{
151 GpLineGradient
*dest
, *src
;
154 dest
= heap_alloc_zero(sizeof(GpLineGradient
));
155 if(!dest
) return OutOfMemory
;
157 src
= (GpLineGradient
*)brush
;
159 memcpy(dest
, src
, sizeof(GpLineGradient
));
161 count
= dest
->blendcount
;
162 dest
->blendfac
= heap_alloc_zero(count
* sizeof(REAL
));
163 dest
->blendpos
= heap_alloc_zero(count
* sizeof(REAL
));
164 pcount
= dest
->pblendcount
;
167 dest
->pblendcolor
= heap_alloc_zero(pcount
* sizeof(ARGB
));
168 dest
->pblendpos
= heap_alloc_zero(pcount
* sizeof(REAL
));
171 if (!dest
->blendfac
|| !dest
->blendpos
||
172 (pcount
&& (!dest
->pblendcolor
|| !dest
->pblendpos
)))
174 heap_free(dest
->blendfac
);
175 heap_free(dest
->blendpos
);
176 heap_free(dest
->pblendcolor
);
177 heap_free(dest
->pblendpos
);
182 dest
->transform
= src
->transform
;
184 memcpy(dest
->blendfac
, src
->blendfac
, count
* sizeof(REAL
));
185 memcpy(dest
->blendpos
, src
->blendpos
, count
* sizeof(REAL
));
189 memcpy(dest
->pblendcolor
, src
->pblendcolor
, pcount
* sizeof(ARGB
));
190 memcpy(dest
->pblendpos
, src
->pblendpos
, pcount
* sizeof(REAL
));
193 *clone
= &dest
->brush
;
196 case BrushTypeTextureFill
:
199 GpTexture
*texture
= (GpTexture
*)brush
;
200 GpTexture
*new_texture
;
203 stat
= GdipGetImageWidth(texture
->image
, &width
);
204 if (stat
!= Ok
) return stat
;
205 stat
= GdipGetImageHeight(texture
->image
, &height
);
206 if (stat
!= Ok
) return stat
;
208 stat
= GdipCreateTextureIA(texture
->image
, texture
->imageattributes
, 0, 0, width
, height
, &new_texture
);
212 new_texture
->transform
= texture
->transform
;
213 *clone
= &new_texture
->brush
;
221 ERR("not implemented for brush type %d\n", brush
->bt
);
222 return NotImplemented
;
225 TRACE("<-- %p\n", *clone
);
229 static const char HatchBrushes
[][8] = {
230 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HatchStyleHorizontal */
231 { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleVertical */
232 { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HatchStyleForwardDiagonal */
233 { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HatchStyleBackwardDiagonal */
234 { 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleCross */
235 { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }, /* HatchStyleDiagonalCross */
236 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80 }, /* HatchStyle05Percent */
237 { 0x00, 0x02, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88 }, /* HatchStyle10Percent */
238 { 0x00, 0x22, 0x00, 0xcc, 0x00, 0x22, 0x00, 0xcc }, /* HatchStyle20Percent */
239 { 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc }, /* HatchStyle25Percent */
240 { 0x00, 0xcc, 0x04, 0xcc, 0x00, 0xcc, 0x40, 0xcc }, /* HatchStyle30Percent */
241 { 0x44, 0xcc, 0x22, 0xcc, 0x44, 0xcc, 0x22, 0xcc }, /* HatchStyle40Percent */
242 { 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc }, /* HatchStyle50Percent */
243 { 0x55, 0xcd, 0x55, 0xee, 0x55, 0xdc, 0x55, 0xee }, /* HatchStyle60Percent */
244 { 0x55, 0xdd, 0x55, 0xff, 0x55, 0xdd, 0x55, 0xff }, /* HatchStyle70Percent */
245 { 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff }, /* HatchStyle75Percent */
246 { 0x55, 0xff, 0x59, 0xff, 0x55, 0xff, 0x99, 0xff }, /* HatchStyle80Percent */
247 { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xfd, 0xff }, /* HatchStyle90Percent */
248 { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 }, /* HatchStyleLightDownwardDiagonal */
249 { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 }, /* HatchStyleLightUpwardDiagonal */
250 { 0x99, 0x33, 0x66, 0xcc, 0x99, 0x33, 0x66, 0xcc }, /* HatchStyleDarkDownwardDiagonal */
251 { 0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33, 0x99 }, /* HatchStyleDarkUpwardDiagonal */
252 { 0xc1, 0x83, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0 }, /* HatchStyleWideDownwardDiagonal */
253 { 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x07, 0x83, 0xc1 }, /* HatchStyleWideUpwardDiagonal */
254 { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 }, /* HatchStyleLightVertical */
255 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff }, /* HatchStyleLightHorizontal */
256 { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, /* HatchStyleNarrowVertical */
257 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, /* HatchStyleNarrowHorizontal */
258 { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }, /* HatchStyleDarkVertical */
259 { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff }, /* HatchStyleDarkHorizontal */
262 GpStatus
get_hatch_data(GpHatchStyle hatchstyle
, const char **result
)
264 if (hatchstyle
< ARRAY_SIZE(HatchBrushes
))
266 *result
= HatchBrushes
[hatchstyle
];
270 return NotImplemented
;
273 /******************************************************************************
274 * GdipCreateHatchBrush [GDIPLUS.@]
276 GpStatus WINGDIPAPI
GdipCreateHatchBrush(GpHatchStyle hatchstyle
, ARGB forecol
, ARGB backcol
, GpHatch
**brush
)
278 TRACE("(%d, %d, %d, %p)\n", hatchstyle
, forecol
, backcol
, brush
);
280 if(!brush
) return InvalidParameter
;
282 if(hatchstyle
< HatchStyleMin
|| hatchstyle
> HatchStyleMax
)
283 return InvalidParameter
;
285 *brush
= heap_alloc_zero(sizeof(GpHatch
));
286 if (!*brush
) return OutOfMemory
;
288 (*brush
)->brush
.bt
= BrushTypeHatchFill
;
289 (*brush
)->forecol
= forecol
;
290 (*brush
)->backcol
= backcol
;
291 (*brush
)->hatchstyle
= hatchstyle
;
292 TRACE("<-- %p\n", *brush
);
297 static void linegradient_init_transform(GpLineGradient
*line
)
299 float trans_x
= line
->rect
.X
+ (line
->rect
.Width
/ 2.f
);
300 float trans_y
= line
->rect
.Y
+ (line
->rect
.Height
/ 2.f
);
301 float dx
= line
->endpoint
.X
- line
->startpoint
.X
;
302 float dy
= line
->endpoint
.Y
- line
->startpoint
.Y
;
303 float t_cos
, t_sin
, w_ratio
, h_ratio
;
307 h
= sqrtf(dx
* dx
+ dy
* dy
);
312 w_ratio
= (fabs(t_cos
) * line
->rect
.Width
+ fabs(t_sin
) * line
->rect
.Height
) / line
->rect
.Width
;
313 h_ratio
= (fabs(t_sin
) * line
->rect
.Width
+ fabs(t_cos
) * line
->rect
.Height
) / line
->rect
.Height
;
315 GdipSetMatrixElements(&line
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
317 GdipSetMatrixElements(&rot
, t_cos
, t_sin
, -1.f
* t_sin
, t_cos
, 0, 0);
319 /* center about the origin */
320 GdipTranslateMatrix(&line
->transform
, -trans_x
, -trans_y
, MatrixOrderAppend
);
322 /* scale to normalize gradient along gradient line (?) */
323 GdipScaleMatrix(&line
->transform
, w_ratio
, h_ratio
, MatrixOrderAppend
);
325 /* rotate so the gradient is horizontal */
326 GdipMultiplyMatrix(&line
->transform
, &rot
, MatrixOrderAppend
);
328 /* restore original offset in new coords */
329 GdipTranslateMatrix(&line
->transform
, trans_x
, trans_y
, MatrixOrderAppend
);
332 /******************************************************************************
333 * GdipCreateLineBrush [GDIPLUS.@]
335 GpStatus WINGDIPAPI
GdipCreateLineBrush(GDIPCONST GpPointF
* startpoint
,
336 GDIPCONST GpPointF
* endpoint
, ARGB startcolor
, ARGB endcolor
,
337 GpWrapMode wrap
, GpLineGradient
**line
)
339 TRACE("(%s, %s, %x, %x, %d, %p)\n", debugstr_pointf(startpoint
),
340 debugstr_pointf(endpoint
), startcolor
, endcolor
, wrap
, line
);
342 if(!line
|| !startpoint
|| !endpoint
|| wrap
== WrapModeClamp
)
343 return InvalidParameter
;
345 if (startpoint
->X
== endpoint
->X
&& startpoint
->Y
== endpoint
->Y
)
348 *line
= heap_alloc_zero(sizeof(GpLineGradient
));
349 if(!*line
) return OutOfMemory
;
351 (*line
)->brush
.bt
= BrushTypeLinearGradient
;
353 (*line
)->startpoint
.X
= startpoint
->X
;
354 (*line
)->startpoint
.Y
= startpoint
->Y
;
355 (*line
)->endpoint
.X
= endpoint
->X
;
356 (*line
)->endpoint
.Y
= endpoint
->Y
;
357 (*line
)->startcolor
= startcolor
;
358 (*line
)->endcolor
= endcolor
;
359 (*line
)->wrap
= wrap
;
360 (*line
)->gamma
= FALSE
;
362 (*line
)->rect
.X
= (startpoint
->X
< endpoint
->X
? startpoint
->X
: endpoint
->X
);
363 (*line
)->rect
.Y
= (startpoint
->Y
< endpoint
->Y
? startpoint
->Y
: endpoint
->Y
);
364 (*line
)->rect
.Width
= fabs(startpoint
->X
- endpoint
->X
);
365 (*line
)->rect
.Height
= fabs(startpoint
->Y
- endpoint
->Y
);
367 if ((*line
)->rect
.Width
== 0)
369 (*line
)->rect
.X
-= (*line
)->rect
.Height
/ 2.0f
;
370 (*line
)->rect
.Width
= (*line
)->rect
.Height
;
372 else if ((*line
)->rect
.Height
== 0)
374 (*line
)->rect
.Y
-= (*line
)->rect
.Width
/ 2.0f
;
375 (*line
)->rect
.Height
= (*line
)->rect
.Width
;
378 (*line
)->blendcount
= 1;
379 (*line
)->blendfac
= heap_alloc_zero(sizeof(REAL
));
380 (*line
)->blendpos
= heap_alloc_zero(sizeof(REAL
));
382 if (!(*line
)->blendfac
|| !(*line
)->blendpos
)
384 heap_free((*line
)->blendfac
);
385 heap_free((*line
)->blendpos
);
391 (*line
)->blendfac
[0] = 1.0f
;
392 (*line
)->blendpos
[0] = 1.0f
;
394 (*line
)->pblendcolor
= NULL
;
395 (*line
)->pblendpos
= NULL
;
396 (*line
)->pblendcount
= 0;
398 linegradient_init_transform(*line
);
400 TRACE("<-- %p\n", *line
);
405 GpStatus WINGDIPAPI
GdipCreateLineBrushI(GDIPCONST GpPoint
* startpoint
,
406 GDIPCONST GpPoint
* endpoint
, ARGB startcolor
, ARGB endcolor
,
407 GpWrapMode wrap
, GpLineGradient
**line
)
412 TRACE("(%p, %p, %x, %x, %d, %p)\n", startpoint
, endpoint
,
413 startcolor
, endcolor
, wrap
, line
);
415 if(!startpoint
|| !endpoint
)
416 return InvalidParameter
;
418 stF
.X
= (REAL
)startpoint
->X
;
419 stF
.Y
= (REAL
)startpoint
->Y
;
420 endF
.X
= (REAL
)endpoint
->X
;
421 endF
.Y
= (REAL
)endpoint
->Y
;
423 return GdipCreateLineBrush(&stF
, &endF
, startcolor
, endcolor
, wrap
, line
);
426 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRect(GDIPCONST GpRectF
* rect
,
427 ARGB startcolor
, ARGB endcolor
, LinearGradientMode mode
, GpWrapMode wrap
,
428 GpLineGradient
**line
)
434 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect
, startcolor
, endcolor
, mode
,
438 return InvalidParameter
;
442 case LinearGradientModeVertical
:
445 case LinearGradientModeForwardDiagonal
:
448 case LinearGradientModeBackwardDiagonal
:
451 case LinearGradientModeHorizontal
:
452 far_x
= rect
->X
+ rect
->Width
;
454 start
.X
= min(rect
->X
, far_x
);
456 end
.X
= max(rect
->X
, far_x
);
458 stat
= GdipCreateLineBrush(&start
, &end
, startcolor
, endcolor
, wrap
, line
);
460 (*line
)->rect
= *rect
;
463 return InvalidParameter
;
466 return GdipCreateLineBrushFromRectWithAngle(rect
, startcolor
, endcolor
, angle
, TRUE
, wrap
, line
);
469 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectI(GDIPCONST GpRect
* rect
,
470 ARGB startcolor
, ARGB endcolor
, LinearGradientMode mode
, GpWrapMode wrap
,
471 GpLineGradient
**line
)
475 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect
, startcolor
, endcolor
, mode
,
478 rectF
.X
= (REAL
) rect
->X
;
479 rectF
.Y
= (REAL
) rect
->Y
;
480 rectF
.Width
= (REAL
) rect
->Width
;
481 rectF
.Height
= (REAL
) rect
->Height
;
483 return GdipCreateLineBrushFromRect(&rectF
, startcolor
, endcolor
, mode
, wrap
, line
);
486 /******************************************************************************
487 * GdipCreateLineBrushFromRectWithAngle [GDIPLUS.@]
489 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF
* rect
,
490 ARGB startcolor
, ARGB endcolor
, REAL angle
, BOOL isAngleScalable
, GpWrapMode wrap
,
491 GpLineGradient
**line
)
494 REAL exofs
, eyofs
, far_x
, far_y
;
495 REAL sin_angle
, cos_angle
, sin_cos_angle
;
498 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect
, startcolor
, endcolor
, angle
, isAngleScalable
,
501 if (!rect
|| !line
|| wrap
== WrapModeClamp
)
502 return InvalidParameter
;
504 if (!rect
->Width
|| !rect
->Height
)
507 angle
= fmodf(angle
, 360);
520 if (angle
!= 90 && angle
!= -90)
521 angle
= atan((rect
->Width
/ rect
->Height
) * tan(deg2rad(angle
)));
523 angle
= deg2rad(angle
);
528 angle
= deg2rad(angle
);
531 sin_angle
= sinf(angle
);
532 cos_angle
= cosf(angle
);
533 sin_cos_angle
= sin_angle
* cos_angle
;
535 far_x
= rect
->X
+ rect
->Width
;
536 far_y
= rect
->Y
+ rect
->Height
;
538 if (sin_cos_angle
>= 0)
540 start
.X
= min(rect
->X
, far_x
);
541 start
.Y
= min(rect
->Y
, far_y
);
542 end
.X
= max(rect
->X
, far_x
);
543 end
.Y
= max(rect
->Y
, far_y
);
547 start
.X
= max(rect
->X
, far_x
);
548 start
.Y
= min(rect
->Y
, far_y
);
549 end
.X
= min(rect
->X
, far_x
);
550 end
.Y
= max(rect
->Y
, far_y
);
553 stat
= GdipCreateLineBrush(&start
, &end
, startcolor
, endcolor
, wrap
, line
);
557 if (sin_cos_angle
>= 0)
559 exofs
= rect
->Height
* sin_cos_angle
+ rect
->Width
* cos_angle
* cos_angle
;
560 eyofs
= rect
->Height
* sin_angle
* sin_angle
+ rect
->Width
* sin_cos_angle
;
564 exofs
= rect
->Width
* sin_angle
* sin_angle
+ rect
->Height
* sin_cos_angle
;
565 eyofs
= -rect
->Width
* sin_cos_angle
+ rect
->Height
* sin_angle
* sin_angle
;
570 (*line
)->endpoint
.X
= rect
->X
+ exofs
;
571 (*line
)->endpoint
.Y
= rect
->Y
+ eyofs
;
575 (*line
)->endpoint
.X
= (*line
)->startpoint
.X
;
576 (*line
)->endpoint
.Y
= (*line
)->startpoint
.Y
;
577 (*line
)->startpoint
.X
= rect
->X
+ exofs
;
578 (*line
)->startpoint
.Y
= rect
->Y
+ eyofs
;
581 linegradient_init_transform(*line
);
587 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectWithAngleI(GDIPCONST GpRect
* rect
,
588 ARGB startcolor
, ARGB endcolor
, REAL angle
, BOOL isAngleScalable
, GpWrapMode wrap
,
589 GpLineGradient
**line
)
591 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect
, startcolor
, endcolor
, angle
, isAngleScalable
,
594 return GdipCreateLineBrushFromRectI(rect
, startcolor
, endcolor
, LinearGradientModeForwardDiagonal
,
598 static GpStatus
create_path_gradient(GpPath
*path
, ARGB centercolor
, GpPathGradient
**grad
)
603 return InvalidParameter
;
605 if (path
->pathdata
.Count
< 2)
608 GdipGetPathWorldBounds(path
, &bounds
, NULL
, NULL
);
610 *grad
= heap_alloc_zero(sizeof(GpPathGradient
));
616 GdipSetMatrixElements(&(*grad
)->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
618 (*grad
)->blendfac
= heap_alloc_zero(sizeof(REAL
));
619 (*grad
)->blendpos
= heap_alloc_zero(sizeof(REAL
));
620 (*grad
)->surroundcolors
= heap_alloc_zero(sizeof(ARGB
));
621 if(!(*grad
)->blendfac
|| !(*grad
)->blendpos
|| !(*grad
)->surroundcolors
){
622 heap_free((*grad
)->blendfac
);
623 heap_free((*grad
)->blendpos
);
624 heap_free((*grad
)->surroundcolors
);
629 (*grad
)->blendfac
[0] = 1.0;
630 (*grad
)->blendpos
[0] = 1.0;
631 (*grad
)->blendcount
= 1;
633 (*grad
)->path
= path
;
635 (*grad
)->brush
.bt
= BrushTypePathGradient
;
636 (*grad
)->centercolor
= centercolor
;
637 (*grad
)->wrap
= WrapModeClamp
;
638 (*grad
)->gamma
= FALSE
;
639 /* FIXME: this should be set to the "centroid" of the path by default */
640 (*grad
)->center
.X
= bounds
.X
+ bounds
.Width
/ 2;
641 (*grad
)->center
.Y
= bounds
.Y
+ bounds
.Height
/ 2;
642 (*grad
)->focus
.X
= 0.0;
643 (*grad
)->focus
.Y
= 0.0;
644 (*grad
)->surroundcolors
[0] = 0xffffffff;
645 (*grad
)->surroundcolorcount
= 1;
647 TRACE("<-- %p\n", *grad
);
652 GpStatus WINGDIPAPI
GdipCreatePathGradient(GDIPCONST GpPointF
* points
,
653 INT count
, GpWrapMode wrap
, GpPathGradient
**grad
)
658 TRACE("(%p, %d, %d, %p)\n", points
, count
, wrap
, grad
);
661 return InvalidParameter
;
663 if(!points
|| count
<= 0)
666 stat
= GdipCreatePath(FillModeAlternate
, &path
);
670 stat
= GdipAddPathLine2(path
, points
, count
);
673 stat
= create_path_gradient(path
, 0xff000000, grad
);
676 GdipDeletePath(path
);
680 (*grad
)->wrap
= wrap
;
685 GpStatus WINGDIPAPI
GdipCreatePathGradientI(GDIPCONST GpPoint
* points
,
686 INT count
, GpWrapMode wrap
, GpPathGradient
**grad
)
691 TRACE("(%p, %d, %d, %p)\n", points
, count
, wrap
, grad
);
694 return InvalidParameter
;
696 if(!points
|| count
<= 0)
699 stat
= GdipCreatePath(FillModeAlternate
, &path
);
703 stat
= GdipAddPathLine2I(path
, points
, count
);
706 stat
= create_path_gradient(path
, 0xff000000, grad
);
709 GdipDeletePath(path
);
713 (*grad
)->wrap
= wrap
;
718 /******************************************************************************
719 * GdipCreatePathGradientFromPath [GDIPLUS.@]
721 GpStatus WINGDIPAPI
GdipCreatePathGradientFromPath(GDIPCONST GpPath
* path
,
722 GpPathGradient
**grad
)
727 TRACE("(%p, %p)\n", path
, grad
);
730 return InvalidParameter
;
735 stat
= GdipClonePath((GpPath
*)path
, &new_path
);
739 stat
= create_path_gradient(new_path
, 0xffffffff, grad
);
742 GdipDeletePath(new_path
);
748 /******************************************************************************
749 * GdipCreateSolidFill [GDIPLUS.@]
751 GpStatus WINGDIPAPI
GdipCreateSolidFill(ARGB color
, GpSolidFill
**sf
)
753 TRACE("(%x, %p)\n", color
, sf
);
755 if(!sf
) return InvalidParameter
;
757 *sf
= heap_alloc_zero(sizeof(GpSolidFill
));
758 if (!*sf
) return OutOfMemory
;
760 (*sf
)->brush
.bt
= BrushTypeSolidColor
;
761 (*sf
)->color
= color
;
763 TRACE("<-- %p\n", *sf
);
768 /******************************************************************************
769 * GdipCreateTexture [GDIPLUS.@]
772 * image [I] image to use
773 * wrapmode [I] optional
774 * texture [O] pointer to the resulting texturebrush
778 * FAILURE: element of GpStatus
780 GpStatus WINGDIPAPI
GdipCreateTexture(GpImage
*image
, GpWrapMode wrapmode
,
784 GpImageAttributes
*attributes
;
787 TRACE("%p, %d %p\n", image
, wrapmode
, texture
);
789 if (!(image
&& texture
))
790 return InvalidParameter
;
792 stat
= GdipGetImageWidth(image
, &width
);
793 if (stat
!= Ok
) return stat
;
794 stat
= GdipGetImageHeight(image
, &height
);
795 if (stat
!= Ok
) return stat
;
797 stat
= GdipCreateImageAttributes(&attributes
);
801 attributes
->wrap
= wrapmode
;
803 stat
= GdipCreateTextureIA(image
, attributes
, 0, 0, width
, height
,
806 GdipDisposeImageAttributes(attributes
);
812 /******************************************************************************
813 * GdipCreateTexture2 [GDIPLUS.@]
815 GpStatus WINGDIPAPI
GdipCreateTexture2(GpImage
*image
, GpWrapMode wrapmode
,
816 REAL x
, REAL y
, REAL width
, REAL height
, GpTexture
**texture
)
818 GpImageAttributes
*attributes
;
821 TRACE("%p %d %f %f %f %f %p\n", image
, wrapmode
,
822 x
, y
, width
, height
, texture
);
824 stat
= GdipCreateImageAttributes(&attributes
);
828 attributes
->wrap
= wrapmode
;
830 stat
= GdipCreateTextureIA(image
, attributes
, x
, y
, width
, height
,
833 GdipDisposeImageAttributes(attributes
);
839 /******************************************************************************
840 * GdipCreateTextureIA [GDIPLUS.@]
842 GpStatus WINGDIPAPI
GdipCreateTextureIA(GpImage
*image
,
843 GDIPCONST GpImageAttributes
*imageattr
, REAL x
, REAL y
, REAL width
,
844 REAL height
, GpTexture
**texture
)
847 GpImage
*new_image
=NULL
;
849 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %p)\n", image
, imageattr
, x
, y
, width
, height
,
852 if(!image
|| !texture
|| x
< 0.0 || y
< 0.0 || width
< 0.0 || height
< 0.0)
853 return InvalidParameter
;
857 if(image
->type
!= ImageTypeBitmap
){
858 FIXME("not implemented for image type %d\n", image
->type
);
859 return NotImplemented
;
862 status
= GdipCloneBitmapArea(x
, y
, width
, height
, PixelFormatDontCare
, (GpBitmap
*)image
, (GpBitmap
**)&new_image
);
866 *texture
= heap_alloc_zero(sizeof(GpTexture
));
868 status
= OutOfMemory
;
872 GdipSetMatrixElements(&(*texture
)->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
876 status
= GdipCloneImageAttributes(imageattr
, &(*texture
)->imageattributes
);
880 status
= GdipCreateImageAttributes(&(*texture
)->imageattributes
);
882 (*texture
)->imageattributes
->wrap
= WrapModeTile
;
886 (*texture
)->brush
.bt
= BrushTypeTextureFill
;
887 (*texture
)->image
= new_image
;
893 TRACE("<-- %p\n", *texture
);
899 GdipDisposeImageAttributes((*texture
)->imageattributes
);
903 GdipDisposeImage(new_image
);
904 TRACE("<-- error %u\n", status
);
910 /******************************************************************************
911 * GdipCreateTextureIAI [GDIPLUS.@]
913 GpStatus WINGDIPAPI
GdipCreateTextureIAI(GpImage
*image
, GDIPCONST GpImageAttributes
*imageattr
,
914 INT x
, INT y
, INT width
, INT height
, GpTexture
**texture
)
916 TRACE("(%p, %p, %d, %d, %d, %d, %p)\n", image
, imageattr
, x
, y
, width
, height
,
919 return GdipCreateTextureIA(image
,imageattr
,(REAL
)x
,(REAL
)y
,(REAL
)width
,(REAL
)height
,texture
);
922 GpStatus WINGDIPAPI
GdipCreateTexture2I(GpImage
*image
, GpWrapMode wrapmode
,
923 INT x
, INT y
, INT width
, INT height
, GpTexture
**texture
)
925 GpImageAttributes
*imageattr
;
928 TRACE("%p %d %d %d %d %d %p\n", image
, wrapmode
, x
, y
, width
, height
,
931 stat
= GdipCreateImageAttributes(&imageattr
);
935 imageattr
->wrap
= wrapmode
;
937 stat
= GdipCreateTextureIA(image
, imageattr
, x
, y
, width
, height
, texture
);
938 GdipDisposeImageAttributes(imageattr
);
944 GpStatus WINGDIPAPI
GdipGetBrushType(GpBrush
*brush
, GpBrushType
*type
)
946 TRACE("(%p, %p)\n", brush
, type
);
948 if(!brush
|| !type
) return InvalidParameter
;
955 GpStatus WINGDIPAPI
GdipGetHatchBackgroundColor(GpHatch
*brush
, ARGB
*backcol
)
957 TRACE("(%p, %p)\n", brush
, backcol
);
959 if(!brush
|| !backcol
) return InvalidParameter
;
961 *backcol
= brush
->backcol
;
966 GpStatus WINGDIPAPI
GdipGetHatchForegroundColor(GpHatch
*brush
, ARGB
*forecol
)
968 TRACE("(%p, %p)\n", brush
, forecol
);
970 if(!brush
|| !forecol
) return InvalidParameter
;
972 *forecol
= brush
->forecol
;
977 GpStatus WINGDIPAPI
GdipGetHatchStyle(GpHatch
*brush
, GpHatchStyle
*hatchstyle
)
979 TRACE("(%p, %p)\n", brush
, hatchstyle
);
981 if(!brush
|| !hatchstyle
) return InvalidParameter
;
983 *hatchstyle
= brush
->hatchstyle
;
988 GpStatus WINGDIPAPI
GdipDeleteBrush(GpBrush
*brush
)
990 TRACE("(%p)\n", brush
);
992 if(!brush
) return InvalidParameter
;
996 case BrushTypePathGradient
:
997 GdipDeletePath(((GpPathGradient
*) brush
)->path
);
998 heap_free(((GpPathGradient
*) brush
)->blendfac
);
999 heap_free(((GpPathGradient
*) brush
)->blendpos
);
1000 heap_free(((GpPathGradient
*) brush
)->surroundcolors
);
1001 heap_free(((GpPathGradient
*) brush
)->pblendcolor
);
1002 heap_free(((GpPathGradient
*) brush
)->pblendpos
);
1004 case BrushTypeLinearGradient
:
1005 heap_free(((GpLineGradient
*)brush
)->blendfac
);
1006 heap_free(((GpLineGradient
*)brush
)->blendpos
);
1007 heap_free(((GpLineGradient
*)brush
)->pblendcolor
);
1008 heap_free(((GpLineGradient
*)brush
)->pblendpos
);
1010 case BrushTypeTextureFill
:
1011 GdipDisposeImage(((GpTexture
*)brush
)->image
);
1012 GdipDisposeImageAttributes(((GpTexture
*)brush
)->imageattributes
);
1013 heap_free(((GpTexture
*)brush
)->bitmap_bits
);
1024 GpStatus WINGDIPAPI
GdipGetLineGammaCorrection(GpLineGradient
*line
,
1027 TRACE("(%p, %p)\n", line
, usinggamma
);
1029 if(!line
|| !usinggamma
)
1030 return InvalidParameter
;
1032 *usinggamma
= line
->gamma
;
1037 GpStatus WINGDIPAPI
GdipGetLineWrapMode(GpLineGradient
*brush
, GpWrapMode
*wrapmode
)
1039 TRACE("(%p, %p)\n", brush
, wrapmode
);
1041 if(!brush
|| !wrapmode
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1042 return InvalidParameter
;
1044 *wrapmode
= brush
->wrap
;
1049 GpStatus WINGDIPAPI
GdipGetPathGradientBlend(GpPathGradient
*brush
, REAL
*blend
,
1050 REAL
*positions
, INT count
)
1052 TRACE("(%p, %p, %p, %d)\n", brush
, blend
, positions
, count
);
1054 if(!brush
|| !blend
|| !positions
|| count
<= 0 || brush
->brush
.bt
!= BrushTypePathGradient
)
1055 return InvalidParameter
;
1057 if(count
< brush
->blendcount
)
1058 return InsufficientBuffer
;
1060 memcpy(blend
, brush
->blendfac
, count
*sizeof(REAL
));
1061 if(brush
->blendcount
> 1){
1062 memcpy(positions
, brush
->blendpos
, count
*sizeof(REAL
));
1068 GpStatus WINGDIPAPI
GdipGetPathGradientBlendCount(GpPathGradient
*brush
, INT
*count
)
1070 TRACE("(%p, %p)\n", brush
, count
);
1072 if(!brush
|| !count
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1073 return InvalidParameter
;
1075 *count
= brush
->blendcount
;
1080 GpStatus WINGDIPAPI
GdipGetPathGradientCenterPoint(GpPathGradient
*grad
,
1083 TRACE("(%p, %p)\n", grad
, point
);
1085 if(!grad
|| !point
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1086 return InvalidParameter
;
1088 point
->X
= grad
->center
.X
;
1089 point
->Y
= grad
->center
.Y
;
1094 GpStatus WINGDIPAPI
GdipGetPathGradientCenterPointI(GpPathGradient
*grad
,
1100 TRACE("(%p, %p)\n", grad
, point
);
1103 return InvalidParameter
;
1105 ret
= GdipGetPathGradientCenterPoint(grad
,&ptf
);
1108 point
->X
= gdip_round(ptf
.X
);
1109 point
->Y
= gdip_round(ptf
.Y
);
1115 GpStatus WINGDIPAPI
GdipGetPathGradientCenterColor(GpPathGradient
*grad
,
1118 TRACE("(%p,%p)\n", grad
, colors
);
1120 if (!grad
|| !colors
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1121 return InvalidParameter
;
1123 *colors
= grad
->centercolor
;
1128 GpStatus WINGDIPAPI
GdipGetPathGradientFocusScales(GpPathGradient
*grad
,
1131 TRACE("(%p, %p, %p)\n", grad
, x
, y
);
1133 if(!grad
|| !x
|| !y
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1134 return InvalidParameter
;
1142 GpStatus WINGDIPAPI
GdipGetPathGradientGammaCorrection(GpPathGradient
*grad
,
1145 TRACE("(%p, %p)\n", grad
, gamma
);
1147 if(!grad
|| !gamma
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1148 return InvalidParameter
;
1150 *gamma
= grad
->gamma
;
1155 GpStatus WINGDIPAPI
GdipGetPathGradientPath(GpPathGradient
*grad
, GpPath
*path
)
1159 TRACE("(%p, %p)\n", grad
, path
);
1162 FIXME("not implemented\n");
1164 return NotImplemented
;
1167 GpStatus WINGDIPAPI
GdipGetPathGradientPointCount(GpPathGradient
*grad
,
1170 TRACE("(%p, %p)\n", grad
, count
);
1172 if(!grad
|| !count
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1173 return InvalidParameter
;
1175 *count
= grad
->path
->pathdata
.Count
;
1180 GpStatus WINGDIPAPI
GdipGetPathGradientRect(GpPathGradient
*brush
, GpRectF
*rect
)
1184 TRACE("(%p, %p)\n", brush
, rect
);
1186 if(!brush
|| !rect
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1187 return InvalidParameter
;
1189 stat
= GdipGetPathWorldBounds(brush
->path
, rect
, NULL
, NULL
);
1194 GpStatus WINGDIPAPI
GdipGetPathGradientRectI(GpPathGradient
*brush
, GpRect
*rect
)
1199 TRACE("(%p, %p)\n", brush
, rect
);
1202 return InvalidParameter
;
1204 stat
= GdipGetPathGradientRect(brush
, &rectf
);
1205 if(stat
!= Ok
) return stat
;
1207 rect
->X
= gdip_round(rectf
.X
);
1208 rect
->Y
= gdip_round(rectf
.Y
);
1209 rect
->Width
= gdip_round(rectf
.Width
);
1210 rect
->Height
= gdip_round(rectf
.Height
);
1215 GpStatus WINGDIPAPI
GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
1216 *grad
, ARGB
*argb
, INT
*count
)
1220 TRACE("(%p,%p,%p)\n", grad
, argb
, count
);
1222 if(!grad
|| !argb
|| !count
|| (*count
< grad
->path
->pathdata
.Count
) || grad
->brush
.bt
!= BrushTypePathGradient
)
1223 return InvalidParameter
;
1225 for (i
=0; i
<grad
->path
->pathdata
.Count
; i
++)
1227 if (i
< grad
->surroundcolorcount
)
1228 argb
[i
] = grad
->surroundcolors
[i
];
1230 argb
[i
] = grad
->surroundcolors
[grad
->surroundcolorcount
-1];
1233 *count
= grad
->surroundcolorcount
;
1238 GpStatus WINGDIPAPI
GdipGetPathGradientSurroundColorCount(GpPathGradient
*brush
, INT
*count
)
1240 TRACE("(%p, %p)\n", brush
, count
);
1242 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1243 return InvalidParameter
;
1245 /* Yes, this actually returns the number of points in the path (which is the
1246 * required size of a buffer to get the surround colors), rather than the
1247 * number of surround colors. The real count is returned when getting the
1249 *count
= brush
->path
->pathdata
.Count
;
1254 GpStatus WINGDIPAPI
GdipGetPathGradientWrapMode(GpPathGradient
*brush
,
1255 GpWrapMode
*wrapmode
)
1257 TRACE("(%p, %p)\n", brush
, wrapmode
);
1259 if(!brush
|| !wrapmode
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1260 return InvalidParameter
;
1262 *wrapmode
= brush
->wrap
;
1267 GpStatus WINGDIPAPI
GdipGetSolidFillColor(GpSolidFill
*sf
, ARGB
*argb
)
1269 TRACE("(%p, %p)\n", sf
, argb
);
1272 return InvalidParameter
;
1279 /******************************************************************************
1280 * GdipGetTextureImage [GDIPLUS.@]
1282 GpStatus WINGDIPAPI
GdipGetTextureImage(GpTexture
*brush
, GpImage
**image
)
1284 TRACE("(%p, %p)\n", brush
, image
);
1286 if(!brush
|| !image
)
1287 return InvalidParameter
;
1289 return GdipCloneImage(brush
->image
, image
);
1292 /******************************************************************************
1293 * GdipGetTextureTransform [GDIPLUS.@]
1295 GpStatus WINGDIPAPI
GdipGetTextureTransform(GpTexture
*brush
, GpMatrix
*matrix
)
1297 TRACE("(%p, %p)\n", brush
, matrix
);
1299 if(!brush
|| !matrix
)
1300 return InvalidParameter
;
1302 *matrix
= brush
->transform
;
1307 /******************************************************************************
1308 * GdipGetTextureWrapMode [GDIPLUS.@]
1310 GpStatus WINGDIPAPI
GdipGetTextureWrapMode(GpTexture
*brush
, GpWrapMode
*wrapmode
)
1312 TRACE("(%p, %p)\n", brush
, wrapmode
);
1314 if(!brush
|| !wrapmode
)
1315 return InvalidParameter
;
1317 *wrapmode
= brush
->imageattributes
->wrap
;
1322 /******************************************************************************
1323 * GdipMultiplyTextureTransform [GDIPLUS.@]
1325 GpStatus WINGDIPAPI
GdipMultiplyTextureTransform(GpTexture
* brush
,
1326 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
1328 TRACE("(%p, %p, %d)\n", brush
, matrix
, order
);
1330 if(!brush
|| !matrix
)
1331 return InvalidParameter
;
1333 return GdipMultiplyMatrix(&brush
->transform
, matrix
, order
);
1336 /******************************************************************************
1337 * GdipResetTextureTransform [GDIPLUS.@]
1339 GpStatus WINGDIPAPI
GdipResetTextureTransform(GpTexture
* brush
)
1341 TRACE("(%p)\n", brush
);
1344 return InvalidParameter
;
1346 return GdipSetMatrixElements(&brush
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1349 /******************************************************************************
1350 * GdipScaleTextureTransform [GDIPLUS.@]
1352 GpStatus WINGDIPAPI
GdipScaleTextureTransform(GpTexture
* brush
,
1353 REAL sx
, REAL sy
, GpMatrixOrder order
)
1355 TRACE("(%p, %.2f, %.2f, %d)\n", brush
, sx
, sy
, order
);
1358 return InvalidParameter
;
1360 return GdipScaleMatrix(&brush
->transform
, sx
, sy
, order
);
1363 GpStatus WINGDIPAPI
GdipSetLineBlend(GpLineGradient
*brush
,
1364 GDIPCONST REAL
*factors
, GDIPCONST REAL
* positions
, INT count
)
1366 REAL
*new_blendfac
, *new_blendpos
;
1368 TRACE("(%p, %p, %p, %i)\n", brush
, factors
, positions
, count
);
1370 if(!brush
|| !factors
|| !positions
|| count
<= 0 || brush
->brush
.bt
!= BrushTypeLinearGradient
||
1371 (count
>= 2 && (positions
[0] != 0.0f
|| positions
[count
-1] != 1.0f
)))
1372 return InvalidParameter
;
1374 new_blendfac
= heap_alloc_zero(count
* sizeof(REAL
));
1375 new_blendpos
= heap_alloc_zero(count
* sizeof(REAL
));
1377 if (!new_blendfac
|| !new_blendpos
)
1379 heap_free(new_blendfac
);
1380 heap_free(new_blendpos
);
1384 memcpy(new_blendfac
, factors
, count
* sizeof(REAL
));
1385 memcpy(new_blendpos
, positions
, count
* sizeof(REAL
));
1387 heap_free(brush
->blendfac
);
1388 heap_free(brush
->blendpos
);
1390 brush
->blendcount
= count
;
1391 brush
->blendfac
= new_blendfac
;
1392 brush
->blendpos
= new_blendpos
;
1397 GpStatus WINGDIPAPI
GdipGetLineBlend(GpLineGradient
*brush
, REAL
*factors
,
1398 REAL
*positions
, INT count
)
1400 TRACE("(%p, %p, %p, %i)\n", brush
, factors
, positions
, count
);
1402 if (!brush
|| !factors
|| !positions
|| count
<= 0 || brush
->brush
.bt
!= BrushTypeLinearGradient
)
1403 return InvalidParameter
;
1405 if (count
< brush
->blendcount
)
1406 return InsufficientBuffer
;
1408 memcpy(factors
, brush
->blendfac
, brush
->blendcount
* sizeof(REAL
));
1409 memcpy(positions
, brush
->blendpos
, brush
->blendcount
* sizeof(REAL
));
1414 GpStatus WINGDIPAPI
GdipGetLineBlendCount(GpLineGradient
*brush
, INT
*count
)
1416 TRACE("(%p, %p)\n", brush
, count
);
1418 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1419 return InvalidParameter
;
1421 *count
= brush
->blendcount
;
1426 GpStatus WINGDIPAPI
GdipSetLineGammaCorrection(GpLineGradient
*line
,
1429 TRACE("(%p, %d)\n", line
, usegamma
);
1431 if(!line
|| line
->brush
.bt
!= BrushTypeLinearGradient
)
1432 return InvalidParameter
;
1434 line
->gamma
= usegamma
;
1439 GpStatus WINGDIPAPI
GdipSetLineSigmaBlend(GpLineGradient
*line
, REAL focus
,
1446 const int precision
= 16;
1447 REAL erf_range
; /* we use values erf(-erf_range) through erf(+erf_range) */
1451 TRACE("(%p, %0.2f, %0.2f)\n", line
, focus
, scale
);
1453 if(!line
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0 || line
->brush
.bt
!= BrushTypeLinearGradient
)
1454 return InvalidParameter
;
1456 /* we want 2 standard deviations */
1457 erf_range
= 2.0 / sqrt(2);
1459 /* calculate the constants we need to normalize the error function to be
1460 between 0.0 and scale over the range we need */
1461 min_erf
= erf(-erf_range
);
1462 scale_erf
= scale
/ (-2.0 * min_erf
);
1468 for (i
=1; i
<precision
; i
++)
1470 positions
[i
] = focus
* i
/ precision
;
1471 factors
[i
] = scale_erf
* (erf(2 * erf_range
* i
/ precision
- erf_range
) - min_erf
);
1473 num_points
+= precision
;
1476 positions
[num_points
] = focus
;
1477 factors
[num_points
] = scale
;
1482 for (i
=1; i
<precision
; i
++)
1484 positions
[i
+num_points
-1] = (focus
+ ((1.0-focus
) * i
/ precision
));
1485 factors
[i
+num_points
-1] = scale_erf
* (erf(erf_range
- 2 * erf_range
* i
/ precision
) - min_erf
);
1487 num_points
+= precision
;
1488 positions
[num_points
-1] = 1.0;
1489 factors
[num_points
-1] = 0.0;
1492 return GdipSetLineBlend(line
, factors
, positions
, num_points
);
1495 GpStatus WINGDIPAPI
GdipSetLineWrapMode(GpLineGradient
*line
,
1498 TRACE("(%p, %d)\n", line
, wrap
);
1500 if(!line
|| wrap
== WrapModeClamp
|| line
->brush
.bt
!= BrushTypeLinearGradient
)
1501 return InvalidParameter
;
1508 GpStatus WINGDIPAPI
GdipSetPathGradientBlend(GpPathGradient
*brush
, GDIPCONST REAL
*blend
,
1509 GDIPCONST REAL
*pos
, INT count
)
1511 REAL
*new_blendfac
, *new_blendpos
;
1513 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1515 if(!brush
|| !blend
|| !pos
|| count
<= 0 || brush
->brush
.bt
!= BrushTypePathGradient
||
1516 (count
>= 2 && (pos
[0] != 0.0f
|| pos
[count
-1] != 1.0f
)))
1517 return InvalidParameter
;
1519 new_blendfac
= heap_alloc_zero(count
* sizeof(REAL
));
1520 new_blendpos
= heap_alloc_zero(count
* sizeof(REAL
));
1522 if (!new_blendfac
|| !new_blendpos
)
1524 heap_free(new_blendfac
);
1525 heap_free(new_blendpos
);
1529 memcpy(new_blendfac
, blend
, count
* sizeof(REAL
));
1530 memcpy(new_blendpos
, pos
, count
* sizeof(REAL
));
1532 heap_free(brush
->blendfac
);
1533 heap_free(brush
->blendpos
);
1535 brush
->blendcount
= count
;
1536 brush
->blendfac
= new_blendfac
;
1537 brush
->blendpos
= new_blendpos
;
1542 GpStatus WINGDIPAPI
GdipSetPathGradientLinearBlend(GpPathGradient
*brush
,
1543 REAL focus
, REAL scale
)
1549 TRACE("(%p,%0.2f,%0.2f)\n", brush
, focus
, scale
);
1551 if (!brush
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1552 return InvalidParameter
;
1556 factors
[num_points
] = 0.0;
1557 positions
[num_points
] = 0.0;
1561 factors
[num_points
] = scale
;
1562 positions
[num_points
] = focus
;
1567 factors
[num_points
] = 0.0;
1568 positions
[num_points
] = 1.0;
1572 return GdipSetPathGradientBlend(brush
, factors
, positions
, num_points
);
1575 GpStatus WINGDIPAPI
GdipSetPathGradientPresetBlend(GpPathGradient
*brush
,
1576 GDIPCONST ARGB
*blend
, GDIPCONST REAL
*pos
, INT count
)
1580 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1582 if (!brush
|| !blend
|| !pos
|| count
< 2 || brush
->brush
.bt
!= BrushTypePathGradient
||
1583 pos
[0] != 0.0f
|| pos
[count
-1] != 1.0f
)
1585 return InvalidParameter
;
1588 new_color
= heap_alloc_zero(count
* sizeof(ARGB
));
1589 new_pos
= heap_alloc_zero(count
* sizeof(REAL
));
1590 if (!new_color
|| !new_pos
)
1592 heap_free(new_color
);
1597 memcpy(new_color
, blend
, sizeof(ARGB
) * count
);
1598 memcpy(new_pos
, pos
, sizeof(REAL
) * count
);
1600 heap_free(brush
->pblendcolor
);
1601 heap_free(brush
->pblendpos
);
1603 brush
->pblendcolor
= new_color
;
1604 brush
->pblendpos
= new_pos
;
1605 brush
->pblendcount
= count
;
1610 GpStatus WINGDIPAPI
GdipGetPathGradientPresetBlend(GpPathGradient
*brush
,
1611 ARGB
*blend
, REAL
*pos
, INT count
)
1613 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1618 if (!brush
|| !blend
|| !pos
|| count
< 2 || brush
->brush
.bt
!= BrushTypePathGradient
)
1619 return InvalidParameter
;
1621 if (brush
->pblendcount
== 0)
1622 return GenericError
;
1624 if (count
!= brush
->pblendcount
)
1626 /* Native lines up the ends of each array, and copies the destination size. */
1627 FIXME("Braindead behavior on wrong-sized buffer not implemented.\n");
1628 return InvalidParameter
;
1631 memcpy(blend
, brush
->pblendcolor
, sizeof(ARGB
) * brush
->pblendcount
);
1632 memcpy(pos
, brush
->pblendpos
, sizeof(REAL
) * brush
->pblendcount
);
1637 GpStatus WINGDIPAPI
GdipGetPathGradientPresetBlendCount(GpPathGradient
*brush
,
1640 TRACE("(%p,%p)\n", brush
, count
);
1642 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1643 return InvalidParameter
;
1645 *count
= brush
->pblendcount
;
1650 GpStatus WINGDIPAPI
GdipSetPathGradientCenterColor(GpPathGradient
*grad
,
1653 TRACE("(%p, %x)\n", grad
, argb
);
1655 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1656 return InvalidParameter
;
1658 grad
->centercolor
= argb
;
1662 GpStatus WINGDIPAPI
GdipSetPathGradientCenterPoint(GpPathGradient
*grad
,
1665 TRACE("(%p, %s)\n", grad
, debugstr_pointf(point
));
1667 if(!grad
|| !point
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1668 return InvalidParameter
;
1670 grad
->center
.X
= point
->X
;
1671 grad
->center
.Y
= point
->Y
;
1676 GpStatus WINGDIPAPI
GdipSetPathGradientCenterPointI(GpPathGradient
*grad
,
1681 TRACE("(%p, %p)\n", grad
, point
);
1684 return InvalidParameter
;
1686 ptf
.X
= (REAL
)point
->X
;
1687 ptf
.Y
= (REAL
)point
->Y
;
1689 return GdipSetPathGradientCenterPoint(grad
,&ptf
);
1692 GpStatus WINGDIPAPI
GdipSetPathGradientFocusScales(GpPathGradient
*grad
,
1695 TRACE("(%p, %.2f, %.2f)\n", grad
, x
, y
);
1697 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1698 return InvalidParameter
;
1706 GpStatus WINGDIPAPI
GdipSetPathGradientGammaCorrection(GpPathGradient
*grad
,
1709 TRACE("(%p, %d)\n", grad
, gamma
);
1711 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1712 return InvalidParameter
;
1714 grad
->gamma
= gamma
;
1719 GpStatus WINGDIPAPI
GdipSetPathGradientPath(GpPathGradient
*grad
, GDIPCONST GpPath
*path
)
1723 TRACE("(%p, %p)\n", grad
, path
);
1726 FIXME("not implemented\n");
1728 return NotImplemented
;
1731 GpStatus WINGDIPAPI
GdipSetPathGradientSigmaBlend(GpPathGradient
*grad
,
1732 REAL focus
, REAL scale
)
1738 const int precision
= 16;
1739 REAL erf_range
; /* we use values erf(-erf_range) through erf(+erf_range) */
1743 TRACE("(%p,%0.2f,%0.2f)\n", grad
, focus
, scale
);
1745 if(!grad
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0 || grad
->brush
.bt
!= BrushTypePathGradient
)
1746 return InvalidParameter
;
1748 /* we want 2 standard deviations */
1749 erf_range
= 2.0 / sqrt(2);
1751 /* calculate the constants we need to normalize the error function to be
1752 between 0.0 and scale over the range we need */
1753 min_erf
= erf(-erf_range
);
1754 scale_erf
= scale
/ (-2.0 * min_erf
);
1760 for (i
=1; i
<precision
; i
++)
1762 positions
[i
] = focus
* i
/ precision
;
1763 factors
[i
] = scale_erf
* (erf(2 * erf_range
* i
/ precision
- erf_range
) - min_erf
);
1765 num_points
+= precision
;
1768 positions
[num_points
] = focus
;
1769 factors
[num_points
] = scale
;
1774 for (i
=1; i
<precision
; i
++)
1776 positions
[i
+num_points
-1] = (focus
+ ((1.0-focus
) * i
/ precision
));
1777 factors
[i
+num_points
-1] = scale_erf
* (erf(erf_range
- 2 * erf_range
* i
/ precision
) - min_erf
);
1779 num_points
+= precision
;
1780 positions
[num_points
-1] = 1.0;
1781 factors
[num_points
-1] = 0.0;
1784 return GdipSetPathGradientBlend(grad
, factors
, positions
, num_points
);
1787 GpStatus WINGDIPAPI
GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
1788 *grad
, GDIPCONST ARGB
*argb
, INT
*count
)
1790 ARGB
*new_surroundcolors
;
1793 TRACE("(%p,%p,%p)\n", grad
, argb
, count
);
1795 if(!grad
|| !argb
|| !count
|| (*count
<= 0) || grad
->brush
.bt
!= BrushTypePathGradient
||
1796 (*count
> grad
->path
->pathdata
.Count
))
1797 return InvalidParameter
;
1799 num_colors
= *count
;
1801 /* If all colors are the same, only store 1 color. */
1804 for (i
=1; i
< num_colors
; i
++)
1805 if (argb
[i
] != argb
[i
-1])
1808 if (i
== num_colors
)
1812 new_surroundcolors
= heap_alloc_zero(num_colors
* sizeof(ARGB
));
1813 if (!new_surroundcolors
)
1816 memcpy(new_surroundcolors
, argb
, num_colors
* sizeof(ARGB
));
1818 heap_free(grad
->surroundcolors
);
1820 grad
->surroundcolors
= new_surroundcolors
;
1821 grad
->surroundcolorcount
= num_colors
;
1826 GpStatus WINGDIPAPI
GdipSetPathGradientWrapMode(GpPathGradient
*grad
,
1829 TRACE("(%p, %d)\n", grad
, wrap
);
1831 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1832 return InvalidParameter
;
1839 GpStatus WINGDIPAPI
GdipSetPathGradientTransform(GpPathGradient
*grad
,
1842 TRACE("(%p,%p)\n", grad
, matrix
);
1844 if (!grad
|| !matrix
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1845 return InvalidParameter
;
1847 grad
->transform
= *matrix
;
1852 GpStatus WINGDIPAPI
GdipGetPathGradientTransform(GpPathGradient
*grad
,
1855 TRACE("(%p,%p)\n", grad
, matrix
);
1857 if (!grad
|| !matrix
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1858 return InvalidParameter
;
1860 *matrix
= grad
->transform
;
1865 GpStatus WINGDIPAPI
GdipMultiplyPathGradientTransform(GpPathGradient
*grad
,
1866 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
1868 TRACE("(%p,%p,%i)\n", grad
, matrix
, order
);
1870 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1871 return InvalidParameter
;
1873 return GdipMultiplyMatrix(&grad
->transform
, matrix
, order
);
1876 GpStatus WINGDIPAPI
GdipResetPathGradientTransform(GpPathGradient
*grad
)
1878 TRACE("(%p)\n", grad
);
1880 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1881 return InvalidParameter
;
1883 return GdipSetMatrixElements(&grad
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1886 GpStatus WINGDIPAPI
GdipRotatePathGradientTransform(GpPathGradient
*grad
,
1887 REAL angle
, GpMatrixOrder order
)
1889 TRACE("(%p,%0.2f,%i)\n", grad
, angle
, order
);
1891 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1892 return InvalidParameter
;
1894 return GdipRotateMatrix(&grad
->transform
, angle
, order
);
1897 GpStatus WINGDIPAPI
GdipScalePathGradientTransform(GpPathGradient
*grad
,
1898 REAL sx
, REAL sy
, GpMatrixOrder order
)
1900 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad
, sx
, sy
, order
);
1902 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1903 return InvalidParameter
;
1905 return GdipScaleMatrix(&grad
->transform
, sx
, sy
, order
);
1908 GpStatus WINGDIPAPI
GdipTranslatePathGradientTransform(GpPathGradient
*grad
,
1909 REAL dx
, REAL dy
, GpMatrixOrder order
)
1911 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad
, dx
, dy
, order
);
1913 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1914 return InvalidParameter
;
1916 return GdipTranslateMatrix(&grad
->transform
, dx
, dy
, order
);
1919 GpStatus WINGDIPAPI
GdipSetSolidFillColor(GpSolidFill
*sf
, ARGB argb
)
1921 TRACE("(%p, %x)\n", sf
, argb
);
1924 return InvalidParameter
;
1930 /******************************************************************************
1931 * GdipSetTextureTransform [GDIPLUS.@]
1933 GpStatus WINGDIPAPI
GdipSetTextureTransform(GpTexture
*texture
,
1934 GDIPCONST GpMatrix
*matrix
)
1936 TRACE("(%p, %p)\n", texture
, matrix
);
1938 if(!texture
|| !matrix
)
1939 return InvalidParameter
;
1941 texture
->transform
= *matrix
;
1946 /******************************************************************************
1947 * GdipSetTextureWrapMode [GDIPLUS.@]
1949 * WrapMode not used, only stored
1951 GpStatus WINGDIPAPI
GdipSetTextureWrapMode(GpTexture
*brush
, GpWrapMode wrapmode
)
1953 TRACE("(%p, %d)\n", brush
, wrapmode
);
1956 return InvalidParameter
;
1958 brush
->imageattributes
->wrap
= wrapmode
;
1963 GpStatus WINGDIPAPI
GdipSetLineColors(GpLineGradient
*brush
, ARGB color1
,
1966 TRACE("(%p, %x, %x)\n", brush
, color1
, color2
);
1968 if(!brush
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1969 return InvalidParameter
;
1971 brush
->startcolor
= color1
;
1972 brush
->endcolor
= color2
;
1977 GpStatus WINGDIPAPI
GdipGetLineColors(GpLineGradient
*brush
, ARGB
*colors
)
1979 TRACE("(%p, %p)\n", brush
, colors
);
1981 if(!brush
|| !colors
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1982 return InvalidParameter
;
1984 colors
[0] = brush
->startcolor
;
1985 colors
[1] = brush
->endcolor
;
1990 /******************************************************************************
1991 * GdipRotateTextureTransform [GDIPLUS.@]
1993 GpStatus WINGDIPAPI
GdipRotateTextureTransform(GpTexture
* brush
, REAL angle
,
1994 GpMatrixOrder order
)
1996 TRACE("(%p, %.2f, %d)\n", brush
, angle
, order
);
1999 return InvalidParameter
;
2001 return GdipRotateMatrix(&brush
->transform
, angle
, order
);
2004 GpStatus WINGDIPAPI
GdipSetLineLinearBlend(GpLineGradient
*brush
, REAL focus
,
2011 TRACE("(%p,%.2f,%.2f)\n", brush
, focus
, scale
);
2013 if (!brush
) return InvalidParameter
;
2017 factors
[num_points
] = 0.0;
2018 positions
[num_points
] = 0.0;
2022 factors
[num_points
] = scale
;
2023 positions
[num_points
] = focus
;
2028 factors
[num_points
] = 0.0;
2029 positions
[num_points
] = 1.0;
2033 return GdipSetLineBlend(brush
, factors
, positions
, num_points
);
2036 GpStatus WINGDIPAPI
GdipSetLinePresetBlend(GpLineGradient
*brush
,
2037 GDIPCONST ARGB
*blend
, GDIPCONST REAL
* positions
, INT count
)
2041 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, positions
, count
);
2043 if (!brush
|| !blend
|| !positions
|| count
< 2 || brush
->brush
.bt
!= BrushTypeLinearGradient
||
2044 positions
[0] != 0.0f
|| positions
[count
-1] != 1.0f
)
2046 return InvalidParameter
;
2049 new_color
= heap_alloc_zero(count
* sizeof(ARGB
));
2050 new_pos
= heap_alloc_zero(count
* sizeof(REAL
));
2051 if (!new_color
|| !new_pos
)
2053 heap_free(new_color
);
2058 memcpy(new_color
, blend
, sizeof(ARGB
) * count
);
2059 memcpy(new_pos
, positions
, sizeof(REAL
) * count
);
2061 heap_free(brush
->pblendcolor
);
2062 heap_free(brush
->pblendpos
);
2064 brush
->pblendcolor
= new_color
;
2065 brush
->pblendpos
= new_pos
;
2066 brush
->pblendcount
= count
;
2071 GpStatus WINGDIPAPI
GdipGetLinePresetBlend(GpLineGradient
*brush
,
2072 ARGB
*blend
, REAL
* positions
, INT count
)
2074 if (!brush
|| !blend
|| !positions
|| count
< 2 || brush
->brush
.bt
!= BrushTypeLinearGradient
)
2075 return InvalidParameter
;
2077 if (brush
->pblendcount
== 0)
2078 return GenericError
;
2080 if (count
< brush
->pblendcount
)
2081 return InsufficientBuffer
;
2083 memcpy(blend
, brush
->pblendcolor
, sizeof(ARGB
) * brush
->pblendcount
);
2084 memcpy(positions
, brush
->pblendpos
, sizeof(REAL
) * brush
->pblendcount
);
2089 GpStatus WINGDIPAPI
GdipGetLinePresetBlendCount(GpLineGradient
*brush
,
2092 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
2093 return InvalidParameter
;
2095 *count
= brush
->pblendcount
;
2100 GpStatus WINGDIPAPI
GdipResetLineTransform(GpLineGradient
*brush
)
2102 TRACE("(%p)\n", brush
);
2105 return InvalidParameter
;
2107 return GdipSetMatrixElements(&brush
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
2110 GpStatus WINGDIPAPI
GdipSetLineTransform(GpLineGradient
*brush
,
2111 GDIPCONST GpMatrix
*matrix
)
2113 TRACE("(%p,%p)\n", brush
, matrix
);
2115 if(!brush
|| !matrix
)
2116 return InvalidParameter
;
2118 brush
->transform
= *matrix
;
2123 GpStatus WINGDIPAPI
GdipGetLineTransform(GpLineGradient
*brush
, GpMatrix
*matrix
)
2125 TRACE("(%p,%p)\n", brush
, matrix
);
2127 if(!brush
|| !matrix
)
2128 return InvalidParameter
;
2130 *matrix
= brush
->transform
;
2135 GpStatus WINGDIPAPI
GdipScaleLineTransform(GpLineGradient
*brush
, REAL sx
, REAL sy
,
2136 GpMatrixOrder order
)
2138 TRACE("(%p,%0.2f,%0.2f,%u)\n", brush
, sx
, sy
, order
);
2141 return InvalidParameter
;
2143 return GdipScaleMatrix(&brush
->transform
, sx
, sy
, order
);
2146 GpStatus WINGDIPAPI
GdipMultiplyLineTransform(GpLineGradient
*brush
,
2147 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
2149 TRACE("(%p,%p,%u)\n", brush
, matrix
, order
);
2152 return InvalidParameter
;
2157 return GdipMultiplyMatrix(&brush
->transform
, matrix
, order
);
2160 GpStatus WINGDIPAPI
GdipTranslateLineTransform(GpLineGradient
*brush
,
2161 REAL dx
, REAL dy
, GpMatrixOrder order
)
2163 TRACE("(%p,%f,%f,%d)\n", brush
, dx
, dy
, order
);
2166 return InvalidParameter
;
2168 return GdipTranslateMatrix(&brush
->transform
, dx
, dy
, order
);
2171 /******************************************************************************
2172 * GdipTranslateTextureTransform [GDIPLUS.@]
2174 GpStatus WINGDIPAPI
GdipTranslateTextureTransform(GpTexture
* brush
, REAL dx
, REAL dy
,
2175 GpMatrixOrder order
)
2177 TRACE("(%p, %.2f, %.2f, %d)\n", brush
, dx
, dy
, order
);
2180 return InvalidParameter
;
2182 return GdipTranslateMatrix(&brush
->transform
, dx
, dy
, order
);
2185 GpStatus WINGDIPAPI
GdipGetLineRect(GpLineGradient
*brush
, GpRectF
*rect
)
2187 TRACE("(%p, %p)\n", brush
, rect
);
2189 if(!brush
|| !rect
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
2190 return InvalidParameter
;
2192 *rect
= brush
->rect
;
2197 GpStatus WINGDIPAPI
GdipGetLineRectI(GpLineGradient
*brush
, GpRect
*rect
)
2202 TRACE("(%p, %p)\n", brush
, rect
);
2205 return InvalidParameter
;
2207 ret
= GdipGetLineRect(brush
, &rectF
);
2210 rect
->X
= gdip_round(rectF
.X
);
2211 rect
->Y
= gdip_round(rectF
.Y
);
2212 rect
->Width
= gdip_round(rectF
.Width
);
2213 rect
->Height
= gdip_round(rectF
.Height
);
2219 GpStatus WINGDIPAPI
GdipRotateLineTransform(GpLineGradient
* brush
,
2220 REAL angle
, GpMatrixOrder order
)
2224 TRACE("(%p,%0.2f,%u)\n", brush
, angle
, order
);
2226 if(!brush
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
2227 return InvalidParameter
;
2230 FIXME("(%p, %.2f, %d) stub\n", brush
, angle
, order
);
2232 return NotImplemented
;