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 stat
= GdipCloneMatrix(src
->transform
, &dest
->transform
);
84 GdipDeletePath(dest
->path
);
90 count
= src
->blendcount
;
91 dest
->blendcount
= count
;
92 dest
->blendfac
= GdipAlloc(count
* sizeof(REAL
));
93 dest
->blendpos
= GdipAlloc(count
* sizeof(REAL
));
94 dest
->surroundcolors
= GdipAlloc(dest
->surroundcolorcount
* sizeof(ARGB
));
95 pcount
= dest
->pblendcount
;
98 dest
->pblendcolor
= GdipAlloc(pcount
* sizeof(ARGB
));
99 dest
->pblendpos
= GdipAlloc(pcount
* sizeof(REAL
));
102 if(!dest
->blendfac
|| !dest
->blendpos
|| !dest
->surroundcolors
||
103 (pcount
&& (!dest
->pblendcolor
|| !dest
->pblendpos
))){
104 GdipDeletePath(dest
->path
);
105 GdipDeleteMatrix(dest
->transform
);
106 GdipFree(dest
->blendfac
);
107 GdipFree(dest
->blendpos
);
108 GdipFree(dest
->surroundcolors
);
109 GdipFree(dest
->pblendcolor
);
110 GdipFree(dest
->pblendpos
);
115 memcpy(dest
->blendfac
, src
->blendfac
, count
* sizeof(REAL
));
116 memcpy(dest
->blendpos
, src
->blendpos
, count
* sizeof(REAL
));
117 memcpy(dest
->surroundcolors
, src
->surroundcolors
, dest
->surroundcolorcount
* sizeof(ARGB
));
121 memcpy(dest
->pblendcolor
, src
->pblendcolor
, pcount
* sizeof(ARGB
));
122 memcpy(dest
->pblendpos
, src
->pblendpos
, pcount
* sizeof(REAL
));
127 case BrushTypeLinearGradient
:{
128 GpLineGradient
*dest
, *src
;
131 dest
= GdipAlloc(sizeof(GpLineGradient
));
132 if(!dest
) return OutOfMemory
;
134 src
= (GpLineGradient
*)brush
;
136 memcpy(dest
, src
, sizeof(GpLineGradient
));
138 count
= dest
->blendcount
;
139 dest
->blendfac
= GdipAlloc(count
* sizeof(REAL
));
140 dest
->blendpos
= GdipAlloc(count
* sizeof(REAL
));
141 pcount
= dest
->pblendcount
;
144 dest
->pblendcolor
= GdipAlloc(pcount
* sizeof(ARGB
));
145 dest
->pblendpos
= GdipAlloc(pcount
* sizeof(REAL
));
148 if (!dest
->blendfac
|| !dest
->blendpos
||
149 (pcount
&& (!dest
->pblendcolor
|| !dest
->pblendpos
)))
151 GdipFree(dest
->blendfac
);
152 GdipFree(dest
->blendpos
);
153 GdipFree(dest
->pblendcolor
);
154 GdipFree(dest
->pblendpos
);
159 memcpy(dest
->blendfac
, src
->blendfac
, count
* sizeof(REAL
));
160 memcpy(dest
->blendpos
, src
->blendpos
, count
* sizeof(REAL
));
164 memcpy(dest
->pblendcolor
, src
->pblendcolor
, pcount
* sizeof(ARGB
));
165 memcpy(dest
->pblendpos
, src
->pblendpos
, pcount
* sizeof(REAL
));
168 *clone
= &dest
->brush
;
171 case BrushTypeTextureFill
:
174 GpTexture
*texture
= (GpTexture
*)brush
;
175 GpTexture
*new_texture
;
178 stat
= GdipGetImageWidth(texture
->image
, &width
);
179 if (stat
!= Ok
) return stat
;
180 stat
= GdipGetImageHeight(texture
->image
, &height
);
181 if (stat
!= Ok
) return stat
;
183 stat
= GdipCreateTextureIA(texture
->image
, texture
->imageattributes
, 0, 0, width
, height
, &new_texture
);
187 memcpy(new_texture
->transform
, texture
->transform
, sizeof(GpMatrix
));
188 *clone
= (GpBrush
*)new_texture
;
196 ERR("not implemented for brush type %d\n", brush
->bt
);
197 return NotImplemented
;
200 TRACE("<-- %p\n", *clone
);
204 static const char HatchBrushes
[][8] = {
205 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HatchStyleHorizontal */
206 { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleVertical */
207 { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HatchStyleForwardDiagonal */
208 { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HatchStyleBackwardDiagonal */
209 { 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleCross */
210 { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }, /* HatchStyleDiagonalCross */
211 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80 }, /* HatchStyle05Percent */
212 { 0x00, 0x02, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88 }, /* HatchStyle10Percent */
213 { 0x00, 0x22, 0x00, 0xcc, 0x00, 0x22, 0x00, 0xcc }, /* HatchStyle20Percent */
214 { 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc }, /* HatchStyle25Percent */
215 { 0x00, 0xcc, 0x04, 0xcc, 0x00, 0xcc, 0x40, 0xcc }, /* HatchStyle30Percent */
216 { 0x44, 0xcc, 0x22, 0xcc, 0x44, 0xcc, 0x22, 0xcc }, /* HatchStyle40Percent */
217 { 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc }, /* HatchStyle50Percent */
218 { 0x55, 0xcd, 0x55, 0xee, 0x55, 0xdc, 0x55, 0xee }, /* HatchStyle60Percent */
219 { 0x55, 0xdd, 0x55, 0xff, 0x55, 0xdd, 0x55, 0xff }, /* HatchStyle70Percent */
220 { 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff }, /* HatchStyle75Percent */
221 { 0x55, 0xff, 0x59, 0xff, 0x55, 0xff, 0x99, 0xff }, /* HatchStyle80Percent */
222 { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xfd, 0xff }, /* HatchStyle90Percent */
223 { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 }, /* HatchStyleLightDownwardDiagonal */
224 { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 }, /* HatchStyleLightUpwardDiagonal */
225 { 0x99, 0x33, 0x66, 0xcc, 0x99, 0x33, 0x66, 0xcc }, /* HatchStyleDarkDownwardDiagonal */
226 { 0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33, 0x99 }, /* HatchStyleDarkUpwardDiagonal */
227 { 0xc1, 0x83, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0 }, /* HatchStyleWideDownwardDiagonal */
228 { 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x07, 0x83, 0xc1 }, /* HatchStyleWideUpwardDiagonal */
229 { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 }, /* HatchStyleLightVertical */
230 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff }, /* HatchStyleLightHorizontal */
231 { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, /* HatchStyleNarrowVertical */
232 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, /* HatchStyleNarrowHorizontal */
233 { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }, /* HatchStyleDarkVertical */
234 { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff }, /* HatchStyleDarkHorizontal */
237 GpStatus
get_hatch_data(HatchStyle hatchstyle
, const char **result
)
239 if (hatchstyle
< sizeof(HatchBrushes
) / sizeof(HatchBrushes
[0]))
241 *result
= HatchBrushes
[hatchstyle
];
245 return NotImplemented
;
248 /******************************************************************************
249 * GdipCreateHatchBrush [GDIPLUS.@]
251 GpStatus WINGDIPAPI
GdipCreateHatchBrush(HatchStyle hatchstyle
, ARGB forecol
, ARGB backcol
, GpHatch
**brush
)
253 TRACE("(%d, %d, %d, %p)\n", hatchstyle
, forecol
, backcol
, brush
);
255 if(!brush
) return InvalidParameter
;
257 *brush
= GdipAlloc(sizeof(GpHatch
));
258 if (!*brush
) return OutOfMemory
;
260 (*brush
)->brush
.bt
= BrushTypeHatchFill
;
261 (*brush
)->forecol
= forecol
;
262 (*brush
)->backcol
= backcol
;
263 (*brush
)->hatchstyle
= hatchstyle
;
264 TRACE("<-- %p\n", *brush
);
269 /******************************************************************************
270 * GdipCreateLineBrush [GDIPLUS.@]
272 GpStatus WINGDIPAPI
GdipCreateLineBrush(GDIPCONST GpPointF
* startpoint
,
273 GDIPCONST GpPointF
* endpoint
, ARGB startcolor
, ARGB endcolor
,
274 GpWrapMode wrap
, GpLineGradient
**line
)
276 TRACE("(%s, %s, %x, %x, %d, %p)\n", debugstr_pointf(startpoint
),
277 debugstr_pointf(endpoint
), startcolor
, endcolor
, wrap
, line
);
279 if(!line
|| !startpoint
|| !endpoint
|| wrap
== WrapModeClamp
)
280 return InvalidParameter
;
282 if (startpoint
->X
== endpoint
->X
&& startpoint
->Y
== endpoint
->Y
)
285 *line
= GdipAlloc(sizeof(GpLineGradient
));
286 if(!*line
) return OutOfMemory
;
288 (*line
)->brush
.bt
= BrushTypeLinearGradient
;
290 (*line
)->startpoint
.X
= startpoint
->X
;
291 (*line
)->startpoint
.Y
= startpoint
->Y
;
292 (*line
)->endpoint
.X
= endpoint
->X
;
293 (*line
)->endpoint
.Y
= endpoint
->Y
;
294 (*line
)->startcolor
= startcolor
;
295 (*line
)->endcolor
= endcolor
;
296 (*line
)->wrap
= wrap
;
297 (*line
)->gamma
= FALSE
;
299 (*line
)->rect
.X
= (startpoint
->X
< endpoint
->X
? startpoint
->X
: endpoint
->X
);
300 (*line
)->rect
.Y
= (startpoint
->Y
< endpoint
->Y
? startpoint
->Y
: endpoint
->Y
);
301 (*line
)->rect
.Width
= fabs(startpoint
->X
- endpoint
->X
);
302 (*line
)->rect
.Height
= fabs(startpoint
->Y
- endpoint
->Y
);
304 if ((*line
)->rect
.Width
== 0)
306 (*line
)->rect
.X
-= (*line
)->rect
.Height
/ 2.0f
;
307 (*line
)->rect
.Width
= (*line
)->rect
.Height
;
309 else if ((*line
)->rect
.Height
== 0)
311 (*line
)->rect
.Y
-= (*line
)->rect
.Width
/ 2.0f
;
312 (*line
)->rect
.Height
= (*line
)->rect
.Width
;
315 (*line
)->blendcount
= 1;
316 (*line
)->blendfac
= GdipAlloc(sizeof(REAL
));
317 (*line
)->blendpos
= GdipAlloc(sizeof(REAL
));
319 if (!(*line
)->blendfac
|| !(*line
)->blendpos
)
321 GdipFree((*line
)->blendfac
);
322 GdipFree((*line
)->blendpos
);
328 (*line
)->blendfac
[0] = 1.0f
;
329 (*line
)->blendpos
[0] = 1.0f
;
331 (*line
)->pblendcolor
= NULL
;
332 (*line
)->pblendpos
= NULL
;
333 (*line
)->pblendcount
= 0;
335 TRACE("<-- %p\n", *line
);
340 GpStatus WINGDIPAPI
GdipCreateLineBrushI(GDIPCONST GpPoint
* startpoint
,
341 GDIPCONST GpPoint
* endpoint
, ARGB startcolor
, ARGB endcolor
,
342 GpWrapMode wrap
, GpLineGradient
**line
)
347 TRACE("(%p, %p, %x, %x, %d, %p)\n", startpoint
, endpoint
,
348 startcolor
, endcolor
, wrap
, line
);
350 if(!startpoint
|| !endpoint
)
351 return InvalidParameter
;
353 stF
.X
= (REAL
)startpoint
->X
;
354 stF
.Y
= (REAL
)startpoint
->Y
;
355 endF
.X
= (REAL
)endpoint
->X
;
356 endF
.Y
= (REAL
)endpoint
->Y
;
358 return GdipCreateLineBrush(&stF
, &endF
, startcolor
, endcolor
, wrap
, line
);
361 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRect(GDIPCONST GpRectF
* rect
,
362 ARGB startcolor
, ARGB endcolor
, LinearGradientMode mode
, GpWrapMode wrap
,
363 GpLineGradient
**line
)
368 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect
, startcolor
, endcolor
, mode
,
372 return InvalidParameter
;
376 case LinearGradientModeHorizontal
:
379 end
.X
= rect
->X
+ rect
->Width
;
382 case LinearGradientModeVertical
:
386 end
.Y
= rect
->Y
+ rect
->Height
;
388 case LinearGradientModeForwardDiagonal
:
391 end
.X
= rect
->X
+ rect
->Width
;
392 end
.Y
= rect
->Y
+ rect
->Height
;
394 case LinearGradientModeBackwardDiagonal
:
395 start
.X
= rect
->X
+ rect
->Width
;
398 end
.Y
= rect
->Y
+ rect
->Height
;
401 return InvalidParameter
;
404 stat
= GdipCreateLineBrush(&start
, &end
, startcolor
, endcolor
, wrap
, line
);
407 (*line
)->rect
= *rect
;
412 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectI(GDIPCONST GpRect
* rect
,
413 ARGB startcolor
, ARGB endcolor
, LinearGradientMode mode
, GpWrapMode wrap
,
414 GpLineGradient
**line
)
418 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect
, startcolor
, endcolor
, mode
,
421 rectF
.X
= (REAL
) rect
->X
;
422 rectF
.Y
= (REAL
) rect
->Y
;
423 rectF
.Width
= (REAL
) rect
->Width
;
424 rectF
.Height
= (REAL
) rect
->Height
;
426 return GdipCreateLineBrushFromRect(&rectF
, startcolor
, endcolor
, mode
, wrap
, line
);
429 /******************************************************************************
430 * GdipCreateLineBrushFromRectWithAngle [GDIPLUS.@]
432 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF
* rect
,
433 ARGB startcolor
, ARGB endcolor
, REAL angle
, BOOL isAngleScalable
, GpWrapMode wrap
,
434 GpLineGradient
**line
)
437 LinearGradientMode mode
;
438 REAL width
, height
, exofs
, eyofs
;
439 REAL sin_angle
, cos_angle
, sin_cos_angle
;
441 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect
, startcolor
, endcolor
, angle
, isAngleScalable
,
444 sin_angle
= sinf(deg2rad(angle
));
445 cos_angle
= cosf(deg2rad(angle
));
446 sin_cos_angle
= sin_angle
* cos_angle
;
450 width
= height
= 1.0;
455 height
= rect
->Height
;
458 if (sin_cos_angle
>= 0)
459 mode
= LinearGradientModeForwardDiagonal
;
461 mode
= LinearGradientModeBackwardDiagonal
;
463 stat
= GdipCreateLineBrushFromRect(rect
, startcolor
, endcolor
, mode
, wrap
, line
);
467 if (sin_cos_angle
>= 0)
469 exofs
= width
* sin_cos_angle
+ height
* cos_angle
* cos_angle
;
470 eyofs
= width
* sin_angle
* sin_angle
+ height
* sin_cos_angle
;
474 exofs
= width
* sin_angle
* sin_angle
+ height
* sin_cos_angle
;
475 eyofs
= -width
* sin_cos_angle
+ height
* sin_angle
* sin_angle
;
480 exofs
= exofs
* rect
->Width
;
481 eyofs
= eyofs
* rect
->Height
;
486 (*line
)->endpoint
.X
= rect
->X
+ exofs
;
487 (*line
)->endpoint
.Y
= rect
->Y
+ eyofs
;
491 (*line
)->endpoint
.X
= (*line
)->startpoint
.X
;
492 (*line
)->endpoint
.Y
= (*line
)->startpoint
.Y
;
493 (*line
)->startpoint
.X
= rect
->X
+ exofs
;
494 (*line
)->startpoint
.Y
= rect
->Y
+ eyofs
;
501 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectWithAngleI(GDIPCONST GpRect
* rect
,
502 ARGB startcolor
, ARGB endcolor
, REAL angle
, BOOL isAngleScalable
, GpWrapMode wrap
,
503 GpLineGradient
**line
)
505 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect
, startcolor
, endcolor
, angle
, isAngleScalable
,
508 return GdipCreateLineBrushFromRectI(rect
, startcolor
, endcolor
, LinearGradientModeForwardDiagonal
,
512 static GpStatus
create_path_gradient(GpPath
*path
, ARGB centercolor
, GpPathGradient
**grad
)
518 return InvalidParameter
;
520 if (path
->pathdata
.Count
< 2)
523 GdipGetPathWorldBounds(path
, &bounds
, NULL
, NULL
);
525 *grad
= GdipAlloc(sizeof(GpPathGradient
));
531 stat
= GdipCreateMatrix(&(*grad
)->transform
);
538 (*grad
)->blendfac
= GdipAlloc(sizeof(REAL
));
539 (*grad
)->blendpos
= GdipAlloc(sizeof(REAL
));
540 (*grad
)->surroundcolors
= GdipAlloc(sizeof(ARGB
));
541 if(!(*grad
)->blendfac
|| !(*grad
)->blendpos
|| !(*grad
)->surroundcolors
){
542 GdipDeleteMatrix((*grad
)->transform
);
543 GdipFree((*grad
)->blendfac
);
544 GdipFree((*grad
)->blendpos
);
545 GdipFree((*grad
)->surroundcolors
);
550 (*grad
)->blendfac
[0] = 1.0;
551 (*grad
)->blendpos
[0] = 1.0;
552 (*grad
)->blendcount
= 1;
554 (*grad
)->path
= path
;
556 (*grad
)->brush
.bt
= BrushTypePathGradient
;
557 (*grad
)->centercolor
= centercolor
;
558 (*grad
)->wrap
= WrapModeClamp
;
559 (*grad
)->gamma
= FALSE
;
560 /* FIXME: this should be set to the "centroid" of the path by default */
561 (*grad
)->center
.X
= bounds
.X
+ bounds
.Width
/ 2;
562 (*grad
)->center
.Y
= bounds
.Y
+ bounds
.Height
/ 2;
563 (*grad
)->focus
.X
= 0.0;
564 (*grad
)->focus
.Y
= 0.0;
565 (*grad
)->surroundcolors
[0] = 0xffffffff;
566 (*grad
)->surroundcolorcount
= 1;
568 TRACE("<-- %p\n", *grad
);
573 GpStatus WINGDIPAPI
GdipCreatePathGradient(GDIPCONST GpPointF
* points
,
574 INT count
, GpWrapMode wrap
, GpPathGradient
**grad
)
579 TRACE("(%p, %d, %d, %p)\n", points
, count
, wrap
, grad
);
582 return InvalidParameter
;
584 if(!points
|| count
<= 0)
587 stat
= GdipCreatePath(FillModeAlternate
, &path
);
591 stat
= GdipAddPathLine2(path
, points
, count
);
594 stat
= create_path_gradient(path
, 0xff000000, grad
);
597 GdipDeletePath(path
);
601 (*grad
)->wrap
= wrap
;
606 GpStatus WINGDIPAPI
GdipCreatePathGradientI(GDIPCONST GpPoint
* points
,
607 INT count
, GpWrapMode wrap
, GpPathGradient
**grad
)
612 TRACE("(%p, %d, %d, %p)\n", points
, count
, wrap
, grad
);
615 return InvalidParameter
;
617 if(!points
|| count
<= 0)
620 stat
= GdipCreatePath(FillModeAlternate
, &path
);
624 stat
= GdipAddPathLine2I(path
, points
, count
);
627 stat
= create_path_gradient(path
, 0xff000000, grad
);
630 GdipDeletePath(path
);
634 (*grad
)->wrap
= wrap
;
639 /******************************************************************************
640 * GdipCreatePathGradientFromPath [GDIPLUS.@]
642 GpStatus WINGDIPAPI
GdipCreatePathGradientFromPath(GDIPCONST GpPath
* path
,
643 GpPathGradient
**grad
)
648 TRACE("(%p, %p)\n", path
, grad
);
651 return InvalidParameter
;
656 stat
= GdipClonePath((GpPath
*)path
, &new_path
);
660 stat
= create_path_gradient(new_path
, 0xffffffff, grad
);
663 GdipDeletePath(new_path
);
669 /******************************************************************************
670 * GdipCreateSolidFill [GDIPLUS.@]
672 GpStatus WINGDIPAPI
GdipCreateSolidFill(ARGB color
, GpSolidFill
**sf
)
674 TRACE("(%x, %p)\n", color
, sf
);
676 if(!sf
) return InvalidParameter
;
678 *sf
= GdipAlloc(sizeof(GpSolidFill
));
679 if (!*sf
) return OutOfMemory
;
681 (*sf
)->brush
.bt
= BrushTypeSolidColor
;
682 (*sf
)->color
= color
;
684 TRACE("<-- %p\n", *sf
);
689 /******************************************************************************
690 * GdipCreateTexture [GDIPLUS.@]
693 * image [I] image to use
694 * wrapmode [I] optional
695 * texture [O] pointer to the resulting texturebrush
699 * FAILURE: element of GpStatus
701 GpStatus WINGDIPAPI
GdipCreateTexture(GpImage
*image
, GpWrapMode wrapmode
,
705 GpImageAttributes
*attributes
;
708 TRACE("%p, %d %p\n", image
, wrapmode
, texture
);
710 if (!(image
&& texture
))
711 return InvalidParameter
;
713 stat
= GdipGetImageWidth(image
, &width
);
714 if (stat
!= Ok
) return stat
;
715 stat
= GdipGetImageHeight(image
, &height
);
716 if (stat
!= Ok
) return stat
;
718 stat
= GdipCreateImageAttributes(&attributes
);
722 attributes
->wrap
= wrapmode
;
724 stat
= GdipCreateTextureIA(image
, attributes
, 0, 0, width
, height
,
727 GdipDisposeImageAttributes(attributes
);
733 /******************************************************************************
734 * GdipCreateTexture2 [GDIPLUS.@]
736 GpStatus WINGDIPAPI
GdipCreateTexture2(GpImage
*image
, GpWrapMode wrapmode
,
737 REAL x
, REAL y
, REAL width
, REAL height
, GpTexture
**texture
)
739 GpImageAttributes
*attributes
;
742 TRACE("%p %d %f %f %f %f %p\n", image
, wrapmode
,
743 x
, y
, width
, height
, texture
);
745 stat
= GdipCreateImageAttributes(&attributes
);
749 attributes
->wrap
= wrapmode
;
751 stat
= GdipCreateTextureIA(image
, attributes
, x
, y
, width
, height
,
754 GdipDisposeImageAttributes(attributes
);
760 /******************************************************************************
761 * GdipCreateTextureIA [GDIPLUS.@]
763 * FIXME: imageattr ignored
765 GpStatus WINGDIPAPI
GdipCreateTextureIA(GpImage
*image
,
766 GDIPCONST GpImageAttributes
*imageattr
, REAL x
, REAL y
, REAL width
,
767 REAL height
, GpTexture
**texture
)
770 GpImage
*new_image
=NULL
;
772 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %p)\n", image
, imageattr
, x
, y
, width
, height
,
775 if(!image
|| !texture
|| x
< 0.0 || y
< 0.0 || width
< 0.0 || height
< 0.0)
776 return InvalidParameter
;
780 if(image
->type
!= ImageTypeBitmap
){
781 FIXME("not implemented for image type %d\n", image
->type
);
782 return NotImplemented
;
785 status
= GdipCloneBitmapArea(x
, y
, width
, height
, PixelFormatDontCare
, (GpBitmap
*)image
, (GpBitmap
**)&new_image
);
789 *texture
= GdipAlloc(sizeof(GpTexture
));
791 status
= OutOfMemory
;
795 if((status
= GdipCreateMatrix(&(*texture
)->transform
)) != Ok
){
801 status
= GdipCloneImageAttributes(imageattr
, &(*texture
)->imageattributes
);
805 status
= GdipCreateImageAttributes(&(*texture
)->imageattributes
);
807 (*texture
)->imageattributes
->wrap
= WrapModeTile
;
811 (*texture
)->brush
.bt
= BrushTypeTextureFill
;
812 (*texture
)->image
= new_image
;
818 TRACE("<-- %p\n", *texture
);
824 GdipDeleteMatrix((*texture
)->transform
);
825 GdipDisposeImageAttributes((*texture
)->imageattributes
);
829 GdipDisposeImage(new_image
);
830 TRACE("<-- error %u\n", status
);
836 /******************************************************************************
837 * GdipCreateTextureIAI [GDIPLUS.@]
839 GpStatus WINGDIPAPI
GdipCreateTextureIAI(GpImage
*image
, GDIPCONST GpImageAttributes
*imageattr
,
840 INT x
, INT y
, INT width
, INT height
, GpTexture
**texture
)
842 TRACE("(%p, %p, %d, %d, %d, %d, %p)\n", image
, imageattr
, x
, y
, width
, height
,
845 return GdipCreateTextureIA(image
,imageattr
,(REAL
)x
,(REAL
)y
,(REAL
)width
,(REAL
)height
,texture
);
848 GpStatus WINGDIPAPI
GdipCreateTexture2I(GpImage
*image
, GpWrapMode wrapmode
,
849 INT x
, INT y
, INT width
, INT height
, GpTexture
**texture
)
851 GpImageAttributes
*imageattr
;
854 TRACE("%p %d %d %d %d %d %p\n", image
, wrapmode
, x
, y
, width
, height
,
857 stat
= GdipCreateImageAttributes(&imageattr
);
861 imageattr
->wrap
= wrapmode
;
863 stat
= GdipCreateTextureIA(image
, imageattr
, x
, y
, width
, height
, texture
);
869 GpStatus WINGDIPAPI
GdipGetBrushType(GpBrush
*brush
, GpBrushType
*type
)
871 TRACE("(%p, %p)\n", brush
, type
);
873 if(!brush
|| !type
) return InvalidParameter
;
880 GpStatus WINGDIPAPI
GdipGetHatchBackgroundColor(GpHatch
*brush
, ARGB
*backcol
)
882 TRACE("(%p, %p)\n", brush
, backcol
);
884 if(!brush
|| !backcol
) return InvalidParameter
;
886 *backcol
= brush
->backcol
;
891 GpStatus WINGDIPAPI
GdipGetHatchForegroundColor(GpHatch
*brush
, ARGB
*forecol
)
893 TRACE("(%p, %p)\n", brush
, forecol
);
895 if(!brush
|| !forecol
) return InvalidParameter
;
897 *forecol
= brush
->forecol
;
902 GpStatus WINGDIPAPI
GdipGetHatchStyle(GpHatch
*brush
, HatchStyle
*hatchstyle
)
904 TRACE("(%p, %p)\n", brush
, hatchstyle
);
906 if(!brush
|| !hatchstyle
) return InvalidParameter
;
908 *hatchstyle
= brush
->hatchstyle
;
913 GpStatus WINGDIPAPI
GdipDeleteBrush(GpBrush
*brush
)
915 TRACE("(%p)\n", brush
);
917 if(!brush
) return InvalidParameter
;
921 case BrushTypePathGradient
:
922 GdipDeletePath(((GpPathGradient
*) brush
)->path
);
923 GdipDeleteMatrix(((GpPathGradient
*) brush
)->transform
);
924 GdipFree(((GpPathGradient
*) brush
)->blendfac
);
925 GdipFree(((GpPathGradient
*) brush
)->blendpos
);
926 GdipFree(((GpPathGradient
*) brush
)->surroundcolors
);
927 GdipFree(((GpPathGradient
*) brush
)->pblendcolor
);
928 GdipFree(((GpPathGradient
*) brush
)->pblendpos
);
930 case BrushTypeLinearGradient
:
931 GdipFree(((GpLineGradient
*)brush
)->blendfac
);
932 GdipFree(((GpLineGradient
*)brush
)->blendpos
);
933 GdipFree(((GpLineGradient
*)brush
)->pblendcolor
);
934 GdipFree(((GpLineGradient
*)brush
)->pblendpos
);
936 case BrushTypeTextureFill
:
937 GdipDeleteMatrix(((GpTexture
*)brush
)->transform
);
938 GdipDisposeImage(((GpTexture
*)brush
)->image
);
939 GdipDisposeImageAttributes(((GpTexture
*)brush
)->imageattributes
);
940 GdipFree(((GpTexture
*)brush
)->bitmap_bits
);
951 GpStatus WINGDIPAPI
GdipGetLineGammaCorrection(GpLineGradient
*line
,
954 TRACE("(%p, %p)\n", line
, usinggamma
);
956 if(!line
|| !usinggamma
)
957 return InvalidParameter
;
959 *usinggamma
= line
->gamma
;
964 GpStatus WINGDIPAPI
GdipGetLineWrapMode(GpLineGradient
*brush
, GpWrapMode
*wrapmode
)
966 TRACE("(%p, %p)\n", brush
, wrapmode
);
968 if(!brush
|| !wrapmode
)
969 return InvalidParameter
;
971 *wrapmode
= brush
->wrap
;
976 GpStatus WINGDIPAPI
GdipGetPathGradientBlend(GpPathGradient
*brush
, REAL
*blend
,
977 REAL
*positions
, INT count
)
979 TRACE("(%p, %p, %p, %d)\n", brush
, blend
, positions
, count
);
981 if(!brush
|| !blend
|| !positions
|| count
<= 0)
982 return InvalidParameter
;
984 if(count
< brush
->blendcount
)
985 return InsufficientBuffer
;
987 memcpy(blend
, brush
->blendfac
, count
*sizeof(REAL
));
988 if(brush
->blendcount
> 1){
989 memcpy(positions
, brush
->blendpos
, count
*sizeof(REAL
));
995 GpStatus WINGDIPAPI
GdipGetPathGradientBlendCount(GpPathGradient
*brush
, INT
*count
)
997 TRACE("(%p, %p)\n", brush
, count
);
1000 return InvalidParameter
;
1002 *count
= brush
->blendcount
;
1007 GpStatus WINGDIPAPI
GdipGetPathGradientCenterPoint(GpPathGradient
*grad
,
1010 TRACE("(%p, %p)\n", grad
, point
);
1013 return InvalidParameter
;
1015 point
->X
= grad
->center
.X
;
1016 point
->Y
= grad
->center
.Y
;
1021 GpStatus WINGDIPAPI
GdipGetPathGradientCenterPointI(GpPathGradient
*grad
,
1027 TRACE("(%p, %p)\n", grad
, point
);
1030 return InvalidParameter
;
1032 ret
= GdipGetPathGradientCenterPoint(grad
,&ptf
);
1035 point
->X
= gdip_round(ptf
.X
);
1036 point
->Y
= gdip_round(ptf
.Y
);
1042 GpStatus WINGDIPAPI
GdipGetPathGradientCenterColor(GpPathGradient
*grad
,
1045 TRACE("(%p,%p)\n", grad
, colors
);
1047 if (!grad
|| !colors
)
1048 return InvalidParameter
;
1050 *colors
= grad
->centercolor
;
1055 GpStatus WINGDIPAPI
GdipGetPathGradientFocusScales(GpPathGradient
*grad
,
1058 TRACE("(%p, %p, %p)\n", grad
, x
, y
);
1060 if(!grad
|| !x
|| !y
)
1061 return InvalidParameter
;
1069 GpStatus WINGDIPAPI
GdipGetPathGradientGammaCorrection(GpPathGradient
*grad
,
1072 TRACE("(%p, %p)\n", grad
, gamma
);
1075 return InvalidParameter
;
1077 *gamma
= grad
->gamma
;
1082 GpStatus WINGDIPAPI
GdipGetPathGradientPath(GpPathGradient
*grad
, GpPath
*path
)
1086 TRACE("(%p, %p)\n", grad
, path
);
1089 FIXME("not implemented\n");
1091 return NotImplemented
;
1094 GpStatus WINGDIPAPI
GdipGetPathGradientPointCount(GpPathGradient
*grad
,
1097 TRACE("(%p, %p)\n", grad
, count
);
1100 return InvalidParameter
;
1102 *count
= grad
->path
->pathdata
.Count
;
1107 GpStatus WINGDIPAPI
GdipGetPathGradientRect(GpPathGradient
*brush
, GpRectF
*rect
)
1111 TRACE("(%p, %p)\n", brush
, rect
);
1114 return InvalidParameter
;
1116 stat
= GdipGetPathWorldBounds(brush
->path
, rect
, NULL
, NULL
);
1121 GpStatus WINGDIPAPI
GdipGetPathGradientRectI(GpPathGradient
*brush
, GpRect
*rect
)
1126 TRACE("(%p, %p)\n", brush
, rect
);
1129 return InvalidParameter
;
1131 stat
= GdipGetPathGradientRect(brush
, &rectf
);
1132 if(stat
!= Ok
) return stat
;
1134 rect
->X
= gdip_round(rectf
.X
);
1135 rect
->Y
= gdip_round(rectf
.Y
);
1136 rect
->Width
= gdip_round(rectf
.Width
);
1137 rect
->Height
= gdip_round(rectf
.Height
);
1142 GpStatus WINGDIPAPI
GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
1143 *grad
, ARGB
*argb
, INT
*count
)
1147 TRACE("(%p,%p,%p)\n", grad
, argb
, count
);
1149 if(!grad
|| !argb
|| !count
|| (*count
< grad
->path
->pathdata
.Count
))
1150 return InvalidParameter
;
1152 for (i
=0; i
<grad
->path
->pathdata
.Count
; i
++)
1154 if (i
< grad
->surroundcolorcount
)
1155 argb
[i
] = grad
->surroundcolors
[i
];
1157 argb
[i
] = grad
->surroundcolors
[grad
->surroundcolorcount
-1];
1160 *count
= grad
->surroundcolorcount
;
1165 GpStatus WINGDIPAPI
GdipGetPathGradientSurroundColorCount(GpPathGradient
*brush
, INT
*count
)
1167 TRACE("(%p, %p)\n", brush
, count
);
1169 if (!brush
|| !count
)
1170 return InvalidParameter
;
1172 /* Yes, this actually returns the number of points in the path (which is the
1173 * required size of a buffer to get the surround colors), rather than the
1174 * number of surround colors. The real count is returned when getting the
1176 *count
= brush
->path
->pathdata
.Count
;
1181 GpStatus WINGDIPAPI
GdipGetPathGradientWrapMode(GpPathGradient
*brush
,
1182 GpWrapMode
*wrapmode
)
1184 TRACE("(%p, %p)\n", brush
, wrapmode
);
1186 if(!brush
|| !wrapmode
)
1187 return InvalidParameter
;
1189 *wrapmode
= brush
->wrap
;
1194 GpStatus WINGDIPAPI
GdipGetSolidFillColor(GpSolidFill
*sf
, ARGB
*argb
)
1196 TRACE("(%p, %p)\n", sf
, argb
);
1199 return InvalidParameter
;
1206 /******************************************************************************
1207 * GdipGetTextureImage [GDIPLUS.@]
1209 GpStatus WINGDIPAPI
GdipGetTextureImage(GpTexture
*brush
, GpImage
**image
)
1211 TRACE("(%p, %p)\n", brush
, image
);
1213 if(!brush
|| !image
)
1214 return InvalidParameter
;
1216 return GdipCloneImage(brush
->image
, image
);
1219 /******************************************************************************
1220 * GdipGetTextureTransform [GDIPLUS.@]
1222 GpStatus WINGDIPAPI
GdipGetTextureTransform(GpTexture
*brush
, GpMatrix
*matrix
)
1224 TRACE("(%p, %p)\n", brush
, matrix
);
1226 if(!brush
|| !matrix
)
1227 return InvalidParameter
;
1229 memcpy(matrix
, brush
->transform
, sizeof(GpMatrix
));
1234 /******************************************************************************
1235 * GdipGetTextureWrapMode [GDIPLUS.@]
1237 GpStatus WINGDIPAPI
GdipGetTextureWrapMode(GpTexture
*brush
, GpWrapMode
*wrapmode
)
1239 TRACE("(%p, %p)\n", brush
, wrapmode
);
1241 if(!brush
|| !wrapmode
)
1242 return InvalidParameter
;
1244 *wrapmode
= brush
->imageattributes
->wrap
;
1249 /******************************************************************************
1250 * GdipMultiplyTextureTransform [GDIPLUS.@]
1252 GpStatus WINGDIPAPI
GdipMultiplyTextureTransform(GpTexture
* brush
,
1253 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
1255 TRACE("(%p, %p, %d)\n", brush
, matrix
, order
);
1257 if(!brush
|| !matrix
)
1258 return InvalidParameter
;
1260 return GdipMultiplyMatrix(brush
->transform
, matrix
, order
);
1263 /******************************************************************************
1264 * GdipResetTextureTransform [GDIPLUS.@]
1266 GpStatus WINGDIPAPI
GdipResetTextureTransform(GpTexture
* brush
)
1268 TRACE("(%p)\n", brush
);
1271 return InvalidParameter
;
1273 return GdipSetMatrixElements(brush
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1276 /******************************************************************************
1277 * GdipScaleTextureTransform [GDIPLUS.@]
1279 GpStatus WINGDIPAPI
GdipScaleTextureTransform(GpTexture
* brush
,
1280 REAL sx
, REAL sy
, GpMatrixOrder order
)
1282 TRACE("(%p, %.2f, %.2f, %d)\n", brush
, sx
, sy
, order
);
1285 return InvalidParameter
;
1287 return GdipScaleMatrix(brush
->transform
, sx
, sy
, order
);
1290 GpStatus WINGDIPAPI
GdipSetLineBlend(GpLineGradient
*brush
,
1291 GDIPCONST REAL
*factors
, GDIPCONST REAL
* positions
, INT count
)
1293 REAL
*new_blendfac
, *new_blendpos
;
1295 TRACE("(%p, %p, %p, %i)\n", brush
, factors
, positions
, count
);
1297 if(!brush
|| !factors
|| !positions
|| count
<= 0 ||
1298 (count
>= 2 && (positions
[0] != 0.0f
|| positions
[count
-1] != 1.0f
)))
1299 return InvalidParameter
;
1301 new_blendfac
= GdipAlloc(count
* sizeof(REAL
));
1302 new_blendpos
= GdipAlloc(count
* sizeof(REAL
));
1304 if (!new_blendfac
|| !new_blendpos
)
1306 GdipFree(new_blendfac
);
1307 GdipFree(new_blendpos
);
1311 memcpy(new_blendfac
, factors
, count
* sizeof(REAL
));
1312 memcpy(new_blendpos
, positions
, count
* sizeof(REAL
));
1314 GdipFree(brush
->blendfac
);
1315 GdipFree(brush
->blendpos
);
1317 brush
->blendcount
= count
;
1318 brush
->blendfac
= new_blendfac
;
1319 brush
->blendpos
= new_blendpos
;
1324 GpStatus WINGDIPAPI
GdipGetLineBlend(GpLineGradient
*brush
, REAL
*factors
,
1325 REAL
*positions
, INT count
)
1327 TRACE("(%p, %p, %p, %i)\n", brush
, factors
, positions
, count
);
1329 if (!brush
|| !factors
|| !positions
|| count
<= 0)
1330 return InvalidParameter
;
1332 if (count
< brush
->blendcount
)
1333 return InsufficientBuffer
;
1335 memcpy(factors
, brush
->blendfac
, brush
->blendcount
* sizeof(REAL
));
1336 memcpy(positions
, brush
->blendpos
, brush
->blendcount
* sizeof(REAL
));
1341 GpStatus WINGDIPAPI
GdipGetLineBlendCount(GpLineGradient
*brush
, INT
*count
)
1343 TRACE("(%p, %p)\n", brush
, count
);
1345 if (!brush
|| !count
)
1346 return InvalidParameter
;
1348 *count
= brush
->blendcount
;
1353 GpStatus WINGDIPAPI
GdipSetLineGammaCorrection(GpLineGradient
*line
,
1356 TRACE("(%p, %d)\n", line
, usegamma
);
1359 return InvalidParameter
;
1361 line
->gamma
= usegamma
;
1366 GpStatus WINGDIPAPI
GdipSetLineSigmaBlend(GpLineGradient
*line
, REAL focus
,
1373 const int precision
= 16;
1374 REAL erf_range
; /* we use values erf(-erf_range) through erf(+erf_range) */
1378 TRACE("(%p, %0.2f, %0.2f)\n", line
, focus
, scale
);
1380 if(!line
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0)
1381 return InvalidParameter
;
1383 /* we want 2 standard deviations */
1384 erf_range
= 2.0 / sqrt(2);
1386 /* calculate the constants we need to normalize the error function to be
1387 between 0.0 and scale over the range we need */
1388 min_erf
= erf(-erf_range
);
1389 scale_erf
= scale
/ (-2.0 * min_erf
);
1395 for (i
=1; i
<precision
; i
++)
1397 positions
[i
] = focus
* i
/ precision
;
1398 factors
[i
] = scale_erf
* (erf(2 * erf_range
* i
/ precision
- erf_range
) - min_erf
);
1400 num_points
+= precision
;
1403 positions
[num_points
] = focus
;
1404 factors
[num_points
] = scale
;
1409 for (i
=1; i
<precision
; i
++)
1411 positions
[i
+num_points
-1] = (focus
+ ((1.0-focus
) * i
/ precision
));
1412 factors
[i
+num_points
-1] = scale_erf
* (erf(erf_range
- 2 * erf_range
* i
/ precision
) - min_erf
);
1414 num_points
+= precision
;
1415 positions
[num_points
-1] = 1.0;
1416 factors
[num_points
-1] = 0.0;
1419 return GdipSetLineBlend(line
, factors
, positions
, num_points
);
1422 GpStatus WINGDIPAPI
GdipSetLineWrapMode(GpLineGradient
*line
,
1425 TRACE("(%p, %d)\n", line
, wrap
);
1427 if(!line
|| wrap
== WrapModeClamp
)
1428 return InvalidParameter
;
1435 GpStatus WINGDIPAPI
GdipSetPathGradientBlend(GpPathGradient
*brush
, GDIPCONST REAL
*blend
,
1436 GDIPCONST REAL
*pos
, INT count
)
1438 REAL
*new_blendfac
, *new_blendpos
;
1440 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1442 if(!brush
|| !blend
|| !pos
|| count
<= 0 ||
1443 (count
>= 2 && (pos
[0] != 0.0f
|| pos
[count
-1] != 1.0f
)))
1444 return InvalidParameter
;
1446 new_blendfac
= GdipAlloc(count
* sizeof(REAL
));
1447 new_blendpos
= GdipAlloc(count
* sizeof(REAL
));
1449 if (!new_blendfac
|| !new_blendpos
)
1451 GdipFree(new_blendfac
);
1452 GdipFree(new_blendpos
);
1456 memcpy(new_blendfac
, blend
, count
* sizeof(REAL
));
1457 memcpy(new_blendpos
, pos
, count
* sizeof(REAL
));
1459 GdipFree(brush
->blendfac
);
1460 GdipFree(brush
->blendpos
);
1462 brush
->blendcount
= count
;
1463 brush
->blendfac
= new_blendfac
;
1464 brush
->blendpos
= new_blendpos
;
1469 GpStatus WINGDIPAPI
GdipSetPathGradientLinearBlend(GpPathGradient
*brush
,
1470 REAL focus
, REAL scale
)
1476 TRACE("(%p,%0.2f,%0.2f)\n", brush
, focus
, scale
);
1478 if (!brush
) return InvalidParameter
;
1482 factors
[num_points
] = 0.0;
1483 positions
[num_points
] = 0.0;
1487 factors
[num_points
] = scale
;
1488 positions
[num_points
] = focus
;
1493 factors
[num_points
] = 0.0;
1494 positions
[num_points
] = 1.0;
1498 return GdipSetPathGradientBlend(brush
, factors
, positions
, num_points
);
1501 GpStatus WINGDIPAPI
GdipSetPathGradientPresetBlend(GpPathGradient
*brush
,
1502 GDIPCONST ARGB
*blend
, GDIPCONST REAL
*pos
, INT count
)
1506 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1508 if (!brush
|| !blend
|| !pos
|| count
< 2 ||
1509 pos
[0] != 0.0f
|| pos
[count
-1] != 1.0f
)
1511 return InvalidParameter
;
1514 new_color
= GdipAlloc(count
* sizeof(ARGB
));
1515 new_pos
= GdipAlloc(count
* sizeof(REAL
));
1516 if (!new_color
|| !new_pos
)
1518 GdipFree(new_color
);
1523 memcpy(new_color
, blend
, sizeof(ARGB
) * count
);
1524 memcpy(new_pos
, pos
, sizeof(REAL
) * count
);
1526 GdipFree(brush
->pblendcolor
);
1527 GdipFree(brush
->pblendpos
);
1529 brush
->pblendcolor
= new_color
;
1530 brush
->pblendpos
= new_pos
;
1531 brush
->pblendcount
= count
;
1536 GpStatus WINGDIPAPI
GdipGetPathGradientPresetBlend(GpPathGradient
*brush
,
1537 ARGB
*blend
, REAL
*pos
, INT count
)
1539 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1544 if (!brush
|| !blend
|| !pos
|| count
< 2)
1545 return InvalidParameter
;
1547 if (brush
->pblendcount
== 0)
1548 return GenericError
;
1550 if (count
!= brush
->pblendcount
)
1552 /* Native lines up the ends of each array, and copies the destination size. */
1553 FIXME("Braindead behavior on wrong-sized buffer not implemented.\n");
1554 return InvalidParameter
;
1557 memcpy(blend
, brush
->pblendcolor
, sizeof(ARGB
) * brush
->pblendcount
);
1558 memcpy(pos
, brush
->pblendpos
, sizeof(REAL
) * brush
->pblendcount
);
1563 GpStatus WINGDIPAPI
GdipGetPathGradientPresetBlendCount(GpPathGradient
*brush
,
1566 TRACE("(%p,%p)\n", brush
, count
);
1568 if (!brush
|| !count
)
1569 return InvalidParameter
;
1571 *count
= brush
->pblendcount
;
1576 GpStatus WINGDIPAPI
GdipSetPathGradientCenterColor(GpPathGradient
*grad
,
1579 TRACE("(%p, %x)\n", grad
, argb
);
1582 return InvalidParameter
;
1584 grad
->centercolor
= argb
;
1588 GpStatus WINGDIPAPI
GdipSetPathGradientCenterPoint(GpPathGradient
*grad
,
1591 TRACE("(%p, %s)\n", grad
, debugstr_pointf(point
));
1594 return InvalidParameter
;
1596 grad
->center
.X
= point
->X
;
1597 grad
->center
.Y
= point
->Y
;
1602 GpStatus WINGDIPAPI
GdipSetPathGradientCenterPointI(GpPathGradient
*grad
,
1607 TRACE("(%p, %p)\n", grad
, point
);
1610 return InvalidParameter
;
1612 ptf
.X
= (REAL
)point
->X
;
1613 ptf
.Y
= (REAL
)point
->Y
;
1615 return GdipSetPathGradientCenterPoint(grad
,&ptf
);
1618 GpStatus WINGDIPAPI
GdipSetPathGradientFocusScales(GpPathGradient
*grad
,
1621 TRACE("(%p, %.2f, %.2f)\n", grad
, x
, y
);
1624 return InvalidParameter
;
1632 GpStatus WINGDIPAPI
GdipSetPathGradientGammaCorrection(GpPathGradient
*grad
,
1635 TRACE("(%p, %d)\n", grad
, gamma
);
1638 return InvalidParameter
;
1640 grad
->gamma
= gamma
;
1645 GpStatus WINGDIPAPI
GdipSetPathGradientSigmaBlend(GpPathGradient
*grad
,
1646 REAL focus
, REAL scale
)
1652 const int precision
= 16;
1653 REAL erf_range
; /* we use values erf(-erf_range) through erf(+erf_range) */
1657 TRACE("(%p,%0.2f,%0.2f)\n", grad
, focus
, scale
);
1659 if(!grad
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0)
1660 return InvalidParameter
;
1662 /* we want 2 standard deviations */
1663 erf_range
= 2.0 / sqrt(2);
1665 /* calculate the constants we need to normalize the error function to be
1666 between 0.0 and scale over the range we need */
1667 min_erf
= erf(-erf_range
);
1668 scale_erf
= scale
/ (-2.0 * min_erf
);
1674 for (i
=1; i
<precision
; i
++)
1676 positions
[i
] = focus
* i
/ precision
;
1677 factors
[i
] = scale_erf
* (erf(2 * erf_range
* i
/ precision
- erf_range
) - min_erf
);
1679 num_points
+= precision
;
1682 positions
[num_points
] = focus
;
1683 factors
[num_points
] = scale
;
1688 for (i
=1; i
<precision
; i
++)
1690 positions
[i
+num_points
-1] = (focus
+ ((1.0-focus
) * i
/ precision
));
1691 factors
[i
+num_points
-1] = scale_erf
* (erf(erf_range
- 2 * erf_range
* i
/ precision
) - min_erf
);
1693 num_points
+= precision
;
1694 positions
[num_points
-1] = 1.0;
1695 factors
[num_points
-1] = 0.0;
1698 return GdipSetPathGradientBlend(grad
, factors
, positions
, num_points
);
1701 GpStatus WINGDIPAPI
GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
1702 *grad
, GDIPCONST ARGB
*argb
, INT
*count
)
1704 ARGB
*new_surroundcolors
;
1707 TRACE("(%p,%p,%p)\n", grad
, argb
, count
);
1709 if(!grad
|| !argb
|| !count
|| (*count
<= 0) ||
1710 (*count
> grad
->path
->pathdata
.Count
))
1711 return InvalidParameter
;
1713 num_colors
= *count
;
1715 /* If all colors are the same, only store 1 color. */
1718 for (i
=1; i
< num_colors
; i
++)
1719 if (argb
[i
] != argb
[i
-1])
1722 if (i
== num_colors
)
1726 new_surroundcolors
= GdipAlloc(num_colors
* sizeof(ARGB
));
1727 if (!new_surroundcolors
)
1730 memcpy(new_surroundcolors
, argb
, num_colors
* sizeof(ARGB
));
1732 GdipFree(grad
->surroundcolors
);
1734 grad
->surroundcolors
= new_surroundcolors
;
1735 grad
->surroundcolorcount
= num_colors
;
1740 GpStatus WINGDIPAPI
GdipSetPathGradientWrapMode(GpPathGradient
*grad
,
1743 TRACE("(%p, %d)\n", grad
, wrap
);
1746 return InvalidParameter
;
1753 GpStatus WINGDIPAPI
GdipSetPathGradientTransform(GpPathGradient
*grad
,
1756 TRACE("(%p,%p)\n", grad
, matrix
);
1758 if (!grad
|| !matrix
)
1759 return InvalidParameter
;
1761 memcpy(grad
->transform
, matrix
, sizeof(GpMatrix
));
1766 GpStatus WINGDIPAPI
GdipGetPathGradientTransform(GpPathGradient
*grad
,
1769 TRACE("(%p,%p)\n", grad
, matrix
);
1771 if (!grad
|| !matrix
)
1772 return InvalidParameter
;
1774 memcpy(matrix
, grad
->transform
, sizeof(GpMatrix
));
1779 GpStatus WINGDIPAPI
GdipMultiplyPathGradientTransform(GpPathGradient
*grad
,
1780 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
1782 TRACE("(%p,%p,%i)\n", grad
, matrix
, order
);
1785 return InvalidParameter
;
1787 return GdipMultiplyMatrix(grad
->transform
, matrix
, order
);
1790 GpStatus WINGDIPAPI
GdipResetPathGradientTransform(GpPathGradient
*grad
)
1792 TRACE("(%p)\n", grad
);
1795 return InvalidParameter
;
1797 return GdipSetMatrixElements(grad
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1800 GpStatus WINGDIPAPI
GdipRotatePathGradientTransform(GpPathGradient
*grad
,
1801 REAL angle
, GpMatrixOrder order
)
1803 TRACE("(%p,%0.2f,%i)\n", grad
, angle
, order
);
1806 return InvalidParameter
;
1808 return GdipRotateMatrix(grad
->transform
, angle
, order
);
1811 GpStatus WINGDIPAPI
GdipScalePathGradientTransform(GpPathGradient
*grad
,
1812 REAL sx
, REAL sy
, GpMatrixOrder order
)
1814 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad
, sx
, sy
, order
);
1817 return InvalidParameter
;
1819 return GdipScaleMatrix(grad
->transform
, sx
, sy
, order
);
1822 GpStatus WINGDIPAPI
GdipTranslatePathGradientTransform(GpPathGradient
*grad
,
1823 REAL dx
, REAL dy
, GpMatrixOrder order
)
1825 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad
, dx
, dy
, order
);
1828 return InvalidParameter
;
1830 return GdipTranslateMatrix(grad
->transform
, dx
, dy
, order
);
1833 GpStatus WINGDIPAPI
GdipSetSolidFillColor(GpSolidFill
*sf
, ARGB argb
)
1835 TRACE("(%p, %x)\n", sf
, argb
);
1838 return InvalidParameter
;
1844 /******************************************************************************
1845 * GdipSetTextureTransform [GDIPLUS.@]
1847 GpStatus WINGDIPAPI
GdipSetTextureTransform(GpTexture
*texture
,
1848 GDIPCONST GpMatrix
*matrix
)
1850 TRACE("(%p, %p)\n", texture
, matrix
);
1852 if(!texture
|| !matrix
)
1853 return InvalidParameter
;
1855 memcpy(texture
->transform
, matrix
, sizeof(GpMatrix
));
1860 /******************************************************************************
1861 * GdipSetTextureWrapMode [GDIPLUS.@]
1863 * WrapMode not used, only stored
1865 GpStatus WINGDIPAPI
GdipSetTextureWrapMode(GpTexture
*brush
, GpWrapMode wrapmode
)
1867 TRACE("(%p, %d)\n", brush
, wrapmode
);
1870 return InvalidParameter
;
1872 brush
->imageattributes
->wrap
= wrapmode
;
1877 GpStatus WINGDIPAPI
GdipSetLineColors(GpLineGradient
*brush
, ARGB color1
,
1880 TRACE("(%p, %x, %x)\n", brush
, color1
, color2
);
1883 return InvalidParameter
;
1885 brush
->startcolor
= color1
;
1886 brush
->endcolor
= color2
;
1891 GpStatus WINGDIPAPI
GdipGetLineColors(GpLineGradient
*brush
, ARGB
*colors
)
1893 TRACE("(%p, %p)\n", brush
, colors
);
1895 if(!brush
|| !colors
)
1896 return InvalidParameter
;
1898 colors
[0] = brush
->startcolor
;
1899 colors
[1] = brush
->endcolor
;
1904 /******************************************************************************
1905 * GdipRotateTextureTransform [GDIPLUS.@]
1907 GpStatus WINGDIPAPI
GdipRotateTextureTransform(GpTexture
* brush
, REAL angle
,
1908 GpMatrixOrder order
)
1910 TRACE("(%p, %.2f, %d)\n", brush
, angle
, order
);
1913 return InvalidParameter
;
1915 return GdipRotateMatrix(brush
->transform
, angle
, order
);
1918 GpStatus WINGDIPAPI
GdipSetLineLinearBlend(GpLineGradient
*brush
, REAL focus
,
1925 TRACE("(%p,%.2f,%.2f)\n", brush
, focus
, scale
);
1927 if (!brush
) return InvalidParameter
;
1931 factors
[num_points
] = 0.0;
1932 positions
[num_points
] = 0.0;
1936 factors
[num_points
] = scale
;
1937 positions
[num_points
] = focus
;
1942 factors
[num_points
] = 0.0;
1943 positions
[num_points
] = 1.0;
1947 return GdipSetLineBlend(brush
, factors
, positions
, num_points
);
1950 GpStatus WINGDIPAPI
GdipSetLinePresetBlend(GpLineGradient
*brush
,
1951 GDIPCONST ARGB
*blend
, GDIPCONST REAL
* positions
, INT count
)
1955 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, positions
, count
);
1957 if (!brush
|| !blend
|| !positions
|| count
< 2 ||
1958 positions
[0] != 0.0f
|| positions
[count
-1] != 1.0f
)
1960 return InvalidParameter
;
1963 new_color
= GdipAlloc(count
* sizeof(ARGB
));
1964 new_pos
= GdipAlloc(count
* sizeof(REAL
));
1965 if (!new_color
|| !new_pos
)
1967 GdipFree(new_color
);
1972 memcpy(new_color
, blend
, sizeof(ARGB
) * count
);
1973 memcpy(new_pos
, positions
, sizeof(REAL
) * count
);
1975 GdipFree(brush
->pblendcolor
);
1976 GdipFree(brush
->pblendpos
);
1978 brush
->pblendcolor
= new_color
;
1979 brush
->pblendpos
= new_pos
;
1980 brush
->pblendcount
= count
;
1985 GpStatus WINGDIPAPI
GdipGetLinePresetBlend(GpLineGradient
*brush
,
1986 ARGB
*blend
, REAL
* positions
, INT count
)
1988 if (!brush
|| !blend
|| !positions
|| count
< 2)
1989 return InvalidParameter
;
1991 if (brush
->pblendcount
== 0)
1992 return GenericError
;
1994 if (count
< brush
->pblendcount
)
1995 return InsufficientBuffer
;
1997 memcpy(blend
, brush
->pblendcolor
, sizeof(ARGB
) * brush
->pblendcount
);
1998 memcpy(positions
, brush
->pblendpos
, sizeof(REAL
) * brush
->pblendcount
);
2003 GpStatus WINGDIPAPI
GdipGetLinePresetBlendCount(GpLineGradient
*brush
,
2006 if (!brush
|| !count
)
2007 return InvalidParameter
;
2009 *count
= brush
->pblendcount
;
2014 GpStatus WINGDIPAPI
GdipResetLineTransform(GpLineGradient
*brush
)
2018 TRACE("(%p)\n", brush
);
2021 FIXME("not implemented\n");
2023 return NotImplemented
;
2026 GpStatus WINGDIPAPI
GdipSetLineTransform(GpLineGradient
*brush
,
2027 GDIPCONST GpMatrix
*matrix
)
2031 TRACE("(%p,%p)\n", brush
, matrix
);
2034 FIXME("not implemented\n");
2036 return NotImplemented
;
2039 GpStatus WINGDIPAPI
GdipGetLineTransform(GpLineGradient
*brush
, GpMatrix
*matrix
)
2043 TRACE("(%p,%p)\n", brush
, matrix
);
2046 FIXME("not implemented\n");
2048 return NotImplemented
;
2051 GpStatus WINGDIPAPI
GdipScaleLineTransform(GpLineGradient
*brush
, REAL sx
, REAL sy
,
2052 GpMatrixOrder order
)
2056 TRACE("(%p,%0.2f,%0.2f,%u)\n", brush
, sx
, sy
, order
);
2059 FIXME("not implemented\n");
2061 return NotImplemented
;
2064 GpStatus WINGDIPAPI
GdipMultiplyLineTransform(GpLineGradient
*brush
,
2065 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
2069 TRACE("(%p,%p,%u)\n", brush
, matrix
, order
);
2072 FIXME("not implemented\n");
2074 return NotImplemented
;
2077 GpStatus WINGDIPAPI
GdipTranslateLineTransform(GpLineGradient
* brush
,
2078 REAL dx
, REAL dy
, GpMatrixOrder order
)
2082 TRACE("(%p,%f,%f,%d)\n", brush
, dx
, dy
, order
);
2085 FIXME("not implemented\n");
2090 /******************************************************************************
2091 * GdipTranslateTextureTransform [GDIPLUS.@]
2093 GpStatus WINGDIPAPI
GdipTranslateTextureTransform(GpTexture
* brush
, REAL dx
, REAL dy
,
2094 GpMatrixOrder order
)
2096 TRACE("(%p, %.2f, %.2f, %d)\n", brush
, dx
, dy
, order
);
2099 return InvalidParameter
;
2101 return GdipTranslateMatrix(brush
->transform
, dx
, dy
, order
);
2104 GpStatus WINGDIPAPI
GdipGetLineRect(GpLineGradient
*brush
, GpRectF
*rect
)
2106 TRACE("(%p, %p)\n", brush
, rect
);
2109 return InvalidParameter
;
2111 *rect
= brush
->rect
;
2116 GpStatus WINGDIPAPI
GdipGetLineRectI(GpLineGradient
*brush
, GpRect
*rect
)
2121 TRACE("(%p, %p)\n", brush
, rect
);
2124 return InvalidParameter
;
2126 ret
= GdipGetLineRect(brush
, &rectF
);
2129 rect
->X
= gdip_round(rectF
.X
);
2130 rect
->Y
= gdip_round(rectF
.Y
);
2131 rect
->Width
= gdip_round(rectF
.Width
);
2132 rect
->Height
= gdip_round(rectF
.Height
);
2138 GpStatus WINGDIPAPI
GdipRotateLineTransform(GpLineGradient
* brush
,
2139 REAL angle
, GpMatrixOrder order
)
2143 TRACE("(%p,%0.2f,%u)\n", brush
, angle
, order
);
2146 return InvalidParameter
;
2149 FIXME("(%p, %.2f, %d) stub\n", brush
, angle
, order
);
2151 return NotImplemented
;