mstask: Use wide-char string literals.
[wine.git] / dlls / gdiplus / brush.c
blobd0da60df3a8ccf9ba43a34b6bf825fe2cce8a2b9
1 /*
2 * Copyright (C) 2007 Google (Evan Stade)
3 * Copyright (C) 2003-2004,2007 Novell, Inc. http://www.novell.com (Ravindra (rkumar@novell.com))
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "winuser.h"
25 #include "wingdi.h"
27 #define COBJMACROS
28 #include "objbase.h"
29 #include "olectl.h"
30 #include "ole2.h"
32 #include "gdiplus.h"
33 #include "gdiplus_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
38 /******************************************************************************
39 * GdipCloneBrush [GDIPLUS.@]
41 GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
43 TRACE("(%p, %p)\n", brush, clone);
45 if(!brush || !clone)
46 return InvalidParameter;
48 switch(brush->bt){
49 case BrushTypeSolidColor:
51 *clone = heap_alloc_zero(sizeof(GpSolidFill));
52 if (!*clone) return OutOfMemory;
53 memcpy(*clone, brush, sizeof(GpSolidFill));
54 break;
56 case BrushTypeHatchFill:
58 GpHatch *hatch = (GpHatch*)brush;
60 return GdipCreateHatchBrush(hatch->hatchstyle, hatch->forecol, hatch->backcol, (GpHatch**)clone);
62 case BrushTypePathGradient:{
63 GpPathGradient *src, *dest;
64 INT count, pcount;
65 GpStatus stat;
67 *clone = heap_alloc_zero(sizeof(GpPathGradient));
68 if (!*clone) return OutOfMemory;
70 src = (GpPathGradient*) brush;
71 dest = (GpPathGradient*) *clone;
73 memcpy(dest, src, sizeof(GpPathGradient));
75 stat = GdipClonePath(src->path, &dest->path);
77 if(stat != Ok){
78 heap_free(dest);
79 return stat;
82 dest->transform = src->transform;
84 /* blending */
85 count = src->blendcount;
86 dest->blendcount = count;
87 dest->blendfac = heap_alloc_zero(count * sizeof(REAL));
88 dest->blendpos = heap_alloc_zero(count * sizeof(REAL));
89 dest->surroundcolors = heap_alloc_zero(dest->surroundcolorcount * sizeof(ARGB));
90 pcount = dest->pblendcount;
91 if (pcount)
93 dest->pblendcolor = heap_alloc_zero(pcount * sizeof(ARGB));
94 dest->pblendpos = heap_alloc_zero(pcount * sizeof(REAL));
97 if(!dest->blendfac || !dest->blendpos || !dest->surroundcolors ||
98 (pcount && (!dest->pblendcolor || !dest->pblendpos))){
99 GdipDeletePath(dest->path);
100 heap_free(dest->blendfac);
101 heap_free(dest->blendpos);
102 heap_free(dest->surroundcolors);
103 heap_free(dest->pblendcolor);
104 heap_free(dest->pblendpos);
105 heap_free(dest);
106 return OutOfMemory;
109 memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL));
110 memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL));
111 memcpy(dest->surroundcolors, src->surroundcolors, dest->surroundcolorcount * sizeof(ARGB));
113 if (pcount)
115 memcpy(dest->pblendcolor, src->pblendcolor, pcount * sizeof(ARGB));
116 memcpy(dest->pblendpos, src->pblendpos, pcount * sizeof(REAL));
119 break;
121 case BrushTypeLinearGradient:{
122 GpLineGradient *dest, *src;
123 INT count, pcount;
125 dest = heap_alloc_zero(sizeof(GpLineGradient));
126 if(!dest) return OutOfMemory;
128 src = (GpLineGradient*)brush;
130 memcpy(dest, src, sizeof(GpLineGradient));
132 count = dest->blendcount;
133 dest->blendfac = heap_alloc_zero(count * sizeof(REAL));
134 dest->blendpos = heap_alloc_zero(count * sizeof(REAL));
135 pcount = dest->pblendcount;
136 if (pcount)
138 dest->pblendcolor = heap_alloc_zero(pcount * sizeof(ARGB));
139 dest->pblendpos = heap_alloc_zero(pcount * sizeof(REAL));
142 if (!dest->blendfac || !dest->blendpos ||
143 (pcount && (!dest->pblendcolor || !dest->pblendpos)))
145 heap_free(dest->blendfac);
146 heap_free(dest->blendpos);
147 heap_free(dest->pblendcolor);
148 heap_free(dest->pblendpos);
149 heap_free(dest);
150 return OutOfMemory;
153 dest->transform = src->transform;
155 memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL));
156 memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL));
158 if (pcount)
160 memcpy(dest->pblendcolor, src->pblendcolor, pcount * sizeof(ARGB));
161 memcpy(dest->pblendpos, src->pblendpos, pcount * sizeof(REAL));
164 *clone = &dest->brush;
165 break;
167 case BrushTypeTextureFill:
169 GpStatus stat;
170 GpTexture *texture = (GpTexture*)brush;
171 GpTexture *new_texture;
172 UINT width, height;
174 stat = GdipGetImageWidth(texture->image, &width);
175 if (stat != Ok) return stat;
176 stat = GdipGetImageHeight(texture->image, &height);
177 if (stat != Ok) return stat;
179 stat = GdipCreateTextureIA(texture->image, texture->imageattributes, 0, 0, width, height, &new_texture);
181 if (stat == Ok)
183 new_texture->transform = texture->transform;
184 *clone = &new_texture->brush;
186 else
187 *clone = NULL;
189 return stat;
191 default:
192 ERR("not implemented for brush type %d\n", brush->bt);
193 return NotImplemented;
196 TRACE("<-- %p\n", *clone);
197 return Ok;
200 /* The first 8 items per entry are bitmaps for each row of the hatch style.
201 * The 9th item of the entry is a flag indicating anti-aliasing. */
202 static const unsigned char HatchBrushes[][9] = {
203 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff }, /* HatchStyleHorizontal */
204 { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, /* HatchStyleVertical */
205 { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, TRUE }, /* HatchStyleForwardDiagonal */
206 { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, TRUE }, /* HatchStyleBackwardDiagonal */
207 { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xff }, /* HatchStyleCross */
208 { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81, TRUE }, /* HatchStyleDiagonalCross */
209 { 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80 }, /* HatchStyle05Percent */
210 { 0x00, 0x08, 0x00, 0x80, 0x00, 0x08, 0x00, 0x80 }, /* HatchStyle10Percent */
211 { 0x00, 0x22, 0x00, 0x88, 0x00, 0x22, 0x00, 0x88 }, /* HatchStyle20Percent */
212 { 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88 }, /* HatchStyle25Percent */
213 { 0x11, 0xaa, 0x44, 0xaa, 0x11, 0xaa, 0x44, 0xaa }, /* HatchStyle30Percent */
214 { 0x15, 0xaa, 0x55, 0xaa, 0x51, 0xaa, 0x55, 0xaa }, /* HatchStyle40Percent */
215 { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa }, /* HatchStyle50Percent */
216 { 0x55, 0xbb, 0x55, 0xee, 0x55, 0xbb, 0x55, 0xee }, /* HatchStyle60Percent */
217 { 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77 }, /* HatchStyle70Percent */
218 { 0xff, 0xdd, 0xff, 0x77, 0xff, 0xdd, 0xff, 0x77 }, /* HatchStyle75Percent */
219 { 0xff, 0xfe, 0xff, 0xef, 0xff, 0xfe, 0xff, 0xef }, /* HatchStyle80Percent */
220 { 0x7f, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff }, /* HatchStyle90Percent */
221 { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 }, /* HatchStyleLightDownwardDiagonal */
222 { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 }, /* HatchStyleLightUpwardDiagonal */
223 { 0x99, 0x33, 0x66, 0xcc, 0x99, 0x33, 0x66, 0xcc }, /* HatchStyleDarkDownwardDiagonal */
224 { 0x99, 0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33 }, /* HatchStyleDarkUpwardDiagonal */
225 { 0x83, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0, 0xc1 }, /* HatchStyleWideDownwardDiagonal */
226 { 0xc1, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x07, 0x83 }, /* HatchStyleWideUpwardDiagonal */
227 { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 }, /* HatchStyleLightVertical */
228 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff }, /* HatchStyleLightHorizontal */
229 { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }, /* HatchStyleNarrowVertical */
230 { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, /* HatchStyleNarrowHorizontal */
231 { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }, /* HatchStyleDarkVertical */
232 { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff }, /* HatchStyleDarkHorizontal */
233 { 0x00, 0x00, 0x11, 0x22, 0x44, 0x88, 0x00, 0x00 }, /* HatchStyleDashedDownwardDiagonal */
234 { 0x00, 0x00, 0x88, 0x44, 0x22, 0x11, 0x00, 0x00 }, /* HatchStyleDashedUpwardDiagonal */
235 { 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xf0 }, /* HatchStyleDashedHorizontal */
236 { 0x08, 0x08, 0x08, 0x08, 0x80, 0x80, 0x80, 0x80 }, /* HatchStyleDashedVertical */
237 { 0x04, 0x20, 0x01, 0x10, 0x02, 0x40, 0x08, 0x80 }, /* HatchStyleSmallConfetti */
238 { 0x8d, 0x0c, 0xc0, 0xd8, 0x1b, 0x03, 0x30, 0xb1 }, /* HatchStyleLargeConfetti */
239 { 0x18, 0x24, 0x42, 0x81, 0x18, 0x24, 0x42, 0x81 }, /* HatchStyleZigZag */
240 { 0xc0, 0x25, 0x18, 0x00, 0xc0, 0x25, 0x18, 0x00 }, /* HatchStyleWave */
241 { 0x81, 0x42, 0x24, 0x18, 0x08, 0x04, 0x02, 0x01 }, /* HatchStyleDiagonalBrick */
242 { 0x08, 0x08, 0x08, 0xff, 0x80, 0x80, 0x80, 0xff }, /* HatchStyleHorizontalBrick */
243 { 0x51, 0x22, 0x14, 0x88, 0x45, 0x22, 0x54, 0x88 }, /* HatchStyleWeave */
244 { 0xf0, 0xf0, 0xf0, 0xf0, 0x55, 0xaa, 0x55, 0xaa }, /* HatchStylePlaid */
245 { 0x80, 0x01, 0x80, 0x00, 0x10, 0x08, 0x10, 0x00 }, /* HatchStyleDivot */
246 { 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xaa }, /* HatchStyleDottedGrid */
247 { 0x00, 0x22, 0x00, 0x08, 0x00, 0x22, 0x00, 0x80 }, /* HatchStyleDottedDiamond */
248 { 0x01, 0x01, 0x02, 0x0c, 0x30, 0x48, 0x84, 0x03 }, /* HatchStyleShingle */
249 { 0x99, 0xff, 0x66, 0xff, 0x99, 0xff, 0x66, 0xff }, /* HatchStyleTrellis */
250 { 0xf8, 0xf8, 0x98, 0x77, 0x8f, 0x8f, 0x89, 0x77 }, /* HatchStyleSphere */
251 { 0x88, 0x88, 0x88, 0xff, 0x88, 0x88, 0x88, 0xff }, /* HatchStyleSmallGrid */
252 { 0x99, 0x66, 0x66, 0x99, 0x99, 0x66, 0x66, 0x99 }, /* HatchStyleSmallCheckerBoard */
253 { 0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0 }, /* HatchStyleLargeCheckerBoard */
254 { 0x01, 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82 }, /* HatchStyleOutlinedDiamond */
255 { 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10 }, /* HatchStyleSolidDiamond */
258 GpStatus get_hatch_data(GpHatchStyle hatchstyle, const unsigned char **result)
260 if (hatchstyle < ARRAY_SIZE(HatchBrushes))
262 *result = HatchBrushes[hatchstyle];
263 return Ok;
265 else
266 return NotImplemented;
269 /******************************************************************************
270 * GdipCreateHatchBrush [GDIPLUS.@]
272 GpStatus WINGDIPAPI GdipCreateHatchBrush(GpHatchStyle hatchstyle, ARGB forecol, ARGB backcol, GpHatch **brush)
274 TRACE("(%d, %d, %d, %p)\n", hatchstyle, forecol, backcol, brush);
276 if(!brush) return InvalidParameter;
278 if(hatchstyle < HatchStyleMin || hatchstyle > HatchStyleMax)
279 return InvalidParameter;
281 *brush = heap_alloc_zero(sizeof(GpHatch));
282 if (!*brush) return OutOfMemory;
284 (*brush)->brush.bt = BrushTypeHatchFill;
285 (*brush)->forecol = forecol;
286 (*brush)->backcol = backcol;
287 (*brush)->hatchstyle = hatchstyle;
288 TRACE("<-- %p\n", *brush);
290 return Ok;
293 static GpStatus create_line_brush(const GpRectF *rect, ARGB startcolor, ARGB endcolor,
294 GpWrapMode wrap, GpLineGradient **line)
296 *line = heap_alloc_zero(sizeof(GpLineGradient));
297 if(!*line) return OutOfMemory;
299 (*line)->brush.bt = BrushTypeLinearGradient;
300 (*line)->startcolor = startcolor;
301 (*line)->endcolor = endcolor;
302 (*line)->wrap = wrap;
303 (*line)->gamma = FALSE;
304 (*line)->rect = *rect;
305 (*line)->blendcount = 1;
306 (*line)->blendfac = heap_alloc_zero(sizeof(REAL));
307 (*line)->blendpos = heap_alloc_zero(sizeof(REAL));
309 if (!(*line)->blendfac || !(*line)->blendpos)
311 heap_free((*line)->blendfac);
312 heap_free((*line)->blendpos);
313 heap_free(*line);
314 *line = NULL;
315 return OutOfMemory;
318 (*line)->blendfac[0] = 1.0f;
319 (*line)->blendpos[0] = 1.0f;
321 (*line)->pblendcolor = NULL;
322 (*line)->pblendpos = NULL;
323 (*line)->pblendcount = 0;
325 GdipSetMatrixElements(&(*line)->transform, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
327 return Ok;
330 static void linegradient_init_transform(const GpPointF *startpoint, const GpPointF *endpoint, GpLineGradient *line)
332 float trans_x = line->rect.X + (line->rect.Width / 2.f);
333 float trans_y = line->rect.Y + (line->rect.Height / 2.f);
334 float dx = endpoint->X - startpoint->X;
335 float dy = endpoint->Y - startpoint->Y;
336 float t_cos, t_sin, w_ratio, h_ratio;
337 float h;
338 GpMatrix rot;
340 h = sqrtf(dx * dx + dy * dy);
342 t_cos = dx / h;
343 t_sin = dy / h;
345 w_ratio = (fabs(t_cos) * line->rect.Width + fabs(t_sin) * line->rect.Height) / line->rect.Width;
346 h_ratio = (fabs(t_sin) * line->rect.Width + fabs(t_cos) * line->rect.Height) / line->rect.Height;
348 GdipSetMatrixElements(&line->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
350 GdipSetMatrixElements(&rot, t_cos, t_sin, -1.f * t_sin, t_cos, 0, 0);
352 /* center about the origin */
353 GdipTranslateMatrix(&line->transform, -trans_x, -trans_y, MatrixOrderAppend);
355 /* scale to normalize gradient along gradient line (?) */
356 GdipScaleMatrix(&line->transform, w_ratio, h_ratio, MatrixOrderAppend);
358 /* rotate so the gradient is horizontal */
359 GdipMultiplyMatrix(&line->transform, &rot, MatrixOrderAppend);
361 /* restore original offset in new coords */
362 GdipTranslateMatrix(&line->transform, trans_x, trans_y, MatrixOrderAppend);
365 /******************************************************************************
366 * GdipCreateLineBrush [GDIPLUS.@]
368 GpStatus WINGDIPAPI GdipCreateLineBrush(GDIPCONST GpPointF* startpoint,
369 GDIPCONST GpPointF* endpoint, ARGB startcolor, ARGB endcolor,
370 GpWrapMode wrap, GpLineGradient **line)
372 GpStatus stat;
373 GpRectF rect;
375 TRACE("(%s, %s, %x, %x, %d, %p)\n", debugstr_pointf(startpoint),
376 debugstr_pointf(endpoint), startcolor, endcolor, wrap, line);
378 if(!line || !startpoint || !endpoint || wrap == WrapModeClamp)
379 return InvalidParameter;
381 if (startpoint->X == endpoint->X && startpoint->Y == endpoint->Y)
382 return OutOfMemory;
384 rect.X = startpoint->X < endpoint->X ? startpoint->X : endpoint->X;
385 rect.Y = startpoint->Y < endpoint->Y ? startpoint->Y : endpoint->Y;
386 rect.Width = fabs(startpoint->X - endpoint->X);
387 rect.Height = fabs(startpoint->Y - endpoint->Y);
389 if (rect.Width == 0.0f)
391 rect.X -= rect.Height / 2.0f;
392 rect.Width = rect.Height;
394 else if (rect.Height == 0.0f)
396 rect.Y -= rect.Width / 2.0f;
397 rect.Height = rect.Width;
400 stat = create_line_brush(&rect, startcolor, endcolor, wrap, line);
401 if (stat != Ok)
402 return stat;
404 linegradient_init_transform(startpoint, endpoint, *line);
406 TRACE("<-- %p\n", *line);
408 return Ok;
411 GpStatus WINGDIPAPI GdipCreateLineBrushI(GDIPCONST GpPoint* startpoint,
412 GDIPCONST GpPoint* endpoint, ARGB startcolor, ARGB endcolor,
413 GpWrapMode wrap, GpLineGradient **line)
415 GpPointF stF;
416 GpPointF endF;
418 TRACE("(%p, %p, %x, %x, %d, %p)\n", startpoint, endpoint,
419 startcolor, endcolor, wrap, line);
421 if(!startpoint || !endpoint)
422 return InvalidParameter;
424 stF.X = (REAL)startpoint->X;
425 stF.Y = (REAL)startpoint->Y;
426 endF.X = (REAL)endpoint->X;
427 endF.Y = (REAL)endpoint->Y;
429 return GdipCreateLineBrush(&stF, &endF, startcolor, endcolor, wrap, line);
432 GpStatus WINGDIPAPI GdipCreateLineBrushFromRect(GDIPCONST GpRectF* rect,
433 ARGB startcolor, ARGB endcolor, LinearGradientMode mode, GpWrapMode wrap,
434 GpLineGradient **line)
436 float angle;
438 TRACE("(%s, %x, %x, %d, %d, %p)\n", debugstr_rectf(rect), startcolor, endcolor, mode,
439 wrap, line);
441 if(!line || !rect)
442 return InvalidParameter;
444 switch (mode)
446 case LinearGradientModeHorizontal:
447 angle = 0.0f;
448 break;
449 case LinearGradientModeVertical:
450 angle = 90.0f;
451 break;
452 case LinearGradientModeForwardDiagonal:
453 angle = 45.0f;
454 break;
455 case LinearGradientModeBackwardDiagonal:
456 angle = 135.0f;
457 break;
458 default:
459 return InvalidParameter;
462 return GdipCreateLineBrushFromRectWithAngle(rect, startcolor, endcolor, angle, TRUE, wrap, line);
465 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectI(GDIPCONST GpRect* rect,
466 ARGB startcolor, ARGB endcolor, LinearGradientMode mode, GpWrapMode wrap,
467 GpLineGradient **line)
469 GpRectF rectF;
471 TRACE("(%p, %x, %x, %d, %d, %p)\n", rect, startcolor, endcolor, mode,
472 wrap, line);
474 rectF.X = (REAL) rect->X;
475 rectF.Y = (REAL) rect->Y;
476 rectF.Width = (REAL) rect->Width;
477 rectF.Height = (REAL) rect->Height;
479 return GdipCreateLineBrushFromRect(&rectF, startcolor, endcolor, mode, wrap, line);
482 /******************************************************************************
483 * GdipCreateLineBrushFromRectWithAngle [GDIPLUS.@]
485 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF* rect,
486 ARGB startcolor, ARGB endcolor, REAL angle, BOOL isAngleScalable, GpWrapMode wrap,
487 GpLineGradient **line)
489 GpStatus stat;
490 REAL exofs, eyofs, far_x, far_y;
491 REAL sin_angle, cos_angle, sin_cos_angle;
492 GpPointF start, end;
494 TRACE("(%s, %x, %x, %.2f, %d, %d, %p)\n", debugstr_rectf(rect), startcolor, endcolor, angle, isAngleScalable,
495 wrap, line);
497 if (!rect || !line || wrap == WrapModeClamp)
498 return InvalidParameter;
500 if (!rect->Width || !rect->Height)
501 return OutOfMemory;
503 angle = fmodf(angle, 360);
504 if (angle < 0)
505 angle += 360;
507 if (isAngleScalable)
509 float add_angle = 0;
511 while(angle >= 90) {
512 angle -= 180;
513 add_angle += M_PI;
516 if (angle != 90 && angle != -90)
517 angle = atan((rect->Width / rect->Height) * tan(deg2rad(angle)));
518 else
519 angle = deg2rad(angle);
520 angle += add_angle;
522 else
524 angle = deg2rad(angle);
527 sin_angle = sinf(angle);
528 cos_angle = cosf(angle);
529 sin_cos_angle = sin_angle * cos_angle;
531 far_x = rect->X + rect->Width;
532 far_y = rect->Y + rect->Height;
534 if (angle == 0.0f)
536 start.X = min(rect->X, far_x);
537 start.Y = rect->Y;
538 end.X = max(rect->X, far_x);
539 end.Y = rect->Y;
541 else if (sin_cos_angle >= 0)
543 start.X = min(rect->X, far_x);
544 start.Y = min(rect->Y, far_y);
545 end.X = max(rect->X, far_x);
546 end.Y = max(rect->Y, far_y);
548 else
550 start.X = max(rect->X, far_x);
551 start.Y = min(rect->Y, far_y);
552 end.X = min(rect->X, far_x);
553 end.Y = max(rect->Y, far_y);
556 stat = create_line_brush(rect, startcolor, endcolor, wrap, line);
557 if (stat != Ok || angle == 0.0f)
558 return stat;
560 if (sin_cos_angle >= 0)
562 exofs = rect->Height * sin_cos_angle + rect->Width * cos_angle * cos_angle;
563 eyofs = rect->Height * sin_angle * sin_angle + rect->Width * sin_cos_angle;
565 else
567 exofs = rect->Width * sin_angle * sin_angle + rect->Height * sin_cos_angle;
568 eyofs = -rect->Width * sin_cos_angle + rect->Height * sin_angle * sin_angle;
571 if (sin_angle >= 0)
573 end.X = rect->X + exofs;
574 end.Y = rect->Y + eyofs;
576 else
578 end.X = start.X;
579 end.Y = start.Y;
580 start.X = rect->X + exofs;
581 start.Y = rect->Y + eyofs;
584 linegradient_init_transform(&start, &end, *line);
586 return stat;
589 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngleI(GDIPCONST GpRect* rect,
590 ARGB startcolor, ARGB endcolor, REAL angle, BOOL isAngleScalable, GpWrapMode wrap,
591 GpLineGradient **line)
593 TRACE("(%p, %x, %x, %.2f, %d, %d, %p)\n", rect, startcolor, endcolor, angle, isAngleScalable,
594 wrap, line);
596 return GdipCreateLineBrushFromRectI(rect, startcolor, endcolor, LinearGradientModeForwardDiagonal,
597 wrap, line);
600 static GpStatus create_path_gradient(GpPath *path, ARGB centercolor, GpPathGradient **grad)
602 INT i;
603 REAL sum_x = 0, sum_y = 0;
605 if(!path || !grad)
606 return InvalidParameter;
608 if (path->pathdata.Count < 2)
609 return OutOfMemory;
611 *grad = heap_alloc_zero(sizeof(GpPathGradient));
612 if (!*grad)
614 return OutOfMemory;
617 GdipSetMatrixElements(&(*grad)->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
619 (*grad)->blendfac = heap_alloc_zero(sizeof(REAL));
620 (*grad)->blendpos = heap_alloc_zero(sizeof(REAL));
621 (*grad)->surroundcolors = heap_alloc_zero(sizeof(ARGB));
622 if(!(*grad)->blendfac || !(*grad)->blendpos || !(*grad)->surroundcolors){
623 heap_free((*grad)->blendfac);
624 heap_free((*grad)->blendpos);
625 heap_free((*grad)->surroundcolors);
626 heap_free(*grad);
627 *grad = NULL;
628 return OutOfMemory;
630 (*grad)->blendfac[0] = 1.0;
631 (*grad)->blendpos[0] = 1.0;
632 (*grad)->blendcount = 1;
634 (*grad)->path = path;
636 (*grad)->brush.bt = BrushTypePathGradient;
637 (*grad)->centercolor = centercolor;
638 (*grad)->wrap = WrapModeClamp;
639 (*grad)->gamma = FALSE;
640 for (i=0; i<path->pathdata.Count; i++)
642 sum_x += path->pathdata.Points[i].X;
643 sum_y += path->pathdata.Points[i].Y;
645 (*grad)->center.X = sum_x / path->pathdata.Count;
646 (*grad)->center.Y = sum_y / path->pathdata.Count;
648 (*grad)->focus.X = 0.0;
649 (*grad)->focus.Y = 0.0;
650 (*grad)->surroundcolors[0] = 0xffffffff;
651 (*grad)->surroundcolorcount = 1;
653 TRACE("<-- %p\n", *grad);
655 return Ok;
658 GpStatus WINGDIPAPI GdipCreatePathGradient(GDIPCONST GpPointF* points,
659 INT count, GpWrapMode wrap, GpPathGradient **grad)
661 GpStatus stat;
662 GpPath *path;
664 TRACE("(%p, %d, %d, %p)\n", points, count, wrap, grad);
666 if(!grad)
667 return InvalidParameter;
669 if(!points || count <= 0)
670 return OutOfMemory;
672 stat = GdipCreatePath(FillModeAlternate, &path);
674 if (stat == Ok)
676 stat = GdipAddPathLine2(path, points, count);
678 if (stat == Ok)
679 stat = create_path_gradient(path, 0xff000000, grad);
681 if (stat != Ok)
682 GdipDeletePath(path);
685 if (stat == Ok)
686 (*grad)->wrap = wrap;
688 return stat;
691 GpStatus WINGDIPAPI GdipCreatePathGradientI(GDIPCONST GpPoint* points,
692 INT count, GpWrapMode wrap, GpPathGradient **grad)
694 GpStatus stat;
695 GpPath *path;
697 TRACE("(%p, %d, %d, %p)\n", points, count, wrap, grad);
699 if(!grad)
700 return InvalidParameter;
702 if(!points || count <= 0)
703 return OutOfMemory;
705 stat = GdipCreatePath(FillModeAlternate, &path);
707 if (stat == Ok)
709 stat = GdipAddPathLine2I(path, points, count);
711 if (stat == Ok)
712 stat = create_path_gradient(path, 0xff000000, grad);
714 if (stat != Ok)
715 GdipDeletePath(path);
718 if (stat == Ok)
719 (*grad)->wrap = wrap;
721 return stat;
724 /******************************************************************************
725 * GdipCreatePathGradientFromPath [GDIPLUS.@]
727 GpStatus WINGDIPAPI GdipCreatePathGradientFromPath(GDIPCONST GpPath* path,
728 GpPathGradient **grad)
730 GpStatus stat;
731 GpPath *new_path;
733 TRACE("(%p, %p)\n", path, grad);
735 if(!grad)
736 return InvalidParameter;
738 if (!path)
739 return OutOfMemory;
741 stat = GdipClonePath((GpPath*)path, &new_path);
743 if (stat == Ok)
745 stat = create_path_gradient(new_path, 0xffffffff, grad);
747 if (stat != Ok)
748 GdipDeletePath(new_path);
751 return stat;
754 /******************************************************************************
755 * GdipCreateSolidFill [GDIPLUS.@]
757 GpStatus WINGDIPAPI GdipCreateSolidFill(ARGB color, GpSolidFill **sf)
759 TRACE("(%x, %p)\n", color, sf);
761 if(!sf) return InvalidParameter;
763 *sf = heap_alloc_zero(sizeof(GpSolidFill));
764 if (!*sf) return OutOfMemory;
766 (*sf)->brush.bt = BrushTypeSolidColor;
767 (*sf)->color = color;
769 TRACE("<-- %p\n", *sf);
771 return Ok;
774 /******************************************************************************
775 * GdipCreateTexture [GDIPLUS.@]
777 * PARAMS
778 * image [I] image to use
779 * wrapmode [I] optional
780 * texture [O] pointer to the resulting texturebrush
782 * RETURNS
783 * SUCCESS: Ok
784 * FAILURE: element of GpStatus
786 GpStatus WINGDIPAPI GdipCreateTexture(GpImage *image, GpWrapMode wrapmode,
787 GpTexture **texture)
789 UINT width, height;
790 GpImageAttributes *attributes;
791 GpStatus stat;
793 TRACE("%p, %d %p\n", image, wrapmode, texture);
795 if (!(image && texture))
796 return InvalidParameter;
798 stat = GdipGetImageWidth(image, &width);
799 if (stat != Ok) return stat;
800 stat = GdipGetImageHeight(image, &height);
801 if (stat != Ok) return stat;
803 stat = GdipCreateImageAttributes(&attributes);
805 if (stat == Ok)
807 attributes->wrap = wrapmode;
809 stat = GdipCreateTextureIA(image, attributes, 0, 0, width, height,
810 texture);
812 GdipDisposeImageAttributes(attributes);
815 return stat;
818 /******************************************************************************
819 * GdipCreateTexture2 [GDIPLUS.@]
821 GpStatus WINGDIPAPI GdipCreateTexture2(GpImage *image, GpWrapMode wrapmode,
822 REAL x, REAL y, REAL width, REAL height, GpTexture **texture)
824 GpImageAttributes *attributes;
825 GpStatus stat;
827 TRACE("%p %d %f %f %f %f %p\n", image, wrapmode,
828 x, y, width, height, texture);
830 stat = GdipCreateImageAttributes(&attributes);
832 if (stat == Ok)
834 attributes->wrap = wrapmode;
836 stat = GdipCreateTextureIA(image, attributes, x, y, width, height,
837 texture);
839 GdipDisposeImageAttributes(attributes);
842 return stat;
845 /******************************************************************************
846 * GdipCreateTextureIA [GDIPLUS.@]
848 GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image,
849 GDIPCONST GpImageAttributes *imageattr, REAL x, REAL y, REAL width,
850 REAL height, GpTexture **texture)
852 GpStatus status;
853 GpImage *new_image=NULL;
855 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %p)\n", image, imageattr, x, y, width, height,
856 texture);
858 if(!image || !texture || x < 0.0 || y < 0.0 || width < 0.0 || height < 0.0)
859 return InvalidParameter;
861 *texture = NULL;
863 if(image->type != ImageTypeBitmap){
864 FIXME("not implemented for image type %d\n", image->type);
865 return NotImplemented;
868 status = GdipCloneBitmapArea(x, y, width, height, PixelFormatDontCare, (GpBitmap*)image, (GpBitmap**)&new_image);
869 if (status != Ok)
870 return status;
872 *texture = heap_alloc_zero(sizeof(GpTexture));
873 if (!*texture){
874 status = OutOfMemory;
875 goto exit;
878 GdipSetMatrixElements(&(*texture)->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
880 if (imageattr)
882 status = GdipCloneImageAttributes(imageattr, &(*texture)->imageattributes);
884 else
886 status = GdipCreateImageAttributes(&(*texture)->imageattributes);
887 if (status == Ok)
888 (*texture)->imageattributes->wrap = WrapModeTile;
890 if (status == Ok)
892 (*texture)->brush.bt = BrushTypeTextureFill;
893 (*texture)->image = new_image;
896 exit:
897 if (status == Ok)
899 TRACE("<-- %p\n", *texture);
901 else
903 if (*texture)
905 GdipDisposeImageAttributes((*texture)->imageattributes);
906 heap_free(*texture);
907 *texture = NULL;
909 GdipDisposeImage(new_image);
910 TRACE("<-- error %u\n", status);
913 return status;
916 /******************************************************************************
917 * GdipCreateTextureIAI [GDIPLUS.@]
919 GpStatus WINGDIPAPI GdipCreateTextureIAI(GpImage *image, GDIPCONST GpImageAttributes *imageattr,
920 INT x, INT y, INT width, INT height, GpTexture **texture)
922 TRACE("(%p, %p, %d, %d, %d, %d, %p)\n", image, imageattr, x, y, width, height,
923 texture);
925 return GdipCreateTextureIA(image,imageattr,(REAL)x,(REAL)y,(REAL)width,(REAL)height,texture);
928 GpStatus WINGDIPAPI GdipCreateTexture2I(GpImage *image, GpWrapMode wrapmode,
929 INT x, INT y, INT width, INT height, GpTexture **texture)
931 GpImageAttributes *imageattr;
932 GpStatus stat;
934 TRACE("%p %d %d %d %d %d %p\n", image, wrapmode, x, y, width, height,
935 texture);
937 stat = GdipCreateImageAttributes(&imageattr);
939 if (stat == Ok)
941 imageattr->wrap = wrapmode;
943 stat = GdipCreateTextureIA(image, imageattr, x, y, width, height, texture);
944 GdipDisposeImageAttributes(imageattr);
947 return stat;
950 GpStatus WINGDIPAPI GdipGetBrushType(GpBrush *brush, GpBrushType *type)
952 TRACE("(%p, %p)\n", brush, type);
954 if(!brush || !type) return InvalidParameter;
956 *type = brush->bt;
958 return Ok;
961 GpStatus WINGDIPAPI GdipGetHatchBackgroundColor(GpHatch *brush, ARGB *backcol)
963 TRACE("(%p, %p)\n", brush, backcol);
965 if(!brush || !backcol) return InvalidParameter;
967 *backcol = brush->backcol;
969 return Ok;
972 GpStatus WINGDIPAPI GdipGetHatchForegroundColor(GpHatch *brush, ARGB *forecol)
974 TRACE("(%p, %p)\n", brush, forecol);
976 if(!brush || !forecol) return InvalidParameter;
978 *forecol = brush->forecol;
980 return Ok;
983 GpStatus WINGDIPAPI GdipGetHatchStyle(GpHatch *brush, GpHatchStyle *hatchstyle)
985 TRACE("(%p, %p)\n", brush, hatchstyle);
987 if(!brush || !hatchstyle) return InvalidParameter;
989 *hatchstyle = brush->hatchstyle;
991 return Ok;
994 GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush)
996 TRACE("(%p)\n", brush);
998 if(!brush) return InvalidParameter;
1000 switch(brush->bt)
1002 case BrushTypePathGradient:
1003 GdipDeletePath(((GpPathGradient*) brush)->path);
1004 heap_free(((GpPathGradient*) brush)->blendfac);
1005 heap_free(((GpPathGradient*) brush)->blendpos);
1006 heap_free(((GpPathGradient*) brush)->surroundcolors);
1007 heap_free(((GpPathGradient*) brush)->pblendcolor);
1008 heap_free(((GpPathGradient*) brush)->pblendpos);
1009 break;
1010 case BrushTypeLinearGradient:
1011 heap_free(((GpLineGradient*)brush)->blendfac);
1012 heap_free(((GpLineGradient*)brush)->blendpos);
1013 heap_free(((GpLineGradient*)brush)->pblendcolor);
1014 heap_free(((GpLineGradient*)brush)->pblendpos);
1015 break;
1016 case BrushTypeTextureFill:
1017 GdipDisposeImage(((GpTexture*)brush)->image);
1018 GdipDisposeImageAttributes(((GpTexture*)brush)->imageattributes);
1019 heap_free(((GpTexture*)brush)->bitmap_bits);
1020 break;
1021 default:
1022 break;
1025 heap_free(brush);
1027 return Ok;
1030 GpStatus WINGDIPAPI GdipGetLineGammaCorrection(GpLineGradient *line,
1031 BOOL *usinggamma)
1033 TRACE("(%p, %p)\n", line, usinggamma);
1035 if(!line || !usinggamma)
1036 return InvalidParameter;
1038 *usinggamma = line->gamma;
1040 return Ok;
1043 GpStatus WINGDIPAPI GdipGetLineWrapMode(GpLineGradient *brush, GpWrapMode *wrapmode)
1045 TRACE("(%p, %p)\n", brush, wrapmode);
1047 if(!brush || !wrapmode || brush->brush.bt != BrushTypeLinearGradient)
1048 return InvalidParameter;
1050 *wrapmode = brush->wrap;
1052 return Ok;
1055 GpStatus WINGDIPAPI GdipGetPathGradientBlend(GpPathGradient *brush, REAL *blend,
1056 REAL *positions, INT count)
1058 TRACE("(%p, %p, %p, %d)\n", brush, blend, positions, count);
1060 if(!brush || !blend || !positions || count <= 0 || brush->brush.bt != BrushTypePathGradient)
1061 return InvalidParameter;
1063 if(count < brush->blendcount)
1064 return InsufficientBuffer;
1066 memcpy(blend, brush->blendfac, count*sizeof(REAL));
1067 if(brush->blendcount > 1){
1068 memcpy(positions, brush->blendpos, count*sizeof(REAL));
1071 return Ok;
1074 GpStatus WINGDIPAPI GdipGetPathGradientBlendCount(GpPathGradient *brush, INT *count)
1076 TRACE("(%p, %p)\n", brush, count);
1078 if(!brush || !count || brush->brush.bt != BrushTypePathGradient)
1079 return InvalidParameter;
1081 *count = brush->blendcount;
1083 return Ok;
1086 GpStatus WINGDIPAPI GdipGetPathGradientCenterPoint(GpPathGradient *grad,
1087 GpPointF *point)
1089 TRACE("(%p, %p)\n", grad, point);
1091 if(!grad || !point || grad->brush.bt != BrushTypePathGradient)
1092 return InvalidParameter;
1094 point->X = grad->center.X;
1095 point->Y = grad->center.Y;
1097 return Ok;
1100 GpStatus WINGDIPAPI GdipGetPathGradientCenterPointI(GpPathGradient *grad,
1101 GpPoint *point)
1103 GpStatus ret;
1104 GpPointF ptf;
1106 TRACE("(%p, %p)\n", grad, point);
1108 if(!point)
1109 return InvalidParameter;
1111 ret = GdipGetPathGradientCenterPoint(grad,&ptf);
1113 if(ret == Ok){
1114 point->X = gdip_round(ptf.X);
1115 point->Y = gdip_round(ptf.Y);
1118 return ret;
1121 GpStatus WINGDIPAPI GdipGetPathGradientCenterColor(GpPathGradient *grad,
1122 ARGB *colors)
1124 TRACE("(%p,%p)\n", grad, colors);
1126 if (!grad || !colors || grad->brush.bt != BrushTypePathGradient)
1127 return InvalidParameter;
1129 *colors = grad->centercolor;
1131 return Ok;
1134 GpStatus WINGDIPAPI GdipGetPathGradientFocusScales(GpPathGradient *grad,
1135 REAL *x, REAL *y)
1137 TRACE("(%p, %p, %p)\n", grad, x, y);
1139 if(!grad || !x || !y || grad->brush.bt != BrushTypePathGradient)
1140 return InvalidParameter;
1142 *x = grad->focus.X;
1143 *y = grad->focus.Y;
1145 return Ok;
1148 GpStatus WINGDIPAPI GdipGetPathGradientGammaCorrection(GpPathGradient *grad,
1149 BOOL *gamma)
1151 TRACE("(%p, %p)\n", grad, gamma);
1153 if(!grad || !gamma || grad->brush.bt != BrushTypePathGradient)
1154 return InvalidParameter;
1156 *gamma = grad->gamma;
1158 return Ok;
1161 GpStatus WINGDIPAPI GdipGetPathGradientPath(GpPathGradient *grad, GpPath *path)
1163 static int calls;
1165 TRACE("(%p, %p)\n", grad, path);
1167 if (!(calls++))
1168 FIXME("not implemented\n");
1170 return NotImplemented;
1173 GpStatus WINGDIPAPI GdipGetPathGradientPointCount(GpPathGradient *grad,
1174 INT *count)
1176 TRACE("(%p, %p)\n", grad, count);
1178 if(!grad || !count || grad->brush.bt != BrushTypePathGradient)
1179 return InvalidParameter;
1181 *count = grad->path->pathdata.Count;
1183 return Ok;
1186 GpStatus WINGDIPAPI GdipGetPathGradientRect(GpPathGradient *brush, GpRectF *rect)
1188 GpStatus stat;
1190 TRACE("(%p, %p)\n", brush, rect);
1192 if(!brush || !rect || brush->brush.bt != BrushTypePathGradient)
1193 return InvalidParameter;
1195 stat = GdipGetPathWorldBounds(brush->path, rect, NULL, NULL);
1197 return stat;
1200 GpStatus WINGDIPAPI GdipGetPathGradientRectI(GpPathGradient *brush, GpRect *rect)
1202 GpRectF rectf;
1203 GpStatus stat;
1205 TRACE("(%p, %p)\n", brush, rect);
1207 if(!brush || !rect)
1208 return InvalidParameter;
1210 stat = GdipGetPathGradientRect(brush, &rectf);
1211 if(stat != Ok) return stat;
1213 rect->X = gdip_round(rectf.X);
1214 rect->Y = gdip_round(rectf.Y);
1215 rect->Width = gdip_round(rectf.Width);
1216 rect->Height = gdip_round(rectf.Height);
1218 return Ok;
1221 GpStatus WINGDIPAPI GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
1222 *grad, ARGB *argb, INT *count)
1224 INT i;
1226 TRACE("(%p,%p,%p)\n", grad, argb, count);
1228 if(!grad || !argb || !count || (*count < grad->path->pathdata.Count) || grad->brush.bt != BrushTypePathGradient)
1229 return InvalidParameter;
1231 for (i=0; i<grad->path->pathdata.Count; i++)
1233 if (i < grad->surroundcolorcount)
1234 argb[i] = grad->surroundcolors[i];
1235 else
1236 argb[i] = grad->surroundcolors[grad->surroundcolorcount-1];
1239 *count = grad->surroundcolorcount;
1241 return Ok;
1244 GpStatus WINGDIPAPI GdipGetPathGradientSurroundColorCount(GpPathGradient *brush, INT *count)
1246 TRACE("(%p, %p)\n", brush, count);
1248 if (!brush || !count || brush->brush.bt != BrushTypePathGradient)
1249 return InvalidParameter;
1251 /* Yes, this actually returns the number of points in the path (which is the
1252 * required size of a buffer to get the surround colors), rather than the
1253 * number of surround colors. The real count is returned when getting the
1254 * colors. */
1255 *count = brush->path->pathdata.Count;
1257 return Ok;
1260 GpStatus WINGDIPAPI GdipGetPathGradientWrapMode(GpPathGradient *brush,
1261 GpWrapMode *wrapmode)
1263 TRACE("(%p, %p)\n", brush, wrapmode);
1265 if(!brush || !wrapmode || brush->brush.bt != BrushTypePathGradient)
1266 return InvalidParameter;
1268 *wrapmode = brush->wrap;
1270 return Ok;
1273 GpStatus WINGDIPAPI GdipGetSolidFillColor(GpSolidFill *sf, ARGB *argb)
1275 TRACE("(%p, %p)\n", sf, argb);
1277 if(!sf || !argb)
1278 return InvalidParameter;
1280 *argb = sf->color;
1282 return Ok;
1285 /******************************************************************************
1286 * GdipGetTextureImage [GDIPLUS.@]
1288 GpStatus WINGDIPAPI GdipGetTextureImage(GpTexture *brush, GpImage **image)
1290 TRACE("(%p, %p)\n", brush, image);
1292 if(!brush || !image)
1293 return InvalidParameter;
1295 return GdipCloneImage(brush->image, image);
1298 /******************************************************************************
1299 * GdipGetTextureTransform [GDIPLUS.@]
1301 GpStatus WINGDIPAPI GdipGetTextureTransform(GpTexture *brush, GpMatrix *matrix)
1303 TRACE("(%p, %p)\n", brush, matrix);
1305 if(!brush || !matrix)
1306 return InvalidParameter;
1308 *matrix = brush->transform;
1310 return Ok;
1313 /******************************************************************************
1314 * GdipGetTextureWrapMode [GDIPLUS.@]
1316 GpStatus WINGDIPAPI GdipGetTextureWrapMode(GpTexture *brush, GpWrapMode *wrapmode)
1318 TRACE("(%p, %p)\n", brush, wrapmode);
1320 if(!brush || !wrapmode)
1321 return InvalidParameter;
1323 *wrapmode = brush->imageattributes->wrap;
1325 return Ok;
1328 /******************************************************************************
1329 * GdipMultiplyTextureTransform [GDIPLUS.@]
1331 GpStatus WINGDIPAPI GdipMultiplyTextureTransform(GpTexture* brush,
1332 GDIPCONST GpMatrix *matrix, GpMatrixOrder order)
1334 TRACE("(%p, %p, %d)\n", brush, matrix, order);
1336 if(!brush || !matrix)
1337 return InvalidParameter;
1339 return GdipMultiplyMatrix(&brush->transform, matrix, order);
1342 /******************************************************************************
1343 * GdipResetTextureTransform [GDIPLUS.@]
1345 GpStatus WINGDIPAPI GdipResetTextureTransform(GpTexture* brush)
1347 TRACE("(%p)\n", brush);
1349 if(!brush)
1350 return InvalidParameter;
1352 return GdipSetMatrixElements(&brush->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1355 /******************************************************************************
1356 * GdipScaleTextureTransform [GDIPLUS.@]
1358 GpStatus WINGDIPAPI GdipScaleTextureTransform(GpTexture* brush,
1359 REAL sx, REAL sy, GpMatrixOrder order)
1361 TRACE("(%p, %.2f, %.2f, %d)\n", brush, sx, sy, order);
1363 if(!brush)
1364 return InvalidParameter;
1366 return GdipScaleMatrix(&brush->transform, sx, sy, order);
1369 GpStatus WINGDIPAPI GdipSetLineBlend(GpLineGradient *brush,
1370 GDIPCONST REAL *factors, GDIPCONST REAL* positions, INT count)
1372 REAL *new_blendfac, *new_blendpos;
1374 TRACE("(%p, %p, %p, %i)\n", brush, factors, positions, count);
1376 if(!brush || !factors || !positions || count <= 0 || brush->brush.bt != BrushTypeLinearGradient ||
1377 (count >= 2 && (positions[0] != 0.0f || positions[count-1] != 1.0f)))
1378 return InvalidParameter;
1380 new_blendfac = heap_alloc_zero(count * sizeof(REAL));
1381 new_blendpos = heap_alloc_zero(count * sizeof(REAL));
1383 if (!new_blendfac || !new_blendpos)
1385 heap_free(new_blendfac);
1386 heap_free(new_blendpos);
1387 return OutOfMemory;
1390 memcpy(new_blendfac, factors, count * sizeof(REAL));
1391 memcpy(new_blendpos, positions, count * sizeof(REAL));
1393 heap_free(brush->blendfac);
1394 heap_free(brush->blendpos);
1396 brush->blendcount = count;
1397 brush->blendfac = new_blendfac;
1398 brush->blendpos = new_blendpos;
1400 return Ok;
1403 GpStatus WINGDIPAPI GdipGetLineBlend(GpLineGradient *brush, REAL *factors,
1404 REAL *positions, INT count)
1406 TRACE("(%p, %p, %p, %i)\n", brush, factors, positions, count);
1408 if (!brush || !factors || !positions || count <= 0 || brush->brush.bt != BrushTypeLinearGradient)
1409 return InvalidParameter;
1411 if (count < brush->blendcount)
1412 return InsufficientBuffer;
1414 memcpy(factors, brush->blendfac, brush->blendcount * sizeof(REAL));
1415 memcpy(positions, brush->blendpos, brush->blendcount * sizeof(REAL));
1417 return Ok;
1420 GpStatus WINGDIPAPI GdipGetLineBlendCount(GpLineGradient *brush, INT *count)
1422 TRACE("(%p, %p)\n", brush, count);
1424 if (!brush || !count || brush->brush.bt != BrushTypeLinearGradient)
1425 return InvalidParameter;
1427 *count = brush->blendcount;
1429 return Ok;
1432 GpStatus WINGDIPAPI GdipSetLineGammaCorrection(GpLineGradient *line,
1433 BOOL usegamma)
1435 TRACE("(%p, %d)\n", line, usegamma);
1437 if(!line || line->brush.bt != BrushTypeLinearGradient)
1438 return InvalidParameter;
1440 line->gamma = usegamma;
1442 return Ok;
1445 GpStatus WINGDIPAPI GdipSetLineSigmaBlend(GpLineGradient *line, REAL focus,
1446 REAL scale)
1448 REAL factors[33];
1449 REAL positions[33];
1450 int num_points = 0;
1451 int i;
1452 const int precision = 16;
1453 REAL erf_range; /* we use values erf(-erf_range) through erf(+erf_range) */
1454 REAL min_erf;
1455 REAL scale_erf;
1457 TRACE("(%p, %0.2f, %0.2f)\n", line, focus, scale);
1459 if(!line || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0 || line->brush.bt != BrushTypeLinearGradient)
1460 return InvalidParameter;
1462 /* we want 2 standard deviations */
1463 erf_range = 2.0 / sqrt(2);
1465 /* calculate the constants we need to normalize the error function to be
1466 between 0.0 and scale over the range we need */
1467 min_erf = erf(-erf_range);
1468 scale_erf = scale / (-2.0 * min_erf);
1470 if (focus != 0.0)
1472 positions[0] = 0.0;
1473 factors[0] = 0.0;
1474 for (i=1; i<precision; i++)
1476 positions[i] = focus * i / precision;
1477 factors[i] = scale_erf * (erf(2 * erf_range * i / precision - erf_range) - min_erf);
1479 num_points += precision;
1482 positions[num_points] = focus;
1483 factors[num_points] = scale;
1484 num_points += 1;
1486 if (focus != 1.0)
1488 for (i=1; i<precision; i++)
1490 positions[i+num_points-1] = (focus + ((1.0-focus) * i / precision));
1491 factors[i+num_points-1] = scale_erf * (erf(erf_range - 2 * erf_range * i / precision) - min_erf);
1493 num_points += precision;
1494 positions[num_points-1] = 1.0;
1495 factors[num_points-1] = 0.0;
1498 return GdipSetLineBlend(line, factors, positions, num_points);
1501 GpStatus WINGDIPAPI GdipSetLineWrapMode(GpLineGradient *line,
1502 GpWrapMode wrap)
1504 TRACE("(%p, %d)\n", line, wrap);
1506 if(!line || wrap == WrapModeClamp || line->brush.bt != BrushTypeLinearGradient)
1507 return InvalidParameter;
1509 line->wrap = wrap;
1511 return Ok;
1514 GpStatus WINGDIPAPI GdipSetPathGradientBlend(GpPathGradient *brush, GDIPCONST REAL *blend,
1515 GDIPCONST REAL *pos, INT count)
1517 REAL *new_blendfac, *new_blendpos;
1519 TRACE("(%p,%p,%p,%i)\n", brush, blend, pos, count);
1521 if(!brush || !blend || !pos || count <= 0 || brush->brush.bt != BrushTypePathGradient ||
1522 (count >= 2 && (pos[0] != 0.0f || pos[count-1] != 1.0f)))
1523 return InvalidParameter;
1525 new_blendfac = heap_alloc_zero(count * sizeof(REAL));
1526 new_blendpos = heap_alloc_zero(count * sizeof(REAL));
1528 if (!new_blendfac || !new_blendpos)
1530 heap_free(new_blendfac);
1531 heap_free(new_blendpos);
1532 return OutOfMemory;
1535 memcpy(new_blendfac, blend, count * sizeof(REAL));
1536 memcpy(new_blendpos, pos, count * sizeof(REAL));
1538 heap_free(brush->blendfac);
1539 heap_free(brush->blendpos);
1541 brush->blendcount = count;
1542 brush->blendfac = new_blendfac;
1543 brush->blendpos = new_blendpos;
1545 return Ok;
1548 GpStatus WINGDIPAPI GdipSetPathGradientLinearBlend(GpPathGradient *brush,
1549 REAL focus, REAL scale)
1551 REAL factors[3];
1552 REAL positions[3];
1553 int num_points = 0;
1555 TRACE("(%p,%0.2f,%0.2f)\n", brush, focus, scale);
1557 if (!brush || brush->brush.bt != BrushTypePathGradient)
1558 return InvalidParameter;
1560 if (focus != 0.0)
1562 factors[num_points] = 0.0;
1563 positions[num_points] = 0.0;
1564 num_points++;
1567 factors[num_points] = scale;
1568 positions[num_points] = focus;
1569 num_points++;
1571 if (focus != 1.0)
1573 factors[num_points] = 0.0;
1574 positions[num_points] = 1.0;
1575 num_points++;
1578 return GdipSetPathGradientBlend(brush, factors, positions, num_points);
1581 GpStatus WINGDIPAPI GdipSetPathGradientPresetBlend(GpPathGradient *brush,
1582 GDIPCONST ARGB *blend, GDIPCONST REAL *pos, INT count)
1584 ARGB *new_color;
1585 REAL *new_pos;
1586 TRACE("(%p,%p,%p,%i)\n", brush, blend, pos, count);
1588 if (!brush || !blend || !pos || count < 2 || brush->brush.bt != BrushTypePathGradient ||
1589 pos[0] != 0.0f || pos[count-1] != 1.0f)
1591 return InvalidParameter;
1594 new_color = heap_alloc_zero(count * sizeof(ARGB));
1595 new_pos = heap_alloc_zero(count * sizeof(REAL));
1596 if (!new_color || !new_pos)
1598 heap_free(new_color);
1599 heap_free(new_pos);
1600 return OutOfMemory;
1603 memcpy(new_color, blend, sizeof(ARGB) * count);
1604 memcpy(new_pos, pos, sizeof(REAL) * count);
1606 heap_free(brush->pblendcolor);
1607 heap_free(brush->pblendpos);
1609 brush->pblendcolor = new_color;
1610 brush->pblendpos = new_pos;
1611 brush->pblendcount = count;
1613 return Ok;
1616 GpStatus WINGDIPAPI GdipGetPathGradientPresetBlend(GpPathGradient *brush,
1617 ARGB *blend, REAL *pos, INT count)
1619 TRACE("(%p,%p,%p,%i)\n", brush, blend, pos, count);
1621 if (count < 0)
1622 return OutOfMemory;
1624 if (!brush || !blend || !pos || count < 2 || brush->brush.bt != BrushTypePathGradient)
1625 return InvalidParameter;
1627 if (brush->pblendcount == 0)
1628 return GenericError;
1630 if (count != brush->pblendcount)
1632 /* Native lines up the ends of each array, and copies the destination size. */
1633 FIXME("Braindead behavior on wrong-sized buffer not implemented.\n");
1634 return InvalidParameter;
1637 memcpy(blend, brush->pblendcolor, sizeof(ARGB) * brush->pblendcount);
1638 memcpy(pos, brush->pblendpos, sizeof(REAL) * brush->pblendcount);
1640 return Ok;
1643 GpStatus WINGDIPAPI GdipGetPathGradientPresetBlendCount(GpPathGradient *brush,
1644 INT *count)
1646 TRACE("(%p,%p)\n", brush, count);
1648 if (!brush || !count || brush->brush.bt != BrushTypePathGradient)
1649 return InvalidParameter;
1651 *count = brush->pblendcount;
1653 return Ok;
1656 GpStatus WINGDIPAPI GdipSetPathGradientCenterColor(GpPathGradient *grad,
1657 ARGB argb)
1659 TRACE("(%p, %x)\n", grad, argb);
1661 if(!grad || grad->brush.bt != BrushTypePathGradient)
1662 return InvalidParameter;
1664 grad->centercolor = argb;
1665 return Ok;
1668 GpStatus WINGDIPAPI GdipSetPathGradientCenterPoint(GpPathGradient *grad,
1669 GpPointF *point)
1671 TRACE("(%p, %s)\n", grad, debugstr_pointf(point));
1673 if(!grad || !point || grad->brush.bt != BrushTypePathGradient)
1674 return InvalidParameter;
1676 grad->center.X = point->X;
1677 grad->center.Y = point->Y;
1679 return Ok;
1682 GpStatus WINGDIPAPI GdipSetPathGradientCenterPointI(GpPathGradient *grad,
1683 GpPoint *point)
1685 GpPointF ptf;
1687 TRACE("(%p, %p)\n", grad, point);
1689 if(!point)
1690 return InvalidParameter;
1692 ptf.X = (REAL)point->X;
1693 ptf.Y = (REAL)point->Y;
1695 return GdipSetPathGradientCenterPoint(grad,&ptf);
1698 GpStatus WINGDIPAPI GdipSetPathGradientFocusScales(GpPathGradient *grad,
1699 REAL x, REAL y)
1701 TRACE("(%p, %.2f, %.2f)\n", grad, x, y);
1703 if(!grad || grad->brush.bt != BrushTypePathGradient)
1704 return InvalidParameter;
1706 grad->focus.X = x;
1707 grad->focus.Y = y;
1709 return Ok;
1712 GpStatus WINGDIPAPI GdipSetPathGradientGammaCorrection(GpPathGradient *grad,
1713 BOOL gamma)
1715 TRACE("(%p, %d)\n", grad, gamma);
1717 if(!grad || grad->brush.bt != BrushTypePathGradient)
1718 return InvalidParameter;
1720 grad->gamma = gamma;
1722 return Ok;
1725 GpStatus WINGDIPAPI GdipSetPathGradientPath(GpPathGradient *grad, GDIPCONST GpPath *path)
1727 static int calls;
1729 TRACE("(%p, %p)\n", grad, path);
1731 if (!(calls++))
1732 FIXME("not implemented\n");
1734 return NotImplemented;
1737 GpStatus WINGDIPAPI GdipSetPathGradientSigmaBlend(GpPathGradient *grad,
1738 REAL focus, REAL scale)
1740 REAL factors[33];
1741 REAL positions[33];
1742 int num_points = 0;
1743 int i;
1744 const int precision = 16;
1745 REAL erf_range; /* we use values erf(-erf_range) through erf(+erf_range) */
1746 REAL min_erf;
1747 REAL scale_erf;
1749 TRACE("(%p,%0.2f,%0.2f)\n", grad, focus, scale);
1751 if(!grad || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0 || grad->brush.bt != BrushTypePathGradient)
1752 return InvalidParameter;
1754 /* we want 2 standard deviations */
1755 erf_range = 2.0 / sqrt(2);
1757 /* calculate the constants we need to normalize the error function to be
1758 between 0.0 and scale over the range we need */
1759 min_erf = erf(-erf_range);
1760 scale_erf = scale / (-2.0 * min_erf);
1762 if (focus != 0.0)
1764 positions[0] = 0.0;
1765 factors[0] = 0.0;
1766 for (i=1; i<precision; i++)
1768 positions[i] = focus * i / precision;
1769 factors[i] = scale_erf * (erf(2 * erf_range * i / precision - erf_range) - min_erf);
1771 num_points += precision;
1774 positions[num_points] = focus;
1775 factors[num_points] = scale;
1776 num_points += 1;
1778 if (focus != 1.0)
1780 for (i=1; i<precision; i++)
1782 positions[i+num_points-1] = (focus + ((1.0-focus) * i / precision));
1783 factors[i+num_points-1] = scale_erf * (erf(erf_range - 2 * erf_range * i / precision) - min_erf);
1785 num_points += precision;
1786 positions[num_points-1] = 1.0;
1787 factors[num_points-1] = 0.0;
1790 return GdipSetPathGradientBlend(grad, factors, positions, num_points);
1793 GpStatus WINGDIPAPI GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
1794 *grad, GDIPCONST ARGB *argb, INT *count)
1796 ARGB *new_surroundcolors;
1797 INT i, num_colors;
1799 TRACE("(%p,%p,%p)\n", grad, argb, count);
1801 if(!grad || !argb || !count || (*count <= 0) || grad->brush.bt != BrushTypePathGradient ||
1802 (*count > grad->path->pathdata.Count))
1803 return InvalidParameter;
1805 num_colors = *count;
1807 /* If all colors are the same, only store 1 color. */
1808 if (*count > 1)
1810 for (i=1; i < num_colors; i++)
1811 if (argb[i] != argb[i-1])
1812 break;
1814 if (i == num_colors)
1815 num_colors = 1;
1818 new_surroundcolors = heap_alloc_zero(num_colors * sizeof(ARGB));
1819 if (!new_surroundcolors)
1820 return OutOfMemory;
1822 memcpy(new_surroundcolors, argb, num_colors * sizeof(ARGB));
1824 heap_free(grad->surroundcolors);
1826 grad->surroundcolors = new_surroundcolors;
1827 grad->surroundcolorcount = num_colors;
1829 return Ok;
1832 GpStatus WINGDIPAPI GdipSetPathGradientWrapMode(GpPathGradient *grad,
1833 GpWrapMode wrap)
1835 TRACE("(%p, %d)\n", grad, wrap);
1837 if(!grad || grad->brush.bt != BrushTypePathGradient)
1838 return InvalidParameter;
1840 grad->wrap = wrap;
1842 return Ok;
1845 GpStatus WINGDIPAPI GdipSetPathGradientTransform(GpPathGradient *grad,
1846 GpMatrix *matrix)
1848 TRACE("(%p,%p)\n", grad, matrix);
1850 if (!grad || !matrix || grad->brush.bt != BrushTypePathGradient)
1851 return InvalidParameter;
1853 grad->transform = *matrix;
1855 return Ok;
1858 GpStatus WINGDIPAPI GdipGetPathGradientTransform(GpPathGradient *grad,
1859 GpMatrix *matrix)
1861 TRACE("(%p,%p)\n", grad, matrix);
1863 if (!grad || !matrix || grad->brush.bt != BrushTypePathGradient)
1864 return InvalidParameter;
1866 *matrix = grad->transform;
1868 return Ok;
1871 GpStatus WINGDIPAPI GdipMultiplyPathGradientTransform(GpPathGradient *grad,
1872 GDIPCONST GpMatrix *matrix, GpMatrixOrder order)
1874 TRACE("(%p,%p,%i)\n", grad, matrix, order);
1876 if (!grad || grad->brush.bt != BrushTypePathGradient)
1877 return InvalidParameter;
1879 return GdipMultiplyMatrix(&grad->transform, matrix, order);
1882 GpStatus WINGDIPAPI GdipResetPathGradientTransform(GpPathGradient *grad)
1884 TRACE("(%p)\n", grad);
1886 if (!grad || grad->brush.bt != BrushTypePathGradient)
1887 return InvalidParameter;
1889 return GdipSetMatrixElements(&grad->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1892 GpStatus WINGDIPAPI GdipRotatePathGradientTransform(GpPathGradient *grad,
1893 REAL angle, GpMatrixOrder order)
1895 TRACE("(%p,%0.2f,%i)\n", grad, angle, order);
1897 if (!grad || grad->brush.bt != BrushTypePathGradient)
1898 return InvalidParameter;
1900 return GdipRotateMatrix(&grad->transform, angle, order);
1903 GpStatus WINGDIPAPI GdipScalePathGradientTransform(GpPathGradient *grad,
1904 REAL sx, REAL sy, GpMatrixOrder order)
1906 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad, sx, sy, order);
1908 if (!grad || grad->brush.bt != BrushTypePathGradient)
1909 return InvalidParameter;
1911 return GdipScaleMatrix(&grad->transform, sx, sy, order);
1914 GpStatus WINGDIPAPI GdipTranslatePathGradientTransform(GpPathGradient *grad,
1915 REAL dx, REAL dy, GpMatrixOrder order)
1917 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad, dx, dy, order);
1919 if (!grad || grad->brush.bt != BrushTypePathGradient)
1920 return InvalidParameter;
1922 return GdipTranslateMatrix(&grad->transform, dx, dy, order);
1925 GpStatus WINGDIPAPI GdipSetSolidFillColor(GpSolidFill *sf, ARGB argb)
1927 TRACE("(%p, %x)\n", sf, argb);
1929 if(!sf)
1930 return InvalidParameter;
1932 sf->color = argb;
1933 return Ok;
1936 /******************************************************************************
1937 * GdipSetTextureTransform [GDIPLUS.@]
1939 GpStatus WINGDIPAPI GdipSetTextureTransform(GpTexture *texture,
1940 GDIPCONST GpMatrix *matrix)
1942 TRACE("(%p, %p)\n", texture, matrix);
1944 if(!texture || !matrix)
1945 return InvalidParameter;
1947 texture->transform = *matrix;
1949 return Ok;
1952 /******************************************************************************
1953 * GdipSetTextureWrapMode [GDIPLUS.@]
1955 * WrapMode not used, only stored
1957 GpStatus WINGDIPAPI GdipSetTextureWrapMode(GpTexture *brush, GpWrapMode wrapmode)
1959 TRACE("(%p, %d)\n", brush, wrapmode);
1961 if(!brush)
1962 return InvalidParameter;
1964 brush->imageattributes->wrap = wrapmode;
1966 return Ok;
1969 GpStatus WINGDIPAPI GdipSetLineColors(GpLineGradient *brush, ARGB color1,
1970 ARGB color2)
1972 TRACE("(%p, %x, %x)\n", brush, color1, color2);
1974 if(!brush || brush->brush.bt != BrushTypeLinearGradient)
1975 return InvalidParameter;
1977 brush->startcolor = color1;
1978 brush->endcolor = color2;
1980 return Ok;
1983 GpStatus WINGDIPAPI GdipGetLineColors(GpLineGradient *brush, ARGB *colors)
1985 TRACE("(%p, %p)\n", brush, colors);
1987 if(!brush || !colors || brush->brush.bt != BrushTypeLinearGradient)
1988 return InvalidParameter;
1990 colors[0] = brush->startcolor;
1991 colors[1] = brush->endcolor;
1993 return Ok;
1996 /******************************************************************************
1997 * GdipRotateTextureTransform [GDIPLUS.@]
1999 GpStatus WINGDIPAPI GdipRotateTextureTransform(GpTexture* brush, REAL angle,
2000 GpMatrixOrder order)
2002 TRACE("(%p, %.2f, %d)\n", brush, angle, order);
2004 if(!brush)
2005 return InvalidParameter;
2007 return GdipRotateMatrix(&brush->transform, angle, order);
2010 GpStatus WINGDIPAPI GdipSetLineLinearBlend(GpLineGradient *brush, REAL focus,
2011 REAL scale)
2013 REAL factors[3];
2014 REAL positions[3];
2015 int num_points = 0;
2017 TRACE("(%p,%.2f,%.2f)\n", brush, focus, scale);
2019 if (!brush) return InvalidParameter;
2021 if (focus != 0.0)
2023 factors[num_points] = 0.0;
2024 positions[num_points] = 0.0;
2025 num_points++;
2028 factors[num_points] = scale;
2029 positions[num_points] = focus;
2030 num_points++;
2032 if (focus != 1.0)
2034 factors[num_points] = 0.0;
2035 positions[num_points] = 1.0;
2036 num_points++;
2039 return GdipSetLineBlend(brush, factors, positions, num_points);
2042 GpStatus WINGDIPAPI GdipSetLinePresetBlend(GpLineGradient *brush,
2043 GDIPCONST ARGB *blend, GDIPCONST REAL* positions, INT count)
2045 ARGB *new_color;
2046 REAL *new_pos;
2047 TRACE("(%p,%p,%p,%i)\n", brush, blend, positions, count);
2049 if (!brush || !blend || !positions || count < 2 || brush->brush.bt != BrushTypeLinearGradient ||
2050 positions[0] != 0.0f || positions[count-1] != 1.0f)
2052 return InvalidParameter;
2055 new_color = heap_alloc_zero(count * sizeof(ARGB));
2056 new_pos = heap_alloc_zero(count * sizeof(REAL));
2057 if (!new_color || !new_pos)
2059 heap_free(new_color);
2060 heap_free(new_pos);
2061 return OutOfMemory;
2064 memcpy(new_color, blend, sizeof(ARGB) * count);
2065 memcpy(new_pos, positions, sizeof(REAL) * count);
2067 heap_free(brush->pblendcolor);
2068 heap_free(brush->pblendpos);
2070 brush->pblendcolor = new_color;
2071 brush->pblendpos = new_pos;
2072 brush->pblendcount = count;
2074 return Ok;
2077 GpStatus WINGDIPAPI GdipGetLinePresetBlend(GpLineGradient *brush,
2078 ARGB *blend, REAL* positions, INT count)
2080 if (!brush || !blend || !positions || count < 2 || brush->brush.bt != BrushTypeLinearGradient)
2081 return InvalidParameter;
2083 if (brush->pblendcount == 0)
2084 return GenericError;
2086 if (count < brush->pblendcount)
2087 return InsufficientBuffer;
2089 memcpy(blend, brush->pblendcolor, sizeof(ARGB) * brush->pblendcount);
2090 memcpy(positions, brush->pblendpos, sizeof(REAL) * brush->pblendcount);
2092 return Ok;
2095 GpStatus WINGDIPAPI GdipGetLinePresetBlendCount(GpLineGradient *brush,
2096 INT *count)
2098 if (!brush || !count || brush->brush.bt != BrushTypeLinearGradient)
2099 return InvalidParameter;
2101 *count = brush->pblendcount;
2103 return Ok;
2106 GpStatus WINGDIPAPI GdipResetLineTransform(GpLineGradient *brush)
2108 TRACE("(%p)\n", brush);
2110 if(!brush)
2111 return InvalidParameter;
2113 return GdipSetMatrixElements(&brush->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
2116 GpStatus WINGDIPAPI GdipSetLineTransform(GpLineGradient *brush,
2117 GDIPCONST GpMatrix *matrix)
2119 TRACE("(%p,%p)\n", brush, matrix);
2121 if(!brush || !matrix)
2122 return InvalidParameter;
2124 brush->transform = *matrix;
2126 return Ok;
2129 GpStatus WINGDIPAPI GdipGetLineTransform(GpLineGradient *brush, GpMatrix *matrix)
2131 TRACE("(%p,%p)\n", brush, matrix);
2133 if(!brush || !matrix)
2134 return InvalidParameter;
2136 *matrix = brush->transform;
2138 return Ok;
2141 GpStatus WINGDIPAPI GdipScaleLineTransform(GpLineGradient *brush, REAL sx, REAL sy,
2142 GpMatrixOrder order)
2144 TRACE("(%p,%0.2f,%0.2f,%u)\n", brush, sx, sy, order);
2146 if(!brush)
2147 return InvalidParameter;
2149 return GdipScaleMatrix(&brush->transform, sx, sy, order);
2152 GpStatus WINGDIPAPI GdipMultiplyLineTransform(GpLineGradient *brush,
2153 GDIPCONST GpMatrix *matrix, GpMatrixOrder order)
2155 TRACE("(%p,%p,%u)\n", brush, matrix, order);
2157 if(!brush)
2158 return InvalidParameter;
2160 if(!matrix)
2161 return Ok;
2163 return GdipMultiplyMatrix(&brush->transform, matrix, order);
2166 GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient *brush,
2167 REAL dx, REAL dy, GpMatrixOrder order)
2169 TRACE("(%p,%f,%f,%d)\n", brush, dx, dy, order);
2171 if(!brush)
2172 return InvalidParameter;
2174 return GdipTranslateMatrix(&brush->transform, dx, dy, order);
2177 /******************************************************************************
2178 * GdipTranslateTextureTransform [GDIPLUS.@]
2180 GpStatus WINGDIPAPI GdipTranslateTextureTransform(GpTexture* brush, REAL dx, REAL dy,
2181 GpMatrixOrder order)
2183 TRACE("(%p, %.2f, %.2f, %d)\n", brush, dx, dy, order);
2185 if(!brush)
2186 return InvalidParameter;
2188 return GdipTranslateMatrix(&brush->transform, dx, dy, order);
2191 GpStatus WINGDIPAPI GdipGetLineRect(GpLineGradient *brush, GpRectF *rect)
2193 TRACE("(%p, %p)\n", brush, rect);
2195 if(!brush || !rect || brush->brush.bt != BrushTypeLinearGradient)
2196 return InvalidParameter;
2198 *rect = brush->rect;
2200 return Ok;
2203 GpStatus WINGDIPAPI GdipGetLineRectI(GpLineGradient *brush, GpRect *rect)
2205 GpRectF rectF;
2206 GpStatus ret;
2208 TRACE("(%p, %p)\n", brush, rect);
2210 if(!rect)
2211 return InvalidParameter;
2213 ret = GdipGetLineRect(brush, &rectF);
2215 if(ret == Ok){
2216 rect->X = gdip_round(rectF.X);
2217 rect->Y = gdip_round(rectF.Y);
2218 rect->Width = gdip_round(rectF.Width);
2219 rect->Height = gdip_round(rectF.Height);
2222 return ret;
2225 GpStatus WINGDIPAPI GdipRotateLineTransform(GpLineGradient* brush,
2226 REAL angle, GpMatrixOrder order)
2228 static int calls;
2230 TRACE("(%p,%0.2f,%u)\n", brush, angle, order);
2232 if(!brush || brush->brush.bt != BrushTypeLinearGradient)
2233 return InvalidParameter;
2235 if(!(calls++))
2236 FIXME("(%p, %.2f, %d) stub\n", brush, angle, order);
2238 return NotImplemented;