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