2 * Copyright (C) 2007 Google (Evan Stade)
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32 #include "gdiplus_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus
);
37 GpStatus WINGDIPAPI
GdipCloneBrush(GpBrush
*brush
, GpBrush
**clone
)
40 return InvalidParameter
;
43 case BrushTypeSolidColor
:
44 *clone
= GdipAlloc(sizeof(GpSolidFill
));
45 if (!*clone
) return OutOfMemory
;
47 memcpy(*clone
, brush
, sizeof(GpSolidFill
));
49 (*clone
)->gdibrush
= CreateBrushIndirect(&(*clone
)->lb
);
51 case BrushTypePathGradient
:{
52 GpPathGradient
*src
, *dest
;
55 *clone
= GdipAlloc(sizeof(GpPathGradient
));
56 if (!*clone
) return OutOfMemory
;
58 src
= (GpPathGradient
*) brush
,
59 dest
= (GpPathGradient
*) *clone
;
60 count
= src
->pathdata
.Count
;
62 memcpy(dest
, src
, sizeof(GpPathGradient
));
64 dest
->pathdata
.Count
= count
;
65 dest
->pathdata
.Points
= GdipAlloc(count
* sizeof(PointF
));
66 dest
->pathdata
.Types
= GdipAlloc(count
);
68 if(!dest
->pathdata
.Points
|| !dest
->pathdata
.Types
){
69 GdipFree(dest
->pathdata
.Points
);
70 GdipFree(dest
->pathdata
.Types
);
75 memcpy(dest
->pathdata
.Points
, src
->pathdata
.Points
, count
* sizeof(PointF
));
76 memcpy(dest
->pathdata
.Types
, src
->pathdata
.Types
, count
);
80 case BrushTypeLinearGradient
:
81 *clone
= GdipAlloc(sizeof(GpLineGradient
));
82 if(!*clone
) return OutOfMemory
;
84 memcpy(*clone
, brush
, sizeof(GpLineGradient
));
86 (*clone
)->gdibrush
= CreateSolidBrush((*clone
)->lb
.lbColor
);
88 case BrushTypeTextureFill
:
89 *clone
= GdipAlloc(sizeof(GpTexture
));
90 if(!*clone
) return OutOfMemory
;
92 memcpy(*clone
, brush
, sizeof(GpTexture
));
94 (*clone
)->gdibrush
= CreateBrushIndirect(&(*clone
)->lb
);
97 ERR("not implemented for brush type %d\n", brush
->bt
);
98 return NotImplemented
;
104 GpStatus WINGDIPAPI
GdipCreateLineBrush(GDIPCONST GpPointF
* startpoint
,
105 GDIPCONST GpPointF
* endpoint
, ARGB startcolor
, ARGB endcolor
,
106 GpWrapMode wrap
, GpLineGradient
**line
)
108 COLORREF col
= ARGB2COLORREF(startcolor
);
110 if(!line
|| !startpoint
|| !endpoint
|| wrap
== WrapModeClamp
)
111 return InvalidParameter
;
113 *line
= GdipAlloc(sizeof(GpLineGradient
));
114 if(!*line
) return OutOfMemory
;
116 (*line
)->brush
.lb
.lbStyle
= BS_SOLID
;
117 (*line
)->brush
.lb
.lbColor
= col
;
118 (*line
)->brush
.lb
.lbHatch
= 0;
119 (*line
)->brush
.gdibrush
= CreateSolidBrush(col
);
120 (*line
)->brush
.bt
= BrushTypeLinearGradient
;
122 (*line
)->startpoint
.X
= startpoint
->X
;
123 (*line
)->startpoint
.Y
= startpoint
->Y
;
124 (*line
)->endpoint
.X
= endpoint
->X
;
125 (*line
)->endpoint
.Y
= endpoint
->Y
;
126 (*line
)->startcolor
= startcolor
;
127 (*line
)->endcolor
= endcolor
;
128 (*line
)->wrap
= wrap
;
129 (*line
)->gamma
= FALSE
;
134 GpStatus WINGDIPAPI
GdipCreateLineBrushFromRectI(GDIPCONST GpRect
* rect
,
135 ARGB startcolor
, ARGB endcolor
, LinearGradientMode mode
, GpWrapMode wrap
,
136 GpLineGradient
**line
)
141 return InvalidParameter
;
143 start
.X
= (REAL
) rect
->X
;
144 start
.Y
= (REAL
) rect
->Y
;
145 end
.X
= (REAL
) (rect
->X
+ rect
->Width
);
146 end
.Y
= (REAL
) (rect
->Y
+ rect
->Height
);
148 return GdipCreateLineBrush(&start
, &end
, startcolor
, endcolor
, wrap
, line
);
151 GpStatus WINGDIPAPI
GdipCreatePathGradient(GDIPCONST GpPointF
* points
,
152 INT count
, GpWrapMode wrap
, GpPathGradient
**grad
)
154 COLORREF col
= ARGB2COLORREF(0xffffffff);
157 return InvalidParameter
;
162 *grad
= GdipAlloc(sizeof(GpPathGradient
));
163 if (!*grad
) return OutOfMemory
;
165 (*grad
)->pathdata
.Count
= count
;
166 (*grad
)->pathdata
.Points
= GdipAlloc(count
* sizeof(PointF
));
167 (*grad
)->pathdata
.Types
= GdipAlloc(count
);
169 if(!(*grad
)->pathdata
.Points
|| !(*grad
)->pathdata
.Types
){
170 GdipFree((*grad
)->pathdata
.Points
);
171 GdipFree((*grad
)->pathdata
.Types
);
176 memcpy((*grad
)->pathdata
.Points
, points
, count
* sizeof(PointF
));
177 memset((*grad
)->pathdata
.Types
, PathPointTypeLine
, count
);
179 (*grad
)->brush
.lb
.lbStyle
= BS_SOLID
;
180 (*grad
)->brush
.lb
.lbColor
= col
;
181 (*grad
)->brush
.lb
.lbHatch
= 0;
183 (*grad
)->brush
.gdibrush
= CreateSolidBrush(col
);
184 (*grad
)->brush
.bt
= BrushTypePathGradient
;
185 (*grad
)->centercolor
= 0xffffffff;
186 (*grad
)->wrap
= wrap
;
187 (*grad
)->gamma
= FALSE
;
188 (*grad
)->center
.X
= 0.0;
189 (*grad
)->center
.Y
= 0.0;
190 (*grad
)->focus
.X
= 0.0;
191 (*grad
)->focus
.Y
= 0.0;
196 /* FIXME: path gradient brushes not truly supported (drawn as solid brushes) */
197 GpStatus WINGDIPAPI
GdipCreatePathGradientFromPath(GDIPCONST GpPath
* path
,
198 GpPathGradient
**grad
)
200 COLORREF col
= ARGB2COLORREF(0xffffffff);
203 return InvalidParameter
;
205 *grad
= GdipAlloc(sizeof(GpPathGradient
));
206 if (!*grad
) return OutOfMemory
;
208 (*grad
)->pathdata
.Count
= path
->pathdata
.Count
;
209 (*grad
)->pathdata
.Points
= GdipAlloc(path
->pathdata
.Count
* sizeof(PointF
));
210 (*grad
)->pathdata
.Types
= GdipAlloc(path
->pathdata
.Count
);
212 if(!(*grad
)->pathdata
.Points
|| !(*grad
)->pathdata
.Types
){
213 GdipFree((*grad
)->pathdata
.Points
);
214 GdipFree((*grad
)->pathdata
.Types
);
219 memcpy((*grad
)->pathdata
.Points
, path
->pathdata
.Points
,
220 path
->pathdata
.Count
* sizeof(PointF
));
221 memcpy((*grad
)->pathdata
.Types
, path
->pathdata
.Types
, path
->pathdata
.Count
);
223 (*grad
)->brush
.lb
.lbStyle
= BS_SOLID
;
224 (*grad
)->brush
.lb
.lbColor
= col
;
225 (*grad
)->brush
.lb
.lbHatch
= 0;
227 (*grad
)->brush
.gdibrush
= CreateSolidBrush(col
);
228 (*grad
)->brush
.bt
= BrushTypePathGradient
;
229 (*grad
)->centercolor
= 0xffffffff;
230 (*grad
)->wrap
= WrapModeClamp
;
231 (*grad
)->gamma
= FALSE
;
232 /* FIXME: this should be set to the "centroid" of the path by default */
233 (*grad
)->center
.X
= 0.0;
234 (*grad
)->center
.Y
= 0.0;
235 (*grad
)->focus
.X
= 0.0;
236 (*grad
)->focus
.Y
= 0.0;
241 GpStatus WINGDIPAPI
GdipCreateSolidFill(ARGB color
, GpSolidFill
**sf
)
243 COLORREF col
= ARGB2COLORREF(color
);
245 if(!sf
) return InvalidParameter
;
247 *sf
= GdipAlloc(sizeof(GpSolidFill
));
248 if (!*sf
) return OutOfMemory
;
250 (*sf
)->brush
.lb
.lbStyle
= BS_SOLID
;
251 (*sf
)->brush
.lb
.lbColor
= col
;
252 (*sf
)->brush
.lb
.lbHatch
= 0;
254 (*sf
)->brush
.gdibrush
= CreateSolidBrush(col
);
255 (*sf
)->brush
.bt
= BrushTypeSolidColor
;
256 (*sf
)->color
= color
;
261 /* FIXME: imageattr ignored */
262 GpStatus WINGDIPAPI
GdipCreateTextureIA(GpImage
*image
,
263 GDIPCONST GpImageAttributes
*imageattr
, REAL x
, REAL y
, REAL width
,
264 REAL height
, GpTexture
**texture
)
270 BITMAPINFOHEADER
*bmih
;
271 INT n_x
, n_y
, n_width
, n_height
, abs_height
, stride
, image_stride
, i
, bytespp
;
273 BYTE
*dibits
, *buff
, *textbits
;
275 if(!image
|| !texture
|| x
< 0.0 || y
< 0.0 || width
< 0.0 || height
< 0.0)
276 return InvalidParameter
;
278 if(image
->type
!= ImageTypeBitmap
){
279 FIXME("not implemented for image type %d\n", image
->type
);
280 return NotImplemented
;
285 n_width
= roundr(width
);
286 n_height
= roundr(height
);
288 if(n_x
+ n_width
> ((GpBitmap
*)image
)->width
||
289 n_y
+ n_height
> ((GpBitmap
*)image
)->height
)
290 return InvalidParameter
;
292 IPicture_get_Handle(image
->picture
, &hbm
);
293 if(!hbm
) return GenericError
;
294 IPicture_get_CurDC(image
->picture
, &hdc
);
295 bm_is_selected
= (hdc
!= 0);
297 bmi
.bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
298 bmi
.bmiHeader
.biBitCount
= 0;
301 hdc
= CreateCompatibleDC(0);
302 old
= SelectObject(hdc
, (HBITMAP
)hbm
);
306 GetDIBits(hdc
, (HBITMAP
)hbm
, 0, 0, NULL
, &bmi
, DIB_RGB_COLORS
);
308 bytespp
= bmi
.bmiHeader
.biBitCount
/ 8;
309 abs_height
= abs(bmi
.bmiHeader
.biHeight
);
311 if(n_x
> bmi
.bmiHeader
.biWidth
|| n_x
+ n_width
> bmi
.bmiHeader
.biWidth
||
312 n_y
> abs_height
|| n_y
+ n_height
> abs_height
)
313 return InvalidParameter
;
315 dibits
= GdipAlloc(bmi
.bmiHeader
.biSizeImage
);
317 if(dibits
) /* this is not a good place to error out */
318 GetDIBits(hdc
, (HBITMAP
)hbm
, 0, abs_height
, dibits
, &bmi
, DIB_RGB_COLORS
);
321 SelectObject(hdc
, old
);
328 image_stride
= (bmi
.bmiHeader
.biWidth
* bytespp
+ 3) & ~3;
329 stride
= (n_width
* bytespp
+ 3) & ~3;
330 buff
= GdipAlloc(sizeof(BITMAPINFOHEADER
) + stride
* n_height
);
336 bmih
= (BITMAPINFOHEADER
*)buff
;
337 textbits
= (BYTE
*) (bmih
+ 1);
338 bmih
->biSize
= sizeof(BITMAPINFOHEADER
);
339 bmih
->biWidth
= n_width
;
340 bmih
->biHeight
= n_height
;
341 bmih
->biCompression
= BI_RGB
;
342 bmih
->biSizeImage
= stride
* n_height
;
343 bmih
->biBitCount
= bmi
.bmiHeader
.biBitCount
;
347 /* image is flipped */
348 if(bmi
.bmiHeader
.biHeight
> 0){
349 dibits
+= bmi
.bmiHeader
.biSizeImage
;
351 textbits
+= stride
* (n_height
- 1);
355 for(i
= 0; i
< n_height
; i
++)
356 memcpy(&textbits
[i
* stride
],
357 &dibits
[n_x
* bytespp
+ (n_y
+ i
) * image_stride
],
360 *texture
= GdipAlloc(sizeof(GpTexture
));
361 if (!*texture
) return OutOfMemory
;
363 (*texture
)->brush
.lb
.lbStyle
= BS_DIBPATTERNPT
;
364 (*texture
)->brush
.lb
.lbColor
= DIB_RGB_COLORS
;
365 (*texture
)->brush
.lb
.lbHatch
= (ULONG_PTR
)buff
;
367 (*texture
)->brush
.gdibrush
= CreateBrushIndirect(&(*texture
)->brush
.lb
);
368 (*texture
)->brush
.bt
= BrushTypeTextureFill
;
376 GpStatus WINGDIPAPI
GdipGetBrushType(GpBrush
*brush
, GpBrushType
*type
)
378 if(!brush
|| !type
) return InvalidParameter
;
385 GpStatus WINGDIPAPI
GdipDeleteBrush(GpBrush
*brush
)
387 if(!brush
) return InvalidParameter
;
391 case BrushTypePathGradient
:
392 GdipFree(((GpPathGradient
*) brush
)->pathdata
.Points
);
393 GdipFree(((GpPathGradient
*) brush
)->pathdata
.Types
);
395 case BrushTypeSolidColor
:
396 case BrushTypeLinearGradient
:
397 case BrushTypeTextureFill
:
402 DeleteObject(brush
->gdibrush
);
408 GpStatus WINGDIPAPI
GdipGetLineGammaCorrection(GpLineGradient
*line
,
412 return InvalidParameter
;
414 *usinggamma
= line
->gamma
;
419 GpStatus WINGDIPAPI
GdipGetPathGradientCenterPoint(GpPathGradient
*grad
,
423 return InvalidParameter
;
425 point
->X
= grad
->center
.X
;
426 point
->Y
= grad
->center
.Y
;
431 GpStatus WINGDIPAPI
GdipGetPathGradientFocusScales(GpPathGradient
*grad
,
434 if(!grad
|| !x
|| !y
)
435 return InvalidParameter
;
443 GpStatus WINGDIPAPI
GdipGetPathGradientGammaCorrection(GpPathGradient
*grad
,
447 return InvalidParameter
;
449 *gamma
= grad
->gamma
;
454 GpStatus WINGDIPAPI
GdipGetPathGradientPointCount(GpPathGradient
*grad
,
458 return InvalidParameter
;
460 *count
= grad
->pathdata
.Count
;
465 GpStatus WINGDIPAPI
GdipGetPathGradientSurroundColorsWithCount(GpPathGradient
466 *grad
, ARGB
*argb
, INT
*count
)
470 if(!grad
|| !argb
|| !count
|| (*count
< grad
->pathdata
.Count
))
471 return InvalidParameter
;
474 FIXME("not implemented\n");
476 return NotImplemented
;
479 GpStatus WINGDIPAPI
GdipGetSolidFillColor(GpSolidFill
*sf
, ARGB
*argb
)
482 return InvalidParameter
;
489 GpStatus WINGDIPAPI
GdipSetLineBlend(GpLineGradient
*brush
,
490 GDIPCONST REAL
*blend
, GDIPCONST REAL
* positions
, INT count
)
494 if(!brush
|| !blend
|| !positions
|| count
<= 0)
495 return InvalidParameter
;
498 FIXME("not implemented\n");
503 GpStatus WINGDIPAPI
GdipSetLineGammaCorrection(GpLineGradient
*line
,
507 return InvalidParameter
;
509 line
->gamma
= usegamma
;
514 GpStatus WINGDIPAPI
GdipSetLineSigmaBlend(GpLineGradient
*line
, REAL focus
,
519 if(!line
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0)
520 return InvalidParameter
;
523 FIXME("not implemented\n");
525 return NotImplemented
;
528 GpStatus WINGDIPAPI
GdipSetLineWrapMode(GpLineGradient
*line
,
531 if(!line
|| wrap
== WrapModeClamp
)
532 return InvalidParameter
;
539 GpStatus WINGDIPAPI
GdipSetPathGradientCenterColor(GpPathGradient
*grad
,
543 return InvalidParameter
;
545 grad
->centercolor
= argb
;
546 grad
->brush
.lb
.lbColor
= ARGB2COLORREF(argb
);
548 DeleteObject(grad
->brush
.gdibrush
);
549 grad
->brush
.gdibrush
= CreateSolidBrush(grad
->brush
.lb
.lbColor
);
554 GpStatus WINGDIPAPI
GdipSetPathGradientCenterPoint(GpPathGradient
*grad
,
558 return InvalidParameter
;
560 grad
->center
.X
= point
->X
;
561 grad
->center
.Y
= point
->Y
;
566 GpStatus WINGDIPAPI
GdipSetPathGradientFocusScales(GpPathGradient
*grad
,
570 return InvalidParameter
;
578 GpStatus WINGDIPAPI
GdipSetPathGradientGammaCorrection(GpPathGradient
*grad
,
582 return InvalidParameter
;
589 GpStatus WINGDIPAPI
GdipSetPathGradientSigmaBlend(GpPathGradient
*grad
,
590 REAL focus
, REAL scale
)
594 if(!grad
|| focus
< 0.0 || focus
> 1.0 || scale
< 0.0 || scale
> 1.0)
595 return InvalidParameter
;
598 FIXME("not implemented\n");
600 return NotImplemented
;
603 GpStatus WINGDIPAPI
GdipSetPathGradientSurroundColorsWithCount(GpPathGradient
604 *grad
, ARGB
*argb
, INT
*count
)
608 if(!grad
|| !argb
|| !count
|| (*count
<= 0) ||
609 (*count
> grad
->pathdata
.Count
))
610 return InvalidParameter
;
613 FIXME("not implemented\n");
615 return NotImplemented
;
618 GpStatus WINGDIPAPI
GdipSetPathGradientWrapMode(GpPathGradient
*grad
,
622 return InvalidParameter
;
629 GpStatus WINGDIPAPI
GdipSetSolidFillColor(GpSolidFill
*sf
, ARGB argb
)
632 return InvalidParameter
;
635 sf
->brush
.lb
.lbColor
= ARGB2COLORREF(argb
);
637 DeleteObject(sf
->brush
.gdibrush
);
638 sf
->brush
.gdibrush
= CreateSolidBrush(sf
->brush
.lb
.lbColor
);
643 GpStatus WINGDIPAPI
GdipSetTextureTransform(GpTexture
*texture
,
644 GDIPCONST GpMatrix
*matrix
)
648 if(!texture
|| !matrix
)
649 return InvalidParameter
;
652 FIXME("not implemented\n");