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