2 * Copyright (C) 2007 Google (Evan Stade)
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "gdiplus_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus
);
37 /******************************************************************************
38 * GdipCloneBrush [GDIPLUS.@]
40 GpStatus WINGDIPAPI
GdipCloneBrush(GpBrush
*brush
, GpBrush
**clone
)
42 TRACE("(%p, %p)\n", brush
, clone
);
45 return InvalidParameter
;
48 case BrushTypeSolidColor
:
50 *clone
= GdipAlloc(sizeof(GpSolidFill
));
51 if (!*clone
) return OutOfMemory
;
52 memcpy(*clone
, brush
, sizeof(GpSolidFill
));
55 case BrushTypeHatchFill
:
57 GpHatch
*hatch
= (GpHatch
*)brush
;
59 return GdipCreateHatchBrush(hatch
->hatchstyle
, hatch
->forecol
, hatch
->backcol
, (GpHatch
**)clone
);
61 case BrushTypePathGradient
:{
62 GpPathGradient
*src
, *dest
;
66 *clone
= GdipAlloc(sizeof(GpPathGradient
));
67 if (!*clone
) return OutOfMemory
;
69 src
= (GpPathGradient
*) brush
,
70 dest
= (GpPathGradient
*) *clone
;
72 memcpy(dest
, src
, sizeof(GpPathGradient
));
74 stat
= GdipClonePath(src
->path
, &dest
->path
);
81 dest
->transform
= src
->transform
;
84 count
= src
->blendcount
;
85 dest
->blendcount
= count
;
86 dest
->blendfac
= GdipAlloc(count
* sizeof(REAL
));
87 dest
->blendpos
= GdipAlloc(count
* sizeof(REAL
));
88 dest
->surroundcolors
= GdipAlloc(dest
->surroundcolorcount
* sizeof(ARGB
));
89 pcount
= dest
->pblendcount
;
92 dest
->pblendcolor
= GdipAlloc(pcount
* sizeof(ARGB
));
93 dest
->pblendpos
= GdipAlloc(pcount
* sizeof(REAL
));
96 if(!dest
->blendfac
|| !dest
->blendpos
|| !dest
->surroundcolors
||
97 (pcount
&& (!dest
->pblendcolor
|| !dest
->pblendpos
))){
98 GdipDeletePath(dest
->path
);
99 GdipFree(dest
->blendfac
);
100 GdipFree(dest
->blendpos
);
101 GdipFree(dest
->surroundcolors
);
102 GdipFree(dest
->pblendcolor
);
103 GdipFree(dest
->pblendpos
);
108 memcpy(dest
->blendfac
, src
->blendfac
, count
* sizeof(REAL
));
109 memcpy(dest
->blendpos
, src
->blendpos
, count
* sizeof(REAL
));
110 memcpy(dest
->surroundcolors
, src
->surroundcolors
, dest
->surroundcolorcount
* sizeof(ARGB
));
114 memcpy(dest
->pblendcolor
, src
->pblendcolor
, pcount
* sizeof(ARGB
));
115 memcpy(dest
->pblendpos
, src
->pblendpos
, pcount
* sizeof(REAL
));
120 case BrushTypeLinearGradient
:{
121 GpLineGradient
*dest
, *src
;
124 dest
= GdipAlloc(sizeof(GpLineGradient
));
125 if(!dest
) return OutOfMemory
;
127 src
= (GpLineGradient
*)brush
;
129 memcpy(dest
, src
, sizeof(GpLineGradient
));
131 count
= dest
->blendcount
;
132 dest
->blendfac
= GdipAlloc(count
* sizeof(REAL
));
133 dest
->blendpos
= GdipAlloc(count
* sizeof(REAL
));
134 pcount
= dest
->pblendcount
;
137 dest
->pblendcolor
= GdipAlloc(pcount
* sizeof(ARGB
));
138 dest
->pblendpos
= GdipAlloc(pcount
* sizeof(REAL
));
141 if (!dest
->blendfac
|| !dest
->blendpos
||
142 (pcount
&& (!dest
->pblendcolor
|| !dest
->pblendpos
)))
144 GdipFree(dest
->blendfac
);
145 GdipFree(dest
->blendpos
);
146 GdipFree(dest
->pblendcolor
);
147 GdipFree(dest
->pblendpos
);
152 memcpy(dest
->blendfac
, src
->blendfac
, count
* sizeof(REAL
));
153 memcpy(dest
->blendpos
, src
->blendpos
, count
* sizeof(REAL
));
157 memcpy(dest
->pblendcolor
, src
->pblendcolor
, pcount
* sizeof(ARGB
));
158 memcpy(dest
->pblendpos
, src
->pblendpos
, pcount
* sizeof(REAL
));
161 *clone
= &dest
->brush
;
164 case BrushTypeTextureFill
:
167 GpTexture
*texture
= (GpTexture
*)brush
;
168 GpTexture
*new_texture
;
171 stat
= GdipGetImageWidth(texture
->image
, &width
);
172 if (stat
!= Ok
) return stat
;
173 stat
= GdipGetImageHeight(texture
->image
, &height
);
174 if (stat
!= Ok
) return stat
;
176 stat
= GdipCreateTextureIA(texture
->image
, texture
->imageattributes
, 0, 0, width
, height
, &new_texture
);
180 new_texture
->transform
= texture
->transform
;
181 *clone
= (GpBrush
*)new_texture
;
189 ERR("not implemented for brush type %d\n", brush
->bt
);
190 return NotImplemented
;
193 TRACE("<-- %p\n", *clone
);
197 static const char HatchBrushes
[][8] = {
198 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HatchStyleHorizontal */
199 { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleVertical */
200 { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HatchStyleForwardDiagonal */
201 { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HatchStyleBackwardDiagonal */
202 { 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleCross */
203 { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }, /* HatchStyleDiagonalCross */
204 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80 }, /* HatchStyle05Percent */
205 { 0x00, 0x02, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88 }, /* HatchStyle10Percent */
206 { 0x00, 0x22, 0x00, 0xcc, 0x00, 0x22, 0x00, 0xcc }, /* HatchStyle20Percent */
207 { 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc }, /* HatchStyle25Percent */
208 { 0x00, 0xcc, 0x04, 0xcc, 0x00, 0xcc, 0x40, 0xcc }, /* HatchStyle30Percent */
209 { 0x44, 0xcc, 0x22, 0xcc, 0x44, 0xcc, 0x22, 0xcc }, /* HatchStyle40Percent */
210 { 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc }, /* HatchStyle50Percent */
211 { 0x55, 0xcd, 0x55, 0xee, 0x55, 0xdc, 0x55, 0xee }, /* HatchStyle60Percent */
212 { 0x55, 0xdd, 0x55, 0xff, 0x55, 0xdd, 0x55, 0xff }, /* HatchStyle70Percent */
213 { 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff }, /* HatchStyle75Percent */
214 { 0x55, 0xff, 0x59, 0xff, 0x55, 0xff, 0x99, 0xff }, /* HatchStyle80Percent */
215 { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xfd, 0xff }, /* HatchStyle90Percent */
216 { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 }, /* HatchStyleLightDownwardDiagonal */
217 { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 }, /* HatchStyleLightUpwardDiagonal */
218 { 0x99, 0x33, 0x66, 0xcc, 0x99, 0x33, 0x66, 0xcc }, /* HatchStyleDarkDownwardDiagonal */
219 { 0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33, 0x99 }, /* HatchStyleDarkUpwardDiagonal */
220 { 0xc1, 0x83, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0 }, /* HatchStyleWideDownwardDiagonal */
221 { 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x07, 0x83, 0xc1 }, /* HatchStyleWideUpwardDiagonal */
222 { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 }, /* HatchStyleLightVertical */
223 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff }, /* HatchStyleLightHorizontal */
224 { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, /* HatchStyleNarrowVertical */
225 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, /* HatchStyleNarrowHorizontal */
226 { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }, /* HatchStyleDarkVertical */
227 { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff }, /* HatchStyleDarkHorizontal */
230 GpStatus
get_hatch_data(HatchStyle hatchstyle
, const char **result
)
232 if (hatchstyle
< sizeof(HatchBrushes
) / sizeof(HatchBrushes
[0]))
234 *result
= HatchBrushes
[hatchstyle
];
238 return NotImplemented
;
241 /******************************************************************************
242 * GdipCreateHatchBrush [GDIPLUS.@]
244 GpStatus WINGDIPAPI
GdipCreateHatchBrush(HatchStyle hatchstyle
, ARGB forecol
, ARGB backcol
, GpHatch
**brush
)
246 TRACE("(%d, %d, %d, %p)\n", hatchstyle
, forecol
, backcol
, brush
);
248 if(!brush
) return InvalidParameter
;
250 *brush
= GdipAlloc(sizeof(GpHatch
));
251 if (!*brush
) return OutOfMemory
;
253 (*brush
)->brush
.bt
= BrushTypeHatchFill
;
254 (*brush
)->forecol
= forecol
;
255 (*brush
)->backcol
= backcol
;
256 (*brush
)->hatchstyle
= hatchstyle
;
257 TRACE("<-- %p\n", *brush
);
262 /******************************************************************************
263 * GdipCreateLineBrush [GDIPLUS.@]
265 GpStatus WINGDIPAPI
GdipCreateLineBrush(GDIPCONST GpPointF
* startpoint
,
266 GDIPCONST GpPointF
* endpoint
, ARGB startcolor
, ARGB endcolor
,
267 GpWrapMode wrap
, GpLineGradient
**line
)
269 TRACE("(%s, %s, %x, %x, %d, %p)\n", debugstr_pointf(startpoint
),
270 debugstr_pointf(endpoint
), startcolor
, endcolor
, wrap
, line
);
272 if(!line
|| !startpoint
|| !endpoint
|| wrap
== WrapModeClamp
)
273 return InvalidParameter
;
275 if (startpoint
->X
== endpoint
->X
&& startpoint
->Y
== endpoint
->Y
)
278 *line
= GdipAlloc(sizeof(GpLineGradient
));
279 if(!*line
) return OutOfMemory
;
281 (*line
)->brush
.bt
= BrushTypeLinearGradient
;
283 (*line
)->startpoint
.X
= startpoint
->X
;
284 (*line
)->startpoint
.Y
= startpoint
->Y
;
285 (*line
)->endpoint
.X
= endpoint
->X
;
286 (*line
)->endpoint
.Y
= endpoint
->Y
;
287 (*line
)->startcolor
= startcolor
;
288 (*line
)->endcolor
= endcolor
;
289 (*line
)->wrap
= wrap
;
290 (*line
)->gamma
= FALSE
;
292 (*line
)->rect
.X
= (startpoint
->X
< endpoint
->X
? startpoint
->X
: endpoint
->X
);
293 (*line
)->rect
.Y
= (startpoint
->Y
< endpoint
->Y
? startpoint
->Y
: endpoint
->Y
);
294 (*line
)->rect
.Width
= fabs(startpoint
->X
- endpoint
->X
);
295 (*line
)->rect
.Height
= fabs(startpoint
->Y
- endpoint
->Y
);
297 if ((*line
)->rect
.Width
== 0)
299 (*line
)->rect
.X
-= (*line
)->rect
.Height
/ 2.0f
;
300 (*line
)->rect
.Width
= (*line
)->rect
.Height
;
302 else if ((*line
)->rect
.Height
== 0)
304 (*line
)->rect
.Y
-= (*line
)->rect
.Width
/ 2.0f
;
305 (*line
)->rect
.Height
= (*line
)->rect
.Width
;
308 (*line
)->blendcount
= 1;
309 (*line
)->blendfac
= GdipAlloc(sizeof(REAL
));
310 (*line
)->blendpos
= GdipAlloc(sizeof(REAL
));
312 if (!(*line
)->blendfac
|| !(*line
)->blendpos
)
314 GdipFree((*line
)->blendfac
);
315 GdipFree((*line
)->blendpos
);
321 (*line
)->blendfac
[0] = 1.0f
;
322 (*line
)->blendpos
[0] = 1.0f
;
324 (*line
)->pblendcolor
= NULL
;
325 (*line
)->pblendpos
= NULL
;
326 (*line
)->pblendcount
= 0;
328 TRACE("<-- %p\n", *line
);
333 GpStatus WINGDIPAPI
GdipCreateLineBrushI(GDIPCONST GpPoint
* startpoint
,
334 GDIPCONST GpPoint
* endpoint
, ARGB startcolor
, ARGB endcolor
,
335 GpWrapMode wrap
, GpLineGradient
**line
)
340 TRACE("(%p, %p, %x, %x, %d, %p)\n", startpoint
, endpoint
,
341 startcolor
, endcolor
, wrap
, line
);
343 if(!startpoint
|| !endpoint
)
344 return InvalidParameter
;
346 stF
.X
= (REAL
)startpoint
->X
;
347 stF
.Y
= (REAL
)startpoint
->Y
;
348 endF
.X
= (REAL
)endpoint
->X
;
349 endF
.Y
= (REAL
)endpoint
->Y
;
351 return GdipCreateLineBrush(&stF
, &endF
, startcolor
, endcolor
, wrap
, line
);
354 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRect(GDIPCONST GpRectF
* rect
,
355 ARGB startcolor
, ARGB endcolor
, LinearGradientMode mode
, GpWrapMode wrap
,
356 GpLineGradient
**line
)
361 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect
, startcolor
, endcolor
, mode
,
365 return InvalidParameter
;
369 case LinearGradientModeHorizontal
:
372 end
.X
= rect
->X
+ rect
->Width
;
375 case LinearGradientModeVertical
:
379 end
.Y
= rect
->Y
+ rect
->Height
;
381 case LinearGradientModeForwardDiagonal
:
384 end
.X
= rect
->X
+ rect
->Width
;
385 end
.Y
= rect
->Y
+ rect
->Height
;
387 case LinearGradientModeBackwardDiagonal
:
388 start
.X
= rect
->X
+ rect
->Width
;
391 end
.Y
= rect
->Y
+ rect
->Height
;
394 return InvalidParameter
;
397 stat
= GdipCreateLineBrush(&start
, &end
, startcolor
, endcolor
, wrap
, line
);
400 (*line
)->rect
= *rect
;
405 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectI(GDIPCONST GpRect
* rect
,
406 ARGB startcolor
, ARGB endcolor
, LinearGradientMode mode
, GpWrapMode wrap
,
407 GpLineGradient
**line
)
411 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect
, startcolor
, endcolor
, mode
,
414 rectF
.X
= (REAL
) rect
->X
;
415 rectF
.Y
= (REAL
) rect
->Y
;
416 rectF
.Width
= (REAL
) rect
->Width
;
417 rectF
.Height
= (REAL
) rect
->Height
;
419 return GdipCreateLineBrushFromRect(&rectF
, startcolor
, endcolor
, mode
, wrap
, line
);
422 /******************************************************************************
423 * GdipCreateLineBrushFromRectWithAngle [GDIPLUS.@]
425 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF
* rect
,
426 ARGB startcolor
, ARGB endcolor
, REAL angle
, BOOL isAngleScalable
, GpWrapMode wrap
,
427 GpLineGradient
**line
)
430 LinearGradientMode mode
;
431 REAL width
, height
, exofs
, eyofs
;
432 REAL sin_angle
, cos_angle
, sin_cos_angle
;
434 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect
, startcolor
, endcolor
, angle
, isAngleScalable
,
437 sin_angle
= sinf(deg2rad(angle
));
438 cos_angle
= cosf(deg2rad(angle
));
439 sin_cos_angle
= sin_angle
* cos_angle
;
443 width
= height
= 1.0;
448 height
= rect
->Height
;
451 if (sin_cos_angle
>= 0)
452 mode
= LinearGradientModeForwardDiagonal
;
454 mode
= LinearGradientModeBackwardDiagonal
;
456 stat
= GdipCreateLineBrushFromRect(rect
, startcolor
, endcolor
, mode
, wrap
, line
);
460 if (sin_cos_angle
>= 0)
462 exofs
= width
* sin_cos_angle
+ height
* cos_angle
* cos_angle
;
463 eyofs
= width
* sin_angle
* sin_angle
+ height
* sin_cos_angle
;
467 exofs
= width
* sin_angle
* sin_angle
+ height
* sin_cos_angle
;
468 eyofs
= -width
* sin_cos_angle
+ height
* sin_angle
* sin_angle
;
473 exofs
= exofs
* rect
->Width
;
474 eyofs
= eyofs
* rect
->Height
;
479 (*line
)->endpoint
.X
= rect
->X
+ exofs
;
480 (*line
)->endpoint
.Y
= rect
->Y
+ eyofs
;
484 (*line
)->endpoint
.X
= (*line
)->startpoint
.X
;
485 (*line
)->endpoint
.Y
= (*line
)->startpoint
.Y
;
486 (*line
)->startpoint
.X
= rect
->X
+ exofs
;
487 (*line
)->startpoint
.Y
= rect
->Y
+ eyofs
;
494 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectWithAngleI(GDIPCONST GpRect
* rect
,
495 ARGB startcolor
, ARGB endcolor
, REAL angle
, BOOL isAngleScalable
, GpWrapMode wrap
,
496 GpLineGradient
**line
)
498 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect
, startcolor
, endcolor
, angle
, isAngleScalable
,
501 return GdipCreateLineBrushFromRectI(rect
, startcolor
, endcolor
, LinearGradientModeForwardDiagonal
,
505 static GpStatus
create_path_gradient(GpPath
*path
, ARGB centercolor
, GpPathGradient
**grad
)
510 return InvalidParameter
;
512 if (path
->pathdata
.Count
< 2)
515 GdipGetPathWorldBounds(path
, &bounds
, NULL
, NULL
);
517 *grad
= GdipAlloc(sizeof(GpPathGradient
));
523 GdipSetMatrixElements(&(*grad
)->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
525 (*grad
)->blendfac
= GdipAlloc(sizeof(REAL
));
526 (*grad
)->blendpos
= GdipAlloc(sizeof(REAL
));
527 (*grad
)->surroundcolors
= GdipAlloc(sizeof(ARGB
));
528 if(!(*grad
)->blendfac
|| !(*grad
)->blendpos
|| !(*grad
)->surroundcolors
){
529 GdipFree((*grad
)->blendfac
);
530 GdipFree((*grad
)->blendpos
);
531 GdipFree((*grad
)->surroundcolors
);
536 (*grad
)->blendfac
[0] = 1.0;
537 (*grad
)->blendpos
[0] = 1.0;
538 (*grad
)->blendcount
= 1;
540 (*grad
)->path
= path
;
542 (*grad
)->brush
.bt
= BrushTypePathGradient
;
543 (*grad
)->centercolor
= centercolor
;
544 (*grad
)->wrap
= WrapModeClamp
;
545 (*grad
)->gamma
= FALSE
;
546 /* FIXME: this should be set to the "centroid" of the path by default */
547 (*grad
)->center
.X
= bounds
.X
+ bounds
.Width
/ 2;
548 (*grad
)->center
.Y
= bounds
.Y
+ bounds
.Height
/ 2;
549 (*grad
)->focus
.X
= 0.0;
550 (*grad
)->focus
.Y
= 0.0;
551 (*grad
)->surroundcolors
[0] = 0xffffffff;
552 (*grad
)->surroundcolorcount
= 1;
554 TRACE("<-- %p\n", *grad
);
559 GpStatus WINGDIPAPI
GdipCreatePathGradient(GDIPCONST GpPointF
* points
,
560 INT count
, GpWrapMode wrap
, GpPathGradient
**grad
)
565 TRACE("(%p, %d, %d, %p)\n", points
, count
, wrap
, grad
);
568 return InvalidParameter
;
570 if(!points
|| count
<= 0)
573 stat
= GdipCreatePath(FillModeAlternate
, &path
);
577 stat
= GdipAddPathLine2(path
, points
, count
);
580 stat
= create_path_gradient(path
, 0xff000000, grad
);
583 GdipDeletePath(path
);
587 (*grad
)->wrap
= wrap
;
592 GpStatus WINGDIPAPI
GdipCreatePathGradientI(GDIPCONST GpPoint
* points
,
593 INT count
, GpWrapMode wrap
, GpPathGradient
**grad
)
598 TRACE("(%p, %d, %d, %p)\n", points
, count
, wrap
, grad
);
601 return InvalidParameter
;
603 if(!points
|| count
<= 0)
606 stat
= GdipCreatePath(FillModeAlternate
, &path
);
610 stat
= GdipAddPathLine2I(path
, points
, count
);
613 stat
= create_path_gradient(path
, 0xff000000, grad
);
616 GdipDeletePath(path
);
620 (*grad
)->wrap
= wrap
;
625 /******************************************************************************
626 * GdipCreatePathGradientFromPath [GDIPLUS.@]
628 GpStatus WINGDIPAPI
GdipCreatePathGradientFromPath(GDIPCONST GpPath
* path
,
629 GpPathGradient
**grad
)
634 TRACE("(%p, %p)\n", path
, grad
);
637 return InvalidParameter
;
642 stat
= GdipClonePath((GpPath
*)path
, &new_path
);
646 stat
= create_path_gradient(new_path
, 0xffffffff, grad
);
649 GdipDeletePath(new_path
);
655 /******************************************************************************
656 * GdipCreateSolidFill [GDIPLUS.@]
658 GpStatus WINGDIPAPI
GdipCreateSolidFill(ARGB color
, GpSolidFill
**sf
)
660 TRACE("(%x, %p)\n", color
, sf
);
662 if(!sf
) return InvalidParameter
;
664 *sf
= GdipAlloc(sizeof(GpSolidFill
));
665 if (!*sf
) return OutOfMemory
;
667 (*sf
)->brush
.bt
= BrushTypeSolidColor
;
668 (*sf
)->color
= color
;
670 TRACE("<-- %p\n", *sf
);
675 /******************************************************************************
676 * GdipCreateTexture [GDIPLUS.@]
679 * image [I] image to use
680 * wrapmode [I] optional
681 * texture [O] pointer to the resulting texturebrush
685 * FAILURE: element of GpStatus
687 GpStatus WINGDIPAPI
GdipCreateTexture(GpImage
*image
, GpWrapMode wrapmode
,
691 GpImageAttributes
*attributes
;
694 TRACE("%p, %d %p\n", image
, wrapmode
, texture
);
696 if (!(image
&& texture
))
697 return InvalidParameter
;
699 stat
= GdipGetImageWidth(image
, &width
);
700 if (stat
!= Ok
) return stat
;
701 stat
= GdipGetImageHeight(image
, &height
);
702 if (stat
!= Ok
) return stat
;
704 stat
= GdipCreateImageAttributes(&attributes
);
708 attributes
->wrap
= wrapmode
;
710 stat
= GdipCreateTextureIA(image
, attributes
, 0, 0, width
, height
,
713 GdipDisposeImageAttributes(attributes
);
719 /******************************************************************************
720 * GdipCreateTexture2 [GDIPLUS.@]
722 GpStatus WINGDIPAPI
GdipCreateTexture2(GpImage
*image
, GpWrapMode wrapmode
,
723 REAL x
, REAL y
, REAL width
, REAL height
, GpTexture
**texture
)
725 GpImageAttributes
*attributes
;
728 TRACE("%p %d %f %f %f %f %p\n", image
, wrapmode
,
729 x
, y
, width
, height
, texture
);
731 stat
= GdipCreateImageAttributes(&attributes
);
735 attributes
->wrap
= wrapmode
;
737 stat
= GdipCreateTextureIA(image
, attributes
, x
, y
, width
, height
,
740 GdipDisposeImageAttributes(attributes
);
746 /******************************************************************************
747 * GdipCreateTextureIA [GDIPLUS.@]
749 * FIXME: imageattr ignored
751 GpStatus WINGDIPAPI
GdipCreateTextureIA(GpImage
*image
,
752 GDIPCONST GpImageAttributes
*imageattr
, REAL x
, REAL y
, REAL width
,
753 REAL height
, GpTexture
**texture
)
756 GpImage
*new_image
=NULL
;
758 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %p)\n", image
, imageattr
, x
, y
, width
, height
,
761 if(!image
|| !texture
|| x
< 0.0 || y
< 0.0 || width
< 0.0 || height
< 0.0)
762 return InvalidParameter
;
766 if(image
->type
!= ImageTypeBitmap
){
767 FIXME("not implemented for image type %d\n", image
->type
);
768 return NotImplemented
;
771 status
= GdipCloneBitmapArea(x
, y
, width
, height
, PixelFormatDontCare
, (GpBitmap
*)image
, (GpBitmap
**)&new_image
);
775 *texture
= GdipAlloc(sizeof(GpTexture
));
777 status
= OutOfMemory
;
781 GdipSetMatrixElements(&(*texture
)->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
785 status
= GdipCloneImageAttributes(imageattr
, &(*texture
)->imageattributes
);
789 status
= GdipCreateImageAttributes(&(*texture
)->imageattributes
);
791 (*texture
)->imageattributes
->wrap
= WrapModeTile
;
795 (*texture
)->brush
.bt
= BrushTypeTextureFill
;
796 (*texture
)->image
= new_image
;
802 TRACE("<-- %p\n", *texture
);
808 GdipDisposeImageAttributes((*texture
)->imageattributes
);
812 GdipDisposeImage(new_image
);
813 TRACE("<-- error %u\n", status
);
819 /******************************************************************************
820 * GdipCreateTextureIAI [GDIPLUS.@]
822 GpStatus WINGDIPAPI
GdipCreateTextureIAI(GpImage
*image
, GDIPCONST GpImageAttributes
*imageattr
,
823 INT x
, INT y
, INT width
, INT height
, GpTexture
**texture
)
825 TRACE("(%p, %p, %d, %d, %d, %d, %p)\n", image
, imageattr
, x
, y
, width
, height
,
828 return GdipCreateTextureIA(image
,imageattr
,(REAL
)x
,(REAL
)y
,(REAL
)width
,(REAL
)height
,texture
);
831 GpStatus WINGDIPAPI
GdipCreateTexture2I(GpImage
*image
, GpWrapMode wrapmode
,
832 INT x
, INT y
, INT width
, INT height
, GpTexture
**texture
)
834 GpImageAttributes
*imageattr
;
837 TRACE("%p %d %d %d %d %d %p\n", image
, wrapmode
, x
, y
, width
, height
,
840 stat
= GdipCreateImageAttributes(&imageattr
);
844 imageattr
->wrap
= wrapmode
;
846 stat
= GdipCreateTextureIA(image
, imageattr
, x
, y
, width
, height
, texture
);
852 GpStatus WINGDIPAPI
GdipGetBrushType(GpBrush
*brush
, GpBrushType
*type
)
854 TRACE("(%p, %p)\n", brush
, type
);
856 if(!brush
|| !type
) return InvalidParameter
;
863 GpStatus WINGDIPAPI
GdipGetHatchBackgroundColor(GpHatch
*brush
, ARGB
*backcol
)
865 TRACE("(%p, %p)\n", brush
, backcol
);
867 if(!brush
|| !backcol
) return InvalidParameter
;
869 *backcol
= brush
->backcol
;
874 GpStatus WINGDIPAPI
GdipGetHatchForegroundColor(GpHatch
*brush
, ARGB
*forecol
)
876 TRACE("(%p, %p)\n", brush
, forecol
);
878 if(!brush
|| !forecol
) return InvalidParameter
;
880 *forecol
= brush
->forecol
;
885 GpStatus WINGDIPAPI
GdipGetHatchStyle(GpHatch
*brush
, HatchStyle
*hatchstyle
)
887 TRACE("(%p, %p)\n", brush
, hatchstyle
);
889 if(!brush
|| !hatchstyle
) return InvalidParameter
;
891 *hatchstyle
= brush
->hatchstyle
;
896 GpStatus WINGDIPAPI
GdipDeleteBrush(GpBrush
*brush
)
898 TRACE("(%p)\n", brush
);
900 if(!brush
) return InvalidParameter
;
904 case BrushTypePathGradient
:
905 GdipDeletePath(((GpPathGradient
*) brush
)->path
);
906 GdipFree(((GpPathGradient
*) brush
)->blendfac
);
907 GdipFree(((GpPathGradient
*) brush
)->blendpos
);
908 GdipFree(((GpPathGradient
*) brush
)->surroundcolors
);
909 GdipFree(((GpPathGradient
*) brush
)->pblendcolor
);
910 GdipFree(((GpPathGradient
*) brush
)->pblendpos
);
912 case BrushTypeLinearGradient
:
913 GdipFree(((GpLineGradient
*)brush
)->blendfac
);
914 GdipFree(((GpLineGradient
*)brush
)->blendpos
);
915 GdipFree(((GpLineGradient
*)brush
)->pblendcolor
);
916 GdipFree(((GpLineGradient
*)brush
)->pblendpos
);
918 case BrushTypeTextureFill
:
919 GdipDisposeImage(((GpTexture
*)brush
)->image
);
920 GdipDisposeImageAttributes(((GpTexture
*)brush
)->imageattributes
);
921 GdipFree(((GpTexture
*)brush
)->bitmap_bits
);
932 GpStatus WINGDIPAPI
GdipGetLineGammaCorrection(GpLineGradient
*line
,
935 TRACE("(%p, %p)\n", line
, usinggamma
);
937 if(!line
|| !usinggamma
)
938 return InvalidParameter
;
940 *usinggamma
= line
->gamma
;
945 GpStatus WINGDIPAPI
GdipGetLineWrapMode(GpLineGradient
*brush
, GpWrapMode
*wrapmode
)
947 TRACE("(%p, %p)\n", brush
, wrapmode
);
949 if(!brush
|| !wrapmode
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
950 return InvalidParameter
;
952 *wrapmode
= brush
->wrap
;
957 GpStatus WINGDIPAPI
GdipGetPathGradientBlend(GpPathGradient
*brush
, REAL
*blend
,
958 REAL
*positions
, INT count
)
960 TRACE("(%p, %p, %p, %d)\n", brush
, blend
, positions
, count
);
962 if(!brush
|| !blend
|| !positions
|| count
<= 0 || brush
->brush
.bt
!= BrushTypePathGradient
)
963 return InvalidParameter
;
965 if(count
< brush
->blendcount
)
966 return InsufficientBuffer
;
968 memcpy(blend
, brush
->blendfac
, count
*sizeof(REAL
));
969 if(brush
->blendcount
> 1){
970 memcpy(positions
, brush
->blendpos
, count
*sizeof(REAL
));
976 GpStatus WINGDIPAPI
GdipGetPathGradientBlendCount(GpPathGradient
*brush
, INT
*count
)
978 TRACE("(%p, %p)\n", brush
, count
);
980 if(!brush
|| !count
|| brush
->brush
.bt
!= BrushTypePathGradient
)
981 return InvalidParameter
;
983 *count
= brush
->blendcount
;
988 GpStatus WINGDIPAPI
GdipGetPathGradientCenterPoint(GpPathGradient
*grad
,
991 TRACE("(%p, %p)\n", grad
, point
);
993 if(!grad
|| !point
|| grad
->brush
.bt
!= BrushTypePathGradient
)
994 return InvalidParameter
;
996 point
->X
= grad
->center
.X
;
997 point
->Y
= grad
->center
.Y
;
1002 GpStatus WINGDIPAPI
GdipGetPathGradientCenterPointI(GpPathGradient
*grad
,
1008 TRACE("(%p, %p)\n", grad
, point
);
1011 return InvalidParameter
;
1013 ret
= GdipGetPathGradientCenterPoint(grad
,&ptf
);
1016 point
->X
= gdip_round(ptf
.X
);
1017 point
->Y
= gdip_round(ptf
.Y
);
1023 GpStatus WINGDIPAPI
GdipGetPathGradientCenterColor(GpPathGradient
*grad
,
1026 TRACE("(%p,%p)\n", grad
, colors
);
1028 if (!grad
|| !colors
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1029 return InvalidParameter
;
1031 *colors
= grad
->centercolor
;
1036 GpStatus WINGDIPAPI
GdipGetPathGradientFocusScales(GpPathGradient
*grad
,
1039 TRACE("(%p, %p, %p)\n", grad
, x
, y
);
1041 if(!grad
|| !x
|| !y
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1042 return InvalidParameter
;
1050 GpStatus WINGDIPAPI
GdipGetPathGradientGammaCorrection(GpPathGradient
*grad
,
1053 TRACE("(%p, %p)\n", grad
, gamma
);
1055 if(!grad
|| !gamma
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1056 return InvalidParameter
;
1058 *gamma
= grad
->gamma
;
1063 GpStatus WINGDIPAPI
GdipGetPathGradientPath(GpPathGradient
*grad
, GpPath
*path
)
1067 TRACE("(%p, %p)\n", grad
, path
);
1070 FIXME("not implemented\n");
1072 return NotImplemented
;
1075 GpStatus WINGDIPAPI
GdipGetPathGradientPointCount(GpPathGradient
*grad
,
1078 TRACE("(%p, %p)\n", grad
, count
);
1080 if(!grad
|| !count
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1081 return InvalidParameter
;
1083 *count
= grad
->path
->pathdata
.Count
;
1088 GpStatus WINGDIPAPI
GdipGetPathGradientRect(GpPathGradient
*brush
, GpRectF
*rect
)
1092 TRACE("(%p, %p)\n", brush
, rect
);
1094 if(!brush
|| !rect
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1095 return InvalidParameter
;
1097 stat
= GdipGetPathWorldBounds(brush
->path
, rect
, NULL
, NULL
);
1102 GpStatus WINGDIPAPI
GdipGetPathGradientRectI(GpPathGradient
*brush
, GpRect
*rect
)
1107 TRACE("(%p, %p)\n", brush
, rect
);
1110 return InvalidParameter
;
1112 stat
= GdipGetPathGradientRect(brush
, &rectf
);
1113 if(stat
!= Ok
) return stat
;
1115 rect
->X
= gdip_round(rectf
.X
);
1116 rect
->Y
= gdip_round(rectf
.Y
);
1117 rect
->Width
= gdip_round(rectf
.Width
);
1118 rect
->Height
= gdip_round(rectf
.Height
);
1123 GpStatus WINGDIPAPI
GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
1124 *grad
, ARGB
*argb
, INT
*count
)
1128 TRACE("(%p,%p,%p)\n", grad
, argb
, count
);
1130 if(!grad
|| !argb
|| !count
|| (*count
< grad
->path
->pathdata
.Count
) || grad
->brush
.bt
!= BrushTypePathGradient
)
1131 return InvalidParameter
;
1133 for (i
=0; i
<grad
->path
->pathdata
.Count
; i
++)
1135 if (i
< grad
->surroundcolorcount
)
1136 argb
[i
] = grad
->surroundcolors
[i
];
1138 argb
[i
] = grad
->surroundcolors
[grad
->surroundcolorcount
-1];
1141 *count
= grad
->surroundcolorcount
;
1146 GpStatus WINGDIPAPI
GdipGetPathGradientSurroundColorCount(GpPathGradient
*brush
, INT
*count
)
1148 TRACE("(%p, %p)\n", brush
, count
);
1150 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1151 return InvalidParameter
;
1153 /* Yes, this actually returns the number of points in the path (which is the
1154 * required size of a buffer to get the surround colors), rather than the
1155 * number of surround colors. The real count is returned when getting the
1157 *count
= brush
->path
->pathdata
.Count
;
1162 GpStatus WINGDIPAPI
GdipGetPathGradientWrapMode(GpPathGradient
*brush
,
1163 GpWrapMode
*wrapmode
)
1165 TRACE("(%p, %p)\n", brush
, wrapmode
);
1167 if(!brush
|| !wrapmode
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1168 return InvalidParameter
;
1170 *wrapmode
= brush
->wrap
;
1175 GpStatus WINGDIPAPI
GdipGetSolidFillColor(GpSolidFill
*sf
, ARGB
*argb
)
1177 TRACE("(%p, %p)\n", sf
, argb
);
1180 return InvalidParameter
;
1187 /******************************************************************************
1188 * GdipGetTextureImage [GDIPLUS.@]
1190 GpStatus WINGDIPAPI
GdipGetTextureImage(GpTexture
*brush
, GpImage
**image
)
1192 TRACE("(%p, %p)\n", brush
, image
);
1194 if(!brush
|| !image
)
1195 return InvalidParameter
;
1197 return GdipCloneImage(brush
->image
, image
);
1200 /******************************************************************************
1201 * GdipGetTextureTransform [GDIPLUS.@]
1203 GpStatus WINGDIPAPI
GdipGetTextureTransform(GpTexture
*brush
, GpMatrix
*matrix
)
1205 TRACE("(%p, %p)\n", brush
, matrix
);
1207 if(!brush
|| !matrix
)
1208 return InvalidParameter
;
1210 *matrix
= brush
->transform
;
1215 /******************************************************************************
1216 * GdipGetTextureWrapMode [GDIPLUS.@]
1218 GpStatus WINGDIPAPI
GdipGetTextureWrapMode(GpTexture
*brush
, GpWrapMode
*wrapmode
)
1220 TRACE("(%p, %p)\n", brush
, wrapmode
);
1222 if(!brush
|| !wrapmode
)
1223 return InvalidParameter
;
1225 *wrapmode
= brush
->imageattributes
->wrap
;
1230 /******************************************************************************
1231 * GdipMultiplyTextureTransform [GDIPLUS.@]
1233 GpStatus WINGDIPAPI
GdipMultiplyTextureTransform(GpTexture
* brush
,
1234 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
1236 TRACE("(%p, %p, %d)\n", brush
, matrix
, order
);
1238 if(!brush
|| !matrix
)
1239 return InvalidParameter
;
1241 return GdipMultiplyMatrix(&brush
->transform
, matrix
, order
);
1244 /******************************************************************************
1245 * GdipResetTextureTransform [GDIPLUS.@]
1247 GpStatus WINGDIPAPI
GdipResetTextureTransform(GpTexture
* brush
)
1249 TRACE("(%p)\n", brush
);
1252 return InvalidParameter
;
1254 return GdipSetMatrixElements(&brush
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1257 /******************************************************************************
1258 * GdipScaleTextureTransform [GDIPLUS.@]
1260 GpStatus WINGDIPAPI
GdipScaleTextureTransform(GpTexture
* brush
,
1261 REAL sx
, REAL sy
, GpMatrixOrder order
)
1263 TRACE("(%p, %.2f, %.2f, %d)\n", brush
, sx
, sy
, order
);
1266 return InvalidParameter
;
1268 return GdipScaleMatrix(&brush
->transform
, sx
, sy
, order
);
1271 GpStatus WINGDIPAPI
GdipSetLineBlend(GpLineGradient
*brush
,
1272 GDIPCONST REAL
*factors
, GDIPCONST REAL
* positions
, INT count
)
1274 REAL
*new_blendfac
, *new_blendpos
;
1276 TRACE("(%p, %p, %p, %i)\n", brush
, factors
, positions
, count
);
1278 if(!brush
|| !factors
|| !positions
|| count
<= 0 || brush
->brush
.bt
!= BrushTypeLinearGradient
||
1279 (count
>= 2 && (positions
[0] != 0.0f
|| positions
[count
-1] != 1.0f
)))
1280 return InvalidParameter
;
1282 new_blendfac
= GdipAlloc(count
* sizeof(REAL
));
1283 new_blendpos
= GdipAlloc(count
* sizeof(REAL
));
1285 if (!new_blendfac
|| !new_blendpos
)
1287 GdipFree(new_blendfac
);
1288 GdipFree(new_blendpos
);
1292 memcpy(new_blendfac
, factors
, count
* sizeof(REAL
));
1293 memcpy(new_blendpos
, positions
, count
* sizeof(REAL
));
1295 GdipFree(brush
->blendfac
);
1296 GdipFree(brush
->blendpos
);
1298 brush
->blendcount
= count
;
1299 brush
->blendfac
= new_blendfac
;
1300 brush
->blendpos
= new_blendpos
;
1305 GpStatus WINGDIPAPI
GdipGetLineBlend(GpLineGradient
*brush
, REAL
*factors
,
1306 REAL
*positions
, INT count
)
1308 TRACE("(%p, %p, %p, %i)\n", brush
, factors
, positions
, count
);
1310 if (!brush
|| !factors
|| !positions
|| count
<= 0 || brush
->brush
.bt
!= BrushTypeLinearGradient
)
1311 return InvalidParameter
;
1313 if (count
< brush
->blendcount
)
1314 return InsufficientBuffer
;
1316 memcpy(factors
, brush
->blendfac
, brush
->blendcount
* sizeof(REAL
));
1317 memcpy(positions
, brush
->blendpos
, brush
->blendcount
* sizeof(REAL
));
1322 GpStatus WINGDIPAPI
GdipGetLineBlendCount(GpLineGradient
*brush
, INT
*count
)
1324 TRACE("(%p, %p)\n", brush
, count
);
1326 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1327 return InvalidParameter
;
1329 *count
= brush
->blendcount
;
1334 GpStatus WINGDIPAPI
GdipSetLineGammaCorrection(GpLineGradient
*line
,
1337 TRACE("(%p, %d)\n", line
, usegamma
);
1339 if(!line
|| line
->brush
.bt
!= BrushTypeLinearGradient
)
1340 return InvalidParameter
;
1342 line
->gamma
= usegamma
;
1347 GpStatus WINGDIPAPI
GdipSetLineSigmaBlend(GpLineGradient
*line
, REAL focus
,
1354 const int precision
= 16;
1355 REAL erf_range
; /* we use values erf(-erf_range) through erf(+erf_range) */
1359 TRACE("(%p, %0.2f, %0.2f)\n", line
, focus
, scale
);
1361 if(!line
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0 || line
->brush
.bt
!= BrushTypeLinearGradient
)
1362 return InvalidParameter
;
1364 /* we want 2 standard deviations */
1365 erf_range
= 2.0 / sqrt(2);
1367 /* calculate the constants we need to normalize the error function to be
1368 between 0.0 and scale over the range we need */
1369 min_erf
= erf(-erf_range
);
1370 scale_erf
= scale
/ (-2.0 * min_erf
);
1376 for (i
=1; i
<precision
; i
++)
1378 positions
[i
] = focus
* i
/ precision
;
1379 factors
[i
] = scale_erf
* (erf(2 * erf_range
* i
/ precision
- erf_range
) - min_erf
);
1381 num_points
+= precision
;
1384 positions
[num_points
] = focus
;
1385 factors
[num_points
] = scale
;
1390 for (i
=1; i
<precision
; i
++)
1392 positions
[i
+num_points
-1] = (focus
+ ((1.0-focus
) * i
/ precision
));
1393 factors
[i
+num_points
-1] = scale_erf
* (erf(erf_range
- 2 * erf_range
* i
/ precision
) - min_erf
);
1395 num_points
+= precision
;
1396 positions
[num_points
-1] = 1.0;
1397 factors
[num_points
-1] = 0.0;
1400 return GdipSetLineBlend(line
, factors
, positions
, num_points
);
1403 GpStatus WINGDIPAPI
GdipSetLineWrapMode(GpLineGradient
*line
,
1406 TRACE("(%p, %d)\n", line
, wrap
);
1408 if(!line
|| wrap
== WrapModeClamp
|| line
->brush
.bt
!= BrushTypeLinearGradient
)
1409 return InvalidParameter
;
1416 GpStatus WINGDIPAPI
GdipSetPathGradientBlend(GpPathGradient
*brush
, GDIPCONST REAL
*blend
,
1417 GDIPCONST REAL
*pos
, INT count
)
1419 REAL
*new_blendfac
, *new_blendpos
;
1421 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1423 if(!brush
|| !blend
|| !pos
|| count
<= 0 || brush
->brush
.bt
!= BrushTypePathGradient
||
1424 (count
>= 2 && (pos
[0] != 0.0f
|| pos
[count
-1] != 1.0f
)))
1425 return InvalidParameter
;
1427 new_blendfac
= GdipAlloc(count
* sizeof(REAL
));
1428 new_blendpos
= GdipAlloc(count
* sizeof(REAL
));
1430 if (!new_blendfac
|| !new_blendpos
)
1432 GdipFree(new_blendfac
);
1433 GdipFree(new_blendpos
);
1437 memcpy(new_blendfac
, blend
, count
* sizeof(REAL
));
1438 memcpy(new_blendpos
, pos
, count
* sizeof(REAL
));
1440 GdipFree(brush
->blendfac
);
1441 GdipFree(brush
->blendpos
);
1443 brush
->blendcount
= count
;
1444 brush
->blendfac
= new_blendfac
;
1445 brush
->blendpos
= new_blendpos
;
1450 GpStatus WINGDIPAPI
GdipSetPathGradientLinearBlend(GpPathGradient
*brush
,
1451 REAL focus
, REAL scale
)
1457 TRACE("(%p,%0.2f,%0.2f)\n", brush
, focus
, scale
);
1459 if (!brush
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1460 return InvalidParameter
;
1464 factors
[num_points
] = 0.0;
1465 positions
[num_points
] = 0.0;
1469 factors
[num_points
] = scale
;
1470 positions
[num_points
] = focus
;
1475 factors
[num_points
] = 0.0;
1476 positions
[num_points
] = 1.0;
1480 return GdipSetPathGradientBlend(brush
, factors
, positions
, num_points
);
1483 GpStatus WINGDIPAPI
GdipSetPathGradientPresetBlend(GpPathGradient
*brush
,
1484 GDIPCONST ARGB
*blend
, GDIPCONST REAL
*pos
, INT count
)
1488 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1490 if (!brush
|| !blend
|| !pos
|| count
< 2 || brush
->brush
.bt
!= BrushTypePathGradient
||
1491 pos
[0] != 0.0f
|| pos
[count
-1] != 1.0f
)
1493 return InvalidParameter
;
1496 new_color
= GdipAlloc(count
* sizeof(ARGB
));
1497 new_pos
= GdipAlloc(count
* sizeof(REAL
));
1498 if (!new_color
|| !new_pos
)
1500 GdipFree(new_color
);
1505 memcpy(new_color
, blend
, sizeof(ARGB
) * count
);
1506 memcpy(new_pos
, pos
, sizeof(REAL
) * count
);
1508 GdipFree(brush
->pblendcolor
);
1509 GdipFree(brush
->pblendpos
);
1511 brush
->pblendcolor
= new_color
;
1512 brush
->pblendpos
= new_pos
;
1513 brush
->pblendcount
= count
;
1518 GpStatus WINGDIPAPI
GdipGetPathGradientPresetBlend(GpPathGradient
*brush
,
1519 ARGB
*blend
, REAL
*pos
, INT count
)
1521 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1526 if (!brush
|| !blend
|| !pos
|| count
< 2 || brush
->brush
.bt
!= BrushTypePathGradient
)
1527 return InvalidParameter
;
1529 if (brush
->pblendcount
== 0)
1530 return GenericError
;
1532 if (count
!= brush
->pblendcount
)
1534 /* Native lines up the ends of each array, and copies the destination size. */
1535 FIXME("Braindead behavior on wrong-sized buffer not implemented.\n");
1536 return InvalidParameter
;
1539 memcpy(blend
, brush
->pblendcolor
, sizeof(ARGB
) * brush
->pblendcount
);
1540 memcpy(pos
, brush
->pblendpos
, sizeof(REAL
) * brush
->pblendcount
);
1545 GpStatus WINGDIPAPI
GdipGetPathGradientPresetBlendCount(GpPathGradient
*brush
,
1548 TRACE("(%p,%p)\n", brush
, count
);
1550 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypePathGradient
)
1551 return InvalidParameter
;
1553 *count
= brush
->pblendcount
;
1558 GpStatus WINGDIPAPI
GdipSetPathGradientCenterColor(GpPathGradient
*grad
,
1561 TRACE("(%p, %x)\n", grad
, argb
);
1563 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1564 return InvalidParameter
;
1566 grad
->centercolor
= argb
;
1570 GpStatus WINGDIPAPI
GdipSetPathGradientCenterPoint(GpPathGradient
*grad
,
1573 TRACE("(%p, %s)\n", grad
, debugstr_pointf(point
));
1575 if(!grad
|| !point
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1576 return InvalidParameter
;
1578 grad
->center
.X
= point
->X
;
1579 grad
->center
.Y
= point
->Y
;
1584 GpStatus WINGDIPAPI
GdipSetPathGradientCenterPointI(GpPathGradient
*grad
,
1589 TRACE("(%p, %p)\n", grad
, point
);
1592 return InvalidParameter
;
1594 ptf
.X
= (REAL
)point
->X
;
1595 ptf
.Y
= (REAL
)point
->Y
;
1597 return GdipSetPathGradientCenterPoint(grad
,&ptf
);
1600 GpStatus WINGDIPAPI
GdipSetPathGradientFocusScales(GpPathGradient
*grad
,
1603 TRACE("(%p, %.2f, %.2f)\n", grad
, x
, y
);
1605 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1606 return InvalidParameter
;
1614 GpStatus WINGDIPAPI
GdipSetPathGradientGammaCorrection(GpPathGradient
*grad
,
1617 TRACE("(%p, %d)\n", grad
, gamma
);
1619 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1620 return InvalidParameter
;
1622 grad
->gamma
= gamma
;
1627 GpStatus WINGDIPAPI
GdipSetPathGradientSigmaBlend(GpPathGradient
*grad
,
1628 REAL focus
, REAL scale
)
1634 const int precision
= 16;
1635 REAL erf_range
; /* we use values erf(-erf_range) through erf(+erf_range) */
1639 TRACE("(%p,%0.2f,%0.2f)\n", grad
, focus
, scale
);
1641 if(!grad
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0 || grad
->brush
.bt
!= BrushTypePathGradient
)
1642 return InvalidParameter
;
1644 /* we want 2 standard deviations */
1645 erf_range
= 2.0 / sqrt(2);
1647 /* calculate the constants we need to normalize the error function to be
1648 between 0.0 and scale over the range we need */
1649 min_erf
= erf(-erf_range
);
1650 scale_erf
= scale
/ (-2.0 * min_erf
);
1656 for (i
=1; i
<precision
; i
++)
1658 positions
[i
] = focus
* i
/ precision
;
1659 factors
[i
] = scale_erf
* (erf(2 * erf_range
* i
/ precision
- erf_range
) - min_erf
);
1661 num_points
+= precision
;
1664 positions
[num_points
] = focus
;
1665 factors
[num_points
] = scale
;
1670 for (i
=1; i
<precision
; i
++)
1672 positions
[i
+num_points
-1] = (focus
+ ((1.0-focus
) * i
/ precision
));
1673 factors
[i
+num_points
-1] = scale_erf
* (erf(erf_range
- 2 * erf_range
* i
/ precision
) - min_erf
);
1675 num_points
+= precision
;
1676 positions
[num_points
-1] = 1.0;
1677 factors
[num_points
-1] = 0.0;
1680 return GdipSetPathGradientBlend(grad
, factors
, positions
, num_points
);
1683 GpStatus WINGDIPAPI
GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
1684 *grad
, GDIPCONST ARGB
*argb
, INT
*count
)
1686 ARGB
*new_surroundcolors
;
1689 TRACE("(%p,%p,%p)\n", grad
, argb
, count
);
1691 if(!grad
|| !argb
|| !count
|| (*count
<= 0) || grad
->brush
.bt
!= BrushTypePathGradient
||
1692 (*count
> grad
->path
->pathdata
.Count
))
1693 return InvalidParameter
;
1695 num_colors
= *count
;
1697 /* If all colors are the same, only store 1 color. */
1700 for (i
=1; i
< num_colors
; i
++)
1701 if (argb
[i
] != argb
[i
-1])
1704 if (i
== num_colors
)
1708 new_surroundcolors
= GdipAlloc(num_colors
* sizeof(ARGB
));
1709 if (!new_surroundcolors
)
1712 memcpy(new_surroundcolors
, argb
, num_colors
* sizeof(ARGB
));
1714 GdipFree(grad
->surroundcolors
);
1716 grad
->surroundcolors
= new_surroundcolors
;
1717 grad
->surroundcolorcount
= num_colors
;
1722 GpStatus WINGDIPAPI
GdipSetPathGradientWrapMode(GpPathGradient
*grad
,
1725 TRACE("(%p, %d)\n", grad
, wrap
);
1727 if(!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1728 return InvalidParameter
;
1735 GpStatus WINGDIPAPI
GdipSetPathGradientTransform(GpPathGradient
*grad
,
1738 TRACE("(%p,%p)\n", grad
, matrix
);
1740 if (!grad
|| !matrix
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1741 return InvalidParameter
;
1743 grad
->transform
= *matrix
;
1748 GpStatus WINGDIPAPI
GdipGetPathGradientTransform(GpPathGradient
*grad
,
1751 TRACE("(%p,%p)\n", grad
, matrix
);
1753 if (!grad
|| !matrix
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1754 return InvalidParameter
;
1756 *matrix
= grad
->transform
;
1761 GpStatus WINGDIPAPI
GdipMultiplyPathGradientTransform(GpPathGradient
*grad
,
1762 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
1764 TRACE("(%p,%p,%i)\n", grad
, matrix
, order
);
1766 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1767 return InvalidParameter
;
1769 return GdipMultiplyMatrix(&grad
->transform
, matrix
, order
);
1772 GpStatus WINGDIPAPI
GdipResetPathGradientTransform(GpPathGradient
*grad
)
1774 TRACE("(%p)\n", grad
);
1776 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1777 return InvalidParameter
;
1779 return GdipSetMatrixElements(&grad
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1782 GpStatus WINGDIPAPI
GdipRotatePathGradientTransform(GpPathGradient
*grad
,
1783 REAL angle
, GpMatrixOrder order
)
1785 TRACE("(%p,%0.2f,%i)\n", grad
, angle
, order
);
1787 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1788 return InvalidParameter
;
1790 return GdipRotateMatrix(&grad
->transform
, angle
, order
);
1793 GpStatus WINGDIPAPI
GdipScalePathGradientTransform(GpPathGradient
*grad
,
1794 REAL sx
, REAL sy
, GpMatrixOrder order
)
1796 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad
, sx
, sy
, order
);
1798 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1799 return InvalidParameter
;
1801 return GdipScaleMatrix(&grad
->transform
, sx
, sy
, order
);
1804 GpStatus WINGDIPAPI
GdipTranslatePathGradientTransform(GpPathGradient
*grad
,
1805 REAL dx
, REAL dy
, GpMatrixOrder order
)
1807 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad
, dx
, dy
, order
);
1809 if (!grad
|| grad
->brush
.bt
!= BrushTypePathGradient
)
1810 return InvalidParameter
;
1812 return GdipTranslateMatrix(&grad
->transform
, dx
, dy
, order
);
1815 GpStatus WINGDIPAPI
GdipSetSolidFillColor(GpSolidFill
*sf
, ARGB argb
)
1817 TRACE("(%p, %x)\n", sf
, argb
);
1820 return InvalidParameter
;
1826 /******************************************************************************
1827 * GdipSetTextureTransform [GDIPLUS.@]
1829 GpStatus WINGDIPAPI
GdipSetTextureTransform(GpTexture
*texture
,
1830 GDIPCONST GpMatrix
*matrix
)
1832 TRACE("(%p, %p)\n", texture
, matrix
);
1834 if(!texture
|| !matrix
)
1835 return InvalidParameter
;
1837 texture
->transform
= *matrix
;
1842 /******************************************************************************
1843 * GdipSetTextureWrapMode [GDIPLUS.@]
1845 * WrapMode not used, only stored
1847 GpStatus WINGDIPAPI
GdipSetTextureWrapMode(GpTexture
*brush
, GpWrapMode wrapmode
)
1849 TRACE("(%p, %d)\n", brush
, wrapmode
);
1852 return InvalidParameter
;
1854 brush
->imageattributes
->wrap
= wrapmode
;
1859 GpStatus WINGDIPAPI
GdipSetLineColors(GpLineGradient
*brush
, ARGB color1
,
1862 TRACE("(%p, %x, %x)\n", brush
, color1
, color2
);
1864 if(!brush
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1865 return InvalidParameter
;
1867 brush
->startcolor
= color1
;
1868 brush
->endcolor
= color2
;
1873 GpStatus WINGDIPAPI
GdipGetLineColors(GpLineGradient
*brush
, ARGB
*colors
)
1875 TRACE("(%p, %p)\n", brush
, colors
);
1877 if(!brush
|| !colors
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1878 return InvalidParameter
;
1880 colors
[0] = brush
->startcolor
;
1881 colors
[1] = brush
->endcolor
;
1886 /******************************************************************************
1887 * GdipRotateTextureTransform [GDIPLUS.@]
1889 GpStatus WINGDIPAPI
GdipRotateTextureTransform(GpTexture
* brush
, REAL angle
,
1890 GpMatrixOrder order
)
1892 TRACE("(%p, %.2f, %d)\n", brush
, angle
, order
);
1895 return InvalidParameter
;
1897 return GdipRotateMatrix(&brush
->transform
, angle
, order
);
1900 GpStatus WINGDIPAPI
GdipSetLineLinearBlend(GpLineGradient
*brush
, REAL focus
,
1907 TRACE("(%p,%.2f,%.2f)\n", brush
, focus
, scale
);
1909 if (!brush
) return InvalidParameter
;
1913 factors
[num_points
] = 0.0;
1914 positions
[num_points
] = 0.0;
1918 factors
[num_points
] = scale
;
1919 positions
[num_points
] = focus
;
1924 factors
[num_points
] = 0.0;
1925 positions
[num_points
] = 1.0;
1929 return GdipSetLineBlend(brush
, factors
, positions
, num_points
);
1932 GpStatus WINGDIPAPI
GdipSetLinePresetBlend(GpLineGradient
*brush
,
1933 GDIPCONST ARGB
*blend
, GDIPCONST REAL
* positions
, INT count
)
1937 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, positions
, count
);
1939 if (!brush
|| !blend
|| !positions
|| count
< 2 || brush
->brush
.bt
!= BrushTypeLinearGradient
||
1940 positions
[0] != 0.0f
|| positions
[count
-1] != 1.0f
)
1942 return InvalidParameter
;
1945 new_color
= GdipAlloc(count
* sizeof(ARGB
));
1946 new_pos
= GdipAlloc(count
* sizeof(REAL
));
1947 if (!new_color
|| !new_pos
)
1949 GdipFree(new_color
);
1954 memcpy(new_color
, blend
, sizeof(ARGB
) * count
);
1955 memcpy(new_pos
, positions
, sizeof(REAL
) * count
);
1957 GdipFree(brush
->pblendcolor
);
1958 GdipFree(brush
->pblendpos
);
1960 brush
->pblendcolor
= new_color
;
1961 brush
->pblendpos
= new_pos
;
1962 brush
->pblendcount
= count
;
1967 GpStatus WINGDIPAPI
GdipGetLinePresetBlend(GpLineGradient
*brush
,
1968 ARGB
*blend
, REAL
* positions
, INT count
)
1970 if (!brush
|| !blend
|| !positions
|| count
< 2 || brush
->brush
.bt
!= BrushTypeLinearGradient
)
1971 return InvalidParameter
;
1973 if (brush
->pblendcount
== 0)
1974 return GenericError
;
1976 if (count
< brush
->pblendcount
)
1977 return InsufficientBuffer
;
1979 memcpy(blend
, brush
->pblendcolor
, sizeof(ARGB
) * brush
->pblendcount
);
1980 memcpy(positions
, brush
->pblendpos
, sizeof(REAL
) * brush
->pblendcount
);
1985 GpStatus WINGDIPAPI
GdipGetLinePresetBlendCount(GpLineGradient
*brush
,
1988 if (!brush
|| !count
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
1989 return InvalidParameter
;
1991 *count
= brush
->pblendcount
;
1996 GpStatus WINGDIPAPI
GdipResetLineTransform(GpLineGradient
*brush
)
2000 TRACE("(%p)\n", brush
);
2003 FIXME("not implemented\n");
2005 return NotImplemented
;
2008 GpStatus WINGDIPAPI
GdipSetLineTransform(GpLineGradient
*brush
,
2009 GDIPCONST GpMatrix
*matrix
)
2013 TRACE("(%p,%p)\n", brush
, matrix
);
2016 FIXME("not implemented\n");
2018 return NotImplemented
;
2021 GpStatus WINGDIPAPI
GdipGetLineTransform(GpLineGradient
*brush
, GpMatrix
*matrix
)
2025 TRACE("(%p,%p)\n", brush
, matrix
);
2028 FIXME("not implemented\n");
2030 return NotImplemented
;
2033 GpStatus WINGDIPAPI
GdipScaleLineTransform(GpLineGradient
*brush
, REAL sx
, REAL sy
,
2034 GpMatrixOrder order
)
2038 TRACE("(%p,%0.2f,%0.2f,%u)\n", brush
, sx
, sy
, order
);
2041 FIXME("not implemented\n");
2043 return NotImplemented
;
2046 GpStatus WINGDIPAPI
GdipMultiplyLineTransform(GpLineGradient
*brush
,
2047 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
2051 TRACE("(%p,%p,%u)\n", brush
, matrix
, order
);
2054 FIXME("not implemented\n");
2056 return NotImplemented
;
2059 GpStatus WINGDIPAPI
GdipTranslateLineTransform(GpLineGradient
* brush
,
2060 REAL dx
, REAL dy
, GpMatrixOrder order
)
2064 TRACE("(%p,%f,%f,%d)\n", brush
, dx
, dy
, order
);
2067 FIXME("not implemented\n");
2072 /******************************************************************************
2073 * GdipTranslateTextureTransform [GDIPLUS.@]
2075 GpStatus WINGDIPAPI
GdipTranslateTextureTransform(GpTexture
* brush
, REAL dx
, REAL dy
,
2076 GpMatrixOrder order
)
2078 TRACE("(%p, %.2f, %.2f, %d)\n", brush
, dx
, dy
, order
);
2081 return InvalidParameter
;
2083 return GdipTranslateMatrix(&brush
->transform
, dx
, dy
, order
);
2086 GpStatus WINGDIPAPI
GdipGetLineRect(GpLineGradient
*brush
, GpRectF
*rect
)
2088 TRACE("(%p, %p)\n", brush
, rect
);
2090 if(!brush
|| !rect
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
2091 return InvalidParameter
;
2093 *rect
= brush
->rect
;
2098 GpStatus WINGDIPAPI
GdipGetLineRectI(GpLineGradient
*brush
, GpRect
*rect
)
2103 TRACE("(%p, %p)\n", brush
, rect
);
2106 return InvalidParameter
;
2108 ret
= GdipGetLineRect(brush
, &rectF
);
2111 rect
->X
= gdip_round(rectF
.X
);
2112 rect
->Y
= gdip_round(rectF
.Y
);
2113 rect
->Width
= gdip_round(rectF
.Width
);
2114 rect
->Height
= gdip_round(rectF
.Height
);
2120 GpStatus WINGDIPAPI
GdipRotateLineTransform(GpLineGradient
* brush
,
2121 REAL angle
, GpMatrixOrder order
)
2125 TRACE("(%p,%0.2f,%u)\n", brush
, angle
, order
);
2127 if(!brush
|| brush
->brush
.bt
!= BrushTypeLinearGradient
)
2128 return InvalidParameter
;
2131 FIXME("(%p, %.2f, %d) stub\n", brush
, angle
, order
);
2133 return NotImplemented
;