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
);
39 Code from http://www.johndcook.com/blog/2009/01/19/stand-alone-error-function-erf/
43 const float a1
= 0.254829592;
44 const float a2
= -0.284496736;
45 const float a3
= 1.421413741;
46 const float a4
= -1.453152027;
47 const float a5
= 1.061405429;
48 const float p
= 0.3275911;
51 /* Save the sign of x */
59 y
= 1.0 - (((((a5
*t
+ a4
)*t
) + a3
)*t
+ a2
)*t
+ a1
)*t
*exp(-x
*x
);
64 /******************************************************************************
65 * GdipCloneBrush [GDIPLUS.@]
67 GpStatus WINGDIPAPI
GdipCloneBrush(GpBrush
*brush
, GpBrush
**clone
)
69 TRACE("(%p, %p)\n", brush
, clone
);
72 return InvalidParameter
;
75 case BrushTypeSolidColor
:
78 *clone
= GdipAlloc(sizeof(GpSolidFill
));
79 if (!*clone
) return OutOfMemory
;
81 fill
= (GpSolidFill
*)*clone
;
83 memcpy(*clone
, brush
, sizeof(GpSolidFill
));
85 (*clone
)->gdibrush
= CreateBrushIndirect(&(*clone
)->lb
);
86 fill
->bmp
= ARGB2BMP(fill
->color
);
89 case BrushTypeHatchFill
:
91 GpHatch
*hatch
= (GpHatch
*)brush
;
93 return GdipCreateHatchBrush(hatch
->hatchstyle
, hatch
->forecol
, hatch
->backcol
, (GpHatch
**)clone
);
95 case BrushTypePathGradient
:{
96 GpPathGradient
*src
, *dest
;
99 *clone
= GdipAlloc(sizeof(GpPathGradient
));
100 if (!*clone
) return OutOfMemory
;
102 src
= (GpPathGradient
*) brush
,
103 dest
= (GpPathGradient
*) *clone
;
104 count
= src
->pathdata
.Count
;
106 memcpy(dest
, src
, sizeof(GpPathGradient
));
108 dest
->pathdata
.Count
= count
;
109 dest
->pathdata
.Points
= GdipAlloc(count
* sizeof(PointF
));
110 dest
->pathdata
.Types
= GdipAlloc(count
);
112 if(!dest
->pathdata
.Points
|| !dest
->pathdata
.Types
){
113 GdipFree(dest
->pathdata
.Points
);
114 GdipFree(dest
->pathdata
.Types
);
119 memcpy(dest
->pathdata
.Points
, src
->pathdata
.Points
, count
* sizeof(PointF
));
120 memcpy(dest
->pathdata
.Types
, src
->pathdata
.Types
, count
);
123 count
= src
->blendcount
;
124 dest
->blendcount
= count
;
125 dest
->blendfac
= GdipAlloc(count
* sizeof(REAL
));
126 dest
->blendpos
= GdipAlloc(count
* sizeof(REAL
));
128 if(!dest
->blendfac
|| !dest
->blendpos
){
129 GdipFree(dest
->pathdata
.Points
);
130 GdipFree(dest
->pathdata
.Types
);
131 GdipFree(dest
->blendfac
);
132 GdipFree(dest
->blendpos
);
137 memcpy(dest
->blendfac
, src
->blendfac
, count
* sizeof(REAL
));
138 memcpy(dest
->blendpos
, src
->blendpos
, count
* sizeof(REAL
));
142 case BrushTypeLinearGradient
:{
143 GpLineGradient
*dest
, *src
;
146 dest
= GdipAlloc(sizeof(GpLineGradient
));
147 if(!dest
) return OutOfMemory
;
149 src
= (GpLineGradient
*)brush
;
151 memcpy(dest
, src
, sizeof(GpLineGradient
));
153 dest
->brush
.gdibrush
= CreateSolidBrush(dest
->brush
.lb
.lbColor
);
155 count
= dest
->blendcount
;
156 dest
->blendfac
= GdipAlloc(count
* sizeof(REAL
));
157 dest
->blendpos
= GdipAlloc(count
* sizeof(REAL
));
158 pcount
= dest
->pblendcount
;
161 dest
->pblendcolor
= GdipAlloc(pcount
* sizeof(ARGB
));
162 dest
->pblendpos
= GdipAlloc(pcount
* sizeof(REAL
));
165 if (!dest
->blendfac
|| !dest
->blendpos
||
166 (pcount
&& (!dest
->pblendcolor
|| !dest
->pblendpos
)))
168 GdipFree(dest
->blendfac
);
169 GdipFree(dest
->blendpos
);
170 GdipFree(dest
->pblendcolor
);
171 GdipFree(dest
->pblendpos
);
172 DeleteObject(dest
->brush
.gdibrush
);
177 memcpy(dest
->blendfac
, src
->blendfac
, count
* sizeof(REAL
));
178 memcpy(dest
->blendpos
, src
->blendpos
, count
* sizeof(REAL
));
182 memcpy(dest
->pblendcolor
, src
->pblendcolor
, pcount
* sizeof(ARGB
));
183 memcpy(dest
->pblendpos
, src
->pblendpos
, pcount
* sizeof(REAL
));
186 *clone
= &dest
->brush
;
189 case BrushTypeTextureFill
:
192 GpTexture
*texture
= (GpTexture
*)brush
;
193 GpTexture
*new_texture
;
195 stat
= GdipCreateTexture(texture
->image
, texture
->wrap
, &new_texture
);
199 memcpy(new_texture
->transform
, texture
->transform
, sizeof(GpMatrix
));
200 *clone
= (GpBrush
*)new_texture
;
208 ERR("not implemented for brush type %d\n", brush
->bt
);
209 return NotImplemented
;
212 TRACE("<-- %p\n", *clone
);
216 static const char HatchBrushes
[][8] = {
217 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HatchStyleHorizontal */
218 { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleVertical */
219 { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HatchStyleForwardDiagonal */
220 { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HatchStyleBackwardDiagonal */
221 { 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleCross */
222 { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }, /* HatchStyleDiagonalCross */
223 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80 }, /* HatchStyle05Percent */
224 { 0x00, 0x02, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88 }, /* HatchStyle10Percent */
225 { 0x00, 0x22, 0x00, 0xcc, 0x00, 0x22, 0x00, 0xcc }, /* HatchStyle20Percent */
226 { 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc }, /* HatchStyle25Percent */
227 { 0x00, 0xcc, 0x04, 0xcc, 0x00, 0xcc, 0x40, 0xcc }, /* HatchStyle30Percent */
228 { 0x44, 0xcc, 0x22, 0xcc, 0x44, 0xcc, 0x22, 0xcc }, /* HatchStyle40Percent */
229 { 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc }, /* HatchStyle50Percent */
230 { 0x55, 0xcd, 0x55, 0xee, 0x55, 0xdc, 0x55, 0xee }, /* HatchStyle60Percent */
231 { 0x55, 0xdd, 0x55, 0xff, 0x55, 0xdd, 0x55, 0xff }, /* HatchStyle70Percent */
232 { 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff }, /* HatchStyle75Percent */
233 { 0x55, 0xff, 0x59, 0xff, 0x55, 0xff, 0x99, 0xff }, /* HatchStyle80Percent */
234 { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xfd, 0xff }, /* HatchStyle90Percent */
235 { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 }, /* HatchStyleLightDownwardDiagonal */
236 { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 }, /* HatchStyleLightUpwardDiagonal */
237 { 0x99, 0x33, 0x66, 0xcc, 0x99, 0x33, 0x66, 0xcc }, /* HatchStyleDarkDownwardDiagonal */
238 { 0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33, 0x99 }, /* HatchStyleDarkUpwardDiagonal */
239 { 0xc1, 0x83, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0 }, /* HatchStyleWideDownwardDiagonal */
240 { 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x07, 0x83, 0xc1 }, /* HatchStyleWideUpwardDiagonal */
241 { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 }, /* HatchStyleLightVertical */
242 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff }, /* HatchStyleLightHorizontal */
243 { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, /* HatchStyleNarrowVertical */
244 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, /* HatchStyleNarrowHorizontal */
245 { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }, /* HatchStyleDarkVertical */
246 { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff }, /* HatchStyleDarkHorizontal */
249 /******************************************************************************
250 * GdipCreateHatchBrush [GDIPLUS.@]
252 GpStatus WINGDIPAPI
GdipCreateHatchBrush(HatchStyle hatchstyle
, ARGB forecol
, ARGB backcol
, GpHatch
**brush
)
254 COLORREF fgcol
= ARGB2COLORREF(forecol
);
257 TRACE("(%d, %d, %d, %p)\n", hatchstyle
, forecol
, backcol
, brush
);
259 if(!brush
) return InvalidParameter
;
261 *brush
= GdipAlloc(sizeof(GpHatch
));
262 if (!*brush
) return OutOfMemory
;
264 if (hatchstyle
< sizeof(HatchBrushes
) / sizeof(HatchBrushes
[0]))
268 BITMAPINFOHEADER bmih
;
272 hdc
= CreateCompatibleDC(0);
276 bmih
.biSize
= sizeof(bmih
);
280 bmih
.biBitCount
= 32;
281 bmih
.biCompression
= BI_RGB
;
282 bmih
.biSizeImage
= 0;
284 hbmp
= CreateDIBSection(hdc
, (BITMAPINFO
*)&bmih
, DIB_RGB_COLORS
, (void**)&bits
, NULL
, 0);
290 if ((HatchBrushes
[hatchstyle
][y
] & (0x80 >> x
)) != 0)
291 bits
[y
*8+x
] = forecol
;
293 bits
[y
*8+x
] = backcol
;
305 (*brush
)->brush
.lb
.lbStyle
= BS_PATTERN
;
306 (*brush
)->brush
.lb
.lbColor
= 0;
307 (*brush
)->brush
.lb
.lbHatch
= (ULONG_PTR
)hbmp
;
308 (*brush
)->brush
.gdibrush
= CreateBrushIndirect(&(*brush
)->brush
.lb
);
315 FIXME("Unimplemented hatch style %d\n", hatchstyle
);
317 (*brush
)->brush
.lb
.lbStyle
= BS_SOLID
;
318 (*brush
)->brush
.lb
.lbColor
= fgcol
;
319 (*brush
)->brush
.lb
.lbHatch
= 0;
320 (*brush
)->brush
.gdibrush
= CreateBrushIndirect(&(*brush
)->brush
.lb
);
325 (*brush
)->brush
.bt
= BrushTypeHatchFill
;
326 (*brush
)->forecol
= forecol
;
327 (*brush
)->backcol
= backcol
;
328 (*brush
)->hatchstyle
= hatchstyle
;
329 TRACE("<-- %p\n", *brush
);
340 /******************************************************************************
341 * GdipCreateLineBrush [GDIPLUS.@]
343 GpStatus WINGDIPAPI
GdipCreateLineBrush(GDIPCONST GpPointF
* startpoint
,
344 GDIPCONST GpPointF
* endpoint
, ARGB startcolor
, ARGB endcolor
,
345 GpWrapMode wrap
, GpLineGradient
**line
)
347 COLORREF col
= ARGB2COLORREF(startcolor
);
349 TRACE("(%s, %s, %x, %x, %d, %p)\n", debugstr_pointf(startpoint
),
350 debugstr_pointf(endpoint
), startcolor
, endcolor
, wrap
, line
);
352 if(!line
|| !startpoint
|| !endpoint
|| wrap
== WrapModeClamp
)
353 return InvalidParameter
;
355 if (startpoint
->X
== endpoint
->X
&& startpoint
->Y
== endpoint
->Y
)
358 *line
= GdipAlloc(sizeof(GpLineGradient
));
359 if(!*line
) return OutOfMemory
;
361 (*line
)->brush
.lb
.lbStyle
= BS_SOLID
;
362 (*line
)->brush
.lb
.lbColor
= col
;
363 (*line
)->brush
.lb
.lbHatch
= 0;
364 (*line
)->brush
.gdibrush
= CreateSolidBrush(col
);
365 (*line
)->brush
.bt
= BrushTypeLinearGradient
;
367 (*line
)->startpoint
.X
= startpoint
->X
;
368 (*line
)->startpoint
.Y
= startpoint
->Y
;
369 (*line
)->endpoint
.X
= endpoint
->X
;
370 (*line
)->endpoint
.Y
= endpoint
->Y
;
371 (*line
)->startcolor
= startcolor
;
372 (*line
)->endcolor
= endcolor
;
373 (*line
)->wrap
= wrap
;
374 (*line
)->gamma
= FALSE
;
376 (*line
)->rect
.X
= (startpoint
->X
< endpoint
->X
? startpoint
->X
: endpoint
->X
);
377 (*line
)->rect
.Y
= (startpoint
->Y
< endpoint
->Y
? startpoint
->Y
: endpoint
->Y
);
378 (*line
)->rect
.Width
= fabs(startpoint
->X
- endpoint
->X
);
379 (*line
)->rect
.Height
= fabs(startpoint
->Y
- endpoint
->Y
);
381 if ((*line
)->rect
.Width
== 0)
383 (*line
)->rect
.X
-= (*line
)->rect
.Height
/ 2.0f
;
384 (*line
)->rect
.Width
= (*line
)->rect
.Height
;
386 else if ((*line
)->rect
.Height
== 0)
388 (*line
)->rect
.Y
-= (*line
)->rect
.Width
/ 2.0f
;
389 (*line
)->rect
.Height
= (*line
)->rect
.Width
;
392 (*line
)->blendcount
= 1;
393 (*line
)->blendfac
= GdipAlloc(sizeof(REAL
));
394 (*line
)->blendpos
= GdipAlloc(sizeof(REAL
));
396 if (!(*line
)->blendfac
|| !(*line
)->blendpos
)
398 GdipFree((*line
)->blendfac
);
399 GdipFree((*line
)->blendpos
);
400 DeleteObject((*line
)->brush
.gdibrush
);
406 (*line
)->blendfac
[0] = 1.0f
;
407 (*line
)->blendpos
[0] = 1.0f
;
409 (*line
)->pblendcolor
= NULL
;
410 (*line
)->pblendpos
= NULL
;
411 (*line
)->pblendcount
= 0;
413 TRACE("<-- %p\n", *line
);
418 GpStatus WINGDIPAPI
GdipCreateLineBrushI(GDIPCONST GpPoint
* startpoint
,
419 GDIPCONST GpPoint
* endpoint
, ARGB startcolor
, ARGB endcolor
,
420 GpWrapMode wrap
, GpLineGradient
**line
)
425 TRACE("(%p, %p, %x, %x, %d, %p)\n", startpoint
, endpoint
,
426 startcolor
, endcolor
, wrap
, line
);
428 if(!startpoint
|| !endpoint
)
429 return InvalidParameter
;
431 stF
.X
= (REAL
)startpoint
->X
;
432 stF
.Y
= (REAL
)startpoint
->Y
;
433 endF
.X
= (REAL
)endpoint
->X
;
434 endF
.Y
= (REAL
)endpoint
->Y
;
436 return GdipCreateLineBrush(&stF
, &endF
, startcolor
, endcolor
, wrap
, line
);
439 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRect(GDIPCONST GpRectF
* rect
,
440 ARGB startcolor
, ARGB endcolor
, LinearGradientMode mode
, GpWrapMode wrap
,
441 GpLineGradient
**line
)
446 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect
, startcolor
, endcolor
, mode
,
450 return InvalidParameter
;
454 case LinearGradientModeHorizontal
:
457 end
.X
= rect
->X
+ rect
->Width
;
460 case LinearGradientModeVertical
:
464 end
.Y
= rect
->Y
+ rect
->Height
;
466 case LinearGradientModeForwardDiagonal
:
469 end
.X
= rect
->X
+ rect
->Width
;
470 end
.Y
= rect
->Y
+ rect
->Height
;
472 case LinearGradientModeBackwardDiagonal
:
473 start
.X
= rect
->X
+ rect
->Width
;
476 end
.Y
= rect
->Y
+ rect
->Height
;
479 return InvalidParameter
;
482 stat
= GdipCreateLineBrush(&start
, &end
, startcolor
, endcolor
, wrap
, line
);
485 (*line
)->rect
= *rect
;
490 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectI(GDIPCONST GpRect
* rect
,
491 ARGB startcolor
, ARGB endcolor
, LinearGradientMode mode
, GpWrapMode wrap
,
492 GpLineGradient
**line
)
496 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect
, startcolor
, endcolor
, mode
,
499 rectF
.X
= (REAL
) rect
->X
;
500 rectF
.Y
= (REAL
) rect
->Y
;
501 rectF
.Width
= (REAL
) rect
->Width
;
502 rectF
.Height
= (REAL
) rect
->Height
;
504 return GdipCreateLineBrushFromRect(&rectF
, startcolor
, endcolor
, mode
, wrap
, line
);
507 /******************************************************************************
508 * GdipCreateLineBrushFromRectWithAngle [GDIPLUS.@]
510 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF
* rect
,
511 ARGB startcolor
, ARGB endcolor
, REAL angle
, BOOL isAngleScalable
, GpWrapMode wrap
,
512 GpLineGradient
**line
)
515 LinearGradientMode mode
;
516 REAL width
, height
, exofs
, eyofs
;
517 REAL sin_angle
, cos_angle
, sin_cos_angle
;
519 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect
, startcolor
, endcolor
, angle
, isAngleScalable
,
522 sin_angle
= sinf(deg2rad(angle
));
523 cos_angle
= cosf(deg2rad(angle
));
524 sin_cos_angle
= sin_angle
* cos_angle
;
528 width
= height
= 1.0;
533 height
= rect
->Height
;
536 if (sin_cos_angle
>= 0)
537 mode
= LinearGradientModeForwardDiagonal
;
539 mode
= LinearGradientModeBackwardDiagonal
;
541 stat
= GdipCreateLineBrushFromRect(rect
, startcolor
, endcolor
, mode
, wrap
, line
);
545 if (sin_cos_angle
>= 0)
547 exofs
= width
* sin_cos_angle
+ height
* cos_angle
* cos_angle
;
548 eyofs
= width
* sin_angle
* sin_angle
+ height
* sin_cos_angle
;
552 exofs
= width
* sin_angle
* sin_angle
+ height
* sin_cos_angle
;
553 eyofs
= -width
* sin_cos_angle
+ height
* sin_angle
* sin_angle
;
558 exofs
= exofs
* rect
->Width
;
559 eyofs
= eyofs
* rect
->Height
;
564 (*line
)->endpoint
.X
= rect
->X
+ exofs
;
565 (*line
)->endpoint
.Y
= rect
->Y
+ eyofs
;
569 (*line
)->endpoint
.X
= (*line
)->startpoint
.X
;
570 (*line
)->endpoint
.Y
= (*line
)->startpoint
.Y
;
571 (*line
)->startpoint
.X
= rect
->X
+ exofs
;
572 (*line
)->startpoint
.Y
= rect
->Y
+ eyofs
;
579 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectWithAngleI(GDIPCONST GpRect
* rect
,
580 ARGB startcolor
, ARGB endcolor
, REAL angle
, BOOL isAngleScalable
, GpWrapMode wrap
,
581 GpLineGradient
**line
)
583 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect
, startcolor
, endcolor
, angle
, isAngleScalable
,
586 return GdipCreateLineBrushFromRectI(rect
, startcolor
, endcolor
, LinearGradientModeForwardDiagonal
,
590 GpStatus WINGDIPAPI
GdipCreatePathGradient(GDIPCONST GpPointF
* points
,
591 INT count
, GpWrapMode wrap
, GpPathGradient
**grad
)
593 COLORREF col
= ARGB2COLORREF(0xffffffff);
595 TRACE("(%p, %d, %d, %p)\n", points
, count
, wrap
, grad
);
598 return InvalidParameter
;
603 *grad
= GdipAlloc(sizeof(GpPathGradient
));
604 if (!*grad
) return OutOfMemory
;
606 (*grad
)->blendfac
= GdipAlloc(sizeof(REAL
));
607 (*grad
)->blendpos
= GdipAlloc(sizeof(REAL
));
608 if(!(*grad
)->blendfac
|| !(*grad
)->blendpos
){
609 GdipFree((*grad
)->blendfac
);
610 GdipFree((*grad
)->blendpos
);
615 (*grad
)->blendfac
[0] = 1.0;
616 (*grad
)->blendpos
[0] = 1.0;
617 (*grad
)->blendcount
= 1;
619 (*grad
)->pathdata
.Count
= count
;
620 (*grad
)->pathdata
.Points
= GdipAlloc(count
* sizeof(PointF
));
621 (*grad
)->pathdata
.Types
= GdipAlloc(count
);
623 if(!(*grad
)->pathdata
.Points
|| !(*grad
)->pathdata
.Types
){
624 GdipFree((*grad
)->pathdata
.Points
);
625 GdipFree((*grad
)->pathdata
.Types
);
630 memcpy((*grad
)->pathdata
.Points
, points
, count
* sizeof(PointF
));
631 memset((*grad
)->pathdata
.Types
, PathPointTypeLine
, count
);
633 (*grad
)->brush
.lb
.lbStyle
= BS_SOLID
;
634 (*grad
)->brush
.lb
.lbColor
= col
;
635 (*grad
)->brush
.lb
.lbHatch
= 0;
637 (*grad
)->brush
.gdibrush
= CreateSolidBrush(col
);
638 (*grad
)->brush
.bt
= BrushTypePathGradient
;
639 (*grad
)->centercolor
= 0xffffffff;
640 (*grad
)->wrap
= wrap
;
641 (*grad
)->gamma
= FALSE
;
642 (*grad
)->center
.X
= 0.0;
643 (*grad
)->center
.Y
= 0.0;
644 (*grad
)->focus
.X
= 0.0;
645 (*grad
)->focus
.Y
= 0.0;
647 TRACE("<-- %p\n", *grad
);
652 GpStatus WINGDIPAPI
GdipCreatePathGradientI(GDIPCONST GpPoint
* points
,
653 INT count
, GpWrapMode wrap
, GpPathGradient
**grad
)
659 TRACE("(%p, %d, %d, %p)\n", points
, count
, wrap
, grad
);
662 return InvalidParameter
;
667 pointsF
= GdipAlloc(sizeof(GpPointF
) * count
);
671 for(i
= 0; i
< count
; i
++){
672 pointsF
[i
].X
= (REAL
)points
[i
].X
;
673 pointsF
[i
].Y
= (REAL
)points
[i
].Y
;
676 ret
= GdipCreatePathGradient(pointsF
, count
, wrap
, grad
);
682 /******************************************************************************
683 * GdipCreatePathGradientFromPath [GDIPLUS.@]
685 * FIXME: path gradient brushes not truly supported (drawn as solid brushes)
687 GpStatus WINGDIPAPI
GdipCreatePathGradientFromPath(GDIPCONST GpPath
* path
,
688 GpPathGradient
**grad
)
690 COLORREF col
= ARGB2COLORREF(0xffffffff);
692 TRACE("(%p, %p)\n", path
, grad
);
695 return InvalidParameter
;
697 *grad
= GdipAlloc(sizeof(GpPathGradient
));
698 if (!*grad
) return OutOfMemory
;
700 (*grad
)->blendfac
= GdipAlloc(sizeof(REAL
));
701 (*grad
)->blendpos
= GdipAlloc(sizeof(REAL
));
702 if(!(*grad
)->blendfac
|| !(*grad
)->blendpos
){
703 GdipFree((*grad
)->blendfac
);
704 GdipFree((*grad
)->blendpos
);
709 (*grad
)->blendfac
[0] = 1.0;
710 (*grad
)->blendpos
[0] = 1.0;
711 (*grad
)->blendcount
= 1;
713 (*grad
)->pathdata
.Count
= path
->pathdata
.Count
;
714 (*grad
)->pathdata
.Points
= GdipAlloc(path
->pathdata
.Count
* sizeof(PointF
));
715 (*grad
)->pathdata
.Types
= GdipAlloc(path
->pathdata
.Count
);
717 if(!(*grad
)->pathdata
.Points
|| !(*grad
)->pathdata
.Types
){
718 GdipFree((*grad
)->pathdata
.Points
);
719 GdipFree((*grad
)->pathdata
.Types
);
724 memcpy((*grad
)->pathdata
.Points
, path
->pathdata
.Points
,
725 path
->pathdata
.Count
* sizeof(PointF
));
726 memcpy((*grad
)->pathdata
.Types
, path
->pathdata
.Types
, path
->pathdata
.Count
);
728 (*grad
)->brush
.lb
.lbStyle
= BS_SOLID
;
729 (*grad
)->brush
.lb
.lbColor
= col
;
730 (*grad
)->brush
.lb
.lbHatch
= 0;
732 (*grad
)->brush
.gdibrush
= CreateSolidBrush(col
);
733 (*grad
)->brush
.bt
= BrushTypePathGradient
;
734 (*grad
)->centercolor
= 0xffffffff;
735 (*grad
)->wrap
= WrapModeClamp
;
736 (*grad
)->gamma
= FALSE
;
737 /* FIXME: this should be set to the "centroid" of the path by default */
738 (*grad
)->center
.X
= 0.0;
739 (*grad
)->center
.Y
= 0.0;
740 (*grad
)->focus
.X
= 0.0;
741 (*grad
)->focus
.Y
= 0.0;
743 TRACE("<-- %p\n", *grad
);
748 /******************************************************************************
749 * GdipCreateSolidFill [GDIPLUS.@]
751 GpStatus WINGDIPAPI
GdipCreateSolidFill(ARGB color
, GpSolidFill
**sf
)
753 COLORREF col
= ARGB2COLORREF(color
);
755 TRACE("(%x, %p)\n", color
, sf
);
757 if(!sf
) return InvalidParameter
;
759 *sf
= GdipAlloc(sizeof(GpSolidFill
));
760 if (!*sf
) return OutOfMemory
;
762 (*sf
)->brush
.lb
.lbStyle
= BS_SOLID
;
763 (*sf
)->brush
.lb
.lbColor
= col
;
764 (*sf
)->brush
.lb
.lbHatch
= 0;
766 (*sf
)->brush
.gdibrush
= CreateSolidBrush(col
);
767 (*sf
)->brush
.bt
= BrushTypeSolidColor
;
768 (*sf
)->color
= color
;
769 (*sf
)->bmp
= ARGB2BMP(color
);
771 TRACE("<-- %p\n", *sf
);
776 /******************************************************************************
777 * GdipCreateTexture [GDIPLUS.@]
780 * image [I] image to use
781 * wrapmode [I] optional
782 * texture [O] pointer to the resulting texturebrush
786 * FAILURE: element of GpStatus
788 GpStatus WINGDIPAPI
GdipCreateTexture(GpImage
*image
, GpWrapMode wrapmode
,
792 GpImageAttributes attributes
;
795 TRACE("%p, %d %p\n", image
, wrapmode
, texture
);
797 if (!(image
&& texture
))
798 return InvalidParameter
;
800 stat
= GdipGetImageWidth(image
, &width
);
801 if (stat
!= Ok
) return stat
;
802 stat
= GdipGetImageHeight(image
, &height
);
803 if (stat
!= Ok
) return stat
;
804 attributes
.wrap
= wrapmode
;
806 return GdipCreateTextureIA(image
, &attributes
, 0, 0, width
, height
,
810 /******************************************************************************
811 * GdipCreateTexture2 [GDIPLUS.@]
813 GpStatus WINGDIPAPI
GdipCreateTexture2(GpImage
*image
, GpWrapMode wrapmode
,
814 REAL x
, REAL y
, REAL width
, REAL height
, GpTexture
**texture
)
816 GpImageAttributes attributes
;
818 TRACE("%p %d %f %f %f %f %p\n", image
, wrapmode
,
819 x
, y
, width
, height
, texture
);
821 attributes
.wrap
= wrapmode
;
822 return GdipCreateTextureIA(image
, &attributes
, x
, y
, width
, height
,
826 /******************************************************************************
827 * GdipCreateTextureIA [GDIPLUS.@]
829 * FIXME: imageattr ignored
831 GpStatus WINGDIPAPI
GdipCreateTextureIA(GpImage
*image
,
832 GDIPCONST GpImageAttributes
*imageattr
, REAL x
, REAL y
, REAL width
,
833 REAL height
, GpTexture
**texture
)
837 GpImage
*new_image
=NULL
;
839 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %p)\n", image
, imageattr
, x
, y
, width
, height
,
842 if(!image
|| !texture
|| x
< 0.0 || y
< 0.0 || width
< 0.0 || height
< 0.0)
843 return InvalidParameter
;
847 if(image
->type
!= ImageTypeBitmap
){
848 FIXME("not implemented for image type %d\n", image
->type
);
849 return NotImplemented
;
852 status
= GdipCloneBitmapArea(x
, y
, width
, height
, PixelFormatDontCare
, (GpBitmap
*)image
, (GpBitmap
**)&new_image
);
856 status
= GdipCreateHBITMAPFromBitmap((GpBitmap
*)new_image
, &hbm
, 0);
859 status
= GenericError
;
863 *texture
= GdipAlloc(sizeof(GpTexture
));
865 status
= OutOfMemory
;
869 if((status
= GdipCreateMatrix(&(*texture
)->transform
)) != Ok
){
873 (*texture
)->brush
.lb
.lbStyle
= BS_PATTERN
;
874 (*texture
)->brush
.lb
.lbColor
= 0;
875 (*texture
)->brush
.lb
.lbHatch
= (ULONG_PTR
)hbm
;
877 (*texture
)->brush
.gdibrush
= CreateBrushIndirect(&(*texture
)->brush
.lb
);
878 (*texture
)->brush
.bt
= BrushTypeTextureFill
;
880 (*texture
)->wrap
= imageattr
->wrap
;
882 (*texture
)->wrap
= WrapModeTile
;
883 (*texture
)->image
= new_image
;
888 TRACE("<-- %p\n", *texture
);
894 GdipDeleteMatrix((*texture
)->transform
);
898 GdipDisposeImage(new_image
);
899 TRACE("<-- error %u\n", status
);
907 /******************************************************************************
908 * GdipCreateTextureIAI [GDIPLUS.@]
910 GpStatus WINGDIPAPI
GdipCreateTextureIAI(GpImage
*image
, GDIPCONST GpImageAttributes
*imageattr
,
911 INT x
, INT y
, INT width
, INT height
, GpTexture
**texture
)
913 TRACE("(%p, %p, %d, %d, %d, %d, %p)\n", image
, imageattr
, x
, y
, width
, height
,
916 return GdipCreateTextureIA(image
,imageattr
,(REAL
)x
,(REAL
)y
,(REAL
)width
,(REAL
)height
,texture
);
919 GpStatus WINGDIPAPI
GdipCreateTexture2I(GpImage
*image
, GpWrapMode wrapmode
,
920 INT x
, INT y
, INT width
, INT height
, GpTexture
**texture
)
922 GpImageAttributes imageattr
;
924 TRACE("%p %d %d %d %d %d %p\n", image
, wrapmode
, x
, y
, width
, height
,
927 imageattr
.wrap
= wrapmode
;
929 return GdipCreateTextureIA(image
, &imageattr
, x
, y
, width
, height
, texture
);
932 GpStatus WINGDIPAPI
GdipGetBrushType(GpBrush
*brush
, GpBrushType
*type
)
934 TRACE("(%p, %p)\n", brush
, type
);
936 if(!brush
|| !type
) return InvalidParameter
;
943 GpStatus WINGDIPAPI
GdipGetHatchBackgroundColor(GpHatch
*brush
, ARGB
*backcol
)
945 TRACE("(%p, %p)\n", brush
, backcol
);
947 if(!brush
|| !backcol
) return InvalidParameter
;
949 *backcol
= brush
->backcol
;
954 GpStatus WINGDIPAPI
GdipGetHatchForegroundColor(GpHatch
*brush
, ARGB
*forecol
)
956 TRACE("(%p, %p)\n", brush
, forecol
);
958 if(!brush
|| !forecol
) return InvalidParameter
;
960 *forecol
= brush
->forecol
;
965 GpStatus WINGDIPAPI
GdipGetHatchStyle(GpHatch
*brush
, HatchStyle
*hatchstyle
)
967 TRACE("(%p, %p)\n", brush
, hatchstyle
);
969 if(!brush
|| !hatchstyle
) return InvalidParameter
;
971 *hatchstyle
= brush
->hatchstyle
;
976 GpStatus WINGDIPAPI
GdipDeleteBrush(GpBrush
*brush
)
978 TRACE("(%p)\n", brush
);
980 if(!brush
) return InvalidParameter
;
984 case BrushTypePathGradient
:
985 GdipFree(((GpPathGradient
*) brush
)->pathdata
.Points
);
986 GdipFree(((GpPathGradient
*) brush
)->pathdata
.Types
);
987 GdipFree(((GpPathGradient
*) brush
)->blendfac
);
988 GdipFree(((GpPathGradient
*) brush
)->blendpos
);
990 case BrushTypeSolidColor
:
991 if (((GpSolidFill
*)brush
)->bmp
)
992 DeleteObject(((GpSolidFill
*)brush
)->bmp
);
994 case BrushTypeLinearGradient
:
995 GdipFree(((GpLineGradient
*)brush
)->blendfac
);
996 GdipFree(((GpLineGradient
*)brush
)->blendpos
);
997 GdipFree(((GpLineGradient
*)brush
)->pblendcolor
);
998 GdipFree(((GpLineGradient
*)brush
)->pblendpos
);
1000 case BrushTypeTextureFill
:
1001 GdipDeleteMatrix(((GpTexture
*)brush
)->transform
);
1002 GdipDisposeImage(((GpTexture
*)brush
)->image
);
1008 DeleteObject(brush
->gdibrush
);
1014 GpStatus WINGDIPAPI
GdipGetLineGammaCorrection(GpLineGradient
*line
,
1017 TRACE("(%p, %p)\n", line
, usinggamma
);
1019 if(!line
|| !usinggamma
)
1020 return InvalidParameter
;
1022 *usinggamma
= line
->gamma
;
1027 GpStatus WINGDIPAPI
GdipGetLineWrapMode(GpLineGradient
*brush
, GpWrapMode
*wrapmode
)
1029 TRACE("(%p, %p)\n", brush
, wrapmode
);
1031 if(!brush
|| !wrapmode
)
1032 return InvalidParameter
;
1034 *wrapmode
= brush
->wrap
;
1039 GpStatus WINGDIPAPI
GdipGetPathGradientBlend(GpPathGradient
*brush
, REAL
*blend
,
1040 REAL
*positions
, INT count
)
1042 TRACE("(%p, %p, %p, %d)\n", brush
, blend
, positions
, count
);
1044 if(!brush
|| !blend
|| !positions
|| count
<= 0)
1045 return InvalidParameter
;
1047 if(count
< brush
->blendcount
)
1048 return InsufficientBuffer
;
1050 memcpy(blend
, brush
->blendfac
, count
*sizeof(REAL
));
1051 if(brush
->blendcount
> 1){
1052 memcpy(positions
, brush
->blendpos
, count
*sizeof(REAL
));
1058 GpStatus WINGDIPAPI
GdipGetPathGradientBlendCount(GpPathGradient
*brush
, INT
*count
)
1060 TRACE("(%p, %p)\n", brush
, count
);
1062 if(!brush
|| !count
)
1063 return InvalidParameter
;
1065 *count
= brush
->blendcount
;
1070 GpStatus WINGDIPAPI
GdipGetPathGradientCenterPoint(GpPathGradient
*grad
,
1073 TRACE("(%p, %p)\n", grad
, point
);
1076 return InvalidParameter
;
1078 point
->X
= grad
->center
.X
;
1079 point
->Y
= grad
->center
.Y
;
1084 GpStatus WINGDIPAPI
GdipGetPathGradientCenterPointI(GpPathGradient
*grad
,
1090 TRACE("(%p, %p)\n", grad
, point
);
1093 return InvalidParameter
;
1095 ret
= GdipGetPathGradientCenterPoint(grad
,&ptf
);
1098 point
->X
= roundr(ptf
.X
);
1099 point
->Y
= roundr(ptf
.Y
);
1105 GpStatus WINGDIPAPI
GdipGetPathGradientCenterColor(GpPathGradient
*grad
,
1110 TRACE("(%p,%p)\n", grad
, colors
);
1113 FIXME("not implemented\n");
1115 return NotImplemented
;
1118 GpStatus WINGDIPAPI
GdipGetPathGradientFocusScales(GpPathGradient
*grad
,
1121 TRACE("(%p, %p, %p)\n", grad
, x
, y
);
1123 if(!grad
|| !x
|| !y
)
1124 return InvalidParameter
;
1132 GpStatus WINGDIPAPI
GdipGetPathGradientGammaCorrection(GpPathGradient
*grad
,
1135 TRACE("(%p, %p)\n", grad
, gamma
);
1138 return InvalidParameter
;
1140 *gamma
= grad
->gamma
;
1145 GpStatus WINGDIPAPI
GdipGetPathGradientPointCount(GpPathGradient
*grad
,
1148 TRACE("(%p, %p)\n", grad
, count
);
1151 return InvalidParameter
;
1153 *count
= grad
->pathdata
.Count
;
1158 GpStatus WINGDIPAPI
GdipGetPathGradientRect(GpPathGradient
*brush
, GpRectF
*rect
)
1164 TRACE("(%p, %p)\n", brush
, rect
);
1167 return InvalidParameter
;
1169 stat
= GdipCreatePath2(brush
->pathdata
.Points
, brush
->pathdata
.Types
,
1170 brush
->pathdata
.Count
, FillModeAlternate
, &path
);
1171 if(stat
!= Ok
) return stat
;
1173 stat
= GdipGetPathWorldBounds(path
, &r
, NULL
, NULL
);
1175 GdipDeletePath(path
);
1179 memcpy(rect
, &r
, sizeof(GpRectF
));
1181 GdipDeletePath(path
);
1186 GpStatus WINGDIPAPI
GdipGetPathGradientRectI(GpPathGradient
*brush
, GpRect
*rect
)
1191 TRACE("(%p, %p)\n", brush
, rect
);
1194 return InvalidParameter
;
1196 stat
= GdipGetPathGradientRect(brush
, &rectf
);
1197 if(stat
!= Ok
) return stat
;
1199 rect
->X
= roundr(rectf
.X
);
1200 rect
->Y
= roundr(rectf
.Y
);
1201 rect
->Width
= roundr(rectf
.Width
);
1202 rect
->Height
= roundr(rectf
.Height
);
1207 GpStatus WINGDIPAPI
GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
1208 *grad
, ARGB
*argb
, INT
*count
)
1212 TRACE("(%p,%p,%p)\n", grad
, argb
, count
);
1214 if(!grad
|| !argb
|| !count
|| (*count
< grad
->pathdata
.Count
))
1215 return InvalidParameter
;
1218 FIXME("not implemented\n");
1220 return NotImplemented
;
1223 GpStatus WINGDIPAPI
GdipGetPathGradientSurroundColorCount(GpPathGradient
*brush
, INT
*count
)
1225 TRACE("(%p, %p)\n", brush
, count
);
1227 if (!brush
|| !count
)
1228 return InvalidParameter
;
1230 return NotImplemented
;
1233 GpStatus WINGDIPAPI
GdipGetPathGradientWrapMode(GpPathGradient
*brush
,
1234 GpWrapMode
*wrapmode
)
1236 TRACE("(%p, %p)\n", brush
, wrapmode
);
1238 if(!brush
|| !wrapmode
)
1239 return InvalidParameter
;
1241 *wrapmode
= brush
->wrap
;
1246 GpStatus WINGDIPAPI
GdipGetSolidFillColor(GpSolidFill
*sf
, ARGB
*argb
)
1248 TRACE("(%p, %p)\n", sf
, argb
);
1251 return InvalidParameter
;
1258 /******************************************************************************
1259 * GdipGetTextureImage [GDIPLUS.@]
1261 GpStatus WINGDIPAPI
GdipGetTextureImage(GpTexture
*brush
, GpImage
**image
)
1263 TRACE("(%p, %p)\n", brush
, image
);
1265 if(!brush
|| !image
)
1266 return InvalidParameter
;
1268 return GdipCloneImage(brush
->image
, image
);
1271 /******************************************************************************
1272 * GdipGetTextureTransform [GDIPLUS.@]
1274 GpStatus WINGDIPAPI
GdipGetTextureTransform(GpTexture
*brush
, GpMatrix
*matrix
)
1276 TRACE("(%p, %p)\n", brush
, matrix
);
1278 if(!brush
|| !matrix
)
1279 return InvalidParameter
;
1281 memcpy(matrix
, brush
->transform
, sizeof(GpMatrix
));
1286 /******************************************************************************
1287 * GdipGetTextureWrapMode [GDIPLUS.@]
1289 GpStatus WINGDIPAPI
GdipGetTextureWrapMode(GpTexture
*brush
, GpWrapMode
*wrapmode
)
1291 TRACE("(%p, %p)\n", brush
, wrapmode
);
1293 if(!brush
|| !wrapmode
)
1294 return InvalidParameter
;
1296 *wrapmode
= brush
->wrap
;
1301 /******************************************************************************
1302 * GdipMultiplyTextureTransform [GDIPLUS.@]
1304 GpStatus WINGDIPAPI
GdipMultiplyTextureTransform(GpTexture
* brush
,
1305 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
1307 TRACE("(%p, %p, %d)\n", brush
, matrix
, order
);
1309 if(!brush
|| !matrix
)
1310 return InvalidParameter
;
1312 return GdipMultiplyMatrix(brush
->transform
, matrix
, order
);
1315 /******************************************************************************
1316 * GdipResetTextureTransform [GDIPLUS.@]
1318 GpStatus WINGDIPAPI
GdipResetTextureTransform(GpTexture
* brush
)
1320 TRACE("(%p)\n", brush
);
1323 return InvalidParameter
;
1325 return GdipSetMatrixElements(brush
->transform
, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1328 /******************************************************************************
1329 * GdipScaleTextureTransform [GDIPLUS.@]
1331 GpStatus WINGDIPAPI
GdipScaleTextureTransform(GpTexture
* brush
,
1332 REAL sx
, REAL sy
, GpMatrixOrder order
)
1334 TRACE("(%p, %.2f, %.2f, %d)\n", brush
, sx
, sy
, order
);
1337 return InvalidParameter
;
1339 return GdipScaleMatrix(brush
->transform
, sx
, sy
, order
);
1342 GpStatus WINGDIPAPI
GdipSetLineBlend(GpLineGradient
*brush
,
1343 GDIPCONST REAL
*factors
, GDIPCONST REAL
* positions
, INT count
)
1345 REAL
*new_blendfac
, *new_blendpos
;
1347 TRACE("(%p, %p, %p, %i)\n", brush
, factors
, positions
, count
);
1349 if(!brush
|| !factors
|| !positions
|| count
<= 0 ||
1350 (count
>= 2 && (positions
[0] != 0.0f
|| positions
[count
-1] != 1.0f
)))
1351 return InvalidParameter
;
1353 new_blendfac
= GdipAlloc(count
* sizeof(REAL
));
1354 new_blendpos
= GdipAlloc(count
* sizeof(REAL
));
1356 if (!new_blendfac
|| !new_blendpos
)
1358 GdipFree(new_blendfac
);
1359 GdipFree(new_blendpos
);
1363 memcpy(new_blendfac
, factors
, count
* sizeof(REAL
));
1364 memcpy(new_blendpos
, positions
, count
* sizeof(REAL
));
1366 GdipFree(brush
->blendfac
);
1367 GdipFree(brush
->blendpos
);
1369 brush
->blendcount
= count
;
1370 brush
->blendfac
= new_blendfac
;
1371 brush
->blendpos
= new_blendpos
;
1376 GpStatus WINGDIPAPI
GdipGetLineBlend(GpLineGradient
*brush
, REAL
*factors
,
1377 REAL
*positions
, INT count
)
1379 TRACE("(%p, %p, %p, %i)\n", brush
, factors
, positions
, count
);
1381 if (!brush
|| !factors
|| !positions
|| count
<= 0)
1382 return InvalidParameter
;
1384 if (count
< brush
->blendcount
)
1385 return InsufficientBuffer
;
1387 memcpy(factors
, brush
->blendfac
, brush
->blendcount
* sizeof(REAL
));
1388 memcpy(positions
, brush
->blendpos
, brush
->blendcount
* sizeof(REAL
));
1393 GpStatus WINGDIPAPI
GdipGetLineBlendCount(GpLineGradient
*brush
, INT
*count
)
1395 TRACE("(%p, %p)\n", brush
, count
);
1397 if (!brush
|| !count
)
1398 return InvalidParameter
;
1400 *count
= brush
->blendcount
;
1405 GpStatus WINGDIPAPI
GdipSetLineGammaCorrection(GpLineGradient
*line
,
1408 TRACE("(%p, %d)\n", line
, usegamma
);
1411 return InvalidParameter
;
1413 line
->gamma
= usegamma
;
1418 GpStatus WINGDIPAPI
GdipSetLineSigmaBlend(GpLineGradient
*line
, REAL focus
,
1425 const int precision
= 16;
1426 REAL erf_range
; /* we use values erf(-erf_range) through erf(+erf_range) */
1430 TRACE("(%p, %0.2f, %0.2f)\n", line
, focus
, scale
);
1432 if(!line
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0)
1433 return InvalidParameter
;
1435 /* we want 2 standard deviations */
1436 erf_range
= 2.0 / sqrt(2);
1438 /* calculate the constants we need to normalize the error function to be
1439 between 0.0 and scale over the range we need */
1440 min_erf
= erf(-erf_range
);
1441 scale_erf
= scale
/ (-2.0 * min_erf
);
1447 for (i
=1; i
<precision
; i
++)
1449 positions
[i
] = focus
* i
/ precision
;
1450 factors
[i
] = scale_erf
* (erf(2 * erf_range
* i
/ precision
- erf_range
) - min_erf
);
1452 num_points
+= precision
;
1455 positions
[num_points
] = focus
;
1456 factors
[num_points
] = scale
;
1461 for (i
=1; i
<precision
; i
++)
1463 positions
[i
+num_points
-1] = (focus
+ ((1.0-focus
) * i
/ precision
));
1464 factors
[i
+num_points
-1] = scale_erf
* (erf(erf_range
- 2 * erf_range
* i
/ precision
) - min_erf
);
1466 num_points
+= precision
;
1467 positions
[num_points
-1] = 1.0;
1468 factors
[num_points
-1] = 0.0;
1471 return GdipSetLineBlend(line
, factors
, positions
, num_points
);
1474 GpStatus WINGDIPAPI
GdipSetLineWrapMode(GpLineGradient
*line
,
1477 TRACE("(%p, %d)\n", line
, wrap
);
1479 if(!line
|| wrap
== WrapModeClamp
)
1480 return InvalidParameter
;
1487 GpStatus WINGDIPAPI
GdipSetPathGradientBlend(GpPathGradient
*brush
, GDIPCONST REAL
*blend
,
1488 GDIPCONST REAL
*pos
, INT count
)
1492 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, pos
, count
);
1495 FIXME("not implemented\n");
1497 return NotImplemented
;
1500 GpStatus WINGDIPAPI
GdipSetPathGradientLinearBlend(GpPathGradient
*brush
,
1501 REAL focus
, REAL scale
)
1505 TRACE("(%p,%0.2f,%0.2f)\n", brush
, focus
, scale
);
1508 FIXME("not implemented\n");
1510 return NotImplemented
;
1513 GpStatus WINGDIPAPI
GdipSetPathGradientPresetBlend(GpPathGradient
*brush
,
1514 GDIPCONST ARGB
*blend
, GDIPCONST REAL
*pos
, INT count
)
1516 FIXME("(%p,%p,%p,%i): stub\n", brush
, blend
, pos
, count
);
1517 return NotImplemented
;
1520 GpStatus WINGDIPAPI
GdipGetPathGradientPresetBlend(GpPathGradient
*brush
,
1521 ARGB
*blend
, REAL
*pos
, INT count
)
1523 FIXME("(%p,%p,%p,%i): stub\n", brush
, blend
, pos
, count
);
1524 return NotImplemented
;
1527 GpStatus WINGDIPAPI
GdipGetPathGradientPresetBlendCount(GpPathGradient
*brush
,
1530 FIXME("(%p,%p): stub\n", brush
, count
);
1531 return NotImplemented
;
1534 GpStatus WINGDIPAPI
GdipSetPathGradientCenterColor(GpPathGradient
*grad
,
1537 TRACE("(%p, %x)\n", grad
, argb
);
1540 return InvalidParameter
;
1542 grad
->centercolor
= argb
;
1543 grad
->brush
.lb
.lbColor
= ARGB2COLORREF(argb
);
1545 DeleteObject(grad
->brush
.gdibrush
);
1546 grad
->brush
.gdibrush
= CreateSolidBrush(grad
->brush
.lb
.lbColor
);
1551 GpStatus WINGDIPAPI
GdipSetPathGradientCenterPoint(GpPathGradient
*grad
,
1554 TRACE("(%p, %s)\n", grad
, debugstr_pointf(point
));
1557 return InvalidParameter
;
1559 grad
->center
.X
= point
->X
;
1560 grad
->center
.Y
= point
->Y
;
1565 GpStatus WINGDIPAPI
GdipSetPathGradientCenterPointI(GpPathGradient
*grad
,
1570 TRACE("(%p, %p)\n", grad
, point
);
1573 return InvalidParameter
;
1575 ptf
.X
= (REAL
)point
->X
;
1576 ptf
.Y
= (REAL
)point
->Y
;
1578 return GdipSetPathGradientCenterPoint(grad
,&ptf
);
1581 GpStatus WINGDIPAPI
GdipSetPathGradientFocusScales(GpPathGradient
*grad
,
1584 TRACE("(%p, %.2f, %.2f)\n", grad
, x
, y
);
1587 return InvalidParameter
;
1595 GpStatus WINGDIPAPI
GdipSetPathGradientGammaCorrection(GpPathGradient
*grad
,
1598 TRACE("(%p, %d)\n", grad
, gamma
);
1601 return InvalidParameter
;
1603 grad
->gamma
= gamma
;
1608 GpStatus WINGDIPAPI
GdipSetPathGradientSigmaBlend(GpPathGradient
*grad
,
1609 REAL focus
, REAL scale
)
1613 TRACE("(%p,%0.2f,%0.2f)\n", grad
, focus
, scale
);
1615 if(!grad
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0)
1616 return InvalidParameter
;
1619 FIXME("not implemented\n");
1621 return NotImplemented
;
1624 GpStatus WINGDIPAPI
GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
1625 *grad
, GDIPCONST ARGB
*argb
, INT
*count
)
1629 TRACE("(%p,%p,%p)\n", grad
, argb
, count
);
1631 if(!grad
|| !argb
|| !count
|| (*count
<= 0) ||
1632 (*count
> grad
->pathdata
.Count
))
1633 return InvalidParameter
;
1636 FIXME("not implemented\n");
1638 return NotImplemented
;
1641 GpStatus WINGDIPAPI
GdipSetPathGradientWrapMode(GpPathGradient
*grad
,
1644 TRACE("(%p, %d)\n", grad
, wrap
);
1647 return InvalidParameter
;
1654 GpStatus WINGDIPAPI
GdipSetPathGradientTransform(GpPathGradient
*grad
,
1659 TRACE("(%p,%p)\n", grad
, matrix
);
1662 FIXME("not implemented\n");
1664 return NotImplemented
;
1667 GpStatus WINGDIPAPI
GdipGetPathGradientTransform(GpPathGradient
*grad
,
1672 TRACE("(%p,%p)\n", grad
, matrix
);
1675 FIXME("not implemented\n");
1677 return NotImplemented
;
1680 GpStatus WINGDIPAPI
GdipMultiplyPathGradientTransform(GpPathGradient
*grad
,
1681 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
1685 TRACE("(%p,%p,%i)\n", grad
, matrix
, order
);
1688 FIXME("not implemented\n");
1690 return NotImplemented
;
1693 GpStatus WINGDIPAPI
GdipRotatePathGradientTransform(GpPathGradient
*grad
,
1694 REAL angle
, GpMatrixOrder order
)
1698 TRACE("(%p,%0.2f,%i)\n", grad
, angle
, order
);
1701 FIXME("not implemented\n");
1703 return NotImplemented
;
1706 GpStatus WINGDIPAPI
GdipScalePathGradientTransform(GpPathGradient
*grad
,
1707 REAL sx
, REAL sy
, GpMatrixOrder order
)
1711 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad
, sx
, sy
, order
);
1714 FIXME("not implemented\n");
1716 return NotImplemented
;
1719 GpStatus WINGDIPAPI
GdipTranslatePathGradientTransform(GpPathGradient
*grad
,
1720 REAL dx
, REAL dy
, GpMatrixOrder order
)
1724 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad
, dx
, dy
, order
);
1727 FIXME("not implemented\n");
1729 return NotImplemented
;
1732 GpStatus WINGDIPAPI
GdipSetSolidFillColor(GpSolidFill
*sf
, ARGB argb
)
1734 TRACE("(%p, %x)\n", sf
, argb
);
1737 return InvalidParameter
;
1740 sf
->brush
.lb
.lbColor
= ARGB2COLORREF(argb
);
1742 DeleteObject(sf
->brush
.gdibrush
);
1743 sf
->brush
.gdibrush
= CreateSolidBrush(sf
->brush
.lb
.lbColor
);
1748 /******************************************************************************
1749 * GdipSetTextureTransform [GDIPLUS.@]
1751 GpStatus WINGDIPAPI
GdipSetTextureTransform(GpTexture
*texture
,
1752 GDIPCONST GpMatrix
*matrix
)
1754 TRACE("(%p, %p)\n", texture
, matrix
);
1756 if(!texture
|| !matrix
)
1757 return InvalidParameter
;
1759 memcpy(texture
->transform
, matrix
, sizeof(GpMatrix
));
1764 /******************************************************************************
1765 * GdipSetTextureWrapMode [GDIPLUS.@]
1767 * WrapMode not used, only stored
1769 GpStatus WINGDIPAPI
GdipSetTextureWrapMode(GpTexture
*brush
, GpWrapMode wrapmode
)
1771 TRACE("(%p, %d)\n", brush
, wrapmode
);
1774 return InvalidParameter
;
1776 brush
->wrap
= wrapmode
;
1781 GpStatus WINGDIPAPI
GdipSetLineColors(GpLineGradient
*brush
, ARGB color1
,
1784 TRACE("(%p, %x, %x)\n", brush
, color1
, color2
);
1787 return InvalidParameter
;
1789 brush
->startcolor
= color1
;
1790 brush
->endcolor
= color2
;
1795 GpStatus WINGDIPAPI
GdipGetLineColors(GpLineGradient
*brush
, ARGB
*colors
)
1797 TRACE("(%p, %p)\n", brush
, colors
);
1799 if(!brush
|| !colors
)
1800 return InvalidParameter
;
1802 colors
[0] = brush
->startcolor
;
1803 colors
[1] = brush
->endcolor
;
1808 /******************************************************************************
1809 * GdipRotateTextureTransform [GDIPLUS.@]
1811 GpStatus WINGDIPAPI
GdipRotateTextureTransform(GpTexture
* brush
, REAL angle
,
1812 GpMatrixOrder order
)
1814 TRACE("(%p, %.2f, %d)\n", brush
, angle
, order
);
1817 return InvalidParameter
;
1819 return GdipRotateMatrix(brush
->transform
, angle
, order
);
1822 GpStatus WINGDIPAPI
GdipSetLineLinearBlend(GpLineGradient
*brush
, REAL focus
,
1829 TRACE("(%p,%.2f,%.2f)\n", brush
, focus
, scale
);
1831 if (!brush
) return InvalidParameter
;
1835 factors
[num_points
] = 0.0;
1836 positions
[num_points
] = 0.0;
1840 factors
[num_points
] = scale
;
1841 positions
[num_points
] = focus
;
1846 factors
[num_points
] = 0.0;
1847 positions
[num_points
] = 1.0;
1851 return GdipSetLineBlend(brush
, factors
, positions
, num_points
);
1854 GpStatus WINGDIPAPI
GdipSetLinePresetBlend(GpLineGradient
*brush
,
1855 GDIPCONST ARGB
*blend
, GDIPCONST REAL
* positions
, INT count
)
1859 TRACE("(%p,%p,%p,%i)\n", brush
, blend
, positions
, count
);
1861 if (!brush
|| !blend
|| !positions
|| count
< 2 ||
1862 positions
[0] != 0.0f
|| positions
[count
-1] != 1.0f
)
1864 return InvalidParameter
;
1867 new_color
= GdipAlloc(count
* sizeof(ARGB
));
1868 new_pos
= GdipAlloc(count
* sizeof(REAL
));
1869 if (!new_color
|| !new_pos
)
1871 GdipFree(new_color
);
1876 memcpy(new_color
, blend
, sizeof(ARGB
) * count
);
1877 memcpy(new_pos
, positions
, sizeof(REAL
) * count
);
1879 GdipFree(brush
->pblendcolor
);
1880 GdipFree(brush
->pblendpos
);
1882 brush
->pblendcolor
= new_color
;
1883 brush
->pblendpos
= new_pos
;
1884 brush
->pblendcount
= count
;
1889 GpStatus WINGDIPAPI
GdipGetLinePresetBlend(GpLineGradient
*brush
,
1890 ARGB
*blend
, REAL
* positions
, INT count
)
1892 if (!brush
|| !blend
|| !positions
|| count
< 2)
1893 return InvalidParameter
;
1895 if (brush
->pblendcount
== 0)
1896 return GenericError
;
1898 if (count
< brush
->pblendcount
)
1899 return InsufficientBuffer
;
1901 memcpy(blend
, brush
->pblendcolor
, sizeof(ARGB
) * brush
->pblendcount
);
1902 memcpy(positions
, brush
->pblendpos
, sizeof(REAL
) * brush
->pblendcount
);
1907 GpStatus WINGDIPAPI
GdipGetLinePresetBlendCount(GpLineGradient
*brush
,
1910 if (!brush
|| !count
)
1911 return InvalidParameter
;
1913 *count
= brush
->pblendcount
;
1918 GpStatus WINGDIPAPI
GdipResetLineTransform(GpLineGradient
*brush
)
1922 TRACE("(%p)\n", brush
);
1925 FIXME("not implemented\n");
1927 return NotImplemented
;
1930 GpStatus WINGDIPAPI
GdipSetLineTransform(GpLineGradient
*brush
,
1931 GDIPCONST GpMatrix
*matrix
)
1935 TRACE("(%p,%p)\n", brush
, matrix
);
1938 FIXME("not implemented\n");
1940 return NotImplemented
;
1943 GpStatus WINGDIPAPI
GdipGetLineTransform(GpLineGradient
*brush
, GpMatrix
*matrix
)
1947 TRACE("(%p,%p)\n", brush
, matrix
);
1950 FIXME("not implemented\n");
1952 return NotImplemented
;
1955 GpStatus WINGDIPAPI
GdipScaleLineTransform(GpLineGradient
*brush
, REAL sx
, REAL sy
,
1956 GpMatrixOrder order
)
1960 TRACE("(%p,%0.2f,%0.2f,%u)\n", brush
, sx
, sy
, order
);
1963 FIXME("not implemented\n");
1965 return NotImplemented
;
1968 GpStatus WINGDIPAPI
GdipMultiplyLineTransform(GpLineGradient
*brush
,
1969 GDIPCONST GpMatrix
*matrix
, GpMatrixOrder order
)
1973 TRACE("(%p,%p,%u)\n", brush
, matrix
, order
);
1976 FIXME("not implemented\n");
1978 return NotImplemented
;
1981 GpStatus WINGDIPAPI
GdipTranslateLineTransform(GpLineGradient
* brush
,
1982 REAL dx
, REAL dy
, GpMatrixOrder order
)
1984 FIXME("stub: %p %f %f %d\n", brush
, dx
, dy
, order
);
1986 return NotImplemented
;
1989 /******************************************************************************
1990 * GdipTranslateTextureTransform [GDIPLUS.@]
1992 GpStatus WINGDIPAPI
GdipTranslateTextureTransform(GpTexture
* brush
, REAL dx
, REAL dy
,
1993 GpMatrixOrder order
)
1995 TRACE("(%p, %.2f, %.2f, %d)\n", brush
, dx
, dy
, order
);
1998 return InvalidParameter
;
2000 return GdipTranslateMatrix(brush
->transform
, dx
, dy
, order
);
2003 GpStatus WINGDIPAPI
GdipGetLineRect(GpLineGradient
*brush
, GpRectF
*rect
)
2005 TRACE("(%p, %p)\n", brush
, rect
);
2008 return InvalidParameter
;
2010 *rect
= brush
->rect
;
2015 GpStatus WINGDIPAPI
GdipGetLineRectI(GpLineGradient
*brush
, GpRect
*rect
)
2020 TRACE("(%p, %p)\n", brush
, rect
);
2023 return InvalidParameter
;
2025 ret
= GdipGetLineRect(brush
, &rectF
);
2028 rect
->X
= roundr(rectF
.X
);
2029 rect
->Y
= roundr(rectF
.Y
);
2030 rect
->Width
= roundr(rectF
.Width
);
2031 rect
->Height
= roundr(rectF
.Height
);
2037 GpStatus WINGDIPAPI
GdipRotateLineTransform(GpLineGradient
* brush
,
2038 REAL angle
, GpMatrixOrder order
)
2042 TRACE("(%p,%0.2f,%u)\n", brush
, angle
, order
);
2045 return InvalidParameter
;
2048 FIXME("(%p, %.2f, %d) stub\n", brush
, angle
, order
);
2050 return NotImplemented
;