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