gdiplus: Create GDI brush only when needed.
[wine/multimedia.git] / dlls / gdiplus / brush.c
blobca4d8eb3bcddd6e8971cd0c86aea0a264308deaa
1 /*
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
19 #include <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "winuser.h"
24 #include "wingdi.h"
26 #define COBJMACROS
27 #include "objbase.h"
28 #include "olectl.h"
29 #include "ole2.h"
31 #include "gdiplus.h"
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);
44 if(!brush || !clone)
45 return InvalidParameter;
47 switch(brush->bt){
48 case BrushTypeSolidColor:
50 GpSolidFill *fill;
51 *clone = GdipAlloc(sizeof(GpSolidFill));
52 if (!*clone) return OutOfMemory;
54 fill = (GpSolidFill*)*clone;
56 memcpy(*clone, brush, sizeof(GpSolidFill));
58 fill->bmp = ARGB2BMP(fill->color);
59 break;
61 case BrushTypeHatchFill:
63 GpHatch *hatch = (GpHatch*)brush;
65 return GdipCreateHatchBrush(hatch->hatchstyle, hatch->forecol, hatch->backcol, (GpHatch**)clone);
67 case BrushTypePathGradient:{
68 GpPathGradient *src, *dest;
69 INT count;
71 *clone = GdipAlloc(sizeof(GpPathGradient));
72 if (!*clone) return OutOfMemory;
74 src = (GpPathGradient*) brush,
75 dest = (GpPathGradient*) *clone;
76 count = src->pathdata.Count;
78 memcpy(dest, src, sizeof(GpPathGradient));
80 dest->pathdata.Count = count;
81 dest->pathdata.Points = GdipAlloc(count * sizeof(PointF));
82 dest->pathdata.Types = GdipAlloc(count);
84 if(!dest->pathdata.Points || !dest->pathdata.Types){
85 GdipFree(dest->pathdata.Points);
86 GdipFree(dest->pathdata.Types);
87 GdipFree(dest);
88 return OutOfMemory;
91 memcpy(dest->pathdata.Points, src->pathdata.Points, count * sizeof(PointF));
92 memcpy(dest->pathdata.Types, src->pathdata.Types, count);
94 /* blending */
95 count = src->blendcount;
96 dest->blendcount = count;
97 dest->blendfac = GdipAlloc(count * sizeof(REAL));
98 dest->blendpos = GdipAlloc(count * sizeof(REAL));
100 if(!dest->blendfac || !dest->blendpos){
101 GdipFree(dest->pathdata.Points);
102 GdipFree(dest->pathdata.Types);
103 GdipFree(dest->blendfac);
104 GdipFree(dest->blendpos);
105 GdipFree(dest);
106 return OutOfMemory;
109 memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL));
110 memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL));
112 break;
114 case BrushTypeLinearGradient:{
115 GpLineGradient *dest, *src;
116 INT count, pcount;
118 dest = GdipAlloc(sizeof(GpLineGradient));
119 if(!dest) return OutOfMemory;
121 src = (GpLineGradient*)brush;
123 memcpy(dest, src, sizeof(GpLineGradient));
125 count = dest->blendcount;
126 dest->blendfac = GdipAlloc(count * sizeof(REAL));
127 dest->blendpos = GdipAlloc(count * sizeof(REAL));
128 pcount = dest->pblendcount;
129 if (pcount)
131 dest->pblendcolor = GdipAlloc(pcount * sizeof(ARGB));
132 dest->pblendpos = GdipAlloc(pcount * sizeof(REAL));
135 if (!dest->blendfac || !dest->blendpos ||
136 (pcount && (!dest->pblendcolor || !dest->pblendpos)))
138 GdipFree(dest->blendfac);
139 GdipFree(dest->blendpos);
140 GdipFree(dest->pblendcolor);
141 GdipFree(dest->pblendpos);
142 GdipFree(dest);
143 return OutOfMemory;
146 memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL));
147 memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL));
149 if (pcount)
151 memcpy(dest->pblendcolor, src->pblendcolor, pcount * sizeof(ARGB));
152 memcpy(dest->pblendpos, src->pblendpos, pcount * sizeof(REAL));
155 *clone = &dest->brush;
156 break;
158 case BrushTypeTextureFill:
160 GpStatus stat;
161 GpTexture *texture = (GpTexture*)brush;
162 GpTexture *new_texture;
163 UINT width, height;
165 stat = GdipGetImageWidth(texture->image, &width);
166 if (stat != Ok) return stat;
167 stat = GdipGetImageHeight(texture->image, &height);
168 if (stat != Ok) return stat;
170 stat = GdipCreateTextureIA(texture->image, texture->imageattributes, 0, 0, width, height, &new_texture);
172 if (stat == Ok)
174 memcpy(new_texture->transform, texture->transform, sizeof(GpMatrix));
175 *clone = (GpBrush*)new_texture;
177 else
178 *clone = NULL;
180 return stat;
182 default:
183 ERR("not implemented for brush type %d\n", brush->bt);
184 return NotImplemented;
187 TRACE("<-- %p\n", *clone);
188 return Ok;
191 static const char HatchBrushes[][8] = {
192 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HatchStyleHorizontal */
193 { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleVertical */
194 { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HatchStyleForwardDiagonal */
195 { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HatchStyleBackwardDiagonal */
196 { 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleCross */
197 { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }, /* HatchStyleDiagonalCross */
198 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80 }, /* HatchStyle05Percent */
199 { 0x00, 0x02, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88 }, /* HatchStyle10Percent */
200 { 0x00, 0x22, 0x00, 0xcc, 0x00, 0x22, 0x00, 0xcc }, /* HatchStyle20Percent */
201 { 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc }, /* HatchStyle25Percent */
202 { 0x00, 0xcc, 0x04, 0xcc, 0x00, 0xcc, 0x40, 0xcc }, /* HatchStyle30Percent */
203 { 0x44, 0xcc, 0x22, 0xcc, 0x44, 0xcc, 0x22, 0xcc }, /* HatchStyle40Percent */
204 { 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc }, /* HatchStyle50Percent */
205 { 0x55, 0xcd, 0x55, 0xee, 0x55, 0xdc, 0x55, 0xee }, /* HatchStyle60Percent */
206 { 0x55, 0xdd, 0x55, 0xff, 0x55, 0xdd, 0x55, 0xff }, /* HatchStyle70Percent */
207 { 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff }, /* HatchStyle75Percent */
208 { 0x55, 0xff, 0x59, 0xff, 0x55, 0xff, 0x99, 0xff }, /* HatchStyle80Percent */
209 { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xfd, 0xff }, /* HatchStyle90Percent */
210 { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 }, /* HatchStyleLightDownwardDiagonal */
211 { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 }, /* HatchStyleLightUpwardDiagonal */
212 { 0x99, 0x33, 0x66, 0xcc, 0x99, 0x33, 0x66, 0xcc }, /* HatchStyleDarkDownwardDiagonal */
213 { 0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33, 0x99 }, /* HatchStyleDarkUpwardDiagonal */
214 { 0xc1, 0x83, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0 }, /* HatchStyleWideDownwardDiagonal */
215 { 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x07, 0x83, 0xc1 }, /* HatchStyleWideUpwardDiagonal */
216 { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 }, /* HatchStyleLightVertical */
217 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff }, /* HatchStyleLightHorizontal */
218 { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, /* HatchStyleNarrowVertical */
219 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, /* HatchStyleNarrowHorizontal */
220 { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }, /* HatchStyleDarkVertical */
221 { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff }, /* HatchStyleDarkHorizontal */
224 GpStatus get_hatch_data(HatchStyle hatchstyle, const char **result)
226 if (hatchstyle < sizeof(HatchBrushes) / sizeof(HatchBrushes[0]))
228 *result = HatchBrushes[hatchstyle];
229 return Ok;
231 else
232 return NotImplemented;
235 /******************************************************************************
236 * GdipCreateHatchBrush [GDIPLUS.@]
238 GpStatus WINGDIPAPI GdipCreateHatchBrush(HatchStyle hatchstyle, ARGB forecol, ARGB backcol, GpHatch **brush)
240 TRACE("(%d, %d, %d, %p)\n", hatchstyle, forecol, backcol, brush);
242 if(!brush) return InvalidParameter;
244 *brush = GdipAlloc(sizeof(GpHatch));
245 if (!*brush) return OutOfMemory;
247 (*brush)->brush.bt = BrushTypeHatchFill;
248 (*brush)->forecol = forecol;
249 (*brush)->backcol = backcol;
250 (*brush)->hatchstyle = hatchstyle;
251 TRACE("<-- %p\n", *brush);
253 return Ok;
256 /******************************************************************************
257 * GdipCreateLineBrush [GDIPLUS.@]
259 GpStatus WINGDIPAPI GdipCreateLineBrush(GDIPCONST GpPointF* startpoint,
260 GDIPCONST GpPointF* endpoint, ARGB startcolor, ARGB endcolor,
261 GpWrapMode wrap, GpLineGradient **line)
263 TRACE("(%s, %s, %x, %x, %d, %p)\n", debugstr_pointf(startpoint),
264 debugstr_pointf(endpoint), startcolor, endcolor, wrap, line);
266 if(!line || !startpoint || !endpoint || wrap == WrapModeClamp)
267 return InvalidParameter;
269 if (startpoint->X == endpoint->X && startpoint->Y == endpoint->Y)
270 return OutOfMemory;
272 *line = GdipAlloc(sizeof(GpLineGradient));
273 if(!*line) return OutOfMemory;
275 (*line)->brush.bt = BrushTypeLinearGradient;
277 (*line)->startpoint.X = startpoint->X;
278 (*line)->startpoint.Y = startpoint->Y;
279 (*line)->endpoint.X = endpoint->X;
280 (*line)->endpoint.Y = endpoint->Y;
281 (*line)->startcolor = startcolor;
282 (*line)->endcolor = endcolor;
283 (*line)->wrap = wrap;
284 (*line)->gamma = FALSE;
286 (*line)->rect.X = (startpoint->X < endpoint->X ? startpoint->X: endpoint->X);
287 (*line)->rect.Y = (startpoint->Y < endpoint->Y ? startpoint->Y: endpoint->Y);
288 (*line)->rect.Width = fabs(startpoint->X - endpoint->X);
289 (*line)->rect.Height = fabs(startpoint->Y - endpoint->Y);
291 if ((*line)->rect.Width == 0)
293 (*line)->rect.X -= (*line)->rect.Height / 2.0f;
294 (*line)->rect.Width = (*line)->rect.Height;
296 else if ((*line)->rect.Height == 0)
298 (*line)->rect.Y -= (*line)->rect.Width / 2.0f;
299 (*line)->rect.Height = (*line)->rect.Width;
302 (*line)->blendcount = 1;
303 (*line)->blendfac = GdipAlloc(sizeof(REAL));
304 (*line)->blendpos = GdipAlloc(sizeof(REAL));
306 if (!(*line)->blendfac || !(*line)->blendpos)
308 GdipFree((*line)->blendfac);
309 GdipFree((*line)->blendpos);
310 GdipFree(*line);
311 *line = NULL;
312 return OutOfMemory;
315 (*line)->blendfac[0] = 1.0f;
316 (*line)->blendpos[0] = 1.0f;
318 (*line)->pblendcolor = NULL;
319 (*line)->pblendpos = NULL;
320 (*line)->pblendcount = 0;
322 TRACE("<-- %p\n", *line);
324 return Ok;
327 GpStatus WINGDIPAPI GdipCreateLineBrushI(GDIPCONST GpPoint* startpoint,
328 GDIPCONST GpPoint* endpoint, ARGB startcolor, ARGB endcolor,
329 GpWrapMode wrap, GpLineGradient **line)
331 GpPointF stF;
332 GpPointF endF;
334 TRACE("(%p, %p, %x, %x, %d, %p)\n", startpoint, endpoint,
335 startcolor, endcolor, wrap, line);
337 if(!startpoint || !endpoint)
338 return InvalidParameter;
340 stF.X = (REAL)startpoint->X;
341 stF.Y = (REAL)startpoint->Y;
342 endF.X = (REAL)endpoint->X;
343 endF.Y = (REAL)endpoint->Y;
345 return GdipCreateLineBrush(&stF, &endF, startcolor, endcolor, wrap, line);
348 GpStatus WINGDIPAPI GdipCreateLineBrushFromRect(GDIPCONST GpRectF* rect,
349 ARGB startcolor, ARGB endcolor, LinearGradientMode mode, GpWrapMode wrap,
350 GpLineGradient **line)
352 GpPointF start, end;
353 GpStatus stat;
355 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect, startcolor, endcolor, mode,
356 wrap, line);
358 if(!line || !rect)
359 return InvalidParameter;
361 switch (mode)
363 case LinearGradientModeHorizontal:
364 start.X = rect->X;
365 start.Y = rect->Y;
366 end.X = rect->X + rect->Width;
367 end.Y = rect->Y;
368 break;
369 case LinearGradientModeVertical:
370 start.X = rect->X;
371 start.Y = rect->Y;
372 end.X = rect->X;
373 end.Y = rect->Y + rect->Height;
374 break;
375 case LinearGradientModeForwardDiagonal:
376 start.X = rect->X;
377 start.Y = rect->Y;
378 end.X = rect->X + rect->Width;
379 end.Y = rect->Y + rect->Height;
380 break;
381 case LinearGradientModeBackwardDiagonal:
382 start.X = rect->X + rect->Width;
383 start.Y = rect->Y;
384 end.X = rect->X;
385 end.Y = rect->Y + rect->Height;
386 break;
387 default:
388 return InvalidParameter;
391 stat = GdipCreateLineBrush(&start, &end, startcolor, endcolor, wrap, line);
393 if (stat == Ok)
394 (*line)->rect = *rect;
396 return stat;
399 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectI(GDIPCONST GpRect* rect,
400 ARGB startcolor, ARGB endcolor, LinearGradientMode mode, GpWrapMode wrap,
401 GpLineGradient **line)
403 GpRectF rectF;
405 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect, startcolor, endcolor, mode,
406 wrap, line);
408 rectF.X = (REAL) rect->X;
409 rectF.Y = (REAL) rect->Y;
410 rectF.Width = (REAL) rect->Width;
411 rectF.Height = (REAL) rect->Height;
413 return GdipCreateLineBrushFromRect(&rectF, startcolor, endcolor, mode, wrap, line);
416 /******************************************************************************
417 * GdipCreateLineBrushFromRectWithAngle [GDIPLUS.@]
419 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF* rect,
420 ARGB startcolor, ARGB endcolor, REAL angle, BOOL isAngleScalable, GpWrapMode wrap,
421 GpLineGradient **line)
423 GpStatus stat;
424 LinearGradientMode mode;
425 REAL width, height, exofs, eyofs;
426 REAL sin_angle, cos_angle, sin_cos_angle;
428 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect, startcolor, endcolor, angle, isAngleScalable,
429 wrap, line);
431 sin_angle = sinf(deg2rad(angle));
432 cos_angle = cosf(deg2rad(angle));
433 sin_cos_angle = sin_angle * cos_angle;
435 if (isAngleScalable)
437 width = height = 1.0;
439 else
441 width = rect->Width;
442 height = rect->Height;
445 if (sin_cos_angle >= 0)
446 mode = LinearGradientModeForwardDiagonal;
447 else
448 mode = LinearGradientModeBackwardDiagonal;
450 stat = GdipCreateLineBrushFromRect(rect, startcolor, endcolor, mode, wrap, line);
452 if (stat == Ok)
454 if (sin_cos_angle >= 0)
456 exofs = width * sin_cos_angle + height * cos_angle * cos_angle;
457 eyofs = width * sin_angle * sin_angle + height * sin_cos_angle;
459 else
461 exofs = width * sin_angle * sin_angle + height * sin_cos_angle;
462 eyofs = -width * sin_cos_angle + height * sin_angle * sin_angle;
465 if (isAngleScalable)
467 exofs = exofs * rect->Width;
468 eyofs = eyofs * rect->Height;
471 if (sin_angle >= 0)
473 (*line)->endpoint.X = rect->X + exofs;
474 (*line)->endpoint.Y = rect->Y + eyofs;
476 else
478 (*line)->endpoint.X = (*line)->startpoint.X;
479 (*line)->endpoint.Y = (*line)->startpoint.Y;
480 (*line)->startpoint.X = rect->X + exofs;
481 (*line)->startpoint.Y = rect->Y + eyofs;
485 return stat;
488 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngleI(GDIPCONST GpRect* rect,
489 ARGB startcolor, ARGB endcolor, REAL angle, BOOL isAngleScalable, GpWrapMode wrap,
490 GpLineGradient **line)
492 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect, startcolor, endcolor, angle, isAngleScalable,
493 wrap, line);
495 return GdipCreateLineBrushFromRectI(rect, startcolor, endcolor, LinearGradientModeForwardDiagonal,
496 wrap, line);
499 GpStatus WINGDIPAPI GdipCreatePathGradient(GDIPCONST GpPointF* points,
500 INT count, GpWrapMode wrap, GpPathGradient **grad)
502 TRACE("(%p, %d, %d, %p)\n", points, count, wrap, grad);
504 if(!points || !grad)
505 return InvalidParameter;
507 if(count <= 0)
508 return OutOfMemory;
510 *grad = GdipAlloc(sizeof(GpPathGradient));
511 if (!*grad) return OutOfMemory;
513 (*grad)->blendfac = GdipAlloc(sizeof(REAL));
514 (*grad)->blendpos = GdipAlloc(sizeof(REAL));
515 if(!(*grad)->blendfac || !(*grad)->blendpos){
516 GdipFree((*grad)->blendfac);
517 GdipFree((*grad)->blendpos);
518 GdipFree(*grad);
519 *grad = NULL;
520 return OutOfMemory;
522 (*grad)->blendfac[0] = 1.0;
523 (*grad)->blendpos[0] = 1.0;
524 (*grad)->blendcount = 1;
526 (*grad)->pathdata.Count = count;
527 (*grad)->pathdata.Points = GdipAlloc(count * sizeof(PointF));
528 (*grad)->pathdata.Types = GdipAlloc(count);
530 if(!(*grad)->pathdata.Points || !(*grad)->pathdata.Types){
531 GdipFree((*grad)->pathdata.Points);
532 GdipFree((*grad)->pathdata.Types);
533 GdipFree(*grad);
534 return OutOfMemory;
537 memcpy((*grad)->pathdata.Points, points, count * sizeof(PointF));
538 memset((*grad)->pathdata.Types, PathPointTypeLine, count);
540 (*grad)->brush.bt = BrushTypePathGradient;
541 (*grad)->centercolor = 0xffffffff;
542 (*grad)->wrap = wrap;
543 (*grad)->gamma = FALSE;
544 (*grad)->center.X = 0.0;
545 (*grad)->center.Y = 0.0;
546 (*grad)->focus.X = 0.0;
547 (*grad)->focus.Y = 0.0;
549 TRACE("<-- %p\n", *grad);
551 return Ok;
554 GpStatus WINGDIPAPI GdipCreatePathGradientI(GDIPCONST GpPoint* points,
555 INT count, GpWrapMode wrap, GpPathGradient **grad)
557 GpPointF *pointsF;
558 GpStatus ret;
559 INT i;
561 TRACE("(%p, %d, %d, %p)\n", points, count, wrap, grad);
563 if(!points || !grad)
564 return InvalidParameter;
566 if(count <= 0)
567 return OutOfMemory;
569 pointsF = GdipAlloc(sizeof(GpPointF) * count);
570 if(!pointsF)
571 return OutOfMemory;
573 for(i = 0; i < count; i++){
574 pointsF[i].X = (REAL)points[i].X;
575 pointsF[i].Y = (REAL)points[i].Y;
578 ret = GdipCreatePathGradient(pointsF, count, wrap, grad);
579 GdipFree(pointsF);
581 return ret;
584 /******************************************************************************
585 * GdipCreatePathGradientFromPath [GDIPLUS.@]
587 * FIXME: path gradient brushes not truly supported (drawn as solid brushes)
589 GpStatus WINGDIPAPI GdipCreatePathGradientFromPath(GDIPCONST GpPath* path,
590 GpPathGradient **grad)
592 TRACE("(%p, %p)\n", path, grad);
594 if(!path || !grad)
595 return InvalidParameter;
597 *grad = GdipAlloc(sizeof(GpPathGradient));
598 if (!*grad) return OutOfMemory;
600 (*grad)->blendfac = GdipAlloc(sizeof(REAL));
601 (*grad)->blendpos = GdipAlloc(sizeof(REAL));
602 if(!(*grad)->blendfac || !(*grad)->blendpos){
603 GdipFree((*grad)->blendfac);
604 GdipFree((*grad)->blendpos);
605 GdipFree(*grad);
606 *grad = NULL;
607 return OutOfMemory;
609 (*grad)->blendfac[0] = 1.0;
610 (*grad)->blendpos[0] = 1.0;
611 (*grad)->blendcount = 1;
613 (*grad)->pathdata.Count = path->pathdata.Count;
614 (*grad)->pathdata.Points = GdipAlloc(path->pathdata.Count * sizeof(PointF));
615 (*grad)->pathdata.Types = GdipAlloc(path->pathdata.Count);
617 if(!(*grad)->pathdata.Points || !(*grad)->pathdata.Types){
618 GdipFree((*grad)->pathdata.Points);
619 GdipFree((*grad)->pathdata.Types);
620 GdipFree(*grad);
621 return OutOfMemory;
624 memcpy((*grad)->pathdata.Points, path->pathdata.Points,
625 path->pathdata.Count * sizeof(PointF));
626 memcpy((*grad)->pathdata.Types, path->pathdata.Types, path->pathdata.Count);
628 (*grad)->brush.bt = BrushTypePathGradient;
629 (*grad)->centercolor = 0xffffffff;
630 (*grad)->wrap = WrapModeClamp;
631 (*grad)->gamma = FALSE;
632 /* FIXME: this should be set to the "centroid" of the path by default */
633 (*grad)->center.X = 0.0;
634 (*grad)->center.Y = 0.0;
635 (*grad)->focus.X = 0.0;
636 (*grad)->focus.Y = 0.0;
638 TRACE("<-- %p\n", *grad);
640 return Ok;
643 /******************************************************************************
644 * GdipCreateSolidFill [GDIPLUS.@]
646 GpStatus WINGDIPAPI GdipCreateSolidFill(ARGB color, GpSolidFill **sf)
648 TRACE("(%x, %p)\n", color, sf);
650 if(!sf) return InvalidParameter;
652 *sf = GdipAlloc(sizeof(GpSolidFill));
653 if (!*sf) return OutOfMemory;
655 (*sf)->brush.bt = BrushTypeSolidColor;
656 (*sf)->color = color;
657 (*sf)->bmp = ARGB2BMP(color);
659 TRACE("<-- %p\n", *sf);
661 return Ok;
664 /******************************************************************************
665 * GdipCreateTexture [GDIPLUS.@]
667 * PARAMS
668 * image [I] image to use
669 * wrapmode [I] optional
670 * texture [O] pointer to the resulting texturebrush
672 * RETURNS
673 * SUCCESS: Ok
674 * FAILURE: element of GpStatus
676 GpStatus WINGDIPAPI GdipCreateTexture(GpImage *image, GpWrapMode wrapmode,
677 GpTexture **texture)
679 UINT width, height;
680 GpImageAttributes *attributes;
681 GpStatus stat;
683 TRACE("%p, %d %p\n", image, wrapmode, texture);
685 if (!(image && texture))
686 return InvalidParameter;
688 stat = GdipGetImageWidth(image, &width);
689 if (stat != Ok) return stat;
690 stat = GdipGetImageHeight(image, &height);
691 if (stat != Ok) return stat;
693 stat = GdipCreateImageAttributes(&attributes);
695 if (stat == Ok)
697 attributes->wrap = wrapmode;
699 stat = GdipCreateTextureIA(image, attributes, 0, 0, width, height,
700 texture);
702 GdipDisposeImageAttributes(attributes);
705 return stat;
708 /******************************************************************************
709 * GdipCreateTexture2 [GDIPLUS.@]
711 GpStatus WINGDIPAPI GdipCreateTexture2(GpImage *image, GpWrapMode wrapmode,
712 REAL x, REAL y, REAL width, REAL height, GpTexture **texture)
714 GpImageAttributes *attributes;
715 GpStatus stat;
717 TRACE("%p %d %f %f %f %f %p\n", image, wrapmode,
718 x, y, width, height, texture);
720 stat = GdipCreateImageAttributes(&attributes);
722 if (stat == Ok)
724 attributes->wrap = wrapmode;
726 stat = GdipCreateTextureIA(image, attributes, x, y, width, height,
727 texture);
729 GdipDisposeImageAttributes(attributes);
732 return stat;
735 /******************************************************************************
736 * GdipCreateTextureIA [GDIPLUS.@]
738 * FIXME: imageattr ignored
740 GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image,
741 GDIPCONST GpImageAttributes *imageattr, REAL x, REAL y, REAL width,
742 REAL height, GpTexture **texture)
744 GpStatus status;
745 GpImage *new_image=NULL;
747 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %p)\n", image, imageattr, x, y, width, height,
748 texture);
750 if(!image || !texture || x < 0.0 || y < 0.0 || width < 0.0 || height < 0.0)
751 return InvalidParameter;
753 *texture = NULL;
755 if(image->type != ImageTypeBitmap){
756 FIXME("not implemented for image type %d\n", image->type);
757 return NotImplemented;
760 status = GdipCloneBitmapArea(x, y, width, height, PixelFormatDontCare, (GpBitmap*)image, (GpBitmap**)&new_image);
761 if (status != Ok)
762 return status;
764 *texture = GdipAlloc(sizeof(GpTexture));
765 if (!*texture){
766 status = OutOfMemory;
767 goto exit;
770 if((status = GdipCreateMatrix(&(*texture)->transform)) != Ok){
771 goto exit;
774 if (imageattr)
776 status = GdipCloneImageAttributes(imageattr, &(*texture)->imageattributes);
778 else
780 status = GdipCreateImageAttributes(&(*texture)->imageattributes);
781 if (status == Ok)
782 (*texture)->imageattributes->wrap = WrapModeTile;
784 if (status == Ok)
786 (*texture)->brush.bt = BrushTypeTextureFill;
787 (*texture)->image = new_image;
790 exit:
791 if (status == Ok)
793 TRACE("<-- %p\n", *texture);
795 else
797 if (*texture)
799 GdipDeleteMatrix((*texture)->transform);
800 GdipDisposeImageAttributes((*texture)->imageattributes);
801 GdipFree(*texture);
802 *texture = NULL;
804 GdipDisposeImage(new_image);
805 TRACE("<-- error %u\n", status);
808 return status;
811 /******************************************************************************
812 * GdipCreateTextureIAI [GDIPLUS.@]
814 GpStatus WINGDIPAPI GdipCreateTextureIAI(GpImage *image, GDIPCONST GpImageAttributes *imageattr,
815 INT x, INT y, INT width, INT height, GpTexture **texture)
817 TRACE("(%p, %p, %d, %d, %d, %d, %p)\n", image, imageattr, x, y, width, height,
818 texture);
820 return GdipCreateTextureIA(image,imageattr,(REAL)x,(REAL)y,(REAL)width,(REAL)height,texture);
823 GpStatus WINGDIPAPI GdipCreateTexture2I(GpImage *image, GpWrapMode wrapmode,
824 INT x, INT y, INT width, INT height, GpTexture **texture)
826 GpImageAttributes *imageattr;
827 GpStatus stat;
829 TRACE("%p %d %d %d %d %d %p\n", image, wrapmode, x, y, width, height,
830 texture);
832 stat = GdipCreateImageAttributes(&imageattr);
834 if (stat == Ok)
836 imageattr->wrap = wrapmode;
838 stat = GdipCreateTextureIA(image, imageattr, x, y, width, height, texture);
841 return stat;
844 GpStatus WINGDIPAPI GdipGetBrushType(GpBrush *brush, GpBrushType *type)
846 TRACE("(%p, %p)\n", brush, type);
848 if(!brush || !type) return InvalidParameter;
850 *type = brush->bt;
852 return Ok;
855 GpStatus WINGDIPAPI GdipGetHatchBackgroundColor(GpHatch *brush, ARGB *backcol)
857 TRACE("(%p, %p)\n", brush, backcol);
859 if(!brush || !backcol) return InvalidParameter;
861 *backcol = brush->backcol;
863 return Ok;
866 GpStatus WINGDIPAPI GdipGetHatchForegroundColor(GpHatch *brush, ARGB *forecol)
868 TRACE("(%p, %p)\n", brush, forecol);
870 if(!brush || !forecol) return InvalidParameter;
872 *forecol = brush->forecol;
874 return Ok;
877 GpStatus WINGDIPAPI GdipGetHatchStyle(GpHatch *brush, HatchStyle *hatchstyle)
879 TRACE("(%p, %p)\n", brush, hatchstyle);
881 if(!brush || !hatchstyle) return InvalidParameter;
883 *hatchstyle = brush->hatchstyle;
885 return Ok;
888 GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush)
890 TRACE("(%p)\n", brush);
892 if(!brush) return InvalidParameter;
894 switch(brush->bt)
896 case BrushTypePathGradient:
897 GdipFree(((GpPathGradient*) brush)->pathdata.Points);
898 GdipFree(((GpPathGradient*) brush)->pathdata.Types);
899 GdipFree(((GpPathGradient*) brush)->blendfac);
900 GdipFree(((GpPathGradient*) brush)->blendpos);
901 break;
902 case BrushTypeSolidColor:
903 if (((GpSolidFill*)brush)->bmp)
904 DeleteObject(((GpSolidFill*)brush)->bmp);
905 break;
906 case BrushTypeLinearGradient:
907 GdipFree(((GpLineGradient*)brush)->blendfac);
908 GdipFree(((GpLineGradient*)brush)->blendpos);
909 GdipFree(((GpLineGradient*)brush)->pblendcolor);
910 GdipFree(((GpLineGradient*)brush)->pblendpos);
911 break;
912 case BrushTypeTextureFill:
913 GdipDeleteMatrix(((GpTexture*)brush)->transform);
914 GdipDisposeImage(((GpTexture*)brush)->image);
915 GdipDisposeImageAttributes(((GpTexture*)brush)->imageattributes);
916 GdipFree(((GpTexture*)brush)->bitmap_bits);
917 break;
918 default:
919 break;
922 GdipFree(brush);
924 return Ok;
927 GpStatus WINGDIPAPI GdipGetLineGammaCorrection(GpLineGradient *line,
928 BOOL *usinggamma)
930 TRACE("(%p, %p)\n", line, usinggamma);
932 if(!line || !usinggamma)
933 return InvalidParameter;
935 *usinggamma = line->gamma;
937 return Ok;
940 GpStatus WINGDIPAPI GdipGetLineWrapMode(GpLineGradient *brush, GpWrapMode *wrapmode)
942 TRACE("(%p, %p)\n", brush, wrapmode);
944 if(!brush || !wrapmode)
945 return InvalidParameter;
947 *wrapmode = brush->wrap;
949 return Ok;
952 GpStatus WINGDIPAPI GdipGetPathGradientBlend(GpPathGradient *brush, REAL *blend,
953 REAL *positions, INT count)
955 TRACE("(%p, %p, %p, %d)\n", brush, blend, positions, count);
957 if(!brush || !blend || !positions || count <= 0)
958 return InvalidParameter;
960 if(count < brush->blendcount)
961 return InsufficientBuffer;
963 memcpy(blend, brush->blendfac, count*sizeof(REAL));
964 if(brush->blendcount > 1){
965 memcpy(positions, brush->blendpos, count*sizeof(REAL));
968 return Ok;
971 GpStatus WINGDIPAPI GdipGetPathGradientBlendCount(GpPathGradient *brush, INT *count)
973 TRACE("(%p, %p)\n", brush, count);
975 if(!brush || !count)
976 return InvalidParameter;
978 *count = brush->blendcount;
980 return Ok;
983 GpStatus WINGDIPAPI GdipGetPathGradientCenterPoint(GpPathGradient *grad,
984 GpPointF *point)
986 TRACE("(%p, %p)\n", grad, point);
988 if(!grad || !point)
989 return InvalidParameter;
991 point->X = grad->center.X;
992 point->Y = grad->center.Y;
994 return Ok;
997 GpStatus WINGDIPAPI GdipGetPathGradientCenterPointI(GpPathGradient *grad,
998 GpPoint *point)
1000 GpStatus ret;
1001 GpPointF ptf;
1003 TRACE("(%p, %p)\n", grad, point);
1005 if(!point)
1006 return InvalidParameter;
1008 ret = GdipGetPathGradientCenterPoint(grad,&ptf);
1010 if(ret == Ok){
1011 point->X = roundr(ptf.X);
1012 point->Y = roundr(ptf.Y);
1015 return ret;
1018 GpStatus WINGDIPAPI GdipGetPathGradientCenterColor(GpPathGradient *grad,
1019 ARGB *colors)
1021 static int calls;
1023 TRACE("(%p,%p)\n", grad, colors);
1025 if(!(calls++))
1026 FIXME("not implemented\n");
1028 return NotImplemented;
1031 GpStatus WINGDIPAPI GdipGetPathGradientFocusScales(GpPathGradient *grad,
1032 REAL *x, REAL *y)
1034 TRACE("(%p, %p, %p)\n", grad, x, y);
1036 if(!grad || !x || !y)
1037 return InvalidParameter;
1039 *x = grad->focus.X;
1040 *y = grad->focus.Y;
1042 return Ok;
1045 GpStatus WINGDIPAPI GdipGetPathGradientGammaCorrection(GpPathGradient *grad,
1046 BOOL *gamma)
1048 TRACE("(%p, %p)\n", grad, gamma);
1050 if(!grad || !gamma)
1051 return InvalidParameter;
1053 *gamma = grad->gamma;
1055 return Ok;
1058 GpStatus WINGDIPAPI GdipGetPathGradientPointCount(GpPathGradient *grad,
1059 INT *count)
1061 TRACE("(%p, %p)\n", grad, count);
1063 if(!grad || !count)
1064 return InvalidParameter;
1066 *count = grad->pathdata.Count;
1068 return Ok;
1071 GpStatus WINGDIPAPI GdipGetPathGradientRect(GpPathGradient *brush, GpRectF *rect)
1073 GpRectF r;
1074 GpPath* path;
1075 GpStatus stat;
1077 TRACE("(%p, %p)\n", brush, rect);
1079 if(!brush || !rect)
1080 return InvalidParameter;
1082 stat = GdipCreatePath2(brush->pathdata.Points, brush->pathdata.Types,
1083 brush->pathdata.Count, FillModeAlternate, &path);
1084 if(stat != Ok) return stat;
1086 stat = GdipGetPathWorldBounds(path, &r, NULL, NULL);
1087 if(stat != Ok){
1088 GdipDeletePath(path);
1089 return stat;
1092 memcpy(rect, &r, sizeof(GpRectF));
1094 GdipDeletePath(path);
1096 return Ok;
1099 GpStatus WINGDIPAPI GdipGetPathGradientRectI(GpPathGradient *brush, GpRect *rect)
1101 GpRectF rectf;
1102 GpStatus stat;
1104 TRACE("(%p, %p)\n", brush, rect);
1106 if(!brush || !rect)
1107 return InvalidParameter;
1109 stat = GdipGetPathGradientRect(brush, &rectf);
1110 if(stat != Ok) return stat;
1112 rect->X = roundr(rectf.X);
1113 rect->Y = roundr(rectf.Y);
1114 rect->Width = roundr(rectf.Width);
1115 rect->Height = roundr(rectf.Height);
1117 return Ok;
1120 GpStatus WINGDIPAPI GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
1121 *grad, ARGB *argb, INT *count)
1123 static int calls;
1125 TRACE("(%p,%p,%p)\n", grad, argb, count);
1127 if(!grad || !argb || !count || (*count < grad->pathdata.Count))
1128 return InvalidParameter;
1130 if(!(calls++))
1131 FIXME("not implemented\n");
1133 return NotImplemented;
1136 GpStatus WINGDIPAPI GdipGetPathGradientSurroundColorCount(GpPathGradient *brush, INT *count)
1138 static int calls;
1140 TRACE("(%p, %p)\n", brush, count);
1142 if (!brush || !count)
1143 return InvalidParameter;
1145 if(!(calls++))
1146 FIXME("not implemented\n");
1148 return NotImplemented;
1151 GpStatus WINGDIPAPI GdipGetPathGradientWrapMode(GpPathGradient *brush,
1152 GpWrapMode *wrapmode)
1154 TRACE("(%p, %p)\n", brush, wrapmode);
1156 if(!brush || !wrapmode)
1157 return InvalidParameter;
1159 *wrapmode = brush->wrap;
1161 return Ok;
1164 GpStatus WINGDIPAPI GdipGetSolidFillColor(GpSolidFill *sf, ARGB *argb)
1166 TRACE("(%p, %p)\n", sf, argb);
1168 if(!sf || !argb)
1169 return InvalidParameter;
1171 *argb = sf->color;
1173 return Ok;
1176 /******************************************************************************
1177 * GdipGetTextureImage [GDIPLUS.@]
1179 GpStatus WINGDIPAPI GdipGetTextureImage(GpTexture *brush, GpImage **image)
1181 TRACE("(%p, %p)\n", brush, image);
1183 if(!brush || !image)
1184 return InvalidParameter;
1186 return GdipCloneImage(brush->image, image);
1189 /******************************************************************************
1190 * GdipGetTextureTransform [GDIPLUS.@]
1192 GpStatus WINGDIPAPI GdipGetTextureTransform(GpTexture *brush, GpMatrix *matrix)
1194 TRACE("(%p, %p)\n", brush, matrix);
1196 if(!brush || !matrix)
1197 return InvalidParameter;
1199 memcpy(matrix, brush->transform, sizeof(GpMatrix));
1201 return Ok;
1204 /******************************************************************************
1205 * GdipGetTextureWrapMode [GDIPLUS.@]
1207 GpStatus WINGDIPAPI GdipGetTextureWrapMode(GpTexture *brush, GpWrapMode *wrapmode)
1209 TRACE("(%p, %p)\n", brush, wrapmode);
1211 if(!brush || !wrapmode)
1212 return InvalidParameter;
1214 *wrapmode = brush->imageattributes->wrap;
1216 return Ok;
1219 /******************************************************************************
1220 * GdipMultiplyTextureTransform [GDIPLUS.@]
1222 GpStatus WINGDIPAPI GdipMultiplyTextureTransform(GpTexture* brush,
1223 GDIPCONST GpMatrix *matrix, GpMatrixOrder order)
1225 TRACE("(%p, %p, %d)\n", brush, matrix, order);
1227 if(!brush || !matrix)
1228 return InvalidParameter;
1230 return GdipMultiplyMatrix(brush->transform, matrix, order);
1233 /******************************************************************************
1234 * GdipResetTextureTransform [GDIPLUS.@]
1236 GpStatus WINGDIPAPI GdipResetTextureTransform(GpTexture* brush)
1238 TRACE("(%p)\n", brush);
1240 if(!brush)
1241 return InvalidParameter;
1243 return GdipSetMatrixElements(brush->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1246 /******************************************************************************
1247 * GdipScaleTextureTransform [GDIPLUS.@]
1249 GpStatus WINGDIPAPI GdipScaleTextureTransform(GpTexture* brush,
1250 REAL sx, REAL sy, GpMatrixOrder order)
1252 TRACE("(%p, %.2f, %.2f, %d)\n", brush, sx, sy, order);
1254 if(!brush)
1255 return InvalidParameter;
1257 return GdipScaleMatrix(brush->transform, sx, sy, order);
1260 GpStatus WINGDIPAPI GdipSetLineBlend(GpLineGradient *brush,
1261 GDIPCONST REAL *factors, GDIPCONST REAL* positions, INT count)
1263 REAL *new_blendfac, *new_blendpos;
1265 TRACE("(%p, %p, %p, %i)\n", brush, factors, positions, count);
1267 if(!brush || !factors || !positions || count <= 0 ||
1268 (count >= 2 && (positions[0] != 0.0f || positions[count-1] != 1.0f)))
1269 return InvalidParameter;
1271 new_blendfac = GdipAlloc(count * sizeof(REAL));
1272 new_blendpos = GdipAlloc(count * sizeof(REAL));
1274 if (!new_blendfac || !new_blendpos)
1276 GdipFree(new_blendfac);
1277 GdipFree(new_blendpos);
1278 return OutOfMemory;
1281 memcpy(new_blendfac, factors, count * sizeof(REAL));
1282 memcpy(new_blendpos, positions, count * sizeof(REAL));
1284 GdipFree(brush->blendfac);
1285 GdipFree(brush->blendpos);
1287 brush->blendcount = count;
1288 brush->blendfac = new_blendfac;
1289 brush->blendpos = new_blendpos;
1291 return Ok;
1294 GpStatus WINGDIPAPI GdipGetLineBlend(GpLineGradient *brush, REAL *factors,
1295 REAL *positions, INT count)
1297 TRACE("(%p, %p, %p, %i)\n", brush, factors, positions, count);
1299 if (!brush || !factors || !positions || count <= 0)
1300 return InvalidParameter;
1302 if (count < brush->blendcount)
1303 return InsufficientBuffer;
1305 memcpy(factors, brush->blendfac, brush->blendcount * sizeof(REAL));
1306 memcpy(positions, brush->blendpos, brush->blendcount * sizeof(REAL));
1308 return Ok;
1311 GpStatus WINGDIPAPI GdipGetLineBlendCount(GpLineGradient *brush, INT *count)
1313 TRACE("(%p, %p)\n", brush, count);
1315 if (!brush || !count)
1316 return InvalidParameter;
1318 *count = brush->blendcount;
1320 return Ok;
1323 GpStatus WINGDIPAPI GdipSetLineGammaCorrection(GpLineGradient *line,
1324 BOOL usegamma)
1326 TRACE("(%p, %d)\n", line, usegamma);
1328 if(!line)
1329 return InvalidParameter;
1331 line->gamma = usegamma;
1333 return Ok;
1336 GpStatus WINGDIPAPI GdipSetLineSigmaBlend(GpLineGradient *line, REAL focus,
1337 REAL scale)
1339 REAL factors[33];
1340 REAL positions[33];
1341 int num_points = 0;
1342 int i;
1343 const int precision = 16;
1344 REAL erf_range; /* we use values erf(-erf_range) through erf(+erf_range) */
1345 REAL min_erf;
1346 REAL scale_erf;
1348 TRACE("(%p, %0.2f, %0.2f)\n", line, focus, scale);
1350 if(!line || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0)
1351 return InvalidParameter;
1353 /* we want 2 standard deviations */
1354 erf_range = 2.0 / sqrt(2);
1356 /* calculate the constants we need to normalize the error function to be
1357 between 0.0 and scale over the range we need */
1358 min_erf = erf(-erf_range);
1359 scale_erf = scale / (-2.0 * min_erf);
1361 if (focus != 0.0)
1363 positions[0] = 0.0;
1364 factors[0] = 0.0;
1365 for (i=1; i<precision; i++)
1367 positions[i] = focus * i / precision;
1368 factors[i] = scale_erf * (erf(2 * erf_range * i / precision - erf_range) - min_erf);
1370 num_points += precision;
1373 positions[num_points] = focus;
1374 factors[num_points] = scale;
1375 num_points += 1;
1377 if (focus != 1.0)
1379 for (i=1; i<precision; i++)
1381 positions[i+num_points-1] = (focus + ((1.0-focus) * i / precision));
1382 factors[i+num_points-1] = scale_erf * (erf(erf_range - 2 * erf_range * i / precision) - min_erf);
1384 num_points += precision;
1385 positions[num_points-1] = 1.0;
1386 factors[num_points-1] = 0.0;
1389 return GdipSetLineBlend(line, factors, positions, num_points);
1392 GpStatus WINGDIPAPI GdipSetLineWrapMode(GpLineGradient *line,
1393 GpWrapMode wrap)
1395 TRACE("(%p, %d)\n", line, wrap);
1397 if(!line || wrap == WrapModeClamp)
1398 return InvalidParameter;
1400 line->wrap = wrap;
1402 return Ok;
1405 GpStatus WINGDIPAPI GdipSetPathGradientBlend(GpPathGradient *brush, GDIPCONST REAL *blend,
1406 GDIPCONST REAL *pos, INT count)
1408 static int calls;
1410 TRACE("(%p,%p,%p,%i)\n", brush, blend, pos, count);
1412 if(!(calls++))
1413 FIXME("not implemented\n");
1415 return NotImplemented;
1418 GpStatus WINGDIPAPI GdipSetPathGradientLinearBlend(GpPathGradient *brush,
1419 REAL focus, REAL scale)
1421 static int calls;
1423 TRACE("(%p,%0.2f,%0.2f)\n", brush, focus, scale);
1425 if(!(calls++))
1426 FIXME("not implemented\n");
1428 return NotImplemented;
1431 GpStatus WINGDIPAPI GdipSetPathGradientPresetBlend(GpPathGradient *brush,
1432 GDIPCONST ARGB *blend, GDIPCONST REAL *pos, INT count)
1434 FIXME("(%p,%p,%p,%i): stub\n", brush, blend, pos, count);
1435 return NotImplemented;
1438 GpStatus WINGDIPAPI GdipGetPathGradientPresetBlend(GpPathGradient *brush,
1439 ARGB *blend, REAL *pos, INT count)
1441 FIXME("(%p,%p,%p,%i): stub\n", brush, blend, pos, count);
1442 return NotImplemented;
1445 GpStatus WINGDIPAPI GdipGetPathGradientPresetBlendCount(GpPathGradient *brush,
1446 INT *count)
1448 FIXME("(%p,%p): stub\n", brush, count);
1449 return NotImplemented;
1452 GpStatus WINGDIPAPI GdipSetPathGradientCenterColor(GpPathGradient *grad,
1453 ARGB argb)
1455 TRACE("(%p, %x)\n", grad, argb);
1457 if(!grad)
1458 return InvalidParameter;
1460 grad->centercolor = argb;
1461 return Ok;
1464 GpStatus WINGDIPAPI GdipSetPathGradientCenterPoint(GpPathGradient *grad,
1465 GpPointF *point)
1467 TRACE("(%p, %s)\n", grad, debugstr_pointf(point));
1469 if(!grad || !point)
1470 return InvalidParameter;
1472 grad->center.X = point->X;
1473 grad->center.Y = point->Y;
1475 return Ok;
1478 GpStatus WINGDIPAPI GdipSetPathGradientCenterPointI(GpPathGradient *grad,
1479 GpPoint *point)
1481 GpPointF ptf;
1483 TRACE("(%p, %p)\n", grad, point);
1485 if(!point)
1486 return InvalidParameter;
1488 ptf.X = (REAL)point->X;
1489 ptf.Y = (REAL)point->Y;
1491 return GdipSetPathGradientCenterPoint(grad,&ptf);
1494 GpStatus WINGDIPAPI GdipSetPathGradientFocusScales(GpPathGradient *grad,
1495 REAL x, REAL y)
1497 TRACE("(%p, %.2f, %.2f)\n", grad, x, y);
1499 if(!grad)
1500 return InvalidParameter;
1502 grad->focus.X = x;
1503 grad->focus.Y = y;
1505 return Ok;
1508 GpStatus WINGDIPAPI GdipSetPathGradientGammaCorrection(GpPathGradient *grad,
1509 BOOL gamma)
1511 TRACE("(%p, %d)\n", grad, gamma);
1513 if(!grad)
1514 return InvalidParameter;
1516 grad->gamma = gamma;
1518 return Ok;
1521 GpStatus WINGDIPAPI GdipSetPathGradientSigmaBlend(GpPathGradient *grad,
1522 REAL focus, REAL scale)
1524 static int calls;
1526 TRACE("(%p,%0.2f,%0.2f)\n", grad, focus, scale);
1528 if(!grad || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0)
1529 return InvalidParameter;
1531 if(!(calls++))
1532 FIXME("not implemented\n");
1534 return NotImplemented;
1537 GpStatus WINGDIPAPI GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
1538 *grad, GDIPCONST ARGB *argb, INT *count)
1540 static int calls;
1542 TRACE("(%p,%p,%p)\n", grad, argb, count);
1544 if(!grad || !argb || !count || (*count <= 0) ||
1545 (*count > grad->pathdata.Count))
1546 return InvalidParameter;
1548 if(!(calls++))
1549 FIXME("not implemented\n");
1551 return NotImplemented;
1554 GpStatus WINGDIPAPI GdipSetPathGradientWrapMode(GpPathGradient *grad,
1555 GpWrapMode wrap)
1557 TRACE("(%p, %d)\n", grad, wrap);
1559 if(!grad)
1560 return InvalidParameter;
1562 grad->wrap = wrap;
1564 return Ok;
1567 GpStatus WINGDIPAPI GdipSetPathGradientTransform(GpPathGradient *grad,
1568 GpMatrix *matrix)
1570 static int calls;
1572 TRACE("(%p,%p)\n", grad, matrix);
1574 if(!(calls++))
1575 FIXME("not implemented\n");
1577 return NotImplemented;
1580 GpStatus WINGDIPAPI GdipGetPathGradientTransform(GpPathGradient *grad,
1581 GpMatrix *matrix)
1583 static int calls;
1585 TRACE("(%p,%p)\n", grad, matrix);
1587 if(!(calls++))
1588 FIXME("not implemented\n");
1590 return NotImplemented;
1593 GpStatus WINGDIPAPI GdipMultiplyPathGradientTransform(GpPathGradient *grad,
1594 GDIPCONST GpMatrix *matrix, GpMatrixOrder order)
1596 static int calls;
1598 TRACE("(%p,%p,%i)\n", grad, matrix, order);
1600 if(!(calls++))
1601 FIXME("not implemented\n");
1603 return NotImplemented;
1606 GpStatus WINGDIPAPI GdipRotatePathGradientTransform(GpPathGradient *grad,
1607 REAL angle, GpMatrixOrder order)
1609 static int calls;
1611 TRACE("(%p,%0.2f,%i)\n", grad, angle, order);
1613 if(!(calls++))
1614 FIXME("not implemented\n");
1616 return NotImplemented;
1619 GpStatus WINGDIPAPI GdipScalePathGradientTransform(GpPathGradient *grad,
1620 REAL sx, REAL sy, GpMatrixOrder order)
1622 static int calls;
1624 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad, sx, sy, order);
1626 if(!(calls++))
1627 FIXME("not implemented\n");
1629 return NotImplemented;
1632 GpStatus WINGDIPAPI GdipTranslatePathGradientTransform(GpPathGradient *grad,
1633 REAL dx, REAL dy, GpMatrixOrder order)
1635 static int calls;
1637 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad, dx, dy, order);
1639 if(!(calls++))
1640 FIXME("not implemented\n");
1642 return NotImplemented;
1645 GpStatus WINGDIPAPI GdipSetSolidFillColor(GpSolidFill *sf, ARGB argb)
1647 TRACE("(%p, %x)\n", sf, argb);
1649 if(!sf)
1650 return InvalidParameter;
1652 sf->color = argb;
1653 return Ok;
1656 /******************************************************************************
1657 * GdipSetTextureTransform [GDIPLUS.@]
1659 GpStatus WINGDIPAPI GdipSetTextureTransform(GpTexture *texture,
1660 GDIPCONST GpMatrix *matrix)
1662 TRACE("(%p, %p)\n", texture, matrix);
1664 if(!texture || !matrix)
1665 return InvalidParameter;
1667 memcpy(texture->transform, matrix, sizeof(GpMatrix));
1669 return Ok;
1672 /******************************************************************************
1673 * GdipSetTextureWrapMode [GDIPLUS.@]
1675 * WrapMode not used, only stored
1677 GpStatus WINGDIPAPI GdipSetTextureWrapMode(GpTexture *brush, GpWrapMode wrapmode)
1679 TRACE("(%p, %d)\n", brush, wrapmode);
1681 if(!brush)
1682 return InvalidParameter;
1684 brush->imageattributes->wrap = wrapmode;
1686 return Ok;
1689 GpStatus WINGDIPAPI GdipSetLineColors(GpLineGradient *brush, ARGB color1,
1690 ARGB color2)
1692 TRACE("(%p, %x, %x)\n", brush, color1, color2);
1694 if(!brush)
1695 return InvalidParameter;
1697 brush->startcolor = color1;
1698 brush->endcolor = color2;
1700 return Ok;
1703 GpStatus WINGDIPAPI GdipGetLineColors(GpLineGradient *brush, ARGB *colors)
1705 TRACE("(%p, %p)\n", brush, colors);
1707 if(!brush || !colors)
1708 return InvalidParameter;
1710 colors[0] = brush->startcolor;
1711 colors[1] = brush->endcolor;
1713 return Ok;
1716 /******************************************************************************
1717 * GdipRotateTextureTransform [GDIPLUS.@]
1719 GpStatus WINGDIPAPI GdipRotateTextureTransform(GpTexture* brush, REAL angle,
1720 GpMatrixOrder order)
1722 TRACE("(%p, %.2f, %d)\n", brush, angle, order);
1724 if(!brush)
1725 return InvalidParameter;
1727 return GdipRotateMatrix(brush->transform, angle, order);
1730 GpStatus WINGDIPAPI GdipSetLineLinearBlend(GpLineGradient *brush, REAL focus,
1731 REAL scale)
1733 REAL factors[3];
1734 REAL positions[3];
1735 int num_points = 0;
1737 TRACE("(%p,%.2f,%.2f)\n", brush, focus, scale);
1739 if (!brush) return InvalidParameter;
1741 if (focus != 0.0)
1743 factors[num_points] = 0.0;
1744 positions[num_points] = 0.0;
1745 num_points++;
1748 factors[num_points] = scale;
1749 positions[num_points] = focus;
1750 num_points++;
1752 if (focus != 1.0)
1754 factors[num_points] = 0.0;
1755 positions[num_points] = 1.0;
1756 num_points++;
1759 return GdipSetLineBlend(brush, factors, positions, num_points);
1762 GpStatus WINGDIPAPI GdipSetLinePresetBlend(GpLineGradient *brush,
1763 GDIPCONST ARGB *blend, GDIPCONST REAL* positions, INT count)
1765 ARGB *new_color;
1766 REAL *new_pos;
1767 TRACE("(%p,%p,%p,%i)\n", brush, blend, positions, count);
1769 if (!brush || !blend || !positions || count < 2 ||
1770 positions[0] != 0.0f || positions[count-1] != 1.0f)
1772 return InvalidParameter;
1775 new_color = GdipAlloc(count * sizeof(ARGB));
1776 new_pos = GdipAlloc(count * sizeof(REAL));
1777 if (!new_color || !new_pos)
1779 GdipFree(new_color);
1780 GdipFree(new_pos);
1781 return OutOfMemory;
1784 memcpy(new_color, blend, sizeof(ARGB) * count);
1785 memcpy(new_pos, positions, sizeof(REAL) * count);
1787 GdipFree(brush->pblendcolor);
1788 GdipFree(brush->pblendpos);
1790 brush->pblendcolor = new_color;
1791 brush->pblendpos = new_pos;
1792 brush->pblendcount = count;
1794 return Ok;
1797 GpStatus WINGDIPAPI GdipGetLinePresetBlend(GpLineGradient *brush,
1798 ARGB *blend, REAL* positions, INT count)
1800 if (!brush || !blend || !positions || count < 2)
1801 return InvalidParameter;
1803 if (brush->pblendcount == 0)
1804 return GenericError;
1806 if (count < brush->pblendcount)
1807 return InsufficientBuffer;
1809 memcpy(blend, brush->pblendcolor, sizeof(ARGB) * brush->pblendcount);
1810 memcpy(positions, brush->pblendpos, sizeof(REAL) * brush->pblendcount);
1812 return Ok;
1815 GpStatus WINGDIPAPI GdipGetLinePresetBlendCount(GpLineGradient *brush,
1816 INT *count)
1818 if (!brush || !count)
1819 return InvalidParameter;
1821 *count = brush->pblendcount;
1823 return Ok;
1826 GpStatus WINGDIPAPI GdipResetLineTransform(GpLineGradient *brush)
1828 static int calls;
1830 TRACE("(%p)\n", brush);
1832 if(!(calls++))
1833 FIXME("not implemented\n");
1835 return NotImplemented;
1838 GpStatus WINGDIPAPI GdipSetLineTransform(GpLineGradient *brush,
1839 GDIPCONST GpMatrix *matrix)
1841 static int calls;
1843 TRACE("(%p,%p)\n", brush, matrix);
1845 if(!(calls++))
1846 FIXME("not implemented\n");
1848 return NotImplemented;
1851 GpStatus WINGDIPAPI GdipGetLineTransform(GpLineGradient *brush, GpMatrix *matrix)
1853 static int calls;
1855 TRACE("(%p,%p)\n", brush, matrix);
1857 if(!(calls++))
1858 FIXME("not implemented\n");
1860 return NotImplemented;
1863 GpStatus WINGDIPAPI GdipScaleLineTransform(GpLineGradient *brush, REAL sx, REAL sy,
1864 GpMatrixOrder order)
1866 static int calls;
1868 TRACE("(%p,%0.2f,%0.2f,%u)\n", brush, sx, sy, order);
1870 if(!(calls++))
1871 FIXME("not implemented\n");
1873 return NotImplemented;
1876 GpStatus WINGDIPAPI GdipMultiplyLineTransform(GpLineGradient *brush,
1877 GDIPCONST GpMatrix *matrix, GpMatrixOrder order)
1879 static int calls;
1881 TRACE("(%p,%p,%u)\n", brush, matrix, order);
1883 if(!(calls++))
1884 FIXME("not implemented\n");
1886 return NotImplemented;
1889 GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient* brush,
1890 REAL dx, REAL dy, GpMatrixOrder order)
1892 static int calls;
1894 TRACE("(%p,%f,%f,%d)\n", brush, dx, dy, order);
1896 if(!(calls++))
1897 FIXME("not implemented\n");
1899 return Ok;
1902 /******************************************************************************
1903 * GdipTranslateTextureTransform [GDIPLUS.@]
1905 GpStatus WINGDIPAPI GdipTranslateTextureTransform(GpTexture* brush, REAL dx, REAL dy,
1906 GpMatrixOrder order)
1908 TRACE("(%p, %.2f, %.2f, %d)\n", brush, dx, dy, order);
1910 if(!brush)
1911 return InvalidParameter;
1913 return GdipTranslateMatrix(brush->transform, dx, dy, order);
1916 GpStatus WINGDIPAPI GdipGetLineRect(GpLineGradient *brush, GpRectF *rect)
1918 TRACE("(%p, %p)\n", brush, rect);
1920 if(!brush || !rect)
1921 return InvalidParameter;
1923 *rect = brush->rect;
1925 return Ok;
1928 GpStatus WINGDIPAPI GdipGetLineRectI(GpLineGradient *brush, GpRect *rect)
1930 GpRectF rectF;
1931 GpStatus ret;
1933 TRACE("(%p, %p)\n", brush, rect);
1935 if(!rect)
1936 return InvalidParameter;
1938 ret = GdipGetLineRect(brush, &rectF);
1940 if(ret == Ok){
1941 rect->X = roundr(rectF.X);
1942 rect->Y = roundr(rectF.Y);
1943 rect->Width = roundr(rectF.Width);
1944 rect->Height = roundr(rectF.Height);
1947 return ret;
1950 GpStatus WINGDIPAPI GdipRotateLineTransform(GpLineGradient* brush,
1951 REAL angle, GpMatrixOrder order)
1953 static int calls;
1955 TRACE("(%p,%0.2f,%u)\n", brush, angle, order);
1957 if(!brush)
1958 return InvalidParameter;
1960 if(!(calls++))
1961 FIXME("(%p, %.2f, %d) stub\n", brush, angle, order);
1963 return NotImplemented;