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