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
);
38 /******************************************************************************
39 * GdipCloneBrush [GDIPLUS.@]
41 GpStatus WINGDIPAPI
GdipCloneBrush(GpBrush
*brush
, GpBrush
**clone
)
43 TRACE("(%p, %p)\n", brush
, clone
);
46 return InvalidParameter
;
49 case BrushTypeSolidColor
:
51 *clone
= heap_alloc_zero(sizeof(GpSolidFill
));
52 if (!*clone
) return OutOfMemory
;
53 memcpy(*clone
, brush
, sizeof(GpSolidFill
));
56 case BrushTypeHatchFill
:
58 GpHatch
*hatch
= (GpHatch
*)brush
;
60 return GdipCreateHatchBrush(hatch
->hatchstyle
, hatch
->forecol
, hatch
->backcol
, (GpHatch
**)clone
);
62 case BrushTypePathGradient
:{
63 GpPathGradient
*src
, *dest
;
67 *clone
= heap_alloc_zero(sizeof(GpPathGradient
));
68 if (!*clone
) return OutOfMemory
;
70 src
= (GpPathGradient
*) brush
,
71 dest
= (GpPathGradient
*) *clone
;
73 memcpy(dest
, src
, sizeof(GpPathGradient
));
75 stat
= GdipClonePath(src
->path
, &dest
->path
);
82 dest
->transform
= src
->transform
;
85 count
= src
->blendcount
;
86 dest
->blendcount
= count
;
87 dest
->blendfac
= heap_alloc_zero(count
* sizeof(REAL
));
88 dest
->blendpos
= heap_alloc_zero(count
* sizeof(REAL
));
89 dest
->surroundcolors
= heap_alloc_zero(dest
->surroundcolorcount
* sizeof(ARGB
));
90 pcount
= dest
->pblendcount
;
93 dest
->pblendcolor
= heap_alloc_zero(pcount
* sizeof(ARGB
));
94 dest
->pblendpos
= heap_alloc_zero(pcount
* sizeof(REAL
));
97 if(!dest
->blendfac
|| !dest
->blendpos
|| !dest
->surroundcolors
||
98 (pcount
&& (!dest
->pblendcolor
|| !dest
->pblendpos
))){
99 GdipDeletePath(dest
->path
);
100 heap_free(dest
->blendfac
);
101 heap_free(dest
->blendpos
);
102 heap_free(dest
->surroundcolors
);
103 heap_free(dest
->pblendcolor
);
104 heap_free(dest
->pblendpos
);
109 memcpy(dest
->blendfac
, src
->blendfac
, count
* sizeof(REAL
));
110 memcpy(dest
->blendpos
, src
->blendpos
, count
* sizeof(REAL
));
111 memcpy(dest
->surroundcolors
, src
->surroundcolors
, dest
->surroundcolorcount
* sizeof(ARGB
));
115 memcpy(dest
->pblendcolor
, src
->pblendcolor
, pcount
* sizeof(ARGB
));
116 memcpy(dest
->pblendpos
, src
->pblendpos
, pcount
* sizeof(REAL
));
121 case BrushTypeLinearGradient
:{
122 GpLineGradient
*dest
, *src
;
125 dest
= heap_alloc_zero(sizeof(GpLineGradient
));
126 if(!dest
) return OutOfMemory
;
128 src
= (GpLineGradient
*)brush
;
130 memcpy(dest
, src
, sizeof(GpLineGradient
));
132 count
= dest
->blendcount
;
133 dest
->blendfac
= heap_alloc_zero(count
* sizeof(REAL
));
134 dest
->blendpos
= heap_alloc_zero(count
* sizeof(REAL
));
135 pcount
= dest
->pblendcount
;
138 dest
->pblendcolor
= heap_alloc_zero(pcount
* sizeof(ARGB
));
139 dest
->pblendpos
= heap_alloc_zero(pcount
* sizeof(REAL
));
142 if (!dest
->blendfac
|| !dest
->blendpos
||
143 (pcount
&& (!dest
->pblendcolor
|| !dest
->pblendpos
)))
145 heap_free(dest
->blendfac
);
146 heap_free(dest
->blendpos
);
147 heap_free(dest
->pblendcolor
);
148 heap_free(dest
->pblendpos
);
153 dest
->transform
= src
->transform
;
155 memcpy(dest
->blendfac
, src
->blendfac
, count
* sizeof(REAL
));
156 memcpy(dest
->blendpos
, src
->blendpos
, count
* sizeof(REAL
));
160 memcpy(dest
->pblendcolor
, src
->pblendcolor
, pcount
* sizeof(ARGB
));
161 memcpy(dest
->pblendpos
, src
->pblendpos
, pcount
* sizeof(REAL
));
164 *clone
= &dest
->brush
;
167 case BrushTypeTextureFill
:
170 GpTexture
*texture
= (GpTexture
*)brush
;
171 GpTexture
*new_texture
;
174 stat
= GdipGetImageWidth(texture
->image
, &width
);
175 if (stat
!= Ok
) return stat
;
176 stat
= GdipGetImageHeight(texture
->image
, &height
);
177 if (stat
!= Ok
) return stat
;
179 stat
= GdipCreateTextureIA(texture
->image
, texture
->imageattributes
, 0, 0, width
, height
, &new_texture
);
183 new_texture
->transform
= texture
->transform
;
184 *clone
= &new_texture
->brush
;
192 ERR("not implemented for brush type %d\n", brush
->bt
);
193 return NotImplemented
;
196 TRACE("<-- %p\n", *clone
);
200 static const char HatchBrushes
[][8] = {
201 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HatchStyleHorizontal */
202 { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleVertical */
203 { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HatchStyleForwardDiagonal */
204 { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HatchStyleBackwardDiagonal */
205 { 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleCross */
206 { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }, /* HatchStyleDiagonalCross */
207 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80 }, /* HatchStyle05Percent */
208 { 0x00, 0x02, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88 }, /* HatchStyle10Percent */
209 { 0x00, 0x22, 0x00, 0xcc, 0x00, 0x22, 0x00, 0xcc }, /* HatchStyle20Percent */
210 { 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc }, /* HatchStyle25Percent */
211 { 0x00, 0xcc, 0x04, 0xcc, 0x00, 0xcc, 0x40, 0xcc }, /* HatchStyle30Percent */
212 { 0x44, 0xcc, 0x22, 0xcc, 0x44, 0xcc, 0x22, 0xcc }, /* HatchStyle40Percent */
213 { 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc }, /* HatchStyle50Percent */
214 { 0x55, 0xcd, 0x55, 0xee, 0x55, 0xdc, 0x55, 0xee }, /* HatchStyle60Percent */
215 { 0x55, 0xdd, 0x55, 0xff, 0x55, 0xdd, 0x55, 0xff }, /* HatchStyle70Percent */
216 { 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff }, /* HatchStyle75Percent */
217 { 0x55, 0xff, 0x59, 0xff, 0x55, 0xff, 0x99, 0xff }, /* HatchStyle80Percent */
218 { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xfd, 0xff }, /* HatchStyle90Percent */
219 { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 }, /* HatchStyleLightDownwardDiagonal */
220 { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 }, /* HatchStyleLightUpwardDiagonal */
221 { 0x99, 0x33, 0x66, 0xcc, 0x99, 0x33, 0x66, 0xcc }, /* HatchStyleDarkDownwardDiagonal */
222 { 0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33, 0x99 }, /* HatchStyleDarkUpwardDiagonal */
223 { 0xc1, 0x83, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0 }, /* HatchStyleWideDownwardDiagonal */
224 { 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x07, 0x83, 0xc1 }, /* HatchStyleWideUpwardDiagonal */
225 { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 }, /* HatchStyleLightVertical */
226 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff }, /* HatchStyleLightHorizontal */
227 { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, /* HatchStyleNarrowVertical */
228 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, /* HatchStyleNarrowHorizontal */
229 { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }, /* HatchStyleDarkVertical */
230 { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff }, /* HatchStyleDarkHorizontal */
233 GpStatus
get_hatch_data(HatchStyle hatchstyle
, const char **result
)
235 if (hatchstyle
< sizeof(HatchBrushes
) / sizeof(HatchBrushes
[0]))
237 *result
= HatchBrushes
[hatchstyle
];
241 return NotImplemented
;
244 /******************************************************************************
245 * GdipCreateHatchBrush [GDIPLUS.@]
247 GpStatus WINGDIPAPI
GdipCreateHatchBrush(HatchStyle hatchstyle
, ARGB forecol
, ARGB backcol
, GpHatch
**brush
)
249 TRACE("(%d, %d, %d, %p)\n", hatchstyle
, forecol
, backcol
, brush
);
251 if(!brush
) return InvalidParameter
;
253 *brush
= heap_alloc_zero(sizeof(GpHatch
));
254 if (!*brush
) return OutOfMemory
;
256 (*brush
)->brush
.bt
= BrushTypeHatchFill
;
257 (*brush
)->forecol
= forecol
;
258 (*brush
)->backcol
= backcol
;
259 (*brush
)->hatchstyle
= hatchstyle
;
260 TRACE("<-- %p\n", *brush
);
265 static void linegradient_init_transform(GpLineGradient
*line
)
267 float trans_x
= line
->rect
.X
+ (line
->rect
.Width
/ 2.f
);
268 float trans_y
= line
->rect
.Y
+ (line
->rect
.Height
/ 2.f
);
269 float dx
= line
->endpoint
.X
- line
->startpoint
.X
;
270 float dy
= line
->endpoint
.Y
- line
->startpoint
.Y
;
271 float t_cos
, t_sin
, w_ratio
, h_ratio
;
275 h
= sqrtf(dx
* dx
+ dy
* dy
);
280 w_ratio
= (fabs(t_cos
) * line
->rect
.Width
+ fabs(t_sin
) * line
->rect
.Height
) / line
->rect
.Width
;
281 h_ratio
= (fabs(t_sin
) * line
->rect
.Width
+ fabs(t_cos
) * line
->rect
.Height
) / line
->rect
.Height
;
283 GdipSetMatrixElements(&line
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
285 GdipSetMatrixElements(&rot
, t_cos
, t_sin
, -1.f
* t_sin
, t_cos
, 0, 0);
287 /* center about the origin */
288 GdipTranslateMatrix(&line
->transform
, -trans_x
, -trans_y
, MatrixOrderAppend
);
290 /* scale to normalize gradient along gradient line (?) */
291 GdipScaleMatrix(&line
->transform
, w_ratio
, h_ratio
, MatrixOrderAppend
);
293 /* rotate so the gradient is horizontal */
294 GdipMultiplyMatrix(&line
->transform
, &rot
, MatrixOrderAppend
);
296 /* restore original offset in new coords */
297 GdipTranslateMatrix(&line
->transform
, trans_x
, trans_y
, MatrixOrderAppend
);
300 /******************************************************************************
301 * GdipCreateLineBrush [GDIPLUS.@]
303 GpStatus WINGDIPAPI
GdipCreateLineBrush(GDIPCONST GpPointF
* startpoint
,
304 GDIPCONST GpPointF
* endpoint
, ARGB startcolor
, ARGB endcolor
,
305 GpWrapMode wrap
, GpLineGradient
**line
)
307 TRACE("(%s, %s, %x, %x, %d, %p)\n", debugstr_pointf(startpoint
),
308 debugstr_pointf(endpoint
), startcolor
, endcolor
, wrap
, line
);
310 if(!line
|| !startpoint
|| !endpoint
|| wrap
== WrapModeClamp
)
311 return InvalidParameter
;
313 if (startpoint
->X
== endpoint
->X
&& startpoint
->Y
== endpoint
->Y
)
316 *line
= heap_alloc_zero(sizeof(GpLineGradient
));
317 if(!*line
) return OutOfMemory
;
319 (*line
)->brush
.bt
= BrushTypeLinearGradient
;
321 (*line
)->startpoint
.X
= startpoint
->X
;
322 (*line
)->startpoint
.Y
= startpoint
->Y
;
323 (*line
)->endpoint
.X
= endpoint
->X
;
324 (*line
)->endpoint
.Y
= endpoint
->Y
;
325 (*line
)->startcolor
= startcolor
;
326 (*line
)->endcolor
= endcolor
;
327 (*line
)->wrap
= wrap
;
328 (*line
)->gamma
= FALSE
;
330 (*line
)->rect
.X
= (startpoint
->X
< endpoint
->X
? startpoint
->X
: endpoint
->X
);
331 (*line
)->rect
.Y
= (startpoint
->Y
< endpoint
->Y
? startpoint
->Y
: endpoint
->Y
);
332 (*line
)->rect
.Width
= fabs(startpoint
->X
- endpoint
->X
);
333 (*line
)->rect
.Height
= fabs(startpoint
->Y
- endpoint
->Y
);
335 if ((*line
)->rect
.Width
== 0)
337 (*line
)->rect
.X
-= (*line
)->rect
.Height
/ 2.0f
;
338 (*line
)->rect
.Width
= (*line
)->rect
.Height
;
340 else if ((*line
)->rect
.Height
== 0)
342 (*line
)->rect
.Y
-= (*line
)->rect
.Width
/ 2.0f
;
343 (*line
)->rect
.Height
= (*line
)->rect
.Width
;
346 (*line
)->blendcount
= 1;
347 (*line
)->blendfac
= heap_alloc_zero(sizeof(REAL
));
348 (*line
)->blendpos
= heap_alloc_zero(sizeof(REAL
));
350 if (!(*line
)->blendfac
|| !(*line
)->blendpos
)
352 heap_free((*line
)->blendfac
);
353 heap_free((*line
)->blendpos
);
359 (*line
)->blendfac
[0] = 1.0f
;
360 (*line
)->blendpos
[0] = 1.0f
;
362 (*line
)->pblendcolor
= NULL
;
363 (*line
)->pblendpos
= NULL
;
364 (*line
)->pblendcount
= 0;
366 linegradient_init_transform(*line
);
368 TRACE("<-- %p\n", *line
);
373 GpStatus WINGDIPAPI
GdipCreateLineBrushI(GDIPCONST GpPoint
* startpoint
,
374 GDIPCONST GpPoint
* endpoint
, ARGB startcolor
, ARGB endcolor
,
375 GpWrapMode wrap
, GpLineGradient
**line
)
380 TRACE("(%p, %p, %x, %x, %d, %p)\n", startpoint
, endpoint
,
381 startcolor
, endcolor
, wrap
, line
);
383 if(!startpoint
|| !endpoint
)
384 return InvalidParameter
;
386 stF
.X
= (REAL
)startpoint
->X
;
387 stF
.Y
= (REAL
)startpoint
->Y
;
388 endF
.X
= (REAL
)endpoint
->X
;
389 endF
.Y
= (REAL
)endpoint
->Y
;
391 return GdipCreateLineBrush(&stF
, &endF
, startcolor
, endcolor
, wrap
, line
);
394 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRect(GDIPCONST GpRectF
* rect
,
395 ARGB startcolor
, ARGB endcolor
, LinearGradientMode mode
, GpWrapMode wrap
,
396 GpLineGradient
**line
)
402 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect
, startcolor
, endcolor
, mode
,
406 return InvalidParameter
;
408 far_x
= rect
->X
+ rect
->Width
;
409 far_y
= rect
->Y
+ rect
->Height
;
413 case LinearGradientModeHorizontal
:
414 start
.X
= min(rect
->X
, far_x
);
416 end
.X
= max(rect
->X
, far_x
);
419 case LinearGradientModeVertical
:
421 start
.Y
= min(rect
->Y
, far_y
);
423 end
.Y
= max(rect
->Y
, far_y
);
425 case LinearGradientModeForwardDiagonal
:
426 start
.X
= min(rect
->X
, far_x
);
427 start
.Y
= min(rect
->Y
, far_y
);
428 end
.X
= max(rect
->X
, far_x
);
429 end
.Y
= max(rect
->Y
, far_y
);
431 case LinearGradientModeBackwardDiagonal
:
432 start
.X
= max(rect
->X
, far_x
);
433 start
.Y
= min(rect
->Y
, far_y
);
434 end
.X
= min(rect
->X
, far_x
);
435 end
.Y
= max(rect
->Y
, far_y
);
438 return InvalidParameter
;
441 stat
= GdipCreateLineBrush(&start
, &end
, startcolor
, endcolor
, wrap
, line
);
444 (*line
)->rect
= *rect
;
449 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectI(GDIPCONST GpRect
* rect
,
450 ARGB startcolor
, ARGB endcolor
, LinearGradientMode mode
, GpWrapMode wrap
,
451 GpLineGradient
**line
)
455 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect
, startcolor
, endcolor
, mode
,
458 rectF
.X
= (REAL
) rect
->X
;
459 rectF
.Y
= (REAL
) rect
->Y
;
460 rectF
.Width
= (REAL
) rect
->Width
;
461 rectF
.Height
= (REAL
) rect
->Height
;
463 return GdipCreateLineBrushFromRect(&rectF
, startcolor
, endcolor
, mode
, wrap
, line
);
466 /******************************************************************************
467 * GdipCreateLineBrushFromRectWithAngle [GDIPLUS.@]
469 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF
* rect
,
470 ARGB startcolor
, ARGB endcolor
, REAL angle
, BOOL isAngleScalable
, GpWrapMode wrap
,
471 GpLineGradient
**line
)
474 LinearGradientMode mode
;
476 REAL sin_angle
, cos_angle
, sin_cos_angle
;
478 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect
, startcolor
, endcolor
, angle
, isAngleScalable
,
481 if (!rect
|| !rect
->Width
|| !rect
->Height
)
482 return InvalidParameter
;
484 angle
= fmodf(angle
, 360);
497 if (angle
!= 90 && angle
!= -90)
498 angle
= atan((rect
->Width
/ rect
->Height
) * tan(deg2rad(angle
)));
500 angle
= deg2rad(angle
);
505 angle
= deg2rad(angle
);
508 sin_angle
= sinf(angle
);
509 cos_angle
= cosf(angle
);
510 sin_cos_angle
= sin_angle
* cos_angle
;
512 if (sin_cos_angle
>= 0)
513 mode
= LinearGradientModeForwardDiagonal
;
515 mode
= LinearGradientModeBackwardDiagonal
;
517 stat
= GdipCreateLineBrushFromRect(rect
, startcolor
, endcolor
, mode
, wrap
, line
);
521 if (sin_cos_angle
>= 0)
523 exofs
= rect
->Height
* sin_cos_angle
+ rect
->Width
* cos_angle
* cos_angle
;
524 eyofs
= rect
->Height
* sin_angle
* sin_angle
+ rect
->Width
* sin_cos_angle
;
528 exofs
= rect
->Width
* sin_angle
* sin_angle
+ rect
->Height
* sin_cos_angle
;
529 eyofs
= -rect
->Width
* sin_cos_angle
+ rect
->Height
* sin_angle
* sin_angle
;
534 (*line
)->endpoint
.X
= rect
->X
+ exofs
;
535 (*line
)->endpoint
.Y
= rect
->Y
+ eyofs
;
539 (*line
)->endpoint
.X
= (*line
)->startpoint
.X
;
540 (*line
)->endpoint
.Y
= (*line
)->startpoint
.Y
;
541 (*line
)->startpoint
.X
= rect
->X
+ exofs
;
542 (*line
)->startpoint
.Y
= rect
->Y
+ eyofs
;
545 linegradient_init_transform(*line
);
551 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectWithAngleI(GDIPCONST GpRect
* rect
,
552 ARGB startcolor
, ARGB endcolor
, REAL angle
, BOOL isAngleScalable
, GpWrapMode wrap
,
553 GpLineGradient
**line
)
555 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect
, startcolor
, endcolor
, angle
, isAngleScalable
,
558 return GdipCreateLineBrushFromRectI(rect
, startcolor
, endcolor
, LinearGradientModeForwardDiagonal
,
562 static GpStatus
create_path_gradient(GpPath
*path
, ARGB centercolor
, GpPathGradient
**grad
)
567 return InvalidParameter
;
569 if (path
->pathdata
.Count
< 2)
572 GdipGetPathWorldBounds(path
, &bounds
, NULL
, NULL
);
574 *grad
= heap_alloc_zero(sizeof(GpPathGradient
));
580 GdipSetMatrixElements(&(*grad
)->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
582 (*grad
)->blendfac
= heap_alloc_zero(sizeof(REAL
));
583 (*grad
)->blendpos
= heap_alloc_zero(sizeof(REAL
));
584 (*grad
)->surroundcolors
= heap_alloc_zero(sizeof(ARGB
));
585 if(!(*grad
)->blendfac
|| !(*grad
)->blendpos
|| !(*grad
)->surroundcolors
){
586 heap_free((*grad
)->blendfac
);
587 heap_free((*grad
)->blendpos
);
588 heap_free((*grad
)->surroundcolors
);
593 (*grad
)->blendfac
[0] = 1.0;
594 (*grad
)->blendpos
[0] = 1.0;
595 (*grad
)->blendcount
= 1;
597 (*grad
)->path
= path
;
599 (*grad
)->brush
.bt
= BrushTypePathGradient
;
600 (*grad
)->centercolor
= centercolor
;
601 (*grad
)->wrap
= WrapModeClamp
;
602 (*grad
)->gamma
= FALSE
;
603 /* FIXME: this should be set to the "centroid" of the path by default */
604 (*grad
)->center
.X
= bounds
.X
+ bounds
.Width
/ 2;
605 (*grad
)->center
.Y
= bounds
.Y
+ bounds
.Height
/ 2;
606 (*grad
)->focus
.X
= 0.0;
607 (*grad
)->focus
.Y
= 0.0;
608 (*grad
)->surroundcolors
[0] = 0xffffffff;
609 (*grad
)->surroundcolorcount
= 1;
611 TRACE("<-- %p\n", *grad
);
616 GpStatus WINGDIPAPI
GdipCreatePathGradient(GDIPCONST GpPointF
* points
,
617 INT count
, GpWrapMode wrap
, GpPathGradient
**grad
)
622 TRACE("(%p, %d, %d, %p)\n", points
, count
, wrap
, grad
);
625 return InvalidParameter
;
627 if(!points
|| count
<= 0)
630 stat
= GdipCreatePath(FillModeAlternate
, &path
);
634 stat
= GdipAddPathLine2(path
, points
, count
);
637 stat
= create_path_gradient(path
, 0xff000000, grad
);
640 GdipDeletePath(path
);
644 (*grad
)->wrap
= wrap
;
649 GpStatus WINGDIPAPI
GdipCreatePathGradientI(GDIPCONST GpPoint
* points
,
650 INT count
, GpWrapMode wrap
, GpPathGradient
**grad
)
655 TRACE("(%p, %d, %d, %p)\n", points
, count
, wrap
, grad
);
658 return InvalidParameter
;
660 if(!points
|| count
<= 0)
663 stat
= GdipCreatePath(FillModeAlternate
, &path
);
667 stat
= GdipAddPathLine2I(path
, points
, count
);
670 stat
= create_path_gradient(path
, 0xff000000, grad
);
673 GdipDeletePath(path
);
677 (*grad
)->wrap
= wrap
;
682 /******************************************************************************
683 * GdipCreatePathGradientFromPath [GDIPLUS.@]
685 GpStatus WINGDIPAPI
GdipCreatePathGradientFromPath(GDIPCONST GpPath
* path
,
686 GpPathGradient
**grad
)
691 TRACE("(%p, %p)\n", path
, grad
);
694 return InvalidParameter
;
699 stat
= GdipClonePath((GpPath
*)path
, &new_path
);
703 stat
= create_path_gradient(new_path
, 0xffffffff, grad
);
706 GdipDeletePath(new_path
);
712 /******************************************************************************
713 * GdipCreateSolidFill [GDIPLUS.@]
715 GpStatus WINGDIPAPI
GdipCreateSolidFill(ARGB color
, GpSolidFill
**sf
)
717 TRACE("(%x, %p)\n", color
, sf
);
719 if(!sf
) return InvalidParameter
;
721 *sf
= heap_alloc_zero(sizeof(GpSolidFill
));
722 if (!*sf
) return OutOfMemory
;
724 (*sf
)->brush
.bt
= BrushTypeSolidColor
;
725 (*sf
)->color
= color
;
727 TRACE("<-- %p\n", *sf
);
732 /******************************************************************************
733 * GdipCreateTexture [GDIPLUS.@]
736 * image [I] image to use
737 * wrapmode [I] optional
738 * texture [O] pointer to the resulting texturebrush
742 * FAILURE: element of GpStatus
744 GpStatus WINGDIPAPI
GdipCreateTexture(GpImage
*image
, GpWrapMode wrapmode
,
748 GpImageAttributes
*attributes
;
751 TRACE("%p, %d %p\n", image
, wrapmode
, texture
);
753 if (!(image
&& texture
))
754 return InvalidParameter
;
756 stat
= GdipGetImageWidth(image
, &width
);
757 if (stat
!= Ok
) return stat
;
758 stat
= GdipGetImageHeight(image
, &height
);
759 if (stat
!= Ok
) return stat
;
761 stat
= GdipCreateImageAttributes(&attributes
);
765 attributes
->wrap
= wrapmode
;
767 stat
= GdipCreateTextureIA(image
, attributes
, 0, 0, width
, height
,
770 GdipDisposeImageAttributes(attributes
);
776 /******************************************************************************
777 * GdipCreateTexture2 [GDIPLUS.@]
779 GpStatus WINGDIPAPI
GdipCreateTexture2(GpImage
*image
, GpWrapMode wrapmode
,
780 REAL x
, REAL y
, REAL width
, REAL height
, GpTexture
**texture
)
782 GpImageAttributes
*attributes
;
785 TRACE("%p %d %f %f %f %f %p\n", image
, wrapmode
,
786 x
, y
, width
, height
, texture
);
788 stat
= GdipCreateImageAttributes(&attributes
);
792 attributes
->wrap
= wrapmode
;
794 stat
= GdipCreateTextureIA(image
, attributes
, x
, y
, width
, height
,
797 GdipDisposeImageAttributes(attributes
);
803 /******************************************************************************
804 * GdipCreateTextureIA [GDIPLUS.@]
806 GpStatus WINGDIPAPI
GdipCreateTextureIA(GpImage
*image
,
807 GDIPCONST GpImageAttributes
*imageattr
, REAL x
, REAL y
, REAL width
,
808 REAL height
, GpTexture
**texture
)
811 GpImage
*new_image
=NULL
;
813 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %p)\n", image
, imageattr
, x
, y
, width
, height
,
816 if(!image
|| !texture
|| x
< 0.0 || y
< 0.0 || width
< 0.0 || height
< 0.0)
817 return InvalidParameter
;
821 if(image
->type
!= ImageTypeBitmap
){
822 FIXME("not implemented for image type %d\n", image
->type
);
823 return NotImplemented
;
826 status
= GdipCloneBitmapArea(x
, y
, width
, height
, PixelFormatDontCare
, (GpBitmap
*)image
, (GpBitmap
**)&new_image
);
830 *texture
= heap_alloc_zero(sizeof(GpTexture
));
832 status
= OutOfMemory
;
836 GdipSetMatrixElements(&(*texture
)->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
840 status
= GdipCloneImageAttributes(imageattr
, &(*texture
)->imageattributes
);
844 status
= GdipCreateImageAttributes(&(*texture
)->imageattributes
);
846 (*texture
)->imageattributes
->wrap
= WrapModeTile
;
850 (*texture
)->brush
.bt
= BrushTypeTextureFill
;
851 (*texture
)->image
= new_image
;
857 TRACE("<-- %p\n", *texture
);
863 GdipDisposeImageAttributes((*texture
)->imageattributes
);
867 GdipDisposeImage(new_image
);
868 TRACE("<-- error %u\n", status
);
874 /******************************************************************************
875 * GdipCreateTextureIAI [GDIPLUS.@]
877 GpStatus WINGDIPAPI
GdipCreateTextureIAI(GpImage
*image
, GDIPCONST GpImageAttributes
*imageattr
,
878 INT x
, INT y
, INT width
, INT height
, GpTexture
**texture
)
880 TRACE("(%p, %p, %d, %d, %d, %d, %p)\n", image
, imageattr
, x
, y
, width
, height
,
883 return GdipCreateTextureIA(image
,imageattr
,(REAL
)x
,(REAL
)y
,(REAL
)width
,(REAL
)height
,texture
);
886 GpStatus WINGDIPAPI
GdipCreateTexture2I(GpImage
*image
, GpWrapMode wrapmode
,
887 INT x
, INT y
, INT width
, INT height
, GpTexture
**texture
)
889 GpImageAttributes
*imageattr
;
892 TRACE("%p %d %d %d %d %d %p\n", image
, wrapmode
, x
, y
, width
, height
,
895 stat
= GdipCreateImageAttributes(&imageattr
);
899 imageattr
->wrap
= wrapmode
;
901 stat
= GdipCreateTextureIA(image
, imageattr
, x
, y
, width
, height
, texture
);
902 GdipDisposeImageAttributes(imageattr
);
908 GpStatus WINGDIPAPI
GdipGetBrushType(GpBrush
*brush
, GpBrushType
*type
)
910 TRACE("(%p, %p)\n", brush
, type
);
912 if(!brush
|| !type
) return InvalidParameter
;
919 GpStatus WINGDIPAPI
GdipGetHatchBackgroundColor(GpHatch
*brush
, ARGB
*backcol
)
921 TRACE("(%p, %p)\n", brush
, backcol
);
923 if(!brush
|| !backcol
) return InvalidParameter
;
925 *backcol
= brush
->backcol
;
930 GpStatus WINGDIPAPI
GdipGetHatchForegroundColor(GpHatch
*brush
, ARGB
*forecol
)
932 TRACE("(%p, %p)\n", brush
, forecol
);
934 if(!brush
|| !forecol
) return InvalidParameter
;
936 *forecol
= brush
->forecol
;
941 GpStatus WINGDIPAPI
GdipGetHatchStyle(GpHatch
*brush
, HatchStyle
*hatchstyle
)
943 TRACE("(%p, %p)\n", brush
, hatchstyle
);
945 if(!brush
|| !hatchstyle
) return InvalidParameter
;
947 *hatchstyle
= brush
->hatchstyle
;
952 GpStatus WINGDIPAPI
GdipDeleteBrush(GpBrush
*brush
)
954 TRACE("(%p)\n", brush
);
956 if(!brush
) return InvalidParameter
;
960 case BrushTypePathGradient
:
961 GdipDeletePath(((GpPathGradient
*) brush
)->path
);
962 heap_free(((GpPathGradient
*) brush
)->blendfac
);
963 heap_free(((GpPathGradient
*) brush
)->blendpos
);
964 heap_free(((GpPathGradient
*) brush
)->surroundcolors
);
965 heap_free(((GpPathGradient
*) brush
)->pblendcolor
);
966 heap_free(((GpPathGradient
*) brush
)->pblendpos
);
968 case BrushTypeLinearGradient
:
969 heap_free(((GpLineGradient
*)brush
)->blendfac
);
970 heap_free(((GpLineGradient
*)brush
)->blendpos
);
971 heap_free(((GpLineGradient
*)brush
)->pblendcolor
);
972 heap_free(((GpLineGradient
*)brush
)->pblendpos
);
974 case BrushTypeTextureFill
:
975 GdipDisposeImage(((GpTexture
*)brush
)->image
);
976 GdipDisposeImageAttributes(((GpTexture
*)brush
)->imageattributes
);
977 heap_free(((GpTexture
*)brush
)->bitmap_bits
);
988 GpStatus WINGDIPAPI
GdipGetLineGammaCorrection(GpLineGradient
*line
,
991 TRACE("(%p, %p)\n", line
, usinggamma
);
993 if(!line
|| !usinggamma
)
994 return InvalidParameter
;
996 *usinggamma
= line
->gamma
;
1001 GpStatus WINGDIPAPI
GdipGetLineWrapMode(GpLineGradient
*brush
, GpWrapMode
*wrapmode
)
1003 TRACE("(%p, %p)\n", brush
, wrapmode
);
1005 if(!brush
|| !wrapmode
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1006 return InvalidParameter
;
1008 *wrapmode
= brush
->wrap
;
1013 GpStatus WINGDIPAPI
GdipGetPathGradientBlend(GpPathGradient
*brush
, REAL
*blend
,
1014 REAL
*positions
, INT count
)
1016 TRACE("(%p, %p, %p, %d)\n", brush
, blend
, positions
, count
);
1018 if(!brush
|| !blend
|| !positions
|| count
<= 0 || brush
->brush
.bt
!= BrushTypePathGradient
)
1019 return InvalidParameter
;
1021 if(count
< brush
->blendcount
)
1022 return InsufficientBuffer
;
1024 memcpy(blend
, brush
->blendfac
, count
*sizeof(REAL
));
1025 if(brush
->blendcount
> 1){
1026 memcpy(positions
, brush
->blendpos
, count
*sizeof(REAL
));
1032 GpStatus WINGDIPAPI
GdipGetPathGradientBlendCount(GpPathGradient
*brush
, INT
*count
)
1034 TRACE("(%p, %p)\n", brush
, count
);
1036 if(!brush
|| !count
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1037 return InvalidParameter
;
1039 *count
= brush
->blendcount
;
1044 GpStatus WINGDIPAPI
GdipGetPathGradientCenterPoint(GpPathGradient
*grad
,
1047 TRACE("(%p, %p)\n", grad
, point
);
1049 if(!grad
|| !point
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1050 return InvalidParameter
;
1052 point
->X
= grad
->center
.X
;
1053 point
->Y
= grad
->center
.Y
;
1058 GpStatus WINGDIPAPI
GdipGetPathGradientCenterPointI(GpPathGradient
*grad
,
1064 TRACE("(%p, %p)\n", grad
, point
);
1067 return InvalidParameter
;
1069 ret
= GdipGetPathGradientCenterPoint(grad
,&ptf
);
1072 point
->X
= gdip_round(ptf
.X
);
1073 point
->Y
= gdip_round(ptf
.Y
);
1079 GpStatus WINGDIPAPI
GdipGetPathGradientCenterColor(GpPathGradient
*grad
,
1082 TRACE("(%p,%p)\n", grad
, colors
);
1084 if (!grad
|| !colors
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1085 return InvalidParameter
;
1087 *colors
= grad
->centercolor
;
1092 GpStatus WINGDIPAPI
GdipGetPathGradientFocusScales(GpPathGradient
*grad
,
1095 TRACE("(%p, %p, %p)\n", grad
, x
, y
);
1097 if(!grad
|| !x
|| !y
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1098 return InvalidParameter
;
1106 GpStatus WINGDIPAPI
GdipGetPathGradientGammaCorrection(GpPathGradient
*grad
,
1109 TRACE("(%p, %p)\n", grad
, gamma
);
1111 if(!grad
|| !gamma
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1112 return InvalidParameter
;
1114 *gamma
= grad
->gamma
;
1119 GpStatus WINGDIPAPI
GdipGetPathGradientPath(GpPathGradient
*grad
, GpPath
*path
)
1123 TRACE("(%p, %p)\n", grad
, path
);
1126 FIXME("not implemented\n");
1128 return NotImplemented
;
1131 GpStatus WINGDIPAPI
GdipGetPathGradientPointCount(GpPathGradient
*grad
,
1134 TRACE("(%p, %p)\n", grad
, count
);
1136 if(!grad
|| !count
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1137 return InvalidParameter
;
1139 *count
= grad
->path
->pathdata
.Count
;
1144 GpStatus WINGDIPAPI
GdipGetPathGradientRect(GpPathGradient
*brush
, GpRectF
*rect
)
1148 TRACE("(%p, %p)\n", brush
, rect
);
1150 if(!brush
|| !rect
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1151 return InvalidParameter
;
1153 stat
= GdipGetPathWorldBounds(brush
->path
, rect
, NULL
, NULL
);
1158 GpStatus WINGDIPAPI
GdipGetPathGradientRectI(GpPathGradient
*brush
, GpRect
*rect
)
1163 TRACE("(%p, %p)\n", brush
, rect
);
1166 return InvalidParameter
;
1168 stat
= GdipGetPathGradientRect(brush
, &rectf
);
1169 if(stat
!= Ok
) return stat
;
1171 rect
->X
= gdip_round(rectf
.X
);
1172 rect
->Y
= gdip_round(rectf
.Y
);
1173 rect
->Width
= gdip_round(rectf
.Width
);
1174 rect
->Height
= gdip_round(rectf
.Height
);
1179 GpStatus WINGDIPAPI
GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
1180 *grad
, ARGB
*argb
, INT
*count
)
1184 TRACE("(%p,%p,%p)\n", grad
, argb
, count
);
1186 if(!grad
|| !argb
|| !count
|| (*count
< grad
->path
->pathdata
.Count
) || grad
->brush
.bt
!= BrushTypePathGradient
)
1187 return InvalidParameter
;
1189 for (i
=0; i
<grad
->path
->pathdata
.Count
; i
++)
1191 if (i
< grad
->surroundcolorcount
)
1192 argb
[i
] = grad
->surroundcolors
[i
];
1194 argb
[i
] = grad
->surroundcolors
[grad
->surroundcolorcount
-1];
1197 *count
= grad
->surroundcolorcount
;
1202 GpStatus WINGDIPAPI
GdipGetPathGradientSurroundColorCount(GpPathGradient
*brush
, INT
*count
)
1204 TRACE("(%p, %p)\n", brush
, count
);
1206 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1207 return InvalidParameter
;
1209 /* Yes, this actually returns the number of points in the path (which is the
1210 * required size of a buffer to get the surround colors), rather than the
1211 * number of surround colors. The real count is returned when getting the
1213 *count
= brush
->path
->pathdata
.Count
;
1218 GpStatus WINGDIPAPI
GdipGetPathGradientWrapMode(GpPathGradient
*brush
,
1219 GpWrapMode
*wrapmode
)
1221 TRACE("(%p, %p)\n", brush
, wrapmode
);
1223 if(!brush
|| !wrapmode
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1224 return InvalidParameter
;
1226 *wrapmode
= brush
->wrap
;
1231 GpStatus WINGDIPAPI
GdipGetSolidFillColor(GpSolidFill
*sf
, ARGB
*argb
)
1233 TRACE("(%p, %p)\n", sf
, argb
);
1236 return InvalidParameter
;
1243 /******************************************************************************
1244 * GdipGetTextureImage [GDIPLUS.@]
1246 GpStatus WINGDIPAPI
GdipGetTextureImage(GpTexture
*brush
, GpImage
**image
)
1248 TRACE("(%p, %p)\n", brush
, image
);
1250 if(!brush
|| !image
)
1251 return InvalidParameter
;
1253 return GdipCloneImage(brush
->image
, image
);
1256 /******************************************************************************
1257 * GdipGetTextureTransform [GDIPLUS.@]
1259 GpStatus WINGDIPAPI
GdipGetTextureTransform(GpTexture
*brush
, GpMatrix
*matrix
)
1261 TRACE("(%p, %p)\n", brush
, matrix
);
1263 if(!brush
|| !matrix
)
1264 return InvalidParameter
;
1266 *matrix
= brush
->transform
;
1271 /******************************************************************************
1272 * GdipGetTextureWrapMode [GDIPLUS.@]
1274 GpStatus WINGDIPAPI
GdipGetTextureWrapMode(GpTexture
*brush
, GpWrapMode
*wrapmode
)
1276 TRACE("(%p, %p)\n", brush
, wrapmode
);
1278 if(!brush
|| !wrapmode
)
1279 return InvalidParameter
;
1281 *wrapmode
= brush
->imageattributes
->wrap
;
1286 /******************************************************************************
1287 * GdipMultiplyTextureTransform [GDIPLUS.@]
1289 GpStatus WINGDIPAPI
GdipMultiplyTextureTransform(GpTexture
* brush
,
1290 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
1292 TRACE("(%p, %p, %d)\n", brush
, matrix
, order
);
1294 if(!brush
|| !matrix
)
1295 return InvalidParameter
;
1297 return GdipMultiplyMatrix(&brush
->transform
, matrix
, order
);
1300 /******************************************************************************
1301 * GdipResetTextureTransform [GDIPLUS.@]
1303 GpStatus WINGDIPAPI
GdipResetTextureTransform(GpTexture
* brush
)
1305 TRACE("(%p)\n", brush
);
1308 return InvalidParameter
;
1310 return GdipSetMatrixElements(&brush
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1313 /******************************************************************************
1314 * GdipScaleTextureTransform [GDIPLUS.@]
1316 GpStatus WINGDIPAPI
GdipScaleTextureTransform(GpTexture
* brush
,
1317 REAL sx
, REAL sy
, GpMatrixOrder order
)
1319 TRACE("(%p, %.2f, %.2f, %d)\n", brush
, sx
, sy
, order
);
1322 return InvalidParameter
;
1324 return GdipScaleMatrix(&brush
->transform
, sx
, sy
, order
);
1327 GpStatus WINGDIPAPI
GdipSetLineBlend(GpLineGradient
*brush
,
1328 GDIPCONST REAL
*factors
, GDIPCONST REAL
* positions
, INT count
)
1330 REAL
*new_blendfac
, *new_blendpos
;
1332 TRACE("(%p, %p, %p, %i)\n", brush
, factors
, positions
, count
);
1334 if(!brush
|| !factors
|| !positions
|| count
<= 0 || brush
->brush
.bt
!= BrushTypeLinearGradient
||
1335 (count
>= 2 && (positions
[0] != 0.0f
|| positions
[count
-1] != 1.0f
)))
1336 return InvalidParameter
;
1338 new_blendfac
= heap_alloc_zero(count
* sizeof(REAL
));
1339 new_blendpos
= heap_alloc_zero(count
* sizeof(REAL
));
1341 if (!new_blendfac
|| !new_blendpos
)
1343 heap_free(new_blendfac
);
1344 heap_free(new_blendpos
);
1348 memcpy(new_blendfac
, factors
, count
* sizeof(REAL
));
1349 memcpy(new_blendpos
, positions
, count
* sizeof(REAL
));
1351 heap_free(brush
->blendfac
);
1352 heap_free(brush
->blendpos
);
1354 brush
->blendcount
= count
;
1355 brush
->blendfac
= new_blendfac
;
1356 brush
->blendpos
= new_blendpos
;
1361 GpStatus WINGDIPAPI
GdipGetLineBlend(GpLineGradient
*brush
, REAL
*factors
,
1362 REAL
*positions
, INT count
)
1364 TRACE("(%p, %p, %p, %i)\n", brush
, factors
, positions
, count
);
1366 if (!brush
|| !factors
|| !positions
|| count
<= 0 || brush
->brush
.bt
!= BrushTypeLinearGradient
)
1367 return InvalidParameter
;
1369 if (count
< brush
->blendcount
)
1370 return InsufficientBuffer
;
1372 memcpy(factors
, brush
->blendfac
, brush
->blendcount
* sizeof(REAL
));
1373 memcpy(positions
, brush
->blendpos
, brush
->blendcount
* sizeof(REAL
));
1378 GpStatus WINGDIPAPI
GdipGetLineBlendCount(GpLineGradient
*brush
, INT
*count
)
1380 TRACE("(%p, %p)\n", brush
, count
);
1382 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1383 return InvalidParameter
;
1385 *count
= brush
->blendcount
;
1390 GpStatus WINGDIPAPI
GdipSetLineGammaCorrection(GpLineGradient
*line
,
1393 TRACE("(%p, %d)\n", line
, usegamma
);
1395 if(!line
|| line
->brush
.bt
!= BrushTypeLinearGradient
)
1396 return InvalidParameter
;
1398 line
->gamma
= usegamma
;
1403 GpStatus WINGDIPAPI
GdipSetLineSigmaBlend(GpLineGradient
*line
, REAL focus
,
1410 const int precision
= 16;
1411 REAL erf_range
; /* we use values erf(-erf_range) through erf(+erf_range) */
1415 TRACE("(%p, %0.2f, %0.2f)\n", line
, focus
, scale
);
1417 if(!line
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0 || line
->brush
.bt
!= BrushTypeLinearGradient
)
1418 return InvalidParameter
;
1420 /* we want 2 standard deviations */
1421 erf_range
= 2.0 / sqrt(2);
1423 /* calculate the constants we need to normalize the error function to be
1424 between 0.0 and scale over the range we need */
1425 min_erf
= erf(-erf_range
);
1426 scale_erf
= scale
/ (-2.0 * min_erf
);
1432 for (i
=1; i
<precision
; i
++)
1434 positions
[i
] = focus
* i
/ precision
;
1435 factors
[i
] = scale_erf
* (erf(2 * erf_range
* i
/ precision
- erf_range
) - min_erf
);
1437 num_points
+= precision
;
1440 positions
[num_points
] = focus
;
1441 factors
[num_points
] = scale
;
1446 for (i
=1; i
<precision
; i
++)
1448 positions
[i
+num_points
-1] = (focus
+ ((1.0-focus
) * i
/ precision
));
1449 factors
[i
+num_points
-1] = scale_erf
* (erf(erf_range
- 2 * erf_range
* i
/ precision
) - min_erf
);
1451 num_points
+= precision
;
1452 positions
[num_points
-1] = 1.0;
1453 factors
[num_points
-1] = 0.0;
1456 return GdipSetLineBlend(line
, factors
, positions
, num_points
);
1459 GpStatus WINGDIPAPI
GdipSetLineWrapMode(GpLineGradient
*line
,
1462 TRACE("(%p, %d)\n", line
, wrap
);
1464 if(!line
|| wrap
== WrapModeClamp
|| line
->brush
.bt
!= BrushTypeLinearGradient
)
1465 return InvalidParameter
;
1472 GpStatus WINGDIPAPI
GdipSetPathGradientBlend(GpPathGradient
*brush
, GDIPCONST REAL
*blend
,
1473 GDIPCONST REAL
*pos
, INT count
)
1475 REAL
*new_blendfac
, *new_blendpos
;
1477 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1479 if(!brush
|| !blend
|| !pos
|| count
<= 0 || brush
->brush
.bt
!= BrushTypePathGradient
||
1480 (count
>= 2 && (pos
[0] != 0.0f
|| pos
[count
-1] != 1.0f
)))
1481 return InvalidParameter
;
1483 new_blendfac
= heap_alloc_zero(count
* sizeof(REAL
));
1484 new_blendpos
= heap_alloc_zero(count
* sizeof(REAL
));
1486 if (!new_blendfac
|| !new_blendpos
)
1488 heap_free(new_blendfac
);
1489 heap_free(new_blendpos
);
1493 memcpy(new_blendfac
, blend
, count
* sizeof(REAL
));
1494 memcpy(new_blendpos
, pos
, count
* sizeof(REAL
));
1496 heap_free(brush
->blendfac
);
1497 heap_free(brush
->blendpos
);
1499 brush
->blendcount
= count
;
1500 brush
->blendfac
= new_blendfac
;
1501 brush
->blendpos
= new_blendpos
;
1506 GpStatus WINGDIPAPI
GdipSetPathGradientLinearBlend(GpPathGradient
*brush
,
1507 REAL focus
, REAL scale
)
1513 TRACE("(%p,%0.2f,%0.2f)\n", brush
, focus
, scale
);
1515 if (!brush
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1516 return InvalidParameter
;
1520 factors
[num_points
] = 0.0;
1521 positions
[num_points
] = 0.0;
1525 factors
[num_points
] = scale
;
1526 positions
[num_points
] = focus
;
1531 factors
[num_points
] = 0.0;
1532 positions
[num_points
] = 1.0;
1536 return GdipSetPathGradientBlend(brush
, factors
, positions
, num_points
);
1539 GpStatus WINGDIPAPI
GdipSetPathGradientPresetBlend(GpPathGradient
*brush
,
1540 GDIPCONST ARGB
*blend
, GDIPCONST REAL
*pos
, INT count
)
1544 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1546 if (!brush
|| !blend
|| !pos
|| count
< 2 || brush
->brush
.bt
!= BrushTypePathGradient
||
1547 pos
[0] != 0.0f
|| pos
[count
-1] != 1.0f
)
1549 return InvalidParameter
;
1552 new_color
= heap_alloc_zero(count
* sizeof(ARGB
));
1553 new_pos
= heap_alloc_zero(count
* sizeof(REAL
));
1554 if (!new_color
|| !new_pos
)
1556 heap_free(new_color
);
1561 memcpy(new_color
, blend
, sizeof(ARGB
) * count
);
1562 memcpy(new_pos
, pos
, sizeof(REAL
) * count
);
1564 heap_free(brush
->pblendcolor
);
1565 heap_free(brush
->pblendpos
);
1567 brush
->pblendcolor
= new_color
;
1568 brush
->pblendpos
= new_pos
;
1569 brush
->pblendcount
= count
;
1574 GpStatus WINGDIPAPI
GdipGetPathGradientPresetBlend(GpPathGradient
*brush
,
1575 ARGB
*blend
, REAL
*pos
, INT count
)
1577 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1582 if (!brush
|| !blend
|| !pos
|| count
< 2 || brush
->brush
.bt
!= BrushTypePathGradient
)
1583 return InvalidParameter
;
1585 if (brush
->pblendcount
== 0)
1586 return GenericError
;
1588 if (count
!= brush
->pblendcount
)
1590 /* Native lines up the ends of each array, and copies the destination size. */
1591 FIXME("Braindead behavior on wrong-sized buffer not implemented.\n");
1592 return InvalidParameter
;
1595 memcpy(blend
, brush
->pblendcolor
, sizeof(ARGB
) * brush
->pblendcount
);
1596 memcpy(pos
, brush
->pblendpos
, sizeof(REAL
) * brush
->pblendcount
);
1601 GpStatus WINGDIPAPI
GdipGetPathGradientPresetBlendCount(GpPathGradient
*brush
,
1604 TRACE("(%p,%p)\n", brush
, count
);
1606 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1607 return InvalidParameter
;
1609 *count
= brush
->pblendcount
;
1614 GpStatus WINGDIPAPI
GdipSetPathGradientCenterColor(GpPathGradient
*grad
,
1617 TRACE("(%p, %x)\n", grad
, argb
);
1619 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1620 return InvalidParameter
;
1622 grad
->centercolor
= argb
;
1626 GpStatus WINGDIPAPI
GdipSetPathGradientCenterPoint(GpPathGradient
*grad
,
1629 TRACE("(%p, %s)\n", grad
, debugstr_pointf(point
));
1631 if(!grad
|| !point
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1632 return InvalidParameter
;
1634 grad
->center
.X
= point
->X
;
1635 grad
->center
.Y
= point
->Y
;
1640 GpStatus WINGDIPAPI
GdipSetPathGradientCenterPointI(GpPathGradient
*grad
,
1645 TRACE("(%p, %p)\n", grad
, point
);
1648 return InvalidParameter
;
1650 ptf
.X
= (REAL
)point
->X
;
1651 ptf
.Y
= (REAL
)point
->Y
;
1653 return GdipSetPathGradientCenterPoint(grad
,&ptf
);
1656 GpStatus WINGDIPAPI
GdipSetPathGradientFocusScales(GpPathGradient
*grad
,
1659 TRACE("(%p, %.2f, %.2f)\n", grad
, x
, y
);
1661 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1662 return InvalidParameter
;
1670 GpStatus WINGDIPAPI
GdipSetPathGradientGammaCorrection(GpPathGradient
*grad
,
1673 TRACE("(%p, %d)\n", grad
, gamma
);
1675 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1676 return InvalidParameter
;
1678 grad
->gamma
= gamma
;
1683 GpStatus WINGDIPAPI
GdipSetPathGradientSigmaBlend(GpPathGradient
*grad
,
1684 REAL focus
, REAL scale
)
1690 const int precision
= 16;
1691 REAL erf_range
; /* we use values erf(-erf_range) through erf(+erf_range) */
1695 TRACE("(%p,%0.2f,%0.2f)\n", grad
, focus
, scale
);
1697 if(!grad
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0 || grad
->brush
.bt
!= BrushTypePathGradient
)
1698 return InvalidParameter
;
1700 /* we want 2 standard deviations */
1701 erf_range
= 2.0 / sqrt(2);
1703 /* calculate the constants we need to normalize the error function to be
1704 between 0.0 and scale over the range we need */
1705 min_erf
= erf(-erf_range
);
1706 scale_erf
= scale
/ (-2.0 * min_erf
);
1712 for (i
=1; i
<precision
; i
++)
1714 positions
[i
] = focus
* i
/ precision
;
1715 factors
[i
] = scale_erf
* (erf(2 * erf_range
* i
/ precision
- erf_range
) - min_erf
);
1717 num_points
+= precision
;
1720 positions
[num_points
] = focus
;
1721 factors
[num_points
] = scale
;
1726 for (i
=1; i
<precision
; i
++)
1728 positions
[i
+num_points
-1] = (focus
+ ((1.0-focus
) * i
/ precision
));
1729 factors
[i
+num_points
-1] = scale_erf
* (erf(erf_range
- 2 * erf_range
* i
/ precision
) - min_erf
);
1731 num_points
+= precision
;
1732 positions
[num_points
-1] = 1.0;
1733 factors
[num_points
-1] = 0.0;
1736 return GdipSetPathGradientBlend(grad
, factors
, positions
, num_points
);
1739 GpStatus WINGDIPAPI
GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
1740 *grad
, GDIPCONST ARGB
*argb
, INT
*count
)
1742 ARGB
*new_surroundcolors
;
1745 TRACE("(%p,%p,%p)\n", grad
, argb
, count
);
1747 if(!grad
|| !argb
|| !count
|| (*count
<= 0) || grad
->brush
.bt
!= BrushTypePathGradient
||
1748 (*count
> grad
->path
->pathdata
.Count
))
1749 return InvalidParameter
;
1751 num_colors
= *count
;
1753 /* If all colors are the same, only store 1 color. */
1756 for (i
=1; i
< num_colors
; i
++)
1757 if (argb
[i
] != argb
[i
-1])
1760 if (i
== num_colors
)
1764 new_surroundcolors
= heap_alloc_zero(num_colors
* sizeof(ARGB
));
1765 if (!new_surroundcolors
)
1768 memcpy(new_surroundcolors
, argb
, num_colors
* sizeof(ARGB
));
1770 heap_free(grad
->surroundcolors
);
1772 grad
->surroundcolors
= new_surroundcolors
;
1773 grad
->surroundcolorcount
= num_colors
;
1778 GpStatus WINGDIPAPI
GdipSetPathGradientWrapMode(GpPathGradient
*grad
,
1781 TRACE("(%p, %d)\n", grad
, wrap
);
1783 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1784 return InvalidParameter
;
1791 GpStatus WINGDIPAPI
GdipSetPathGradientTransform(GpPathGradient
*grad
,
1794 TRACE("(%p,%p)\n", grad
, matrix
);
1796 if (!grad
|| !matrix
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1797 return InvalidParameter
;
1799 grad
->transform
= *matrix
;
1804 GpStatus WINGDIPAPI
GdipGetPathGradientTransform(GpPathGradient
*grad
,
1807 TRACE("(%p,%p)\n", grad
, matrix
);
1809 if (!grad
|| !matrix
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1810 return InvalidParameter
;
1812 *matrix
= grad
->transform
;
1817 GpStatus WINGDIPAPI
GdipMultiplyPathGradientTransform(GpPathGradient
*grad
,
1818 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
1820 TRACE("(%p,%p,%i)\n", grad
, matrix
, order
);
1822 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1823 return InvalidParameter
;
1825 return GdipMultiplyMatrix(&grad
->transform
, matrix
, order
);
1828 GpStatus WINGDIPAPI
GdipResetPathGradientTransform(GpPathGradient
*grad
)
1830 TRACE("(%p)\n", grad
);
1832 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1833 return InvalidParameter
;
1835 return GdipSetMatrixElements(&grad
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1838 GpStatus WINGDIPAPI
GdipRotatePathGradientTransform(GpPathGradient
*grad
,
1839 REAL angle
, GpMatrixOrder order
)
1841 TRACE("(%p,%0.2f,%i)\n", grad
, angle
, order
);
1843 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1844 return InvalidParameter
;
1846 return GdipRotateMatrix(&grad
->transform
, angle
, order
);
1849 GpStatus WINGDIPAPI
GdipScalePathGradientTransform(GpPathGradient
*grad
,
1850 REAL sx
, REAL sy
, GpMatrixOrder order
)
1852 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad
, sx
, sy
, order
);
1854 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1855 return InvalidParameter
;
1857 return GdipScaleMatrix(&grad
->transform
, sx
, sy
, order
);
1860 GpStatus WINGDIPAPI
GdipTranslatePathGradientTransform(GpPathGradient
*grad
,
1861 REAL dx
, REAL dy
, GpMatrixOrder order
)
1863 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad
, dx
, dy
, order
);
1865 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1866 return InvalidParameter
;
1868 return GdipTranslateMatrix(&grad
->transform
, dx
, dy
, order
);
1871 GpStatus WINGDIPAPI
GdipSetSolidFillColor(GpSolidFill
*sf
, ARGB argb
)
1873 TRACE("(%p, %x)\n", sf
, argb
);
1876 return InvalidParameter
;
1882 /******************************************************************************
1883 * GdipSetTextureTransform [GDIPLUS.@]
1885 GpStatus WINGDIPAPI
GdipSetTextureTransform(GpTexture
*texture
,
1886 GDIPCONST GpMatrix
*matrix
)
1888 TRACE("(%p, %p)\n", texture
, matrix
);
1890 if(!texture
|| !matrix
)
1891 return InvalidParameter
;
1893 texture
->transform
= *matrix
;
1898 /******************************************************************************
1899 * GdipSetTextureWrapMode [GDIPLUS.@]
1901 * WrapMode not used, only stored
1903 GpStatus WINGDIPAPI
GdipSetTextureWrapMode(GpTexture
*brush
, GpWrapMode wrapmode
)
1905 TRACE("(%p, %d)\n", brush
, wrapmode
);
1908 return InvalidParameter
;
1910 brush
->imageattributes
->wrap
= wrapmode
;
1915 GpStatus WINGDIPAPI
GdipSetLineColors(GpLineGradient
*brush
, ARGB color1
,
1918 TRACE("(%p, %x, %x)\n", brush
, color1
, color2
);
1920 if(!brush
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1921 return InvalidParameter
;
1923 brush
->startcolor
= color1
;
1924 brush
->endcolor
= color2
;
1929 GpStatus WINGDIPAPI
GdipGetLineColors(GpLineGradient
*brush
, ARGB
*colors
)
1931 TRACE("(%p, %p)\n", brush
, colors
);
1933 if(!brush
|| !colors
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1934 return InvalidParameter
;
1936 colors
[0] = brush
->startcolor
;
1937 colors
[1] = brush
->endcolor
;
1942 /******************************************************************************
1943 * GdipRotateTextureTransform [GDIPLUS.@]
1945 GpStatus WINGDIPAPI
GdipRotateTextureTransform(GpTexture
* brush
, REAL angle
,
1946 GpMatrixOrder order
)
1948 TRACE("(%p, %.2f, %d)\n", brush
, angle
, order
);
1951 return InvalidParameter
;
1953 return GdipRotateMatrix(&brush
->transform
, angle
, order
);
1956 GpStatus WINGDIPAPI
GdipSetLineLinearBlend(GpLineGradient
*brush
, REAL focus
,
1963 TRACE("(%p,%.2f,%.2f)\n", brush
, focus
, scale
);
1965 if (!brush
) return InvalidParameter
;
1969 factors
[num_points
] = 0.0;
1970 positions
[num_points
] = 0.0;
1974 factors
[num_points
] = scale
;
1975 positions
[num_points
] = focus
;
1980 factors
[num_points
] = 0.0;
1981 positions
[num_points
] = 1.0;
1985 return GdipSetLineBlend(brush
, factors
, positions
, num_points
);
1988 GpStatus WINGDIPAPI
GdipSetLinePresetBlend(GpLineGradient
*brush
,
1989 GDIPCONST ARGB
*blend
, GDIPCONST REAL
* positions
, INT count
)
1993 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, positions
, count
);
1995 if (!brush
|| !blend
|| !positions
|| count
< 2 || brush
->brush
.bt
!= BrushTypeLinearGradient
||
1996 positions
[0] != 0.0f
|| positions
[count
-1] != 1.0f
)
1998 return InvalidParameter
;
2001 new_color
= heap_alloc_zero(count
* sizeof(ARGB
));
2002 new_pos
= heap_alloc_zero(count
* sizeof(REAL
));
2003 if (!new_color
|| !new_pos
)
2005 heap_free(new_color
);
2010 memcpy(new_color
, blend
, sizeof(ARGB
) * count
);
2011 memcpy(new_pos
, positions
, sizeof(REAL
) * count
);
2013 heap_free(brush
->pblendcolor
);
2014 heap_free(brush
->pblendpos
);
2016 brush
->pblendcolor
= new_color
;
2017 brush
->pblendpos
= new_pos
;
2018 brush
->pblendcount
= count
;
2023 GpStatus WINGDIPAPI
GdipGetLinePresetBlend(GpLineGradient
*brush
,
2024 ARGB
*blend
, REAL
* positions
, INT count
)
2026 if (!brush
|| !blend
|| !positions
|| count
< 2 || brush
->brush
.bt
!= BrushTypeLinearGradient
)
2027 return InvalidParameter
;
2029 if (brush
->pblendcount
== 0)
2030 return GenericError
;
2032 if (count
< brush
->pblendcount
)
2033 return InsufficientBuffer
;
2035 memcpy(blend
, brush
->pblendcolor
, sizeof(ARGB
) * brush
->pblendcount
);
2036 memcpy(positions
, brush
->pblendpos
, sizeof(REAL
) * brush
->pblendcount
);
2041 GpStatus WINGDIPAPI
GdipGetLinePresetBlendCount(GpLineGradient
*brush
,
2044 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
2045 return InvalidParameter
;
2047 *count
= brush
->pblendcount
;
2052 GpStatus WINGDIPAPI
GdipResetLineTransform(GpLineGradient
*brush
)
2054 TRACE("(%p)\n", brush
);
2057 return InvalidParameter
;
2059 return GdipSetMatrixElements(&brush
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
2062 GpStatus WINGDIPAPI
GdipSetLineTransform(GpLineGradient
*brush
,
2063 GDIPCONST GpMatrix
*matrix
)
2065 TRACE("(%p,%p)\n", brush
, matrix
);
2067 if(!brush
|| !matrix
)
2068 return InvalidParameter
;
2070 brush
->transform
= *matrix
;
2075 GpStatus WINGDIPAPI
GdipGetLineTransform(GpLineGradient
*brush
, GpMatrix
*matrix
)
2077 TRACE("(%p,%p)\n", brush
, matrix
);
2079 if(!brush
|| !matrix
)
2080 return InvalidParameter
;
2082 *matrix
= brush
->transform
;
2087 GpStatus WINGDIPAPI
GdipScaleLineTransform(GpLineGradient
*brush
, REAL sx
, REAL sy
,
2088 GpMatrixOrder order
)
2090 TRACE("(%p,%0.2f,%0.2f,%u)\n", brush
, sx
, sy
, order
);
2093 return InvalidParameter
;
2095 return GdipScaleMatrix(&brush
->transform
, sx
, sy
, order
);
2098 GpStatus WINGDIPAPI
GdipMultiplyLineTransform(GpLineGradient
*brush
,
2099 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
2101 TRACE("(%p,%p,%u)\n", brush
, matrix
, order
);
2104 return InvalidParameter
;
2109 return GdipMultiplyMatrix(&brush
->transform
, matrix
, order
);
2112 GpStatus WINGDIPAPI
GdipTranslateLineTransform(GpLineGradient
*brush
,
2113 REAL dx
, REAL dy
, GpMatrixOrder order
)
2115 TRACE("(%p,%f,%f,%d)\n", brush
, dx
, dy
, order
);
2118 return InvalidParameter
;
2120 return GdipTranslateMatrix(&brush
->transform
, dx
, dy
, order
);
2123 /******************************************************************************
2124 * GdipTranslateTextureTransform [GDIPLUS.@]
2126 GpStatus WINGDIPAPI
GdipTranslateTextureTransform(GpTexture
* brush
, REAL dx
, REAL dy
,
2127 GpMatrixOrder order
)
2129 TRACE("(%p, %.2f, %.2f, %d)\n", brush
, dx
, dy
, order
);
2132 return InvalidParameter
;
2134 return GdipTranslateMatrix(&brush
->transform
, dx
, dy
, order
);
2137 GpStatus WINGDIPAPI
GdipGetLineRect(GpLineGradient
*brush
, GpRectF
*rect
)
2139 TRACE("(%p, %p)\n", brush
, rect
);
2141 if(!brush
|| !rect
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
2142 return InvalidParameter
;
2144 *rect
= brush
->rect
;
2149 GpStatus WINGDIPAPI
GdipGetLineRectI(GpLineGradient
*brush
, GpRect
*rect
)
2154 TRACE("(%p, %p)\n", brush
, rect
);
2157 return InvalidParameter
;
2159 ret
= GdipGetLineRect(brush
, &rectF
);
2162 rect
->X
= gdip_round(rectF
.X
);
2163 rect
->Y
= gdip_round(rectF
.Y
);
2164 rect
->Width
= gdip_round(rectF
.Width
);
2165 rect
->Height
= gdip_round(rectF
.Height
);
2171 GpStatus WINGDIPAPI
GdipRotateLineTransform(GpLineGradient
* brush
,
2172 REAL angle
, GpMatrixOrder order
)
2176 TRACE("(%p,%0.2f,%u)\n", brush
, angle
, order
);
2178 if(!brush
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
2179 return InvalidParameter
;
2182 FIXME("(%p, %.2f, %d) stub\n", brush
, angle
, order
);
2184 return NotImplemented
;