mfplat/sample: Optimize copying to 2d buffer.
[wine.git] / dlls / gdiplus / brush.c
blobed1b559dc9a0203be19ed5aa43e48e25a5d60530
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, %ld, %ld, %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, %lx, %lx, %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, %lx, %lx, %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, %lx, %lx, %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, %lx, %lx, %d, %d, %p)\n", rect, startcolor, endcolor, mode,
472 wrap, line);
474 set_rect(&rectF, rect->X, rect->Y, rect->Width, rect->Height);
475 return GdipCreateLineBrushFromRect(&rectF, startcolor, endcolor, mode, wrap, line);
478 /******************************************************************************
479 * GdipCreateLineBrushFromRectWithAngle [GDIPLUS.@]
481 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngle(GDIPCONST GpRectF* rect,
482 ARGB startcolor, ARGB endcolor, REAL angle, BOOL isAngleScalable, GpWrapMode wrap,
483 GpLineGradient **line)
485 GpStatus stat;
486 REAL exofs, eyofs, far_x, far_y;
487 REAL sin_angle, cos_angle, sin_cos_angle;
488 GpPointF start, end;
490 TRACE("(%s, %lx, %lx, %.2f, %d, %d, %p)\n", debugstr_rectf(rect), startcolor, endcolor, angle, isAngleScalable,
491 wrap, line);
493 if (!rect || !line || wrap == WrapModeClamp)
494 return InvalidParameter;
496 if (!rect->Width || !rect->Height)
497 return OutOfMemory;
499 angle = fmodf(angle, 360);
500 if (angle < 0)
501 angle += 360;
503 if (isAngleScalable)
505 float add_angle = 0;
507 while(angle >= 90) {
508 angle -= 180;
509 add_angle += M_PI;
512 if (angle != 90 && angle != -90)
513 angle = atan((rect->Width / rect->Height) * tan(deg2rad(angle)));
514 else
515 angle = deg2rad(angle);
516 angle += add_angle;
518 else
520 angle = deg2rad(angle);
523 sin_angle = sinf(angle);
524 cos_angle = cosf(angle);
525 sin_cos_angle = sin_angle * cos_angle;
527 far_x = rect->X + rect->Width;
528 far_y = rect->Y + rect->Height;
530 if (angle == 0.0f)
532 start.X = min(rect->X, far_x);
533 start.Y = rect->Y;
534 end.X = max(rect->X, far_x);
535 end.Y = rect->Y;
537 else if (sin_cos_angle >= 0)
539 start.X = min(rect->X, far_x);
540 start.Y = min(rect->Y, far_y);
541 end.X = max(rect->X, far_x);
542 end.Y = max(rect->Y, far_y);
544 else
546 start.X = max(rect->X, far_x);
547 start.Y = min(rect->Y, far_y);
548 end.X = min(rect->X, far_x);
549 end.Y = max(rect->Y, far_y);
552 stat = create_line_brush(rect, startcolor, endcolor, wrap, line);
553 if (stat != Ok || angle == 0.0f)
554 return stat;
556 if (sin_cos_angle >= 0)
558 exofs = rect->Height * sin_cos_angle + rect->Width * cos_angle * cos_angle;
559 eyofs = rect->Height * sin_angle * sin_angle + rect->Width * sin_cos_angle;
561 else
563 exofs = rect->Width * sin_angle * sin_angle + rect->Height * sin_cos_angle;
564 eyofs = -rect->Width * sin_cos_angle + rect->Height * sin_angle * sin_angle;
567 if (sin_angle >= 0)
569 end.X = rect->X + exofs;
570 end.Y = rect->Y + eyofs;
572 else
574 end.X = start.X;
575 end.Y = start.Y;
576 start.X = rect->X + exofs;
577 start.Y = rect->Y + eyofs;
580 linegradient_init_transform(&start, &end, *line);
582 return stat;
585 GpStatus WINGDIPAPI GdipCreateLineBrushFromRectWithAngleI(GDIPCONST GpRect* rect,
586 ARGB startcolor, ARGB endcolor, REAL angle, BOOL isAngleScalable, GpWrapMode wrap,
587 GpLineGradient **line)
589 TRACE("(%p, %lx, %lx, %.2f, %d, %d, %p)\n", rect, startcolor, endcolor, angle, isAngleScalable,
590 wrap, line);
592 return GdipCreateLineBrushFromRectI(rect, startcolor, endcolor, LinearGradientModeForwardDiagonal,
593 wrap, line);
596 static GpStatus create_path_gradient(GpPath *path, ARGB centercolor, GpPathGradient **grad)
598 INT i;
599 REAL sum_x = 0, sum_y = 0;
601 if(!path || !grad)
602 return InvalidParameter;
604 if (path->pathdata.Count < 2)
605 return OutOfMemory;
607 *grad = heap_alloc_zero(sizeof(GpPathGradient));
608 if (!*grad)
610 return OutOfMemory;
613 GdipSetMatrixElements(&(*grad)->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
615 (*grad)->blendfac = heap_alloc_zero(sizeof(REAL));
616 (*grad)->blendpos = heap_alloc_zero(sizeof(REAL));
617 (*grad)->surroundcolors = heap_alloc_zero(sizeof(ARGB));
618 if(!(*grad)->blendfac || !(*grad)->blendpos || !(*grad)->surroundcolors){
619 heap_free((*grad)->blendfac);
620 heap_free((*grad)->blendpos);
621 heap_free((*grad)->surroundcolors);
622 heap_free(*grad);
623 *grad = NULL;
624 return OutOfMemory;
626 (*grad)->blendfac[0] = 1.0;
627 (*grad)->blendpos[0] = 1.0;
628 (*grad)->blendcount = 1;
630 (*grad)->path = path;
632 (*grad)->brush.bt = BrushTypePathGradient;
633 (*grad)->centercolor = centercolor;
634 (*grad)->wrap = WrapModeClamp;
635 (*grad)->gamma = FALSE;
636 for (i=0; i<path->pathdata.Count; i++)
638 sum_x += path->pathdata.Points[i].X;
639 sum_y += path->pathdata.Points[i].Y;
641 (*grad)->center.X = sum_x / path->pathdata.Count;
642 (*grad)->center.Y = sum_y / path->pathdata.Count;
644 (*grad)->focus.X = 0.0;
645 (*grad)->focus.Y = 0.0;
646 (*grad)->surroundcolors[0] = 0xffffffff;
647 (*grad)->surroundcolorcount = 1;
649 TRACE("<-- %p\n", *grad);
651 return Ok;
654 GpStatus WINGDIPAPI GdipCreatePathGradient(GDIPCONST GpPointF* points,
655 INT count, GpWrapMode wrap, GpPathGradient **grad)
657 GpStatus stat;
658 GpPath *path;
660 TRACE("(%p, %d, %d, %p)\n", points, count, wrap, grad);
662 if(!grad)
663 return InvalidParameter;
665 if(!points || count <= 0)
666 return OutOfMemory;
668 stat = GdipCreatePath(FillModeAlternate, &path);
670 if (stat == Ok)
672 stat = GdipAddPathLine2(path, points, count);
674 if (stat == Ok)
675 stat = create_path_gradient(path, 0xff000000, grad);
677 if (stat != Ok)
678 GdipDeletePath(path);
681 if (stat == Ok)
682 (*grad)->wrap = wrap;
684 return stat;
687 GpStatus WINGDIPAPI GdipCreatePathGradientI(GDIPCONST GpPoint* points,
688 INT count, GpWrapMode wrap, GpPathGradient **grad)
690 GpStatus stat;
691 GpPath *path;
693 TRACE("(%p, %d, %d, %p)\n", points, count, wrap, grad);
695 if(!grad)
696 return InvalidParameter;
698 if(!points || count <= 0)
699 return OutOfMemory;
701 stat = GdipCreatePath(FillModeAlternate, &path);
703 if (stat == Ok)
705 stat = GdipAddPathLine2I(path, points, count);
707 if (stat == Ok)
708 stat = create_path_gradient(path, 0xff000000, grad);
710 if (stat != Ok)
711 GdipDeletePath(path);
714 if (stat == Ok)
715 (*grad)->wrap = wrap;
717 return stat;
720 /******************************************************************************
721 * GdipCreatePathGradientFromPath [GDIPLUS.@]
723 GpStatus WINGDIPAPI GdipCreatePathGradientFromPath(GDIPCONST GpPath* path,
724 GpPathGradient **grad)
726 GpStatus stat;
727 GpPath *new_path;
729 TRACE("(%p, %p)\n", path, grad);
731 if(!grad)
732 return InvalidParameter;
734 if (!path)
735 return OutOfMemory;
737 stat = GdipClonePath((GpPath*)path, &new_path);
739 if (stat == Ok)
741 stat = create_path_gradient(new_path, 0xffffffff, grad);
743 if (stat != Ok)
744 GdipDeletePath(new_path);
747 return stat;
750 /******************************************************************************
751 * GdipCreateSolidFill [GDIPLUS.@]
753 GpStatus WINGDIPAPI GdipCreateSolidFill(ARGB color, GpSolidFill **sf)
755 TRACE("(%lx, %p)\n", color, sf);
757 if(!sf) return InvalidParameter;
759 *sf = heap_alloc_zero(sizeof(GpSolidFill));
760 if (!*sf) return OutOfMemory;
762 (*sf)->brush.bt = BrushTypeSolidColor;
763 (*sf)->color = color;
765 TRACE("<-- %p\n", *sf);
767 return Ok;
770 /******************************************************************************
771 * GdipCreateTexture [GDIPLUS.@]
773 * PARAMS
774 * image [I] image to use
775 * wrapmode [I] optional
776 * texture [O] pointer to the resulting texturebrush
778 * RETURNS
779 * SUCCESS: Ok
780 * FAILURE: element of GpStatus
782 GpStatus WINGDIPAPI GdipCreateTexture(GpImage *image, GpWrapMode wrapmode,
783 GpTexture **texture)
785 UINT width, height;
786 GpImageAttributes *attributes;
787 GpStatus stat;
789 TRACE("%p, %d %p\n", image, wrapmode, texture);
791 if (!(image && texture))
792 return InvalidParameter;
794 stat = GdipGetImageWidth(image, &width);
795 if (stat != Ok) return stat;
796 stat = GdipGetImageHeight(image, &height);
797 if (stat != Ok) return stat;
799 stat = GdipCreateImageAttributes(&attributes);
801 if (stat == Ok)
803 attributes->wrap = wrapmode;
805 stat = GdipCreateTextureIA(image, attributes, 0, 0, width, height,
806 texture);
808 GdipDisposeImageAttributes(attributes);
811 return stat;
814 /******************************************************************************
815 * GdipCreateTexture2 [GDIPLUS.@]
817 GpStatus WINGDIPAPI GdipCreateTexture2(GpImage *image, GpWrapMode wrapmode,
818 REAL x, REAL y, REAL width, REAL height, GpTexture **texture)
820 GpImageAttributes *attributes;
821 GpStatus stat;
823 TRACE("%p %d %f %f %f %f %p\n", image, wrapmode,
824 x, y, width, height, texture);
826 stat = GdipCreateImageAttributes(&attributes);
828 if (stat == Ok)
830 attributes->wrap = wrapmode;
832 stat = GdipCreateTextureIA(image, attributes, x, y, width, height,
833 texture);
835 GdipDisposeImageAttributes(attributes);
838 return stat;
841 /******************************************************************************
842 * GdipCreateTextureIA [GDIPLUS.@]
844 GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image,
845 GDIPCONST GpImageAttributes *imageattr, REAL x, REAL y, REAL width,
846 REAL height, GpTexture **texture)
848 GpStatus status;
849 GpImage *new_image=NULL;
851 TRACE("(%p, %p, %.2f, %.2f, %.2f, %.2f, %p)\n", image, imageattr, x, y, width, height,
852 texture);
854 if(!image || !texture || x < 0.0 || y < 0.0 || width < 0.0 || height < 0.0)
855 return InvalidParameter;
857 *texture = NULL;
859 if(image->type != ImageTypeBitmap){
860 FIXME("not implemented for image type %d\n", image->type);
861 return NotImplemented;
864 status = GdipCloneBitmapArea(x, y, width, height, PixelFormatDontCare, (GpBitmap*)image, (GpBitmap**)&new_image);
865 if (status != Ok)
866 return status;
868 *texture = heap_alloc_zero(sizeof(GpTexture));
869 if (!*texture){
870 status = OutOfMemory;
871 goto exit;
874 GdipSetMatrixElements(&(*texture)->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
876 if (imageattr)
878 status = GdipCloneImageAttributes(imageattr, &(*texture)->imageattributes);
880 else
882 status = GdipCreateImageAttributes(&(*texture)->imageattributes);
883 if (status == Ok)
884 (*texture)->imageattributes->wrap = WrapModeTile;
886 if (status == Ok)
888 (*texture)->brush.bt = BrushTypeTextureFill;
889 (*texture)->image = new_image;
892 exit:
893 if (status == Ok)
895 TRACE("<-- %p\n", *texture);
897 else
899 if (*texture)
901 GdipDisposeImageAttributes((*texture)->imageattributes);
902 heap_free(*texture);
903 *texture = NULL;
905 GdipDisposeImage(new_image);
906 TRACE("<-- error %u\n", status);
909 return status;
912 /******************************************************************************
913 * GdipCreateTextureIAI [GDIPLUS.@]
915 GpStatus WINGDIPAPI GdipCreateTextureIAI(GpImage *image, GDIPCONST GpImageAttributes *imageattr,
916 INT x, INT y, INT width, INT height, GpTexture **texture)
918 TRACE("(%p, %p, %d, %d, %d, %d, %p)\n", image, imageattr, x, y, width, height,
919 texture);
921 return GdipCreateTextureIA(image,imageattr,(REAL)x,(REAL)y,(REAL)width,(REAL)height,texture);
924 GpStatus WINGDIPAPI GdipCreateTexture2I(GpImage *image, GpWrapMode wrapmode,
925 INT x, INT y, INT width, INT height, GpTexture **texture)
927 GpImageAttributes *imageattr;
928 GpStatus stat;
930 TRACE("%p %d %d %d %d %d %p\n", image, wrapmode, x, y, width, height,
931 texture);
933 stat = GdipCreateImageAttributes(&imageattr);
935 if (stat == Ok)
937 imageattr->wrap = wrapmode;
939 stat = GdipCreateTextureIA(image, imageattr, x, y, width, height, texture);
940 GdipDisposeImageAttributes(imageattr);
943 return stat;
946 GpStatus WINGDIPAPI GdipGetBrushType(GpBrush *brush, GpBrushType *type)
948 TRACE("(%p, %p)\n", brush, type);
950 if(!brush || !type) return InvalidParameter;
952 *type = brush->bt;
954 return Ok;
957 GpStatus WINGDIPAPI GdipGetHatchBackgroundColor(GpHatch *brush, ARGB *backcol)
959 TRACE("(%p, %p)\n", brush, backcol);
961 if(!brush || !backcol) return InvalidParameter;
963 *backcol = brush->backcol;
965 return Ok;
968 GpStatus WINGDIPAPI GdipGetHatchForegroundColor(GpHatch *brush, ARGB *forecol)
970 TRACE("(%p, %p)\n", brush, forecol);
972 if(!brush || !forecol) return InvalidParameter;
974 *forecol = brush->forecol;
976 return Ok;
979 GpStatus WINGDIPAPI GdipGetHatchStyle(GpHatch *brush, GpHatchStyle *hatchstyle)
981 TRACE("(%p, %p)\n", brush, hatchstyle);
983 if(!brush || !hatchstyle) return InvalidParameter;
985 *hatchstyle = brush->hatchstyle;
987 return Ok;
990 GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush)
992 TRACE("(%p)\n", brush);
994 if(!brush) return InvalidParameter;
996 switch(brush->bt)
998 case BrushTypePathGradient:
999 GdipDeletePath(((GpPathGradient*) brush)->path);
1000 heap_free(((GpPathGradient*) brush)->blendfac);
1001 heap_free(((GpPathGradient*) brush)->blendpos);
1002 heap_free(((GpPathGradient*) brush)->surroundcolors);
1003 heap_free(((GpPathGradient*) brush)->pblendcolor);
1004 heap_free(((GpPathGradient*) brush)->pblendpos);
1005 break;
1006 case BrushTypeLinearGradient:
1007 heap_free(((GpLineGradient*)brush)->blendfac);
1008 heap_free(((GpLineGradient*)brush)->blendpos);
1009 heap_free(((GpLineGradient*)brush)->pblendcolor);
1010 heap_free(((GpLineGradient*)brush)->pblendpos);
1011 break;
1012 case BrushTypeTextureFill:
1013 GdipDisposeImage(((GpTexture*)brush)->image);
1014 GdipDisposeImageAttributes(((GpTexture*)brush)->imageattributes);
1015 heap_free(((GpTexture*)brush)->bitmap_bits);
1016 break;
1017 default:
1018 break;
1021 heap_free(brush);
1023 return Ok;
1026 GpStatus WINGDIPAPI GdipGetLineGammaCorrection(GpLineGradient *line,
1027 BOOL *usinggamma)
1029 TRACE("(%p, %p)\n", line, usinggamma);
1031 if(!line || !usinggamma)
1032 return InvalidParameter;
1034 *usinggamma = line->gamma;
1036 return Ok;
1039 GpStatus WINGDIPAPI GdipGetLineWrapMode(GpLineGradient *brush, GpWrapMode *wrapmode)
1041 TRACE("(%p, %p)\n", brush, wrapmode);
1043 if(!brush || !wrapmode || brush->brush.bt != BrushTypeLinearGradient)
1044 return InvalidParameter;
1046 *wrapmode = brush->wrap;
1048 return Ok;
1051 GpStatus WINGDIPAPI GdipGetPathGradientBlend(GpPathGradient *brush, REAL *blend,
1052 REAL *positions, INT count)
1054 TRACE("(%p, %p, %p, %d)\n", brush, blend, positions, count);
1056 if(!brush || !blend || !positions || count <= 0 || brush->brush.bt != BrushTypePathGradient)
1057 return InvalidParameter;
1059 if(count < brush->blendcount)
1060 return InsufficientBuffer;
1062 memcpy(blend, brush->blendfac, count*sizeof(REAL));
1063 if(brush->blendcount > 1){
1064 memcpy(positions, brush->blendpos, count*sizeof(REAL));
1067 return Ok;
1070 GpStatus WINGDIPAPI GdipGetPathGradientBlendCount(GpPathGradient *brush, INT *count)
1072 TRACE("(%p, %p)\n", brush, count);
1074 if(!brush || !count || brush->brush.bt != BrushTypePathGradient)
1075 return InvalidParameter;
1077 *count = brush->blendcount;
1079 return Ok;
1082 GpStatus WINGDIPAPI GdipGetPathGradientCenterPoint(GpPathGradient *grad,
1083 GpPointF *point)
1085 TRACE("(%p, %p)\n", grad, point);
1087 if(!grad || !point || grad->brush.bt != BrushTypePathGradient)
1088 return InvalidParameter;
1090 point->X = grad->center.X;
1091 point->Y = grad->center.Y;
1093 return Ok;
1096 GpStatus WINGDIPAPI GdipGetPathGradientCenterPointI(GpPathGradient *grad,
1097 GpPoint *point)
1099 GpStatus ret;
1100 GpPointF ptf;
1102 TRACE("(%p, %p)\n", grad, point);
1104 if(!point)
1105 return InvalidParameter;
1107 ret = GdipGetPathGradientCenterPoint(grad,&ptf);
1109 if(ret == Ok){
1110 point->X = gdip_round(ptf.X);
1111 point->Y = gdip_round(ptf.Y);
1114 return ret;
1117 GpStatus WINGDIPAPI GdipGetPathGradientCenterColor(GpPathGradient *grad,
1118 ARGB *colors)
1120 TRACE("(%p,%p)\n", grad, colors);
1122 if (!grad || !colors || grad->brush.bt != BrushTypePathGradient)
1123 return InvalidParameter;
1125 *colors = grad->centercolor;
1127 return Ok;
1130 GpStatus WINGDIPAPI GdipGetPathGradientFocusScales(GpPathGradient *grad,
1131 REAL *x, REAL *y)
1133 TRACE("(%p, %p, %p)\n", grad, x, y);
1135 if(!grad || !x || !y || grad->brush.bt != BrushTypePathGradient)
1136 return InvalidParameter;
1138 *x = grad->focus.X;
1139 *y = grad->focus.Y;
1141 return Ok;
1144 GpStatus WINGDIPAPI GdipGetPathGradientGammaCorrection(GpPathGradient *grad,
1145 BOOL *gamma)
1147 TRACE("(%p, %p)\n", grad, gamma);
1149 if(!grad || !gamma || grad->brush.bt != BrushTypePathGradient)
1150 return InvalidParameter;
1152 *gamma = grad->gamma;
1154 return Ok;
1157 GpStatus WINGDIPAPI GdipGetPathGradientPath(GpPathGradient *grad, GpPath *path)
1159 static int calls;
1161 TRACE("(%p, %p)\n", grad, path);
1163 if (!(calls++))
1164 FIXME("not implemented\n");
1166 return NotImplemented;
1169 GpStatus WINGDIPAPI GdipGetPathGradientPointCount(GpPathGradient *grad,
1170 INT *count)
1172 TRACE("(%p, %p)\n", grad, count);
1174 if(!grad || !count || grad->brush.bt != BrushTypePathGradient)
1175 return InvalidParameter;
1177 *count = grad->path->pathdata.Count;
1179 return Ok;
1182 GpStatus WINGDIPAPI GdipGetPathGradientRect(GpPathGradient *brush, GpRectF *rect)
1184 GpStatus stat;
1186 TRACE("(%p, %p)\n", brush, rect);
1188 if(!brush || !rect || brush->brush.bt != BrushTypePathGradient)
1189 return InvalidParameter;
1191 stat = GdipGetPathWorldBounds(brush->path, rect, NULL, NULL);
1193 return stat;
1196 GpStatus WINGDIPAPI GdipGetPathGradientRectI(GpPathGradient *brush, GpRect *rect)
1198 GpRectF rectf;
1199 GpStatus stat;
1201 TRACE("(%p, %p)\n", brush, rect);
1203 if(!brush || !rect)
1204 return InvalidParameter;
1206 stat = GdipGetPathGradientRect(brush, &rectf);
1207 if(stat != Ok) return stat;
1209 rect->X = gdip_round(rectf.X);
1210 rect->Y = gdip_round(rectf.Y);
1211 rect->Width = gdip_round(rectf.Width);
1212 rect->Height = gdip_round(rectf.Height);
1214 return Ok;
1217 GpStatus WINGDIPAPI GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
1218 *grad, ARGB *argb, INT *count)
1220 INT i;
1222 TRACE("(%p,%p,%p)\n", grad, argb, count);
1224 if(!grad || !argb || !count || (*count < grad->path->pathdata.Count) || grad->brush.bt != BrushTypePathGradient)
1225 return InvalidParameter;
1227 for (i=0; i<grad->path->pathdata.Count; i++)
1229 if (i < grad->surroundcolorcount)
1230 argb[i] = grad->surroundcolors[i];
1231 else
1232 argb[i] = grad->surroundcolors[grad->surroundcolorcount-1];
1235 *count = grad->surroundcolorcount;
1237 return Ok;
1240 GpStatus WINGDIPAPI GdipGetPathGradientSurroundColorCount(GpPathGradient *brush, INT *count)
1242 TRACE("(%p, %p)\n", brush, count);
1244 if (!brush || !count || brush->brush.bt != BrushTypePathGradient)
1245 return InvalidParameter;
1247 /* Yes, this actually returns the number of points in the path (which is the
1248 * required size of a buffer to get the surround colors), rather than the
1249 * number of surround colors. The real count is returned when getting the
1250 * colors. */
1251 *count = brush->path->pathdata.Count;
1253 return Ok;
1256 GpStatus WINGDIPAPI GdipGetPathGradientWrapMode(GpPathGradient *brush,
1257 GpWrapMode *wrapmode)
1259 TRACE("(%p, %p)\n", brush, wrapmode);
1261 if(!brush || !wrapmode || brush->brush.bt != BrushTypePathGradient)
1262 return InvalidParameter;
1264 *wrapmode = brush->wrap;
1266 return Ok;
1269 GpStatus WINGDIPAPI GdipGetSolidFillColor(GpSolidFill *sf, ARGB *argb)
1271 TRACE("(%p, %p)\n", sf, argb);
1273 if(!sf || !argb)
1274 return InvalidParameter;
1276 *argb = sf->color;
1278 return Ok;
1281 /******************************************************************************
1282 * GdipGetTextureImage [GDIPLUS.@]
1284 GpStatus WINGDIPAPI GdipGetTextureImage(GpTexture *brush, GpImage **image)
1286 TRACE("(%p, %p)\n", brush, image);
1288 if(!brush || !image)
1289 return InvalidParameter;
1291 return GdipCloneImage(brush->image, image);
1294 /******************************************************************************
1295 * GdipGetTextureTransform [GDIPLUS.@]
1297 GpStatus WINGDIPAPI GdipGetTextureTransform(GpTexture *brush, GpMatrix *matrix)
1299 TRACE("(%p, %s)\n", brush, debugstr_matrix(matrix));
1301 if(!brush || !matrix)
1302 return InvalidParameter;
1304 *matrix = brush->transform;
1306 return Ok;
1309 /******************************************************************************
1310 * GdipGetTextureWrapMode [GDIPLUS.@]
1312 GpStatus WINGDIPAPI GdipGetTextureWrapMode(GpTexture *brush, GpWrapMode *wrapmode)
1314 TRACE("(%p, %p)\n", brush, wrapmode);
1316 if(!brush || !wrapmode)
1317 return InvalidParameter;
1319 *wrapmode = brush->imageattributes->wrap;
1321 return Ok;
1324 /******************************************************************************
1325 * GdipMultiplyTextureTransform [GDIPLUS.@]
1327 GpStatus WINGDIPAPI GdipMultiplyTextureTransform(GpTexture* brush,
1328 GDIPCONST GpMatrix *matrix, GpMatrixOrder order)
1330 TRACE("(%p, %s, %d)\n", brush, debugstr_matrix(matrix), order);
1332 if(!brush || !matrix)
1333 return InvalidParameter;
1335 return GdipMultiplyMatrix(&brush->transform, matrix, order);
1338 /******************************************************************************
1339 * GdipResetTextureTransform [GDIPLUS.@]
1341 GpStatus WINGDIPAPI GdipResetTextureTransform(GpTexture* brush)
1343 TRACE("(%p)\n", brush);
1345 if(!brush)
1346 return InvalidParameter;
1348 return GdipSetMatrixElements(&brush->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1351 /******************************************************************************
1352 * GdipScaleTextureTransform [GDIPLUS.@]
1354 GpStatus WINGDIPAPI GdipScaleTextureTransform(GpTexture* brush,
1355 REAL sx, REAL sy, GpMatrixOrder order)
1357 TRACE("(%p, %.2f, %.2f, %d)\n", brush, sx, sy, order);
1359 if(!brush)
1360 return InvalidParameter;
1362 return GdipScaleMatrix(&brush->transform, sx, sy, order);
1365 GpStatus WINGDIPAPI GdipSetLineBlend(GpLineGradient *brush,
1366 GDIPCONST REAL *factors, GDIPCONST REAL* positions, INT count)
1368 REAL *new_blendfac, *new_blendpos;
1370 TRACE("(%p, %p, %p, %i)\n", brush, factors, positions, count);
1372 if(!brush || !factors || !positions || count <= 0 || brush->brush.bt != BrushTypeLinearGradient ||
1373 (count >= 2 && (positions[0] != 0.0f || positions[count-1] != 1.0f)))
1374 return InvalidParameter;
1376 new_blendfac = heap_alloc_zero(count * sizeof(REAL));
1377 new_blendpos = heap_alloc_zero(count * sizeof(REAL));
1379 if (!new_blendfac || !new_blendpos)
1381 heap_free(new_blendfac);
1382 heap_free(new_blendpos);
1383 return OutOfMemory;
1386 memcpy(new_blendfac, factors, count * sizeof(REAL));
1387 memcpy(new_blendpos, positions, count * sizeof(REAL));
1389 heap_free(brush->blendfac);
1390 heap_free(brush->blendpos);
1392 brush->blendcount = count;
1393 brush->blendfac = new_blendfac;
1394 brush->blendpos = new_blendpos;
1396 return Ok;
1399 GpStatus WINGDIPAPI GdipGetLineBlend(GpLineGradient *brush, REAL *factors,
1400 REAL *positions, INT count)
1402 TRACE("(%p, %p, %p, %i)\n", brush, factors, positions, count);
1404 if (!brush || !factors || !positions || count <= 0 || brush->brush.bt != BrushTypeLinearGradient)
1405 return InvalidParameter;
1407 if (count < brush->blendcount)
1408 return InsufficientBuffer;
1410 memcpy(factors, brush->blendfac, brush->blendcount * sizeof(REAL));
1411 memcpy(positions, brush->blendpos, brush->blendcount * sizeof(REAL));
1413 return Ok;
1416 GpStatus WINGDIPAPI GdipGetLineBlendCount(GpLineGradient *brush, INT *count)
1418 TRACE("(%p, %p)\n", brush, count);
1420 if (!brush || !count || brush->brush.bt != BrushTypeLinearGradient)
1421 return InvalidParameter;
1423 *count = brush->blendcount;
1425 return Ok;
1428 GpStatus WINGDIPAPI GdipSetLineGammaCorrection(GpLineGradient *line,
1429 BOOL usegamma)
1431 TRACE("(%p, %d)\n", line, usegamma);
1433 if(!line || line->brush.bt != BrushTypeLinearGradient)
1434 return InvalidParameter;
1436 line->gamma = usegamma;
1438 return Ok;
1441 GpStatus WINGDIPAPI GdipSetLineSigmaBlend(GpLineGradient *line, REAL focus,
1442 REAL scale)
1444 REAL factors[33];
1445 REAL positions[33];
1446 int num_points = 0;
1447 int i;
1448 const int precision = 16;
1449 REAL erf_range; /* we use values erf(-erf_range) through erf(+erf_range) */
1450 REAL min_erf;
1451 REAL scale_erf;
1453 TRACE("(%p, %0.2f, %0.2f)\n", line, focus, scale);
1455 if(!line || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0 || line->brush.bt != BrushTypeLinearGradient)
1456 return InvalidParameter;
1458 /* we want 2 standard deviations */
1459 erf_range = 2.0 / sqrt(2);
1461 /* calculate the constants we need to normalize the error function to be
1462 between 0.0 and scale over the range we need */
1463 min_erf = erf(-erf_range);
1464 scale_erf = scale / (-2.0 * min_erf);
1466 if (focus != 0.0)
1468 positions[0] = 0.0;
1469 factors[0] = 0.0;
1470 for (i=1; i<precision; i++)
1472 positions[i] = focus * i / precision;
1473 factors[i] = scale_erf * (erf(2 * erf_range * i / precision - erf_range) - min_erf);
1475 num_points += precision;
1478 positions[num_points] = focus;
1479 factors[num_points] = scale;
1480 num_points += 1;
1482 if (focus != 1.0)
1484 for (i=1; i<precision; i++)
1486 positions[i+num_points-1] = (focus + ((1.0-focus) * i / precision));
1487 factors[i+num_points-1] = scale_erf * (erf(erf_range - 2 * erf_range * i / precision) - min_erf);
1489 num_points += precision;
1490 positions[num_points-1] = 1.0;
1491 factors[num_points-1] = 0.0;
1494 return GdipSetLineBlend(line, factors, positions, num_points);
1497 GpStatus WINGDIPAPI GdipSetLineWrapMode(GpLineGradient *line,
1498 GpWrapMode wrap)
1500 TRACE("(%p, %d)\n", line, wrap);
1502 if(!line || wrap == WrapModeClamp || line->brush.bt != BrushTypeLinearGradient)
1503 return InvalidParameter;
1505 line->wrap = wrap;
1507 return Ok;
1510 GpStatus WINGDIPAPI GdipSetPathGradientBlend(GpPathGradient *brush, GDIPCONST REAL *blend,
1511 GDIPCONST REAL *pos, INT count)
1513 REAL *new_blendfac, *new_blendpos;
1515 TRACE("(%p,%p,%p,%i)\n", brush, blend, pos, count);
1517 if(!brush || !blend || !pos || count <= 0 || brush->brush.bt != BrushTypePathGradient ||
1518 (count >= 2 && (pos[0] != 0.0f || pos[count-1] != 1.0f)))
1519 return InvalidParameter;
1521 new_blendfac = heap_alloc_zero(count * sizeof(REAL));
1522 new_blendpos = heap_alloc_zero(count * sizeof(REAL));
1524 if (!new_blendfac || !new_blendpos)
1526 heap_free(new_blendfac);
1527 heap_free(new_blendpos);
1528 return OutOfMemory;
1531 memcpy(new_blendfac, blend, count * sizeof(REAL));
1532 memcpy(new_blendpos, pos, count * sizeof(REAL));
1534 heap_free(brush->blendfac);
1535 heap_free(brush->blendpos);
1537 brush->blendcount = count;
1538 brush->blendfac = new_blendfac;
1539 brush->blendpos = new_blendpos;
1541 return Ok;
1544 GpStatus WINGDIPAPI GdipSetPathGradientLinearBlend(GpPathGradient *brush,
1545 REAL focus, REAL scale)
1547 REAL factors[3];
1548 REAL positions[3];
1549 int num_points = 0;
1551 TRACE("(%p,%0.2f,%0.2f)\n", brush, focus, scale);
1553 if (!brush || brush->brush.bt != BrushTypePathGradient)
1554 return InvalidParameter;
1556 if (focus != 0.0)
1558 factors[num_points] = 0.0;
1559 positions[num_points] = 0.0;
1560 num_points++;
1563 factors[num_points] = scale;
1564 positions[num_points] = focus;
1565 num_points++;
1567 if (focus != 1.0)
1569 factors[num_points] = 0.0;
1570 positions[num_points] = 1.0;
1571 num_points++;
1574 return GdipSetPathGradientBlend(brush, factors, positions, num_points);
1577 GpStatus WINGDIPAPI GdipSetPathGradientPresetBlend(GpPathGradient *brush,
1578 GDIPCONST ARGB *blend, GDIPCONST REAL *pos, INT count)
1580 ARGB *new_color;
1581 REAL *new_pos;
1582 TRACE("(%p,%p,%p,%i)\n", brush, blend, pos, count);
1584 if (!brush || !blend || !pos || count < 2 || brush->brush.bt != BrushTypePathGradient ||
1585 pos[0] != 0.0f || pos[count-1] != 1.0f)
1587 return InvalidParameter;
1590 new_color = heap_alloc_zero(count * sizeof(ARGB));
1591 new_pos = heap_alloc_zero(count * sizeof(REAL));
1592 if (!new_color || !new_pos)
1594 heap_free(new_color);
1595 heap_free(new_pos);
1596 return OutOfMemory;
1599 memcpy(new_color, blend, sizeof(ARGB) * count);
1600 memcpy(new_pos, pos, sizeof(REAL) * count);
1602 heap_free(brush->pblendcolor);
1603 heap_free(brush->pblendpos);
1605 brush->pblendcolor = new_color;
1606 brush->pblendpos = new_pos;
1607 brush->pblendcount = count;
1609 return Ok;
1612 GpStatus WINGDIPAPI GdipGetPathGradientPresetBlend(GpPathGradient *brush,
1613 ARGB *blend, REAL *pos, INT count)
1615 TRACE("(%p,%p,%p,%i)\n", brush, blend, pos, count);
1617 if (count < 0)
1618 return OutOfMemory;
1620 if (!brush || !blend || !pos || count < 2 || brush->brush.bt != BrushTypePathGradient)
1621 return InvalidParameter;
1623 if (brush->pblendcount == 0)
1624 return GenericError;
1626 if (count != brush->pblendcount)
1628 /* Native lines up the ends of each array, and copies the destination size. */
1629 FIXME("Braindead behavior on wrong-sized buffer not implemented.\n");
1630 return InvalidParameter;
1633 memcpy(blend, brush->pblendcolor, sizeof(ARGB) * brush->pblendcount);
1634 memcpy(pos, brush->pblendpos, sizeof(REAL) * brush->pblendcount);
1636 return Ok;
1639 GpStatus WINGDIPAPI GdipGetPathGradientPresetBlendCount(GpPathGradient *brush,
1640 INT *count)
1642 TRACE("(%p,%p)\n", brush, count);
1644 if (!brush || !count || brush->brush.bt != BrushTypePathGradient)
1645 return InvalidParameter;
1647 *count = brush->pblendcount;
1649 return Ok;
1652 GpStatus WINGDIPAPI GdipSetPathGradientCenterColor(GpPathGradient *grad,
1653 ARGB argb)
1655 TRACE("(%p, %lx)\n", grad, argb);
1657 if(!grad || grad->brush.bt != BrushTypePathGradient)
1658 return InvalidParameter;
1660 grad->centercolor = argb;
1661 return Ok;
1664 GpStatus WINGDIPAPI GdipSetPathGradientCenterPoint(GpPathGradient *grad,
1665 GpPointF *point)
1667 TRACE("(%p, %s)\n", grad, debugstr_pointf(point));
1669 if(!grad || !point || grad->brush.bt != BrushTypePathGradient)
1670 return InvalidParameter;
1672 grad->center.X = point->X;
1673 grad->center.Y = point->Y;
1675 return Ok;
1678 GpStatus WINGDIPAPI GdipSetPathGradientCenterPointI(GpPathGradient *grad,
1679 GpPoint *point)
1681 GpPointF ptf;
1683 TRACE("(%p, %p)\n", grad, point);
1685 if(!point)
1686 return InvalidParameter;
1688 ptf.X = (REAL)point->X;
1689 ptf.Y = (REAL)point->Y;
1691 return GdipSetPathGradientCenterPoint(grad,&ptf);
1694 GpStatus WINGDIPAPI GdipSetPathGradientFocusScales(GpPathGradient *grad,
1695 REAL x, REAL y)
1697 TRACE("(%p, %.2f, %.2f)\n", grad, x, y);
1699 if(!grad || grad->brush.bt != BrushTypePathGradient)
1700 return InvalidParameter;
1702 grad->focus.X = x;
1703 grad->focus.Y = y;
1705 return Ok;
1708 GpStatus WINGDIPAPI GdipSetPathGradientGammaCorrection(GpPathGradient *grad,
1709 BOOL gamma)
1711 TRACE("(%p, %d)\n", grad, gamma);
1713 if(!grad || grad->brush.bt != BrushTypePathGradient)
1714 return InvalidParameter;
1716 grad->gamma = gamma;
1718 return Ok;
1721 GpStatus WINGDIPAPI GdipSetPathGradientPath(GpPathGradient *grad, GDIPCONST GpPath *path)
1723 static int calls;
1725 TRACE("(%p, %p)\n", grad, path);
1727 if (!(calls++))
1728 FIXME("not implemented\n");
1730 return NotImplemented;
1733 GpStatus WINGDIPAPI GdipSetPathGradientSigmaBlend(GpPathGradient *grad,
1734 REAL focus, REAL scale)
1736 REAL factors[33];
1737 REAL positions[33];
1738 int num_points = 0;
1739 int i;
1740 const int precision = 16;
1741 REAL erf_range; /* we use values erf(-erf_range) through erf(+erf_range) */
1742 REAL min_erf;
1743 REAL scale_erf;
1745 TRACE("(%p,%0.2f,%0.2f)\n", grad, focus, scale);
1747 if(!grad || focus < 0.0 || focus > 1.0 || scale < 0.0 || scale > 1.0 || grad->brush.bt != BrushTypePathGradient)
1748 return InvalidParameter;
1750 /* we want 2 standard deviations */
1751 erf_range = 2.0 / sqrt(2);
1753 /* calculate the constants we need to normalize the error function to be
1754 between 0.0 and scale over the range we need */
1755 min_erf = erf(-erf_range);
1756 scale_erf = scale / (-2.0 * min_erf);
1758 if (focus != 0.0)
1760 positions[0] = 0.0;
1761 factors[0] = 0.0;
1762 for (i=1; i<precision; i++)
1764 positions[i] = focus * i / precision;
1765 factors[i] = scale_erf * (erf(2 * erf_range * i / precision - erf_range) - min_erf);
1767 num_points += precision;
1770 positions[num_points] = focus;
1771 factors[num_points] = scale;
1772 num_points += 1;
1774 if (focus != 1.0)
1776 for (i=1; i<precision; i++)
1778 positions[i+num_points-1] = (focus + ((1.0-focus) * i / precision));
1779 factors[i+num_points-1] = scale_erf * (erf(erf_range - 2 * erf_range * i / precision) - min_erf);
1781 num_points += precision;
1782 positions[num_points-1] = 1.0;
1783 factors[num_points-1] = 0.0;
1786 return GdipSetPathGradientBlend(grad, factors, positions, num_points);
1789 GpStatus WINGDIPAPI GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
1790 *grad, GDIPCONST ARGB *argb, INT *count)
1792 ARGB *new_surroundcolors;
1793 INT i, num_colors;
1795 TRACE("(%p,%p,%p)\n", grad, argb, count);
1797 if(!grad || !argb || !count || (*count <= 0) || grad->brush.bt != BrushTypePathGradient ||
1798 (*count > grad->path->pathdata.Count))
1799 return InvalidParameter;
1801 num_colors = *count;
1803 /* If all colors are the same, only store 1 color. */
1804 if (*count > 1)
1806 for (i=1; i < num_colors; i++)
1807 if (argb[i] != argb[i-1])
1808 break;
1810 if (i == num_colors)
1811 num_colors = 1;
1814 new_surroundcolors = heap_alloc_zero(num_colors * sizeof(ARGB));
1815 if (!new_surroundcolors)
1816 return OutOfMemory;
1818 memcpy(new_surroundcolors, argb, num_colors * sizeof(ARGB));
1820 heap_free(grad->surroundcolors);
1822 grad->surroundcolors = new_surroundcolors;
1823 grad->surroundcolorcount = num_colors;
1825 return Ok;
1828 GpStatus WINGDIPAPI GdipSetPathGradientWrapMode(GpPathGradient *grad,
1829 GpWrapMode wrap)
1831 TRACE("(%p, %d)\n", grad, wrap);
1833 if(!grad || grad->brush.bt != BrushTypePathGradient)
1834 return InvalidParameter;
1836 grad->wrap = wrap;
1838 return Ok;
1841 GpStatus WINGDIPAPI GdipSetPathGradientTransform(GpPathGradient *grad,
1842 GpMatrix *matrix)
1844 TRACE("(%p,%s)\n", grad, debugstr_matrix(matrix));
1846 if (!grad || !matrix || grad->brush.bt != BrushTypePathGradient)
1847 return InvalidParameter;
1849 grad->transform = *matrix;
1851 return Ok;
1854 GpStatus WINGDIPAPI GdipGetPathGradientTransform(GpPathGradient *grad,
1855 GpMatrix *matrix)
1857 TRACE("(%p,%s)\n", grad, debugstr_matrix(matrix));
1859 if (!grad || !matrix || grad->brush.bt != BrushTypePathGradient)
1860 return InvalidParameter;
1862 *matrix = grad->transform;
1864 return Ok;
1867 GpStatus WINGDIPAPI GdipMultiplyPathGradientTransform(GpPathGradient *grad,
1868 GDIPCONST GpMatrix *matrix, GpMatrixOrder order)
1870 TRACE("(%p,%s,%i)\n", grad, debugstr_matrix(matrix), order);
1872 if (!grad || grad->brush.bt != BrushTypePathGradient)
1873 return InvalidParameter;
1875 return GdipMultiplyMatrix(&grad->transform, matrix, order);
1878 GpStatus WINGDIPAPI GdipResetPathGradientTransform(GpPathGradient *grad)
1880 TRACE("(%p)\n", grad);
1882 if (!grad || grad->brush.bt != BrushTypePathGradient)
1883 return InvalidParameter;
1885 return GdipSetMatrixElements(&grad->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
1888 GpStatus WINGDIPAPI GdipRotatePathGradientTransform(GpPathGradient *grad,
1889 REAL angle, GpMatrixOrder order)
1891 TRACE("(%p,%0.2f,%i)\n", grad, angle, order);
1893 if (!grad || grad->brush.bt != BrushTypePathGradient)
1894 return InvalidParameter;
1896 return GdipRotateMatrix(&grad->transform, angle, order);
1899 GpStatus WINGDIPAPI GdipScalePathGradientTransform(GpPathGradient *grad,
1900 REAL sx, REAL sy, GpMatrixOrder order)
1902 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad, sx, sy, order);
1904 if (!grad || grad->brush.bt != BrushTypePathGradient)
1905 return InvalidParameter;
1907 return GdipScaleMatrix(&grad->transform, sx, sy, order);
1910 GpStatus WINGDIPAPI GdipTranslatePathGradientTransform(GpPathGradient *grad,
1911 REAL dx, REAL dy, GpMatrixOrder order)
1913 TRACE("(%p,%0.2f,%0.2f,%i)\n", grad, dx, dy, order);
1915 if (!grad || grad->brush.bt != BrushTypePathGradient)
1916 return InvalidParameter;
1918 return GdipTranslateMatrix(&grad->transform, dx, dy, order);
1921 GpStatus WINGDIPAPI GdipSetSolidFillColor(GpSolidFill *sf, ARGB argb)
1923 TRACE("(%p, %lx)\n", sf, argb);
1925 if(!sf)
1926 return InvalidParameter;
1928 sf->color = argb;
1929 return Ok;
1932 /******************************************************************************
1933 * GdipSetTextureTransform [GDIPLUS.@]
1935 GpStatus WINGDIPAPI GdipSetTextureTransform(GpTexture *texture,
1936 GDIPCONST GpMatrix *matrix)
1938 TRACE("(%p, %s)\n", texture, debugstr_matrix(matrix));
1940 if(!texture || !matrix)
1941 return InvalidParameter;
1943 texture->transform = *matrix;
1945 return Ok;
1948 /******************************************************************************
1949 * GdipSetTextureWrapMode [GDIPLUS.@]
1951 * WrapMode not used, only stored
1953 GpStatus WINGDIPAPI GdipSetTextureWrapMode(GpTexture *brush, GpWrapMode wrapmode)
1955 TRACE("(%p, %d)\n", brush, wrapmode);
1957 if(!brush)
1958 return InvalidParameter;
1960 brush->imageattributes->wrap = wrapmode;
1962 return Ok;
1965 GpStatus WINGDIPAPI GdipSetLineColors(GpLineGradient *brush, ARGB color1,
1966 ARGB color2)
1968 TRACE("(%p, %lx, %lx)\n", brush, color1, color2);
1970 if(!brush || brush->brush.bt != BrushTypeLinearGradient)
1971 return InvalidParameter;
1973 brush->startcolor = color1;
1974 brush->endcolor = color2;
1976 return Ok;
1979 GpStatus WINGDIPAPI GdipGetLineColors(GpLineGradient *brush, ARGB *colors)
1981 TRACE("(%p, %p)\n", brush, colors);
1983 if(!brush || !colors || brush->brush.bt != BrushTypeLinearGradient)
1984 return InvalidParameter;
1986 colors[0] = brush->startcolor;
1987 colors[1] = brush->endcolor;
1989 return Ok;
1992 /******************************************************************************
1993 * GdipRotateTextureTransform [GDIPLUS.@]
1995 GpStatus WINGDIPAPI GdipRotateTextureTransform(GpTexture* brush, REAL angle,
1996 GpMatrixOrder order)
1998 TRACE("(%p, %.2f, %d)\n", brush, angle, order);
2000 if(!brush)
2001 return InvalidParameter;
2003 return GdipRotateMatrix(&brush->transform, angle, order);
2006 GpStatus WINGDIPAPI GdipSetLineLinearBlend(GpLineGradient *brush, REAL focus,
2007 REAL scale)
2009 REAL factors[3];
2010 REAL positions[3];
2011 int num_points = 0;
2013 TRACE("(%p,%.2f,%.2f)\n", brush, focus, scale);
2015 if (!brush) return InvalidParameter;
2017 if (focus != 0.0)
2019 factors[num_points] = 0.0;
2020 positions[num_points] = 0.0;
2021 num_points++;
2024 factors[num_points] = scale;
2025 positions[num_points] = focus;
2026 num_points++;
2028 if (focus != 1.0)
2030 factors[num_points] = 0.0;
2031 positions[num_points] = 1.0;
2032 num_points++;
2035 return GdipSetLineBlend(brush, factors, positions, num_points);
2038 GpStatus WINGDIPAPI GdipSetLinePresetBlend(GpLineGradient *brush,
2039 GDIPCONST ARGB *blend, GDIPCONST REAL* positions, INT count)
2041 ARGB *new_color;
2042 REAL *new_pos;
2043 TRACE("(%p,%p,%p,%i)\n", brush, blend, positions, count);
2045 if (!brush || !blend || !positions || count < 2 || brush->brush.bt != BrushTypeLinearGradient ||
2046 positions[0] != 0.0f || positions[count-1] != 1.0f)
2048 return InvalidParameter;
2051 new_color = heap_alloc_zero(count * sizeof(ARGB));
2052 new_pos = heap_alloc_zero(count * sizeof(REAL));
2053 if (!new_color || !new_pos)
2055 heap_free(new_color);
2056 heap_free(new_pos);
2057 return OutOfMemory;
2060 memcpy(new_color, blend, sizeof(ARGB) * count);
2061 memcpy(new_pos, positions, sizeof(REAL) * count);
2063 heap_free(brush->pblendcolor);
2064 heap_free(brush->pblendpos);
2066 brush->pblendcolor = new_color;
2067 brush->pblendpos = new_pos;
2068 brush->pblendcount = count;
2070 return Ok;
2073 GpStatus WINGDIPAPI GdipGetLinePresetBlend(GpLineGradient *brush,
2074 ARGB *blend, REAL* positions, INT count)
2076 if (!brush || !blend || !positions || count < 2 || brush->brush.bt != BrushTypeLinearGradient)
2077 return InvalidParameter;
2079 if (brush->pblendcount == 0)
2080 return GenericError;
2082 if (count < brush->pblendcount)
2083 return InsufficientBuffer;
2085 memcpy(blend, brush->pblendcolor, sizeof(ARGB) * brush->pblendcount);
2086 memcpy(positions, brush->pblendpos, sizeof(REAL) * brush->pblendcount);
2088 return Ok;
2091 GpStatus WINGDIPAPI GdipGetLinePresetBlendCount(GpLineGradient *brush,
2092 INT *count)
2094 if (!brush || !count || brush->brush.bt != BrushTypeLinearGradient)
2095 return InvalidParameter;
2097 *count = brush->pblendcount;
2099 return Ok;
2102 GpStatus WINGDIPAPI GdipResetLineTransform(GpLineGradient *brush)
2104 TRACE("(%p)\n", brush);
2106 if(!brush)
2107 return InvalidParameter;
2109 return GdipSetMatrixElements(&brush->transform, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
2112 GpStatus WINGDIPAPI GdipSetLineTransform(GpLineGradient *brush,
2113 GDIPCONST GpMatrix *matrix)
2115 TRACE("(%p,%s)\n", brush, debugstr_matrix(matrix));
2117 if(!brush || !matrix)
2118 return InvalidParameter;
2120 brush->transform = *matrix;
2122 return Ok;
2125 GpStatus WINGDIPAPI GdipGetLineTransform(GpLineGradient *brush, GpMatrix *matrix)
2127 TRACE("(%p,%s)\n", brush, debugstr_matrix(matrix));
2129 if(!brush || !matrix)
2130 return InvalidParameter;
2132 *matrix = brush->transform;
2134 return Ok;
2137 GpStatus WINGDIPAPI GdipScaleLineTransform(GpLineGradient *brush, REAL sx, REAL sy,
2138 GpMatrixOrder order)
2140 TRACE("(%p,%0.2f,%0.2f,%u)\n", brush, sx, sy, order);
2142 if(!brush)
2143 return InvalidParameter;
2145 return GdipScaleMatrix(&brush->transform, sx, sy, order);
2148 GpStatus WINGDIPAPI GdipMultiplyLineTransform(GpLineGradient *brush,
2149 GDIPCONST GpMatrix *matrix, GpMatrixOrder order)
2151 TRACE("(%p,%s,%u)\n", brush, debugstr_matrix(matrix), order);
2153 if(!brush)
2154 return InvalidParameter;
2156 if(!matrix)
2157 return Ok;
2159 return GdipMultiplyMatrix(&brush->transform, matrix, order);
2162 GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient *brush,
2163 REAL dx, REAL dy, GpMatrixOrder order)
2165 TRACE("(%p,%f,%f,%d)\n", brush, dx, dy, order);
2167 if(!brush)
2168 return InvalidParameter;
2170 return GdipTranslateMatrix(&brush->transform, dx, dy, order);
2173 /******************************************************************************
2174 * GdipTranslateTextureTransform [GDIPLUS.@]
2176 GpStatus WINGDIPAPI GdipTranslateTextureTransform(GpTexture* brush, REAL dx, REAL dy,
2177 GpMatrixOrder order)
2179 TRACE("(%p, %.2f, %.2f, %d)\n", brush, dx, dy, order);
2181 if(!brush)
2182 return InvalidParameter;
2184 return GdipTranslateMatrix(&brush->transform, dx, dy, order);
2187 GpStatus WINGDIPAPI GdipGetLineRect(GpLineGradient *brush, GpRectF *rect)
2189 TRACE("(%p, %p)\n", brush, rect);
2191 if(!brush || !rect || brush->brush.bt != BrushTypeLinearGradient)
2192 return InvalidParameter;
2194 *rect = brush->rect;
2196 return Ok;
2199 GpStatus WINGDIPAPI GdipGetLineRectI(GpLineGradient *brush, GpRect *rect)
2201 GpRectF rectF;
2202 GpStatus ret;
2204 TRACE("(%p, %p)\n", brush, rect);
2206 if(!rect)
2207 return InvalidParameter;
2209 ret = GdipGetLineRect(brush, &rectF);
2211 if(ret == Ok){
2212 rect->X = gdip_round(rectF.X);
2213 rect->Y = gdip_round(rectF.Y);
2214 rect->Width = gdip_round(rectF.Width);
2215 rect->Height = gdip_round(rectF.Height);
2218 return ret;
2221 GpStatus WINGDIPAPI GdipRotateLineTransform(GpLineGradient* brush,
2222 REAL angle, GpMatrixOrder order)
2224 static int calls;
2226 TRACE("(%p,%0.2f,%u)\n", brush, angle, order);
2228 if(!brush || brush->brush.bt != BrushTypeLinearGradient)
2229 return InvalidParameter;
2231 if(!(calls++))
2232 FIXME("(%p, %.2f, %d) stub\n", brush, angle, order);
2234 return NotImplemented;