msctf: Use FAILED instead of !SUCCEDED.
[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 /******************************************************************************
38  * GdipCloneBrush [GDIPLUS.@]
39  */
40 GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
41 {
42     TRACE("(%p, %p)\n", brush, clone);
43
44     if(!brush || !clone)
45         return InvalidParameter;
46
47     switch(brush->bt){
48         case BrushTypeSolidColor:
49             *clone = GdipAlloc(sizeof(GpSolidFill));
50             if (!*clone) return OutOfMemory;
51
52             memcpy(*clone, brush, sizeof(GpSolidFill));
53
54             (*clone)->gdibrush = CreateBrushIndirect(&(*clone)->lb);
55             break;
56         case BrushTypeHatchFill:
57             *clone = GdipAlloc(sizeof(GpHatch));
58             if (!*clone) return OutOfMemory;
59
60             memcpy(*clone, brush, sizeof(GpHatch));
61
62             (*clone)->gdibrush = CreateBrushIndirect(&(*clone)->lb);
63             break;
64         case BrushTypePathGradient:{
65             GpPathGradient *src, *dest;
66             INT count;
67
68             *clone = GdipAlloc(sizeof(GpPathGradient));
69             if (!*clone) return OutOfMemory;
70
71             src = (GpPathGradient*) brush,
72             dest = (GpPathGradient*) *clone;
73             count = src->pathdata.Count;
74
75             memcpy(dest, src, sizeof(GpPathGradient));
76
77             dest->pathdata.Count = count;
78             dest->pathdata.Points = GdipAlloc(count * sizeof(PointF));
79             dest->pathdata.Types = GdipAlloc(count);
80
81             if(!dest->pathdata.Points || !dest->pathdata.Types){
82                 GdipFree(dest->pathdata.Points);
83                 GdipFree(dest->pathdata.Types);
84                 GdipFree(dest);
85                 return OutOfMemory;
86             }
87
88             memcpy(dest->pathdata.Points, src->pathdata.Points, count * sizeof(PointF));
89             memcpy(dest->pathdata.Types, src->pathdata.Types, count);
90
91             /* blending */
92             count = src->blendcount;
93             dest->blendcount = count;
94             dest->blendfac = GdipAlloc(count * sizeof(REAL));
95             dest->blendpos = GdipAlloc(count * sizeof(REAL));
96
97             if(!dest->blendfac || !dest->blendpos){
98                 GdipFree(dest->pathdata.Points);
99                 GdipFree(dest->pathdata.Types);
100                 GdipFree(dest->blendfac);
101                 GdipFree(dest->blendpos);
102                 GdipFree(dest);
103                 return OutOfMemory;
104             }
105
106             memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL));
107             memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL));
108
109             break;
110         }
111         case BrushTypeLinearGradient:{
112             GpLineGradient *dest, *src;
113             INT count;
114
115             dest = GdipAlloc(sizeof(GpLineGradient));
116             if(!dest)    return OutOfMemory;
117
118             src = (GpLineGradient*)brush;
119
120             memcpy(dest, src, sizeof(GpLineGradient));
121
122             dest->brush.gdibrush = CreateSolidBrush(dest->brush.lb.lbColor);
123
124             count = dest->blendcount;
125             dest->blendfac = GdipAlloc(count * sizeof(REAL));
126             dest->blendpos = GdipAlloc(count * sizeof(REAL));
127
128             if (!dest->blendfac || !dest->blendpos)
129             {
130                 GdipFree(dest->blendfac);
131                 GdipFree(dest->blendpos);
132                 DeleteObject(dest->brush.gdibrush);
133                 GdipFree(dest);
134                 return OutOfMemory;
135             }
136
137             memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL));
138             memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL));
139
140             *clone = &dest->brush;
141             break;
142         }
143         case BrushTypeTextureFill:
144             *clone = GdipAlloc(sizeof(GpTexture));
145             if(!*clone)    return OutOfMemory;
146
147             memcpy(*clone, brush, sizeof(GpTexture));
148
149             (*clone)->gdibrush = CreateBrushIndirect(&(*clone)->lb);
150             break;
151         default:
152             ERR("not implemented for brush type %d\n", brush->bt);
153             return NotImplemented;
154     }
155
156     return Ok;
157 }
158
159 static LONG HatchStyleToHatch(HatchStyle hatchstyle)
160 {
161     switch (hatchstyle)
162     {
163         case HatchStyleHorizontal:        return HS_HORIZONTAL;
164         case HatchStyleVertical:          return HS_VERTICAL;
165         case HatchStyleForwardDiagonal:   return HS_FDIAGONAL;
166         case HatchStyleBackwardDiagonal:  return HS_BDIAGONAL;
167         case HatchStyleCross:             return HS_CROSS;
168         case HatchStyleDiagonalCross:     return HS_DIAGCROSS;
169         default:                          return 0;
170     }
171 }
172
173 /******************************************************************************
174  * GdipCreateHatchBrush [GDIPLUS.@]
175  */
176 GpStatus WINGDIPAPI GdipCreateHatchBrush(HatchStyle hatchstyle, ARGB forecol, ARGB backcol, GpHatch **brush)
177 {
178     COLORREF fgcol = ARGB2COLORREF(forecol);
179
180     TRACE("(%d, %d, %d, %p)\n", hatchstyle, forecol, backcol, brush);
181
182     if(!brush)  return InvalidParameter;
183
184     *brush = GdipAlloc(sizeof(GpHatch));
185     if (!*brush) return OutOfMemory;
186
187     switch (hatchstyle)
188     {
189         case HatchStyleHorizontal:
190         case HatchStyleVertical:
191         case HatchStyleForwardDiagonal:
192         case HatchStyleBackwardDiagonal:
193         case HatchStyleCross:
194         case HatchStyleDiagonalCross:
195             /* Brushes that map to BS_HATCHED */
196             (*brush)->brush.lb.lbStyle = BS_HATCHED;
197             (*brush)->brush.lb.lbColor = fgcol;
198             (*brush)->brush.lb.lbHatch = HatchStyleToHatch(hatchstyle);
199             break;
200
201         default:
202             FIXME("Unimplemented hatch style %d\n", hatchstyle);
203
204             (*brush)->brush.lb.lbStyle = BS_SOLID;
205             (*brush)->brush.lb.lbColor = fgcol;
206             (*brush)->brush.lb.lbHatch = 0;
207             break;
208     }
209
210
211     (*brush)->brush.gdibrush = CreateBrushIndirect(&(*brush)->brush.lb);
212     (*brush)->brush.bt = BrushTypeHatchFill;
213     (*brush)->forecol = forecol;
214     (*brush)->backcol = backcol;
215     (*brush)->hatchstyle = hatchstyle;
216
217     return Ok;
218 }
219
220 /******************************************************************************
221  * GdipCreateLineBrush [GDIPLUS.@]
222  */
223 GpStatus WINGDIPAPI GdipCreateLineBrush(GDIPCONST GpPointF* startpoint,
224     GDIPCONST GpPointF* endpoint, ARGB startcolor, ARGB endcolor,
225     GpWrapMode wrap, GpLineGradient **line)
226 {
227     COLORREF col = ARGB2COLORREF(startcolor);
228
229     TRACE("(%p, %p, %x, %x, %d, %p)\n", startpoint, endpoint,
230           startcolor, endcolor, wrap, line);
231
232     if(!line || !startpoint || !endpoint || wrap == WrapModeClamp)
233         return InvalidParameter;
234
235     *line = GdipAlloc(sizeof(GpLineGradient));
236     if(!*line)  return OutOfMemory;
237
238     (*line)->brush.lb.lbStyle = BS_SOLID;
239     (*line)->brush.lb.lbColor = col;
240     (*line)->brush.lb.lbHatch = 0;
241     (*line)->brush.gdibrush = CreateSolidBrush(col);
242     (*line)->brush.bt = BrushTypeLinearGradient;
243
244     (*line)->startpoint.X = startpoint->X;
245     (*line)->startpoint.Y = startpoint->Y;
246     (*line)->endpoint.X = endpoint->X;
247     (*line)->endpoint.Y = endpoint->Y;
248     (*line)->startcolor = startcolor;
249     (*line)->endcolor = endcolor;
250     (*line)->wrap = wrap;
251     (*line)->gamma = FALSE;
252
253     (*line)->rect.X = (startpoint->X < endpoint->X ? startpoint->X: endpoint->X);
254     (*line)->rect.Y = (startpoint->Y < endpoint->Y ? startpoint->Y: endpoint->Y);
255     (*line)->rect.Width  = fabs(startpoint->X - endpoint->X);
256     (*line)->rect.Height = fabs(startpoint->Y - endpoint->Y);
257
258     (*line)->blendcount = 1;
259     (*line)->blendfac = GdipAlloc(sizeof(REAL));
260     (*line)->blendpos = GdipAlloc(sizeof(REAL));
261
262     if (!(*line)->blendfac || !(*line)->blendpos)
263     {
264         GdipFree((*line)->blendfac);
265         GdipFree((*line)->blendpos);
266         DeleteObject((*line)->brush.gdibrush);
267         GdipFree(*line);
268         *line = NULL;
269         return OutOfMemory;
270     }
271
272     (*line)->blendfac[0] = 1.0f;
273     (*line)->blendpos[0] = 1.0f;
274
275     return Ok;
276 }
277
278 GpStatus WINGDIPAPI GdipCreateLineBrushI(GDIPCONST GpPoint* startpoint,
279     GDIPCONST GpPoint* endpoint, ARGB startcolor, ARGB endcolor,
280     GpWrapMode wrap, GpLineGradient **line)
281 {
282     GpPointF stF;
283     GpPointF endF;
284
285     TRACE("(%p, %p, %x, %x, %d, %p)\n", startpoint, endpoint,
286           startcolor, endcolor, wrap, line);
287
288     if(!startpoint || !endpoint)
289         return InvalidParameter;
290
291     stF.X  = (REAL)startpoint->X;
292     stF.Y  = (REAL)startpoint->Y;
293     endF.X = (REAL)endpoint->X;
294     endF.X = (REAL)endpoint->Y;
295
296     return GdipCreateLineBrush(&stF, &endF, startcolor, endcolor, wrap, line);
297 }
298
299 GpStatus WINGDIPAPI GdipCreateLineBrushFromRect(GDIPCONST GpRectF* rect,
300     ARGB startcolor, ARGB endcolor, LinearGradientMode mode, GpWrapMode wrap,
301     GpLineGradient **line)
302 {
303     GpPointF start, end;
304     GpStatus stat;
305
306     TRACE("(%p, %x, %x, %d, %d, %p)\n", rect, startcolor, endcolor, mode,
307           wrap, line);
308
309     if(!line || !rect)
310         return InvalidParameter;
311
312     switch (mode)
313     {
314     case LinearGradientModeHorizontal:
315         start.X = rect->X;
316         start.Y = rect->Y;
317         end.X = rect->X + rect->Width;
318         end.Y = rect->Y;
319         break;
320     case LinearGradientModeVertical:
321         start.X = rect->X;
322         start.Y = rect->Y;
323         end.X = rect->X;
324         end.Y = rect->Y + rect->Height;
325         break;
326     case LinearGradientModeForwardDiagonal:
327         start.X = rect->X;
328         start.Y = rect->Y;
329         end.X = rect->X + rect->Width;
330         end.Y = rect->Y + rect->Height;
331         break;
332     case LinearGradientModeBackwardDiagonal:
333         start.X = rect->X + rect->Width;
334         start.Y = rect->Y;
335         end.X = rect->X;
336         end.Y = rect->Y + rect->Height;
337         break;
338     default:
339         return InvalidParameter;
340     }
341
342     stat = GdipCreateLineBrush(&start, &end, startcolor, endcolor, wrap, line);
343
344     if (stat == Ok)
345         (*line)->rect = *rect;
346
347     return stat;
348 }
349
350 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectI(GDIPCONST GpRect* rect,
351     ARGB startcolor, ARGB endcolor, LinearGradientMode mode, GpWrapMode wrap,
352     GpLineGradient **line)
353 {
354     GpRectF rectF;
355
356     TRACE("(%p, %x, %x, %d, %d, %p)\n", rect, startcolor, endcolor, mode,
357           wrap, line);
358
359     rectF.X      = (REAL) rect->X;
360     rectF.Y      = (REAL) rect->Y;
361     rectF.Width  = (REAL) rect->Width;
362     rectF.Height = (REAL) rect->Height;
363
364     return GdipCreateLineBrushFromRect(&rectF, startcolor, endcolor, mode, wrap, line);
365 }
366
367 /******************************************************************************
368  * GdipCreateLineBrushFromRectWithAngle [GDIPLUS.@]
369  *
370  * FIXME: angle value completely ignored. Don't know how to use it since native
371  *        always set Brush rectangle to rect (independetly of this angle).
372  *        Maybe it's used only on drawing.
373  */
374 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF* rect,
375     ARGB startcolor, ARGB endcolor, REAL angle, BOOL isAngleScalable, GpWrapMode wrap,
376     GpLineGradient **line)
377 {
378     TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect, startcolor, endcolor, angle, isAngleScalable,
379           wrap, line);
380
381     return GdipCreateLineBrushFromRect(rect, startcolor, endcolor, LinearGradientModeForwardDiagonal,
382                                        wrap, line);
383 }
384
385 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngleI(GDIPCONST GpRect* rect,
386     ARGB startcolor, ARGB endcolor, REAL angle, BOOL isAngleScalable, GpWrapMode wrap,
387     GpLineGradient **line)
388 {
389     TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect, startcolor, endcolor, angle, isAngleScalable,
390           wrap, line);
391
392     return GdipCreateLineBrushFromRectI(rect, startcolor, endcolor, LinearGradientModeForwardDiagonal,
393                                         wrap, line);
394 }
395
396 GpStatus WINGDIPAPI GdipCreatePathGradient(GDIPCONST GpPointF* points,
397     INT count, GpWrapMode wrap, GpPathGradient **grad)
398 {
399     COLORREF col = ARGB2COLORREF(0xffffffff);
400
401     TRACE("(%p, %d, %d, %p)\n", points, count, wrap, grad);
402
403     if(!points || !grad)
404         return InvalidParameter;
405
406     if(count <= 0)
407         return OutOfMemory;
408
409     *grad = GdipAlloc(sizeof(GpPathGradient));
410     if (!*grad) return OutOfMemory;
411
412     (*grad)->blendfac = GdipAlloc(sizeof(REAL));
413     if(!(*grad)->blendfac){
414         GdipFree(*grad);
415         return OutOfMemory;
416     }
417     (*grad)->blendfac[0] = 1.0;
418     (*grad)->blendpos    = NULL;
419     (*grad)->blendcount  = 1;
420
421     (*grad)->pathdata.Count = count;
422     (*grad)->pathdata.Points = GdipAlloc(count * sizeof(PointF));
423     (*grad)->pathdata.Types = GdipAlloc(count);
424
425     if(!(*grad)->pathdata.Points || !(*grad)->pathdata.Types){
426         GdipFree((*grad)->pathdata.Points);
427         GdipFree((*grad)->pathdata.Types);
428         GdipFree(*grad);
429         return OutOfMemory;
430     }
431
432     memcpy((*grad)->pathdata.Points, points, count * sizeof(PointF));
433     memset((*grad)->pathdata.Types, PathPointTypeLine, count);
434
435     (*grad)->brush.lb.lbStyle = BS_SOLID;
436     (*grad)->brush.lb.lbColor = col;
437     (*grad)->brush.lb.lbHatch = 0;
438
439     (*grad)->brush.gdibrush = CreateSolidBrush(col);
440     (*grad)->brush.bt = BrushTypePathGradient;
441     (*grad)->centercolor = 0xffffffff;
442     (*grad)->wrap = wrap;
443     (*grad)->gamma = FALSE;
444     (*grad)->center.X = 0.0;
445     (*grad)->center.Y = 0.0;
446     (*grad)->focus.X = 0.0;
447     (*grad)->focus.Y = 0.0;
448
449     return Ok;
450 }
451
452 GpStatus WINGDIPAPI GdipCreatePathGradientI(GDIPCONST GpPoint* points,
453     INT count, GpWrapMode wrap, GpPathGradient **grad)
454 {
455     GpPointF *pointsF;
456     GpStatus ret;
457     INT i;
458
459     TRACE("(%p, %d, %d, %p)\n", points, count, wrap, grad);
460
461     if(!points || !grad)
462         return InvalidParameter;
463
464     if(count <= 0)
465         return OutOfMemory;
466
467     pointsF = GdipAlloc(sizeof(GpPointF) * count);
468     if(!pointsF)
469         return OutOfMemory;
470
471     for(i = 0; i < count; i++){
472         pointsF[i].X = (REAL)points[i].X;
473         pointsF[i].Y = (REAL)points[i].Y;
474     }
475
476     ret = GdipCreatePathGradient(pointsF, count, wrap, grad);
477     GdipFree(pointsF);
478
479     return ret;
480 }
481
482 /******************************************************************************
483  * GdipCreatePathGradientFromPath [GDIPLUS.@]
484  *
485  * FIXME: path gradient brushes not truly supported (drawn as solid brushes)
486  */
487 GpStatus WINGDIPAPI GdipCreatePathGradientFromPath(GDIPCONST GpPath* path,
488     GpPathGradient **grad)
489 {
490     COLORREF col = ARGB2COLORREF(0xffffffff);
491
492     TRACE("(%p, %p)\n", path, grad);
493
494     if(!path || !grad)
495         return InvalidParameter;
496
497     *grad = GdipAlloc(sizeof(GpPathGradient));
498     if (!*grad) return OutOfMemory;
499
500     (*grad)->blendfac = GdipAlloc(sizeof(REAL));
501     if(!(*grad)->blendfac){
502         GdipFree(*grad);
503         return OutOfMemory;
504     }
505     (*grad)->blendfac[0] = 1.0;
506     (*grad)->blendpos    = NULL;
507     (*grad)->blendcount  = 1;
508
509     (*grad)->pathdata.Count = path->pathdata.Count;
510     (*grad)->pathdata.Points = GdipAlloc(path->pathdata.Count * sizeof(PointF));
511     (*grad)->pathdata.Types = GdipAlloc(path->pathdata.Count);
512
513     if(!(*grad)->pathdata.Points || !(*grad)->pathdata.Types){
514         GdipFree((*grad)->pathdata.Points);
515         GdipFree((*grad)->pathdata.Types);
516         GdipFree(*grad);
517         return OutOfMemory;
518     }
519
520     memcpy((*grad)->pathdata.Points, path->pathdata.Points,
521            path->pathdata.Count * sizeof(PointF));
522     memcpy((*grad)->pathdata.Types, path->pathdata.Types, path->pathdata.Count);
523
524     (*grad)->brush.lb.lbStyle = BS_SOLID;
525     (*grad)->brush.lb.lbColor = col;
526     (*grad)->brush.lb.lbHatch = 0;
527
528     (*grad)->brush.gdibrush = CreateSolidBrush(col);
529     (*grad)->brush.bt = BrushTypePathGradient;
530     (*grad)->centercolor = 0xffffffff;
531     (*grad)->wrap = WrapModeClamp;
532     (*grad)->gamma = FALSE;
533     /* FIXME: this should be set to the "centroid" of the path by default */
534     (*grad)->center.X = 0.0;
535     (*grad)->center.Y = 0.0;
536     (*grad)->focus.X = 0.0;
537     (*grad)->focus.Y = 0.0;
538
539     return Ok;
540 }
541
542 /******************************************************************************
543  * GdipCreateSolidFill [GDIPLUS.@]
544  */
545 GpStatus WINGDIPAPI GdipCreateSolidFill(ARGB color, GpSolidFill **sf)
546 {
547     COLORREF col = ARGB2COLORREF(color);
548
549     TRACE("(%x, %p)\n", color, sf);
550
551     if(!sf)  return InvalidParameter;
552
553     *sf = GdipAlloc(sizeof(GpSolidFill));
554     if (!*sf) return OutOfMemory;
555
556     (*sf)->brush.lb.lbStyle = BS_SOLID;
557     (*sf)->brush.lb.lbColor = col;
558     (*sf)->brush.lb.lbHatch = 0;
559
560     (*sf)->brush.gdibrush = CreateSolidBrush(col);
561     (*sf)->brush.bt = BrushTypeSolidColor;
562     (*sf)->color = color;
563
564     return Ok;
565 }
566
567 /******************************************************************************
568  * GdipCreateTexture [GDIPLUS.@]
569  *
570  * PARAMS
571  *  image       [I] image to use
572  *  wrapmode    [I] optional
573  *  texture     [O] pointer to the resulting texturebrush
574  *
575  * RETURNS
576  *  SUCCESS: Ok
577  *  FAILURE: element of GpStatus
578  */
579 GpStatus WINGDIPAPI GdipCreateTexture(GpImage *image, GpWrapMode wrapmode,
580         GpTexture **texture)
581 {
582     UINT width, height;
583     GpImageAttributes attributes;
584     GpStatus stat;
585
586     TRACE("%p, %d %p\n", image, wrapmode, texture);
587
588     if (!(image && texture))
589         return InvalidParameter;
590
591     stat = GdipGetImageWidth(image, &width);
592     if (stat != Ok) return stat;
593     stat = GdipGetImageHeight(image, &height);
594     if (stat != Ok) return stat;
595     attributes.wrap = wrapmode;
596
597     return GdipCreateTextureIA(image, &attributes, 0, 0, width, height,
598             texture);
599 }
600
601 /******************************************************************************
602  * GdipCreateTexture2 [GDIPLUS.@]
603  */
604 GpStatus WINGDIPAPI GdipCreateTexture2(GpImage *image, GpWrapMode wrapmode,
605         REAL x, REAL y, REAL width, REAL height, GpTexture **texture)
606 {
607     GpImageAttributes attributes;
608
609     TRACE("%p %d %f %f %f %f %p\n", image, wrapmode,
610             x, y, width, height, texture);
611
612     attributes.wrap = wrapmode;
613     return GdipCreateTextureIA(image, &attributes, x, y, width, height,
614             texture);
615 }
616
617 /******************************************************************************
618  * GdipCreateTextureIA [GDIPLUS.@]
619  *
620  * FIXME: imageattr ignored
621  */
622 GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image,
623     GDIPCONST GpImageAttributes *imageattr, REAL x, REAL y, REAL width,
624     REAL height, GpTexture **texture)
625 {
626     HDC hdc;
627     HBITMAP hbm, old = NULL;
628     BITMAPINFO *pbmi;
629     BITMAPINFOHEADER *bmih;
630     INT n_x, n_y, n_width, n_height, abs_height, stride, image_stride, i, bytespp;
631     BOOL bm_is_selected;
632     BYTE *dibits, *buff, *textbits;
633     GpStatus status;
634
635     TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %p)\n", image, imageattr, x, y, width, height,
636            texture);
637
638     if(!image || !texture || x < 0.0 || y < 0.0 || width < 0.0 || height < 0.0)
639         return InvalidParameter;
640
641     if(image->type != ImageTypeBitmap){
642         FIXME("not implemented for image type %d\n", image->type);
643         return NotImplemented;
644     }
645
646     n_x = roundr(x);
647     n_y = roundr(y);
648     n_width = roundr(width);
649     n_height = roundr(height);
650
651     if(n_x + n_width > ((GpBitmap*)image)->width ||
652        n_y + n_height > ((GpBitmap*)image)->height)
653         return InvalidParameter;
654
655     IPicture_get_Handle(image->picture, (OLE_HANDLE*)&hbm);
656     if(!hbm)   return GenericError;
657     IPicture_get_CurDC(image->picture, &hdc);
658     bm_is_selected = (hdc != 0);
659
660     pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
661     if (!pbmi)
662         return OutOfMemory;
663     pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
664     pbmi->bmiHeader.biBitCount = 0;
665
666     if(!bm_is_selected){
667         hdc = CreateCompatibleDC(0);
668         old = SelectObject(hdc, hbm);
669     }
670
671     /* fill out bmi */
672     GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
673
674     bytespp = pbmi->bmiHeader.biBitCount / 8;
675     abs_height = abs(pbmi->bmiHeader.biHeight);
676
677     if(n_x > pbmi->bmiHeader.biWidth || n_x + n_width > pbmi->bmiHeader.biWidth ||
678        n_y > abs_height || n_y + n_height > abs_height){
679         GdipFree(pbmi);
680         return InvalidParameter;
681     }
682
683     dibits = GdipAlloc(pbmi->bmiHeader.biSizeImage);
684
685     if(dibits)  /* this is not a good place to error out */
686         GetDIBits(hdc, hbm, 0, abs_height, dibits, pbmi, DIB_RGB_COLORS);
687
688     if(!bm_is_selected){
689         SelectObject(hdc, old);
690         DeleteDC(hdc);
691     }
692
693     if(!dibits){
694         GdipFree(pbmi);
695         return OutOfMemory;
696     }
697
698     image_stride = (pbmi->bmiHeader.biWidth * bytespp + 3) & ~3;
699     stride = (n_width * bytespp + 3) & ~3;
700     buff = GdipAlloc(sizeof(BITMAPINFOHEADER) + stride * n_height);
701     if(!buff){
702         GdipFree(pbmi);
703         GdipFree(dibits);
704         return OutOfMemory;
705     }
706
707     bmih = (BITMAPINFOHEADER*)buff;
708     textbits = (BYTE*) (bmih + 1);
709     bmih->biSize = sizeof(BITMAPINFOHEADER);
710     bmih->biWidth = n_width;
711     bmih->biHeight = n_height;
712     bmih->biCompression = BI_RGB;
713     bmih->biSizeImage = stride * n_height;
714     bmih->biBitCount = pbmi->bmiHeader.biBitCount;
715     bmih->biClrUsed = 0;
716     bmih->biPlanes = 1;
717
718     /* image is flipped */
719     if(pbmi->bmiHeader.biHeight > 0){
720         dibits += pbmi->bmiHeader.biSizeImage;
721         image_stride *= -1;
722         textbits += stride * (n_height - 1);
723         stride *= -1;
724     }
725
726     GdipFree(pbmi);
727
728     for(i = 0; i < n_height; i++)
729         memcpy(&textbits[i * stride],
730                &dibits[n_x * bytespp + (n_y + i) * image_stride],
731                abs(stride));
732
733     *texture = GdipAlloc(sizeof(GpTexture));
734     if (!*texture){
735         GdipFree(dibits);
736         GdipFree(buff);
737         return OutOfMemory;
738     }
739
740     if((status = GdipCreateMatrix(&(*texture)->transform)) != Ok){
741         GdipFree(*texture);
742         GdipFree(dibits);
743         GdipFree(buff);
744         return status;
745     }
746
747     (*texture)->brush.lb.lbStyle = BS_DIBPATTERNPT;
748     (*texture)->brush.lb.lbColor = DIB_RGB_COLORS;
749     (*texture)->brush.lb.lbHatch = (ULONG_PTR)buff;
750
751     (*texture)->brush.gdibrush = CreateBrushIndirect(&(*texture)->brush.lb);
752     (*texture)->brush.bt = BrushTypeTextureFill;
753     (*texture)->wrap = imageattr->wrap;
754
755     GdipFree(dibits);
756     GdipFree(buff);
757
758     return Ok;
759 }
760
761 /******************************************************************************
762  * GdipCreateTextureIAI [GDIPLUS.@]
763  */
764 GpStatus WINGDIPAPI GdipCreateTextureIAI(GpImage *image, GDIPCONST GpImageAttributes *imageattr,
765     INT x, INT y, INT width, INT height, GpTexture **texture)
766 {
767     TRACE("(%p, %p, %d, %d, %d, %d, %p)\n", image, imageattr, x, y, width, height,
768            texture);
769
770     return GdipCreateTextureIA(image,imageattr,(REAL)x,(REAL)y,(REAL)width,(REAL)height,texture);
771 }
772
773 GpStatus WINGDIPAPI GdipCreateTexture2I(GpImage *image, GpWrapMode wrapmode,
774         INT x, INT y, INT width, INT height, GpTexture **texture)
775 {
776     GpImageAttributes imageattr;
777
778     TRACE("%p %d %d %d %d %d %p\n", image, wrapmode, x, y, width, height,
779             texture);
780
781     imageattr.wrap = wrapmode;
782
783     return GdipCreateTextureIA(image, &imageattr, x, y, width, height, texture);
784 }
785
786 GpStatus WINGDIPAPI GdipGetBrushType(GpBrush *brush, GpBrushType *type)
787 {
788     TRACE("(%p, %p)\n", brush, type);
789
790     if(!brush || !type)  return InvalidParameter;
791
792     *type = brush->bt;
793
794     return Ok;
795 }
796
797 GpStatus WINGDIPAPI GdipGetHatchBackgroundColor(GpHatch *brush, ARGB *backcol)
798 {
799     TRACE("(%p, %p)\n", brush, backcol);
800
801     if(!brush || !backcol)  return InvalidParameter;
802
803     *backcol = brush->backcol;
804
805     return Ok;
806 }
807
808 GpStatus WINGDIPAPI GdipGetHatchForegroundColor(GpHatch *brush, ARGB *forecol)
809 {
810     TRACE("(%p, %p)\n", brush, forecol);
811
812     if(!brush || !forecol)  return InvalidParameter;
813
814     *forecol = brush->forecol;
815
816     return Ok;
817 }
818
819 GpStatus WINGDIPAPI GdipGetHatchStyle(GpHatch *brush, HatchStyle *hatchstyle)
820 {
821     TRACE("(%p, %p)\n", brush, hatchstyle);
822
823     if(!brush || !hatchstyle)  return InvalidParameter;
824
825     *hatchstyle = brush->hatchstyle;
826
827     return Ok;
828 }
829
830 GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush)
831 {
832     TRACE("(%p)\n", brush);
833
834     if(!brush)  return InvalidParameter;
835
836     switch(brush->bt)
837     {
838         case BrushTypePathGradient:
839             GdipFree(((GpPathGradient*) brush)->pathdata.Points);
840             GdipFree(((GpPathGradient*) brush)->pathdata.Types);
841             GdipFree(((GpPathGradient*) brush)->blendfac);
842             GdipFree(((GpPathGradient*) brush)->blendpos);
843             break;
844         case BrushTypeSolidColor:
845             break;
846         case BrushTypeLinearGradient:
847             GdipFree(((GpLineGradient*)brush)->blendfac);
848             GdipFree(((GpLineGradient*)brush)->blendpos);
849             break;
850         case BrushTypeTextureFill:
851             GdipDeleteMatrix(((GpTexture*)brush)->transform);
852             break;
853         default:
854             break;
855     }
856
857     DeleteObject(brush->gdibrush);
858     GdipFree(brush);
859
860     return Ok;
861 }
862
863 GpStatus WINGDIPAPI GdipGetLineGammaCorrection(GpLineGradient *line,
864     BOOL *usinggamma)
865 {
866     TRACE("(%p, %p)\n", line, usinggamma);
867
868     if(!line || !usinggamma)
869         return InvalidParameter;
870
871     *usinggamma = line->gamma;
872
873     return Ok;
874 }
875
876 GpStatus WINGDIPAPI GdipGetLineWrapMode(GpLineGradient *brush, GpWrapMode *wrapmode)
877 {
878     TRACE("(%p, %p)\n", brush, wrapmode);
879
880     if(!brush || !wrapmode)
881         return InvalidParameter;
882
883     *wrapmode = brush->wrap;
884
885     return Ok;
886 }
887
888 GpStatus WINGDIPAPI GdipGetPathGradientBlend(GpPathGradient *brush, REAL *blend,
889     REAL *positions, INT count)
890 {
891     TRACE("(%p, %p, %p, %d)\n", brush, blend, positions, count);
892
893     if(!brush || !blend || !positions || count <= 0)
894         return InvalidParameter;
895
896     if(count < brush->blendcount)
897         return InsufficientBuffer;
898
899     memcpy(blend, brush->blendfac, count*sizeof(REAL));
900     if(brush->blendcount > 1){
901         memcpy(positions, brush->blendpos, count*sizeof(REAL));
902     }
903
904     return Ok;
905 }
906
907 GpStatus WINGDIPAPI GdipGetPathGradientBlendCount(GpPathGradient *brush, INT *count)
908 {
909     TRACE("(%p, %p)\n", brush, count);
910
911     if(!brush || !count)
912         return InvalidParameter;
913
914     *count = brush->blendcount;
915
916     return Ok;
917 }
918
919 GpStatus WINGDIPAPI GdipGetPathGradientCenterPoint(GpPathGradient *grad,
920     GpPointF *point)
921 {
922     TRACE("(%p, %p)\n", grad, point);
923
924     if(!grad || !point)
925         return InvalidParameter;
926
927     point->X = grad->center.X;
928     point->Y = grad->center.Y;
929
930     return Ok;
931 }
932
933 GpStatus WINGDIPAPI GdipGetPathGradientCenterPointI(GpPathGradient *grad,
934     GpPoint *point)
935 {
936     GpStatus ret;
937     GpPointF ptf;
938
939     TRACE("(%p, %p)\n", grad, point);
940
941     if(!point)
942         return InvalidParameter;
943
944     ret = GdipGetPathGradientCenterPoint(grad,&ptf);
945
946     if(ret == Ok){
947         point->X = roundr(ptf.X);
948         point->Y = roundr(ptf.Y);
949     }
950
951     return ret;
952 }
953
954 GpStatus WINGDIPAPI GdipGetPathGradientFocusScales(GpPathGradient *grad,
955     REAL *x, REAL *y)
956 {
957     TRACE("(%p, %p, %p)\n", grad, x, y);
958
959     if(!grad || !x || !y)
960         return InvalidParameter;
961
962     *x = grad->focus.X;
963     *y = grad->focus.Y;
964
965     return Ok;
966 }
967
968 GpStatus WINGDIPAPI GdipGetPathGradientGammaCorrection(GpPathGradient *grad,
969     BOOL *gamma)
970 {
971     TRACE("(%p, %p)\n", grad, gamma);
972
973     if(!grad || !gamma)
974         return InvalidParameter;
975
976     *gamma = grad->gamma;
977
978     return Ok;
979 }
980
981 GpStatus WINGDIPAPI GdipGetPathGradientPointCount(GpPathGradient *grad,
982     INT *count)
983 {
984     TRACE("(%p, %p)\n", grad, count);
985
986     if(!grad || !count)
987         return InvalidParameter;
988
989     *count = grad->pathdata.Count;
990
991     return Ok;
992 }
993
994 GpStatus WINGDIPAPI GdipGetPathGradientRect(GpPathGradient *brush, GpRectF *rect)
995 {
996     GpRectF r;
997     GpPath* path;
998     GpStatus stat;
999
1000     TRACE("(%p, %p)\n", brush, rect);
1001
1002     if(!brush || !rect)
1003         return InvalidParameter;
1004
1005     stat = GdipCreatePath2(brush->pathdata.Points, brush->pathdata.Types,
1006                            brush->pathdata.Count, FillModeAlternate, &path);
1007     if(stat != Ok)  return stat;
1008
1009     stat = GdipGetPathWorldBounds(path, &r, NULL, NULL);
1010     if(stat != Ok){
1011         GdipDeletePath(path);
1012         return stat;
1013     }
1014
1015     memcpy(rect, &r, sizeof(GpRectF));
1016
1017     GdipDeletePath(path);
1018
1019     return Ok;
1020 }
1021
1022 GpStatus WINGDIPAPI GdipGetPathGradientRectI(GpPathGradient *brush, GpRect *rect)
1023 {
1024     GpRectF rectf;
1025     GpStatus stat;
1026
1027     TRACE("(%p, %p)\n", brush, rect);
1028
1029     if(!brush || !rect)
1030         return InvalidParameter;
1031
1032     stat = GdipGetPathGradientRect(brush, &rectf);
1033     if(stat != Ok)  return stat;
1034
1035     rect->X = roundr(rectf.X);
1036     rect->Y = roundr(rectf.Y);
1037     rect->Width  = roundr(rectf.Width);
1038     rect->Height = roundr(rectf.Height);
1039
1040     return Ok;
1041 }
1042
1043 GpStatus WINGDIPAPI GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
1044     *grad, ARGB *argb, INT *count)
1045 {
1046     static int calls;
1047
1048     if(!grad || !argb || !count || (*count < grad->pathdata.Count))
1049         return InvalidParameter;
1050
1051     if(!(calls++))
1052         FIXME("not implemented\n");
1053
1054     return NotImplemented;
1055 }
1056
1057 GpStatus WINGDIPAPI GdipGetPathGradientWrapMode(GpPathGradient *brush,
1058     GpWrapMode *wrapmode)
1059 {
1060     TRACE("(%p, %p)\n", brush, wrapmode);
1061
1062     if(!brush || !wrapmode)
1063         return InvalidParameter;
1064
1065     *wrapmode = brush->wrap;
1066
1067     return Ok;
1068 }
1069
1070 GpStatus WINGDIPAPI GdipGetSolidFillColor(GpSolidFill *sf, ARGB *argb)
1071 {
1072     TRACE("(%p, %p)\n", sf, argb);
1073
1074     if(!sf || !argb)
1075         return InvalidParameter;
1076
1077     *argb = sf->color;
1078
1079     return Ok;
1080 }
1081
1082 /******************************************************************************
1083  * GdipGetTextureTransform [GDIPLUS.@]
1084  */
1085 GpStatus WINGDIPAPI GdipGetTextureTransform(GpTexture *brush, GpMatrix *matrix)
1086 {
1087     TRACE("(%p, %p)\n", brush, matrix);
1088
1089     if(!brush || !matrix)
1090         return InvalidParameter;
1091
1092     memcpy(matrix, brush->transform, sizeof(GpMatrix));
1093
1094     return Ok;
1095 }
1096
1097 /******************************************************************************
1098  * GdipGetTextureWrapMode [GDIPLUS.@]
1099  */
1100 GpStatus WINGDIPAPI GdipGetTextureWrapMode(GpTexture *brush, GpWrapMode *wrapmode)
1101 {
1102     TRACE("(%p, %p)\n", brush, wrapmode);
1103
1104     if(!brush || !wrapmode)
1105         return InvalidParameter;
1106
1107     *wrapmode = brush->wrap;
1108
1109     return Ok;
1110 }
1111
1112 /******************************************************************************
1113  * GdipMultiplyTextureTransform [GDIPLUS.@]
1114  */
1115 GpStatus WINGDIPAPI GdipMultiplyTextureTransform(GpTexture* brush,
1116     GDIPCONST GpMatrix *matrix, GpMatrixOrder order)
1117 {
1118     TRACE("(%p, %p, %d)\n", brush, matrix, order);
1119
1120     if(!brush || !matrix)
1121         return InvalidParameter;
1122
1123     return GdipMultiplyMatrix(brush->transform, matrix, order);
1124 }
1125
1126 /******************************************************************************
1127  * GdipResetTextureTransform [GDIPLUS.@]
1128  */
1129 GpStatus WINGDIPAPI GdipResetTextureTransform(GpTexture* brush)
1130 {
1131     TRACE("(%p)\n", brush);
1132
1133     if(!brush)
1134         return InvalidParameter;
1135
1136     return GdipSetMatrixElements(brush->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1137 }
1138
1139 /******************************************************************************
1140  * GdipScaleTextureTransform [GDIPLUS.@]
1141  */
1142 GpStatus WINGDIPAPI GdipScaleTextureTransform(GpTexture* brush,
1143     REAL sx, REAL sy, GpMatrixOrder order)
1144 {
1145     TRACE("(%p, %.2f, %.2f, %d)\n", brush, sx, sy, order);
1146
1147     if(!brush)
1148         return InvalidParameter;
1149
1150     return GdipScaleMatrix(brush->transform, sx, sy, order);
1151 }
1152
1153 GpStatus WINGDIPAPI GdipSetLineBlend(GpLineGradient *brush,
1154     GDIPCONST REAL *factors, GDIPCONST REAL* positions, INT count)
1155 {
1156     REAL *new_blendfac, *new_blendpos;
1157
1158     TRACE("(%p, %p, %p, %i)\n", brush, factors, positions, count);
1159
1160     if(!brush || !factors || !positions || count <= 0 ||
1161        (count >= 2 && (positions[0] != 0.0f || positions[count-1] != 1.0f)))
1162         return InvalidParameter;
1163
1164     new_blendfac = GdipAlloc(count * sizeof(REAL));
1165     new_blendpos = GdipAlloc(count * sizeof(REAL));
1166
1167     if (!new_blendfac || !new_blendpos)
1168     {
1169         GdipFree(new_blendfac);
1170         GdipFree(new_blendpos);
1171         return OutOfMemory;
1172     }
1173
1174     memcpy(new_blendfac, factors, count * sizeof(REAL));
1175     memcpy(new_blendpos, positions, count * sizeof(REAL));
1176
1177     GdipFree(brush->blendfac);
1178     GdipFree(brush->blendpos);
1179
1180     brush->blendcount = count;
1181     brush->blendfac = new_blendfac;
1182     brush->blendpos = new_blendpos;
1183
1184     return Ok;
1185 }
1186
1187 GpStatus WINGDIPAPI GdipGetLineBlend(GpLineGradient *brush, REAL *factors,
1188     REAL *positions, INT count)
1189 {
1190     TRACE("(%p, %p, %p, %i)\n", brush, factors, positions, count);
1191
1192     if (!brush || !factors || !positions || count <= 0)
1193         return InvalidParameter;
1194
1195     if (count < brush->blendcount)
1196         return InsufficientBuffer;
1197
1198     memcpy(factors, brush->blendfac, brush->blendcount * sizeof(REAL));
1199     memcpy(positions, brush->blendpos, brush->blendcount * sizeof(REAL));
1200
1201     return Ok;
1202 }
1203
1204 GpStatus WINGDIPAPI GdipGetLineBlendCount(GpLineGradient *brush, INT *count)
1205 {
1206     TRACE("(%p, %p)\n", brush, count);
1207
1208     if (!brush || !count)
1209         return InvalidParameter;
1210
1211     *count = brush->blendcount;
1212
1213     return Ok;
1214 }
1215
1216 GpStatus WINGDIPAPI GdipSetLineGammaCorrection(GpLineGradient *line,
1217     BOOL usegamma)
1218 {
1219     TRACE("(%p, %d)\n", line, usegamma);
1220
1221     if(!line)
1222         return InvalidParameter;
1223
1224     line->gamma = usegamma;
1225
1226     return Ok;
1227 }
1228
1229 GpStatus WINGDIPAPI GdipSetLineSigmaBlend(GpLineGradient *line, REAL focus,
1230     REAL scale)
1231 {
1232     REAL factors[33];
1233     REAL positions[33];
1234     int num_points = 0;
1235     int i;
1236     const int precision = 16;
1237     REAL erf_range; /* we use values erf(-erf_range) through erf(+erf_range) */
1238     REAL min_erf;
1239     REAL scale_erf;
1240
1241     TRACE("(%p, %0.2f, %0.2f)\n", line, focus, scale);
1242
1243     if(!line || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0)
1244         return InvalidParameter;
1245
1246     /* we want 2 standard deviations */
1247     erf_range = 2.0 / sqrt(2);
1248
1249     /* calculate the constants we need to normalize the error function to be
1250         between 0.0 and scale over the range we need */
1251     min_erf = erf(-erf_range);
1252     scale_erf = scale / (-2.0 * min_erf);
1253
1254     if (focus != 0.0)
1255     {
1256         positions[0] = 0.0;
1257         factors[0] = 0.0;
1258         for (i=1; i<precision; i++)
1259         {
1260             positions[i] = focus * i / precision;
1261             factors[i] = scale_erf * (erf(2 * erf_range * i / precision - erf_range) - min_erf);
1262         }
1263         num_points += precision;
1264     }
1265
1266     positions[num_points] = focus;
1267     factors[num_points] = scale;
1268     num_points += 1;
1269
1270     if (focus != 1.0)
1271     {
1272         for (i=1; i<precision; i++)
1273         {
1274             positions[i+num_points-1] = (focus + ((1.0-focus) * i / precision));
1275             factors[i+num_points-1] = scale_erf * (erf(erf_range - 2 * erf_range * i / precision) - min_erf);
1276         }
1277         num_points += precision;
1278         positions[num_points-1] = 1.0;
1279         factors[num_points-1] = 0.0;
1280     }
1281
1282     return GdipSetLineBlend(line, factors, positions, num_points);
1283 }
1284
1285 GpStatus WINGDIPAPI GdipSetLineWrapMode(GpLineGradient *line,
1286     GpWrapMode wrap)
1287 {
1288     TRACE("(%p, %d)\n", line, wrap);
1289
1290     if(!line || wrap == WrapModeClamp)
1291         return InvalidParameter;
1292
1293     line->wrap = wrap;
1294
1295     return Ok;
1296 }
1297
1298 GpStatus WINGDIPAPI GdipSetPathGradientBlend(GpPathGradient *brush, GDIPCONST REAL *blend,
1299     GDIPCONST REAL *pos, INT count)
1300 {
1301     static int calls;
1302
1303     if(!(calls++))
1304         FIXME("not implemented\n");
1305
1306     return NotImplemented;
1307 }
1308
1309 GpStatus WINGDIPAPI GdipSetPathGradientCenterColor(GpPathGradient *grad,
1310     ARGB argb)
1311 {
1312     TRACE("(%p, %x)\n", grad, argb);
1313
1314     if(!grad)
1315         return InvalidParameter;
1316
1317     grad->centercolor = argb;
1318     grad->brush.lb.lbColor = ARGB2COLORREF(argb);
1319
1320     DeleteObject(grad->brush.gdibrush);
1321     grad->brush.gdibrush = CreateSolidBrush(grad->brush.lb.lbColor);
1322
1323     return Ok;
1324 }
1325
1326 GpStatus WINGDIPAPI GdipSetPathGradientCenterPoint(GpPathGradient *grad,
1327     GpPointF *point)
1328 {
1329     TRACE("(%p, %p)\n", grad, point);
1330
1331     if(!grad || !point)
1332         return InvalidParameter;
1333
1334     grad->center.X = point->X;
1335     grad->center.Y = point->Y;
1336
1337     return Ok;
1338 }
1339
1340 GpStatus WINGDIPAPI GdipSetPathGradientCenterPointI(GpPathGradient *grad,
1341     GpPoint *point)
1342 {
1343     GpPointF ptf;
1344
1345     TRACE("(%p, %p)\n", grad, point);
1346
1347     if(!point)
1348         return InvalidParameter;
1349
1350     ptf.X = (REAL)point->X;
1351     ptf.Y = (REAL)point->Y;
1352
1353     return GdipSetPathGradientCenterPoint(grad,&ptf);
1354 }
1355
1356 GpStatus WINGDIPAPI GdipSetPathGradientFocusScales(GpPathGradient *grad,
1357     REAL x, REAL y)
1358 {
1359     TRACE("(%p, %.2f, %.2f)\n", grad, x, y);
1360
1361     if(!grad)
1362         return InvalidParameter;
1363
1364     grad->focus.X = x;
1365     grad->focus.Y = y;
1366
1367     return Ok;
1368 }
1369
1370 GpStatus WINGDIPAPI GdipSetPathGradientGammaCorrection(GpPathGradient *grad,
1371     BOOL gamma)
1372 {
1373     TRACE("(%p, %d)\n", grad, gamma);
1374
1375     if(!grad)
1376         return InvalidParameter;
1377
1378     grad->gamma = gamma;
1379
1380     return Ok;
1381 }
1382
1383 GpStatus WINGDIPAPI GdipSetPathGradientSigmaBlend(GpPathGradient *grad,
1384     REAL focus, REAL scale)
1385 {
1386     static int calls;
1387
1388     if(!grad || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0)
1389         return InvalidParameter;
1390
1391     if(!(calls++))
1392         FIXME("not implemented\n");
1393
1394     return NotImplemented;
1395 }
1396
1397 GpStatus WINGDIPAPI GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
1398     *grad, ARGB *argb, INT *count)
1399 {
1400     static int calls;
1401
1402     if(!grad || !argb || !count || (*count <= 0) ||
1403         (*count > grad->pathdata.Count))
1404         return InvalidParameter;
1405
1406     if(!(calls++))
1407         FIXME("not implemented\n");
1408
1409     return NotImplemented;
1410 }
1411
1412 GpStatus WINGDIPAPI GdipSetPathGradientWrapMode(GpPathGradient *grad,
1413     GpWrapMode wrap)
1414 {
1415     TRACE("(%p, %d)\n", grad, wrap);
1416
1417     if(!grad)
1418         return InvalidParameter;
1419
1420     grad->wrap = wrap;
1421
1422     return Ok;
1423 }
1424
1425 GpStatus WINGDIPAPI GdipSetSolidFillColor(GpSolidFill *sf, ARGB argb)
1426 {
1427     TRACE("(%p, %x)\n", sf, argb);
1428
1429     if(!sf)
1430         return InvalidParameter;
1431
1432     sf->color = argb;
1433     sf->brush.lb.lbColor = ARGB2COLORREF(argb);
1434
1435     DeleteObject(sf->brush.gdibrush);
1436     sf->brush.gdibrush = CreateSolidBrush(sf->brush.lb.lbColor);
1437
1438     return Ok;
1439 }
1440
1441 /******************************************************************************
1442  * GdipSetTextureTransform [GDIPLUS.@]
1443  */
1444 GpStatus WINGDIPAPI GdipSetTextureTransform(GpTexture *texture,
1445     GDIPCONST GpMatrix *matrix)
1446 {
1447     TRACE("(%p, %p)\n", texture, matrix);
1448
1449     if(!texture || !matrix)
1450         return InvalidParameter;
1451
1452     memcpy(texture->transform, matrix, sizeof(GpMatrix));
1453
1454     return Ok;
1455 }
1456
1457 /******************************************************************************
1458  * GdipSetTextureWrapMode [GDIPLUS.@]
1459  *
1460  * WrapMode not used, only stored
1461  */
1462 GpStatus WINGDIPAPI GdipSetTextureWrapMode(GpTexture *brush, GpWrapMode wrapmode)
1463 {
1464     TRACE("(%p, %d)\n", brush, wrapmode);
1465
1466     if(!brush)
1467         return InvalidParameter;
1468
1469     brush->wrap = wrapmode;
1470
1471     return Ok;
1472 }
1473
1474 GpStatus WINGDIPAPI GdipSetLineColors(GpLineGradient *brush, ARGB color1,
1475     ARGB color2)
1476 {
1477     TRACE("(%p, %x, %x)\n", brush, color1, color2);
1478
1479     if(!brush)
1480         return InvalidParameter;
1481
1482     brush->startcolor = color1;
1483     brush->endcolor   = color2;
1484
1485     return Ok;
1486 }
1487
1488 GpStatus WINGDIPAPI GdipGetLineColors(GpLineGradient *brush, ARGB *colors)
1489 {
1490     TRACE("(%p, %p)\n", brush, colors);
1491
1492     if(!brush || !colors)
1493         return InvalidParameter;
1494
1495     colors[0] = brush->startcolor;
1496     colors[1] = brush->endcolor;
1497
1498     return Ok;
1499 }
1500
1501 /******************************************************************************
1502  * GdipRotateTextureTransform [GDIPLUS.@]
1503  */
1504 GpStatus WINGDIPAPI GdipRotateTextureTransform(GpTexture* brush, REAL angle,
1505     GpMatrixOrder order)
1506 {
1507     TRACE("(%p, %.2f, %d)\n", brush, angle, order);
1508
1509     if(!brush)
1510         return InvalidParameter;
1511
1512     return GdipRotateMatrix(brush->transform, angle, order);
1513 }
1514
1515 GpStatus WINGDIPAPI GdipSetLineLinearBlend(GpLineGradient *brush, REAL focus,
1516     REAL scale)
1517 {
1518     static int calls;
1519
1520     if(!(calls++))
1521         FIXME("not implemented\n");
1522
1523     return NotImplemented;
1524 }
1525
1526 GpStatus WINGDIPAPI GdipSetLinePresetBlend(GpLineGradient *brush,
1527     GDIPCONST ARGB *blend, GDIPCONST REAL* positions, INT count)
1528 {
1529     static int calls;
1530
1531     if(!(calls++))
1532         FIXME("not implemented\n");
1533
1534     return NotImplemented;
1535 }
1536
1537 GpStatus WINGDIPAPI GdipSetLineTransform(GpLineGradient *brush,
1538     GDIPCONST GpMatrix *matrix)
1539 {
1540     static int calls;
1541
1542     if(!(calls++))
1543         FIXME("not implemented\n");
1544
1545     return NotImplemented;
1546 }
1547
1548 GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient* brush,
1549         REAL dx, REAL dy, GpMatrixOrder order)
1550 {
1551     FIXME("stub: %p %f %f %d\n", brush, dx, dy, order);
1552
1553     return NotImplemented;
1554 }
1555
1556 /******************************************************************************
1557  * GdipTranslateTextureTransform [GDIPLUS.@]
1558  */
1559 GpStatus WINGDIPAPI GdipTranslateTextureTransform(GpTexture* brush, REAL dx, REAL dy,
1560     GpMatrixOrder order)
1561 {
1562     TRACE("(%p, %.2f, %.2f, %d)\n", brush, dx, dy, order);
1563
1564     if(!brush)
1565         return InvalidParameter;
1566
1567     return GdipTranslateMatrix(brush->transform, dx, dy, order);
1568 }
1569
1570 GpStatus WINGDIPAPI GdipGetLineRect(GpLineGradient *brush, GpRectF *rect)
1571 {
1572     TRACE("(%p, %p)\n", brush, rect);
1573
1574     if(!brush || !rect)
1575         return InvalidParameter;
1576
1577     *rect = brush->rect;
1578
1579     return Ok;
1580 }
1581
1582 GpStatus WINGDIPAPI GdipGetLineRectI(GpLineGradient *brush, GpRect *rect)
1583 {
1584     GpRectF  rectF;
1585     GpStatus ret;
1586
1587     TRACE("(%p, %p)\n", brush, rect);
1588
1589     if(!rect)
1590         return InvalidParameter;
1591
1592     ret = GdipGetLineRect(brush, &rectF);
1593
1594     if(ret == Ok){
1595         rect->X      = roundr(rectF.X);
1596         rect->Y      = roundr(rectF.Y);
1597         rect->Width  = roundr(rectF.Width);
1598         rect->Height = roundr(rectF.Height);
1599     }
1600
1601     return ret;
1602 }
1603
1604 GpStatus WINGDIPAPI GdipRotateLineTransform(GpLineGradient* brush,
1605     REAL angle, GpMatrixOrder order)
1606 {
1607     static int calls;
1608
1609     if(!brush)
1610         return InvalidParameter;
1611
1612     if(!(calls++))
1613         FIXME("(%p, %.2f, %d) stub\n", brush, angle, order);
1614
1615     return NotImplemented;
1616 }