gdiplus: Implemented GdipCreateTextureIAI using float args version.
[wine] / dlls / gdiplus / brush.c
1 /*
2  * Copyright (C) 2007 Google (Evan Stade)
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #include <stdarg.h>
20
21 #include "windef.h"
22 #include "winbase.h"
23 #include "winuser.h"
24 #include "wingdi.h"
25
26 #define COBJMACROS
27 #include "objbase.h"
28 #include "olectl.h"
29 #include "ole2.h"
30
31 #include "gdiplus.h"
32 #include "gdiplus_private.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
36
37 GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
38 {
39     if(!brush || !clone)
40         return InvalidParameter;
41
42     switch(brush->bt){
43         case BrushTypeSolidColor:
44             *clone = GdipAlloc(sizeof(GpSolidFill));
45             if (!*clone) return OutOfMemory;
46
47             memcpy(*clone, brush, sizeof(GpSolidFill));
48
49             (*clone)->gdibrush = CreateBrushIndirect(&(*clone)->lb);
50             break;
51         case BrushTypePathGradient:{
52             GpPathGradient *src, *dest;
53             INT count;
54
55             *clone = GdipAlloc(sizeof(GpPathGradient));
56             if (!*clone) return OutOfMemory;
57
58             src = (GpPathGradient*) brush,
59             dest = (GpPathGradient*) *clone;
60             count = src->pathdata.Count;
61
62             memcpy(dest, src, sizeof(GpPathGradient));
63
64             dest->pathdata.Count = count;
65             dest->pathdata.Points = GdipAlloc(count * sizeof(PointF));
66             dest->pathdata.Types = GdipAlloc(count);
67
68             if(!dest->pathdata.Points || !dest->pathdata.Types){
69                 GdipFree(dest->pathdata.Points);
70                 GdipFree(dest->pathdata.Types);
71                 GdipFree(dest);
72                 return OutOfMemory;
73             }
74
75             memcpy(dest->pathdata.Points, src->pathdata.Points, count * sizeof(PointF));
76             memcpy(dest->pathdata.Types, src->pathdata.Types, count);
77
78             break;
79         }
80         case BrushTypeLinearGradient:
81             *clone = GdipAlloc(sizeof(GpLineGradient));
82             if(!*clone)    return OutOfMemory;
83
84             memcpy(*clone, brush, sizeof(GpLineGradient));
85
86             (*clone)->gdibrush = CreateSolidBrush((*clone)->lb.lbColor);
87             break;
88         case BrushTypeTextureFill:
89             *clone = GdipAlloc(sizeof(GpTexture));
90             if(!*clone)    return OutOfMemory;
91
92             memcpy(*clone, brush, sizeof(GpTexture));
93
94             (*clone)->gdibrush = CreateBrushIndirect(&(*clone)->lb);
95             break;
96         default:
97             ERR("not implemented for brush type %d\n", brush->bt);
98             return NotImplemented;
99     }
100
101     return Ok;
102 }
103
104 GpStatus WINGDIPAPI GdipCreateLineBrush(GDIPCONST GpPointF* startpoint,
105     GDIPCONST GpPointF* endpoint, ARGB startcolor, ARGB endcolor,
106     GpWrapMode wrap, GpLineGradient **line)
107 {
108     COLORREF col = ARGB2COLORREF(startcolor);
109
110     if(!line || !startpoint || !endpoint || wrap == WrapModeClamp)
111         return InvalidParameter;
112
113     *line = GdipAlloc(sizeof(GpLineGradient));
114     if(!*line)  return OutOfMemory;
115
116     (*line)->brush.lb.lbStyle = BS_SOLID;
117     (*line)->brush.lb.lbColor = col;
118     (*line)->brush.lb.lbHatch = 0;
119     (*line)->brush.gdibrush = CreateSolidBrush(col);
120     (*line)->brush.bt = BrushTypeLinearGradient;
121
122     (*line)->startpoint.X = startpoint->X;
123     (*line)->startpoint.Y = startpoint->Y;
124     (*line)->endpoint.X = endpoint->X;
125     (*line)->endpoint.Y = endpoint->Y;
126     (*line)->startcolor = startcolor;
127     (*line)->endcolor = endcolor;
128     (*line)->wrap = wrap;
129     (*line)->gamma = FALSE;
130
131     return Ok;
132 }
133
134 GpStatus WINGDIPAPI GdipCreateLineBrushI(GDIPCONST GpPoint* startpoint,
135     GDIPCONST GpPoint* endpoint, ARGB startcolor, ARGB endcolor,
136     GpWrapMode wrap, GpLineGradient **line)
137 {
138     GpPointF stF;
139     GpPointF endF;
140
141     if(!startpoint || !endpoint)
142         return InvalidParameter;
143
144     stF.X  = (REAL)startpoint->X;
145     stF.Y  = (REAL)startpoint->Y;
146     endF.X = (REAL)endpoint->X;
147     endF.X = (REAL)endpoint->Y;
148
149     return GdipCreateLineBrush(&stF, &endF, startcolor, endcolor, wrap, line);
150 }
151
152 GpStatus WINGDIPAPI GdipCreateLineBrushFromRect(GDIPCONST GpRectF* rect,
153     ARGB startcolor, ARGB endcolor, LinearGradientMode mode, GpWrapMode wrap,
154     GpLineGradient **line)
155 {
156     GpPointF start, end;
157
158     if(!line || !rect)
159         return InvalidParameter;
160
161     start.X = rect->X;
162     start.Y = rect->Y;
163     end.X = rect->X + rect->Width;
164     end.Y = rect->Y + rect->Height;
165
166     return GdipCreateLineBrush(&start, &end, startcolor, endcolor, wrap, line);
167 }
168
169 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectI(GDIPCONST GpRect* rect,
170     ARGB startcolor, ARGB endcolor, LinearGradientMode mode, GpWrapMode wrap,
171     GpLineGradient **line)
172 {
173     GpRectF rectF;
174
175     rectF.X      = (REAL) rect->X;
176     rectF.Y      = (REAL) rect->Y;
177     rectF.Width  = (REAL) rect->Width;
178     rectF.Height = (REAL) rect->Height;
179
180     return GdipCreateLineBrushFromRect(&rectF, startcolor, endcolor, mode, wrap, line);
181 }
182
183 GpStatus WINGDIPAPI GdipCreatePathGradient(GDIPCONST GpPointF* points,
184     INT count, GpWrapMode wrap, GpPathGradient **grad)
185 {
186     COLORREF col = ARGB2COLORREF(0xffffffff);
187
188     if(!points || !grad)
189         return InvalidParameter;
190
191     if(count <= 0)
192         return OutOfMemory;
193
194     *grad = GdipAlloc(sizeof(GpPathGradient));
195     if (!*grad) return OutOfMemory;
196
197     (*grad)->pathdata.Count = count;
198     (*grad)->pathdata.Points = GdipAlloc(count * sizeof(PointF));
199     (*grad)->pathdata.Types = GdipAlloc(count);
200
201     if(!(*grad)->pathdata.Points || !(*grad)->pathdata.Types){
202         GdipFree((*grad)->pathdata.Points);
203         GdipFree((*grad)->pathdata.Types);
204         GdipFree(*grad);
205         return OutOfMemory;
206     }
207
208     memcpy((*grad)->pathdata.Points, points, count * sizeof(PointF));
209     memset((*grad)->pathdata.Types, PathPointTypeLine, count);
210
211     (*grad)->brush.lb.lbStyle = BS_SOLID;
212     (*grad)->brush.lb.lbColor = col;
213     (*grad)->brush.lb.lbHatch = 0;
214
215     (*grad)->brush.gdibrush = CreateSolidBrush(col);
216     (*grad)->brush.bt = BrushTypePathGradient;
217     (*grad)->centercolor = 0xffffffff;
218     (*grad)->wrap = wrap;
219     (*grad)->gamma = FALSE;
220     (*grad)->center.X = 0.0;
221     (*grad)->center.Y = 0.0;
222     (*grad)->focus.X = 0.0;
223     (*grad)->focus.Y = 0.0;
224
225     return Ok;
226 }
227
228 GpStatus WINGDIPAPI GdipCreatePathGradientI(GDIPCONST GpPoint* points,
229     INT count, GpWrapMode wrap, GpPathGradient **grad)
230 {
231     GpPointF *pointsF;
232     GpStatus ret;
233     INT i;
234
235     if(!points || !grad)
236         return InvalidParameter;
237
238     if(count <= 0)
239         return OutOfMemory;
240
241     pointsF = GdipAlloc(sizeof(GpPointF) * count);
242     if(!pointsF)
243         return OutOfMemory;
244
245     for(i = 0; i < count; i++){
246         pointsF[i].X = (REAL)points[i].X;
247         pointsF[i].Y = (REAL)points[i].Y;
248     }
249
250     ret = GdipCreatePathGradient(pointsF, count, wrap, grad);
251     GdipFree(pointsF);
252
253     return ret;
254 }
255
256 /* FIXME: path gradient brushes not truly supported (drawn as solid brushes) */
257 GpStatus WINGDIPAPI GdipCreatePathGradientFromPath(GDIPCONST GpPath* path,
258     GpPathGradient **grad)
259 {
260     COLORREF col = ARGB2COLORREF(0xffffffff);
261
262     if(!path || !grad)
263         return InvalidParameter;
264
265     *grad = GdipAlloc(sizeof(GpPathGradient));
266     if (!*grad) return OutOfMemory;
267
268     (*grad)->pathdata.Count = path->pathdata.Count;
269     (*grad)->pathdata.Points = GdipAlloc(path->pathdata.Count * sizeof(PointF));
270     (*grad)->pathdata.Types = GdipAlloc(path->pathdata.Count);
271
272     if(!(*grad)->pathdata.Points || !(*grad)->pathdata.Types){
273         GdipFree((*grad)->pathdata.Points);
274         GdipFree((*grad)->pathdata.Types);
275         GdipFree(*grad);
276         return OutOfMemory;
277     }
278
279     memcpy((*grad)->pathdata.Points, path->pathdata.Points,
280            path->pathdata.Count * sizeof(PointF));
281     memcpy((*grad)->pathdata.Types, path->pathdata.Types, path->pathdata.Count);
282
283     (*grad)->brush.lb.lbStyle = BS_SOLID;
284     (*grad)->brush.lb.lbColor = col;
285     (*grad)->brush.lb.lbHatch = 0;
286
287     (*grad)->brush.gdibrush = CreateSolidBrush(col);
288     (*grad)->brush.bt = BrushTypePathGradient;
289     (*grad)->centercolor = 0xffffffff;
290     (*grad)->wrap = WrapModeClamp;
291     (*grad)->gamma = FALSE;
292     /* FIXME: this should be set to the "centroid" of the path by default */
293     (*grad)->center.X = 0.0;
294     (*grad)->center.Y = 0.0;
295     (*grad)->focus.X = 0.0;
296     (*grad)->focus.Y = 0.0;
297
298     return Ok;
299 }
300
301 GpStatus WINGDIPAPI GdipCreateSolidFill(ARGB color, GpSolidFill **sf)
302 {
303     COLORREF col = ARGB2COLORREF(color);
304
305     if(!sf)  return InvalidParameter;
306
307     *sf = GdipAlloc(sizeof(GpSolidFill));
308     if (!*sf) return OutOfMemory;
309
310     (*sf)->brush.lb.lbStyle = BS_SOLID;
311     (*sf)->brush.lb.lbColor = col;
312     (*sf)->brush.lb.lbHatch = 0;
313
314     (*sf)->brush.gdibrush = CreateSolidBrush(col);
315     (*sf)->brush.bt = BrushTypeSolidColor;
316     (*sf)->color = color;
317
318     return Ok;
319 }
320
321 /* FIXME: imageattr ignored */
322 GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image,
323     GDIPCONST GpImageAttributes *imageattr, REAL x, REAL y, REAL width,
324     REAL height, GpTexture **texture)
325 {
326     HDC hdc;
327     OLE_HANDLE hbm;
328     HBITMAP old = NULL;
329     BITMAPINFO bmi;
330     BITMAPINFOHEADER *bmih;
331     INT n_x, n_y, n_width, n_height, abs_height, stride, image_stride, i, bytespp;
332     BOOL bm_is_selected;
333     BYTE *dibits, *buff, *textbits;
334
335     if(!image || !texture || x < 0.0 || y < 0.0 || width < 0.0 || height < 0.0)
336         return InvalidParameter;
337
338     if(image->type != ImageTypeBitmap){
339         FIXME("not implemented for image type %d\n", image->type);
340         return NotImplemented;
341     }
342
343     n_x = roundr(x);
344     n_y = roundr(y);
345     n_width = roundr(width);
346     n_height = roundr(height);
347
348     if(n_x + n_width > ((GpBitmap*)image)->width ||
349        n_y + n_height > ((GpBitmap*)image)->height)
350         return InvalidParameter;
351
352     IPicture_get_Handle(image->picture, &hbm);
353     if(!hbm)   return GenericError;
354     IPicture_get_CurDC(image->picture, &hdc);
355     bm_is_selected = (hdc != 0);
356
357     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
358     bmi.bmiHeader.biBitCount = 0;
359
360     if(!bm_is_selected){
361         hdc = CreateCompatibleDC(0);
362         old = SelectObject(hdc, (HBITMAP)hbm);
363     }
364
365     /* fill out bmi */
366     GetDIBits(hdc, (HBITMAP)hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
367
368     bytespp = bmi.bmiHeader.biBitCount / 8;
369     abs_height = abs(bmi.bmiHeader.biHeight);
370
371     if(n_x > bmi.bmiHeader.biWidth || n_x + n_width > bmi.bmiHeader.biWidth ||
372        n_y > abs_height || n_y + n_height > abs_height)
373         return InvalidParameter;
374
375     dibits = GdipAlloc(bmi.bmiHeader.biSizeImage);
376
377     if(dibits)  /* this is not a good place to error out */
378         GetDIBits(hdc, (HBITMAP)hbm, 0, abs_height, dibits, &bmi, DIB_RGB_COLORS);
379
380     if(!bm_is_selected){
381         SelectObject(hdc, old);
382         DeleteDC(hdc);
383     }
384
385     if(!dibits)
386         return OutOfMemory;
387
388     image_stride = (bmi.bmiHeader.biWidth * bytespp + 3) & ~3;
389     stride = (n_width * bytespp + 3) & ~3;
390     buff = GdipAlloc(sizeof(BITMAPINFOHEADER) + stride * n_height);
391     if(!buff){
392         GdipFree(dibits);
393         return OutOfMemory;
394     }
395
396     bmih = (BITMAPINFOHEADER*)buff;
397     textbits = (BYTE*) (bmih + 1);
398     bmih->biSize = sizeof(BITMAPINFOHEADER);
399     bmih->biWidth = n_width;
400     bmih->biHeight = n_height;
401     bmih->biCompression = BI_RGB;
402     bmih->biSizeImage = stride * n_height;
403     bmih->biBitCount = bmi.bmiHeader.biBitCount;
404     bmih->biClrUsed = 0;
405     bmih->biPlanes = 1;
406
407     /* image is flipped */
408     if(bmi.bmiHeader.biHeight > 0){
409         dibits += bmi.bmiHeader.biSizeImage;
410         image_stride *= -1;
411         textbits += stride * (n_height - 1);
412         stride *= -1;
413     }
414
415     for(i = 0; i < n_height; i++)
416         memcpy(&textbits[i * stride],
417                &dibits[n_x * bytespp + (n_y + i) * image_stride],
418                abs(stride));
419
420     *texture = GdipAlloc(sizeof(GpTexture));
421     if (!*texture) return OutOfMemory;
422
423     (*texture)->brush.lb.lbStyle = BS_DIBPATTERNPT;
424     (*texture)->brush.lb.lbColor = DIB_RGB_COLORS;
425     (*texture)->brush.lb.lbHatch = (ULONG_PTR)buff;
426
427     (*texture)->brush.gdibrush = CreateBrushIndirect(&(*texture)->brush.lb);
428     (*texture)->brush.bt = BrushTypeTextureFill;
429
430     GdipFree(dibits);
431     GdipFree(buff);
432
433     return Ok;
434 }
435
436 GpStatus WINGDIPAPI GdipCreateTextureIAI(GpImage *image, GDIPCONST GpImageAttributes *imageattr,
437     INT x, INT y, INT width, INT height, GpTexture **texture)
438 {
439     return GdipCreateTextureIA(image,imageattr,(REAL)x,(REAL)y,(REAL)width,(REAL)height,texture);
440 }
441
442 GpStatus WINGDIPAPI GdipGetBrushType(GpBrush *brush, GpBrushType *type)
443 {
444     if(!brush || !type)  return InvalidParameter;
445
446     *type = brush->bt;
447
448     return Ok;
449 }
450
451 GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush)
452 {
453     if(!brush)  return InvalidParameter;
454
455     switch(brush->bt)
456     {
457         case BrushTypePathGradient:
458             GdipFree(((GpPathGradient*) brush)->pathdata.Points);
459             GdipFree(((GpPathGradient*) brush)->pathdata.Types);
460             break;
461         case BrushTypeSolidColor:
462         case BrushTypeLinearGradient:
463         case BrushTypeTextureFill:
464         default:
465             break;
466     }
467
468     DeleteObject(brush->gdibrush);
469     GdipFree(brush);
470
471     return Ok;
472 }
473
474 GpStatus WINGDIPAPI GdipGetLineGammaCorrection(GpLineGradient *line,
475     BOOL *usinggamma)
476 {
477     if(!line)
478         return InvalidParameter;
479
480     *usinggamma = line->gamma;
481
482     return Ok;
483 }
484
485 GpStatus WINGDIPAPI GdipGetPathGradientCenterPoint(GpPathGradient *grad,
486     GpPointF *point)
487 {
488     if(!grad || !point)
489         return InvalidParameter;
490
491     point->X = grad->center.X;
492     point->Y = grad->center.Y;
493
494     return Ok;
495 }
496
497 GpStatus WINGDIPAPI GdipGetPathGradientCenterPointI(GpPathGradient *grad,
498     GpPoint *point)
499 {
500     GpStatus ret;
501     GpPointF ptf;
502
503     if(!point)
504         return InvalidParameter;
505
506     ret = GdipGetPathGradientCenterPoint(grad,&ptf);
507
508     if(ret == Ok){
509         point->X = roundr(ptf.X);
510         point->Y = roundr(ptf.Y);
511     }
512
513     return ret;
514 }
515
516 GpStatus WINGDIPAPI GdipGetPathGradientFocusScales(GpPathGradient *grad,
517     REAL *x, REAL *y)
518 {
519     if(!grad || !x || !y)
520         return InvalidParameter;
521
522     *x = grad->focus.X;
523     *y = grad->focus.Y;
524
525     return Ok;
526 }
527
528 GpStatus WINGDIPAPI GdipGetPathGradientGammaCorrection(GpPathGradient *grad,
529     BOOL *gamma)
530 {
531     if(!grad || !gamma)
532         return InvalidParameter;
533
534     *gamma = grad->gamma;
535
536     return Ok;
537 }
538
539 GpStatus WINGDIPAPI GdipGetPathGradientPointCount(GpPathGradient *grad,
540     INT *count)
541 {
542     if(!grad || !count)
543         return InvalidParameter;
544
545     *count = grad->pathdata.Count;
546
547     return Ok;
548 }
549
550 GpStatus WINGDIPAPI GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
551     *grad, ARGB *argb, INT *count)
552 {
553     static int calls;
554
555     if(!grad || !argb || !count || (*count < grad->pathdata.Count))
556         return InvalidParameter;
557
558     if(!(calls++))
559         FIXME("not implemented\n");
560
561     return NotImplemented;
562 }
563
564 GpStatus WINGDIPAPI GdipGetPathGradientWrapMode(GpPathGradient *brush,
565     GpWrapMode *wrapmode)
566 {
567     if(!brush || !wrapmode)
568         return InvalidParameter;
569
570     *wrapmode = brush->wrap;
571
572     return Ok;
573 }
574
575 GpStatus WINGDIPAPI GdipGetSolidFillColor(GpSolidFill *sf, ARGB *argb)
576 {
577     if(!sf || !argb)
578         return InvalidParameter;
579
580     *argb = sf->color;
581
582     return Ok;
583 }
584
585 GpStatus WINGDIPAPI GdipSetLineBlend(GpLineGradient *brush,
586     GDIPCONST REAL *blend, GDIPCONST REAL* positions, INT count)
587 {
588     static int calls;
589
590     if(!brush || !blend || !positions || count <= 0)
591         return InvalidParameter;
592
593     if(!(calls++))
594         FIXME("not implemented\n");
595
596     return Ok;
597 }
598
599 GpStatus WINGDIPAPI GdipSetLineGammaCorrection(GpLineGradient *line,
600     BOOL usegamma)
601 {
602     if(!line)
603         return InvalidParameter;
604
605     line->gamma = usegamma;
606
607     return Ok;
608 }
609
610 GpStatus WINGDIPAPI GdipSetLineSigmaBlend(GpLineGradient *line, REAL focus,
611     REAL scale)
612 {
613     static int calls;
614
615     if(!line || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0)
616         return InvalidParameter;
617
618     if(!(calls++))
619         FIXME("not implemented\n");
620
621     return NotImplemented;
622 }
623
624 GpStatus WINGDIPAPI GdipSetLineWrapMode(GpLineGradient *line,
625     GpWrapMode wrap)
626 {
627     if(!line || wrap == WrapModeClamp)
628         return InvalidParameter;
629
630     line->wrap = wrap;
631
632     return Ok;
633 }
634
635 GpStatus WINGDIPAPI GdipSetPathGradientCenterColor(GpPathGradient *grad,
636     ARGB argb)
637 {
638     if(!grad)
639         return InvalidParameter;
640
641     grad->centercolor = argb;
642     grad->brush.lb.lbColor = ARGB2COLORREF(argb);
643
644     DeleteObject(grad->brush.gdibrush);
645     grad->brush.gdibrush = CreateSolidBrush(grad->brush.lb.lbColor);
646
647     return Ok;
648 }
649
650 GpStatus WINGDIPAPI GdipSetPathGradientCenterPoint(GpPathGradient *grad,
651     GpPointF *point)
652 {
653     if(!grad || !point)
654         return InvalidParameter;
655
656     grad->center.X = point->X;
657     grad->center.Y = point->Y;
658
659     return Ok;
660 }
661
662 GpStatus WINGDIPAPI GdipSetPathGradientCenterPointI(GpPathGradient *grad,
663     GpPoint *point)
664 {
665     GpPointF ptf;
666
667     if(!point)
668         return InvalidParameter;
669
670     ptf.X = (REAL)point->X;
671     ptf.Y = (REAL)point->Y;
672
673     return GdipSetPathGradientCenterPoint(grad,&ptf);
674 }
675
676 GpStatus WINGDIPAPI GdipSetPathGradientFocusScales(GpPathGradient *grad,
677     REAL x, REAL y)
678 {
679     if(!grad)
680         return InvalidParameter;
681
682     grad->focus.X = x;
683     grad->focus.Y = y;
684
685     return Ok;
686 }
687
688 GpStatus WINGDIPAPI GdipSetPathGradientGammaCorrection(GpPathGradient *grad,
689     BOOL gamma)
690 {
691     if(!grad)
692         return InvalidParameter;
693
694     grad->gamma = gamma;
695
696     return Ok;
697 }
698
699 GpStatus WINGDIPAPI GdipSetPathGradientSigmaBlend(GpPathGradient *grad,
700     REAL focus, REAL scale)
701 {
702     static int calls;
703
704     if(!grad || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0)
705         return InvalidParameter;
706
707     if(!(calls++))
708         FIXME("not implemented\n");
709
710     return NotImplemented;
711 }
712
713 GpStatus WINGDIPAPI GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
714     *grad, ARGB *argb, INT *count)
715 {
716     static int calls;
717
718     if(!grad || !argb || !count || (*count <= 0) ||
719         (*count > grad->pathdata.Count))
720         return InvalidParameter;
721
722     if(!(calls++))
723         FIXME("not implemented\n");
724
725     return NotImplemented;
726 }
727
728 GpStatus WINGDIPAPI GdipSetPathGradientWrapMode(GpPathGradient *grad,
729     GpWrapMode wrap)
730 {
731     if(!grad)
732         return InvalidParameter;
733
734     grad->wrap = wrap;
735
736     return Ok;
737 }
738
739 GpStatus WINGDIPAPI GdipSetSolidFillColor(GpSolidFill *sf, ARGB argb)
740 {
741     if(!sf)
742         return InvalidParameter;
743
744     sf->color = argb;
745     sf->brush.lb.lbColor = ARGB2COLORREF(argb);
746
747     DeleteObject(sf->brush.gdibrush);
748     sf->brush.gdibrush = CreateSolidBrush(sf->brush.lb.lbColor);
749
750     return Ok;
751 }
752
753 GpStatus WINGDIPAPI GdipSetTextureTransform(GpTexture *texture,
754     GDIPCONST GpMatrix *matrix)
755 {
756     static int calls;
757
758     if(!texture || !matrix)
759         return InvalidParameter;
760
761     if(!(calls++))
762         FIXME("not implemented\n");
763
764     return Ok;
765 }
766
767 GpStatus WINGDIPAPI GdipSetLineColors(GpLineGradient *brush, ARGB color1,
768     ARGB color2)
769 {
770     if(!brush)
771         return InvalidParameter;
772
773     brush->startcolor = color1;
774     brush->endcolor   = color2;
775
776     return Ok;
777 }
778
779 GpStatus WINGDIPAPI GdipGetLineColors(GpLineGradient *brush, ARGB *colors)
780 {
781     if(!brush || !colors)
782         return InvalidParameter;
783
784     colors[0] = brush->startcolor;
785     colors[1] = brush->endcolor;
786
787     return Ok;
788 }
789
790 GpStatus WINGDIPAPI GdipSetLineLinearBlend(GpLineGradient *brush, REAL focus,
791     REAL scale)
792 {
793     static int calls;
794
795     if(!(calls++))
796         FIXME("not implemented\n");
797
798     return NotImplemented;
799 }
800
801 GpStatus WINGDIPAPI GdipSetLinePresetBlend(GpLineGradient *brush,
802     GDIPCONST ARGB *blend, GDIPCONST REAL* positions, INT count)
803 {
804     static int calls;
805
806     if(!(calls++))
807         FIXME("not implemented\n");
808
809     return NotImplemented;
810 }
811
812 GpStatus WINGDIPAPI GdipSetLineTransform(GpLineGradient *brush,
813     GDIPCONST GpMatrix *matrix)
814 {
815     static int calls;
816
817     if(!(calls++))
818         FIXME("not implemented\n");
819
820     return NotImplemented;
821 }
822
823 GpStatus WINGDIPAPI GdipGetLineRect(GpLineGradient *brush, GpRectF *rect)
824 {
825     if(!brush || !rect)
826         return InvalidParameter;
827
828     rect->X = (brush->startpoint.X < brush->endpoint.X ? brush->startpoint.X: brush->endpoint.X);
829     rect->Y = (brush->startpoint.Y < brush->endpoint.Y ? brush->startpoint.Y: brush->endpoint.Y);
830
831     rect->Width  = fabs(brush->startpoint.X - brush->endpoint.X);
832     rect->Height = fabs(brush->startpoint.Y - brush->endpoint.Y);
833
834     return Ok;
835 }
836
837 GpStatus WINGDIPAPI GdipGetLineRectI(GpLineGradient *brush, GpRect *rect)
838 {
839     GpRectF  rectF;
840     GpStatus ret;
841
842     if(!rect)
843         return InvalidParameter;
844
845     ret = GdipGetLineRect(brush, &rectF);
846
847     if(ret == Ok){
848         rect->X      = roundr(rectF.X);
849         rect->Y      = roundr(rectF.Y);
850         rect->Width  = roundr(rectF.Width);
851         rect->Height = roundr(rectF.Height);
852     }
853
854     return ret;
855 }