xref: /reactos/dll/win32/gdiplus/gdiplus.c (revision 5f279f2d)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * Copyright (C) 2007 Google (Evan Stade)
3c2c66affSColin Finck  *
4c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
5c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
6c2c66affSColin Finck  * License as published by the Free Software Foundation; either
7c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
8c2c66affSColin Finck  *
9c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
10c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12c2c66affSColin Finck  * Lesser General Public License for more details.
13c2c66affSColin Finck  *
14c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
15c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
16c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17c2c66affSColin Finck  */
18c2c66affSColin Finck 
19*5f279f2dSAmine Khaldi #include <stdarg.h>
20*5f279f2dSAmine Khaldi #include <math.h>
21*5f279f2dSAmine Khaldi 
22*5f279f2dSAmine Khaldi #include "windef.h"
23*5f279f2dSAmine Khaldi #include "winbase.h"
24*5f279f2dSAmine Khaldi #include "winerror.h"
25*5f279f2dSAmine Khaldi #include "wine/debug.h"
26*5f279f2dSAmine Khaldi #include "wingdi.h"
27*5f279f2dSAmine Khaldi 
28*5f279f2dSAmine Khaldi #include "objbase.h"
29*5f279f2dSAmine Khaldi 
30*5f279f2dSAmine Khaldi #include "winreg.h"
31*5f279f2dSAmine Khaldi #include "shlwapi.h"
32*5f279f2dSAmine Khaldi 
33*5f279f2dSAmine Khaldi #include "gdiplus.h"
34c2c66affSColin Finck #include "gdiplus_private.h"
35c2c66affSColin Finck 
36*5f279f2dSAmine Khaldi WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
37*5f279f2dSAmine Khaldi 
38c2c66affSColin Finck static const REAL mm_per_inch = 25.4;
39c2c66affSColin Finck static const REAL point_per_inch = 72.0;
40c2c66affSColin Finck 
NotificationHook(ULONG_PTR * token)41c2c66affSColin Finck static Status WINAPI NotificationHook(ULONG_PTR *token)
42c2c66affSColin Finck {
43c2c66affSColin Finck     TRACE("%p\n", token);
44c2c66affSColin Finck     if(!token)
45c2c66affSColin Finck         return InvalidParameter;
46c2c66affSColin Finck 
47c2c66affSColin Finck     return Ok;
48c2c66affSColin Finck }
49c2c66affSColin Finck 
NotificationUnhook(ULONG_PTR token)50c2c66affSColin Finck static void WINAPI NotificationUnhook(ULONG_PTR token)
51c2c66affSColin Finck {
52c2c66affSColin Finck     TRACE("%ld\n", token);
53c2c66affSColin Finck }
54c2c66affSColin Finck 
55c2c66affSColin Finck /*****************************************************
56c2c66affSColin Finck  *      DllMain
57c2c66affSColin Finck  */
DllMain(HINSTANCE hinst,DWORD reason,LPVOID reserved)58c2c66affSColin Finck BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved)
59c2c66affSColin Finck {
60c2c66affSColin Finck     TRACE("(%p, %d, %p)\n", hinst, reason, reserved);
61c2c66affSColin Finck 
62c2c66affSColin Finck     switch(reason)
63c2c66affSColin Finck     {
64c2c66affSColin Finck     case DLL_PROCESS_ATTACH:
65c2c66affSColin Finck         DisableThreadLibraryCalls( hinst );
66c2c66affSColin Finck         init_generic_string_formats();
67c2c66affSColin Finck         break;
68c2c66affSColin Finck 
69c2c66affSColin Finck     case DLL_PROCESS_DETACH:
70c2c66affSColin Finck         if (reserved) break;
71c2c66affSColin Finck         free_installed_fonts();
72c2c66affSColin Finck         free_generic_string_formats();
73c2c66affSColin Finck         break;
74c2c66affSColin Finck     }
75c2c66affSColin Finck     return TRUE;
76c2c66affSColin Finck }
77c2c66affSColin Finck 
78c2c66affSColin Finck /*****************************************************
79c2c66affSColin Finck  *      GdiplusStartup [GDIPLUS.@]
80c2c66affSColin Finck  */
GdiplusStartup(ULONG_PTR * token,const struct GdiplusStartupInput * input,struct GdiplusStartupOutput * output)81c2c66affSColin Finck Status WINAPI GdiplusStartup(ULONG_PTR *token, const struct GdiplusStartupInput *input,
82c2c66affSColin Finck                              struct GdiplusStartupOutput *output)
83c2c66affSColin Finck {
84c2c66affSColin Finck     if(!token || !input)
85c2c66affSColin Finck         return InvalidParameter;
86c2c66affSColin Finck 
87c2c66affSColin Finck     TRACE("%p %p %p\n", token, input, output);
88c2c66affSColin Finck     TRACE("GdiplusStartupInput %d %p %d %d\n", input->GdiplusVersion,
89c2c66affSColin Finck           input->DebugEventCallback, input->SuppressBackgroundThread,
90c2c66affSColin Finck           input->SuppressExternalCodecs);
91c2c66affSColin Finck 
92c2c66affSColin Finck     if(input->GdiplusVersion < 1 || input->GdiplusVersion > 2)
93c2c66affSColin Finck         return UnsupportedGdiplusVersion;
94c2c66affSColin Finck 
95c2c66affSColin Finck     if(input->SuppressBackgroundThread){
96c2c66affSColin Finck         if(!output)
97c2c66affSColin Finck             return InvalidParameter;
98c2c66affSColin Finck 
99c2c66affSColin Finck         output->NotificationHook = NotificationHook;
100c2c66affSColin Finck         output->NotificationUnhook = NotificationUnhook;
101c2c66affSColin Finck     }
102c2c66affSColin Finck 
103c2c66affSColin Finck     *token = 0xdeadbeef;
104c2c66affSColin Finck 
105c2c66affSColin Finck     /* FIXME: DebugEventCallback ignored */
106c2c66affSColin Finck 
107c2c66affSColin Finck     return Ok;
108c2c66affSColin Finck }
109c2c66affSColin Finck 
GdiplusNotificationHook(ULONG_PTR * token)110c2c66affSColin Finck GpStatus WINAPI GdiplusNotificationHook(ULONG_PTR *token)
111c2c66affSColin Finck {
112c2c66affSColin Finck     FIXME("%p\n", token);
113c2c66affSColin Finck     return NotificationHook(token);
114c2c66affSColin Finck }
115c2c66affSColin Finck 
GdiplusNotificationUnhook(ULONG_PTR token)116c2c66affSColin Finck void WINAPI GdiplusNotificationUnhook(ULONG_PTR token)
117c2c66affSColin Finck {
118c2c66affSColin Finck     FIXME("%ld\n", token);
119c2c66affSColin Finck     NotificationUnhook(token);
120c2c66affSColin Finck }
121c2c66affSColin Finck 
122c2c66affSColin Finck /*****************************************************
123c2c66affSColin Finck  *      GdiplusShutdown [GDIPLUS.@]
124c2c66affSColin Finck  */
GdiplusShutdown_wrapper(ULONG_PTR token)125c2c66affSColin Finck ULONG WINAPI GdiplusShutdown_wrapper(ULONG_PTR token)
126c2c66affSColin Finck {
127c2c66affSColin Finck     /* Notice the slightly different prototype from the official
128c2c66affSColin Finck      * signature which forces us to use the _wrapper suffix.
129c2c66affSColin Finck      */
130c2c66affSColin Finck 
131c2c66affSColin Finck     /* FIXME: no object tracking */
132c2c66affSColin Finck 
133c2c66affSColin Finck     /* "bricksntiles" expects a return value of 0, which native
134c2c66affSColin Finck      * coincidentally gives.
135c2c66affSColin Finck      */
136c2c66affSColin Finck     return 0;
137c2c66affSColin Finck }
138c2c66affSColin Finck 
139c2c66affSColin Finck /*****************************************************
140c2c66affSColin Finck  *      GdipAlloc [GDIPLUS.@]
141c2c66affSColin Finck  */
GdipAlloc(SIZE_T size)142c2c66affSColin Finck void* WINGDIPAPI GdipAlloc(SIZE_T size)
143c2c66affSColin Finck {
144c2c66affSColin Finck     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
145c2c66affSColin Finck }
146c2c66affSColin Finck 
147c2c66affSColin Finck /*****************************************************
148c2c66affSColin Finck  *      GdipFree [GDIPLUS.@]
149c2c66affSColin Finck  */
GdipFree(void * ptr)150c2c66affSColin Finck void WINGDIPAPI GdipFree(void* ptr)
151c2c66affSColin Finck {
152c2c66affSColin Finck     HeapFree(GetProcessHeap(), 0, ptr);
153c2c66affSColin Finck }
154c2c66affSColin Finck 
155c2c66affSColin Finck /* Calculates the bezier points needed to fill in the arc portion starting at
156c2c66affSColin Finck  * angle start and ending at end.  These two angles should be no more than 90
157c2c66affSColin Finck  * degrees from each other.  x1, y1, x2, y2 describes the bounding box (upper
158c2c66affSColin Finck  * left and width and height).  Angles must be in radians. write_first indicates
159c2c66affSColin Finck  * that the first bezier point should be written out (usually this is false).
160c2c66affSColin Finck  * pt is the array of GpPointFs that gets written to.
161c2c66affSColin Finck  **/
add_arc_part(GpPointF * pt,REAL x1,REAL y1,REAL x2,REAL y2,REAL start,REAL end,BOOL write_first)162c2c66affSColin Finck static void add_arc_part(GpPointF * pt, REAL x1, REAL y1, REAL x2, REAL y2,
163c2c66affSColin Finck     REAL start, REAL end, BOOL write_first)
164c2c66affSColin Finck {
165c2c66affSColin Finck     REAL center_x, center_y, rad_x, rad_y, cos_start, cos_end,
166c2c66affSColin Finck         sin_start, sin_end, a, half;
167c2c66affSColin Finck     INT i;
168c2c66affSColin Finck 
169c2c66affSColin Finck     rad_x = x2 / 2.0;
170c2c66affSColin Finck     rad_y = y2 / 2.0;
171c2c66affSColin Finck     center_x = x1 + rad_x;
172c2c66affSColin Finck     center_y = y1 + rad_y;
173c2c66affSColin Finck 
174c2c66affSColin Finck     cos_start = cos(start);
175c2c66affSColin Finck     cos_end = cos(end);
176c2c66affSColin Finck     sin_start = sin(start);
177c2c66affSColin Finck     sin_end = sin(end);
178c2c66affSColin Finck 
179c2c66affSColin Finck     half = (end - start) / 2.0;
180c2c66affSColin Finck     a = 4.0 / 3.0 * (1 - cos(half)) / sin(half);
181c2c66affSColin Finck 
182c2c66affSColin Finck     if(write_first){
183c2c66affSColin Finck         pt[0].X = cos_start;
184c2c66affSColin Finck         pt[0].Y = sin_start;
185c2c66affSColin Finck     }
186c2c66affSColin Finck     pt[1].X = cos_start - a * sin_start;
187c2c66affSColin Finck     pt[1].Y = sin_start + a * cos_start;
188c2c66affSColin Finck 
189c2c66affSColin Finck     pt[3].X = cos_end;
190c2c66affSColin Finck     pt[3].Y = sin_end;
191c2c66affSColin Finck     pt[2].X = cos_end + a * sin_end;
192c2c66affSColin Finck     pt[2].Y = sin_end - a * cos_end;
193c2c66affSColin Finck 
194c2c66affSColin Finck     /* expand the points back from the unit circle to the ellipse */
195c2c66affSColin Finck     for(i = (write_first ? 0 : 1); i < 4; i ++){
196c2c66affSColin Finck         pt[i].X = pt[i].X * rad_x + center_x;
197c2c66affSColin Finck         pt[i].Y = pt[i].Y * rad_y + center_y;
198c2c66affSColin Finck     }
199c2c66affSColin Finck }
200c2c66affSColin Finck 
201c2c66affSColin Finck /* We plot the curve as if it is on a circle then stretch the points.  This
202c2c66affSColin Finck  * adjusts the angles so that when we stretch the points they will end in the
203c2c66affSColin Finck  * right place. This is only complicated because atan and atan2 do not behave
204c2c66affSColin Finck  * conveniently. */
unstretch_angle(REAL * angle,REAL rad_x,REAL rad_y)205c2c66affSColin Finck static void unstretch_angle(REAL * angle, REAL rad_x, REAL rad_y)
206c2c66affSColin Finck {
207c2c66affSColin Finck     REAL stretched;
208c2c66affSColin Finck     INT revs_off;
209c2c66affSColin Finck 
210c2c66affSColin Finck     *angle = deg2rad(*angle);
211c2c66affSColin Finck 
212c2c66affSColin Finck     if(fabs(cos(*angle)) < 0.00001 || fabs(sin(*angle)) < 0.00001)
213c2c66affSColin Finck         return;
214c2c66affSColin Finck 
215c2c66affSColin Finck     stretched = gdiplus_atan2(sin(*angle) / fabs(rad_y), cos(*angle) / fabs(rad_x));
216c2c66affSColin Finck     revs_off = gdip_round(*angle / (2.0 * M_PI)) - gdip_round(stretched / (2.0 * M_PI));
217c2c66affSColin Finck     stretched += ((REAL)revs_off) * M_PI * 2.0;
218c2c66affSColin Finck     *angle = stretched;
219c2c66affSColin Finck }
220c2c66affSColin Finck 
221c2c66affSColin Finck /* Stores the bezier points that correspond to the arc in points.  If points is
222c2c66affSColin Finck  * null, just return the number of points needed to represent the arc. */
arc2polybezier(GpPointF * points,REAL x1,REAL y1,REAL x2,REAL y2,REAL startAngle,REAL sweepAngle)223c2c66affSColin Finck INT arc2polybezier(GpPointF * points, REAL x1, REAL y1, REAL x2, REAL y2,
224c2c66affSColin Finck     REAL startAngle, REAL sweepAngle)
225c2c66affSColin Finck {
226c2c66affSColin Finck     INT i;
227c2c66affSColin Finck     REAL end_angle, start_angle, endAngle;
228c2c66affSColin Finck 
229c2c66affSColin Finck     endAngle = startAngle + sweepAngle;
230c2c66affSColin Finck     unstretch_angle(&startAngle, x2 / 2.0, y2 / 2.0);
231c2c66affSColin Finck     unstretch_angle(&endAngle, x2 / 2.0, y2 / 2.0);
232c2c66affSColin Finck 
233c2c66affSColin Finck     /* start_angle and end_angle are the iterative variables */
234c2c66affSColin Finck     start_angle = startAngle;
235c2c66affSColin Finck 
236c2c66affSColin Finck     for(i = 0; i < MAX_ARC_PTS - 1; i += 3){
237c2c66affSColin Finck         /* check if we've overshot the end angle */
238c2c66affSColin Finck         if( sweepAngle > 0.0 )
239c2c66affSColin Finck         {
240c2c66affSColin Finck             if (start_angle >= endAngle) break;
241c2c66affSColin Finck             end_angle = min(start_angle + M_PI_2, endAngle);
242c2c66affSColin Finck         }
243c2c66affSColin Finck         else
244c2c66affSColin Finck         {
245c2c66affSColin Finck             if (start_angle <= endAngle) break;
246c2c66affSColin Finck             end_angle = max(start_angle - M_PI_2, endAngle);
247c2c66affSColin Finck         }
248c2c66affSColin Finck 
249c2c66affSColin Finck         if (points)
250c2c66affSColin Finck             add_arc_part(&points[i], x1, y1, x2, y2, start_angle, end_angle, i == 0);
251c2c66affSColin Finck 
252c2c66affSColin Finck         start_angle += M_PI_2 * (sweepAngle < 0.0 ? -1.0 : 1.0);
253c2c66affSColin Finck     }
254c2c66affSColin Finck 
255c2c66affSColin Finck     if (i == 0) return 0;
256c2c66affSColin Finck     else return i+1;
257c2c66affSColin Finck }
258c2c66affSColin Finck 
ARGB2COLORREF(ARGB color)259c2c66affSColin Finck COLORREF ARGB2COLORREF(ARGB color)
260c2c66affSColin Finck {
261c2c66affSColin Finck     /*
262c2c66affSColin Finck     Packing of these color structures:
263c2c66affSColin Finck     COLORREF:   00bbggrr
264c2c66affSColin Finck     ARGB:       aarrggbb
265c2c66affSColin Finck     FIXME:doesn't handle alpha channel
266c2c66affSColin Finck     */
267c2c66affSColin Finck     return ((color & 0x0000ff) << 16) +
268c2c66affSColin Finck            (color & 0x00ff00) +
269c2c66affSColin Finck            ((color & 0xff0000) >> 16);
270c2c66affSColin Finck }
271c2c66affSColin Finck 
ARGB2BMP(ARGB color)272c2c66affSColin Finck HBITMAP ARGB2BMP(ARGB color)
273c2c66affSColin Finck {
274c2c66affSColin Finck     BITMAPINFO bi;
275c2c66affSColin Finck     HBITMAP result;
276c2c66affSColin Finck     RGBQUAD *bits;
277c2c66affSColin Finck     int alpha;
278c2c66affSColin Finck 
279c2c66affSColin Finck     if ((color & 0xff000000) == 0xff000000) return 0;
280c2c66affSColin Finck 
281c2c66affSColin Finck     bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
282c2c66affSColin Finck     bi.bmiHeader.biWidth = 1;
283c2c66affSColin Finck     bi.bmiHeader.biHeight = 1;
284c2c66affSColin Finck     bi.bmiHeader.biPlanes = 1;
285c2c66affSColin Finck     bi.bmiHeader.biBitCount = 32;
286c2c66affSColin Finck     bi.bmiHeader.biCompression = BI_RGB;
287c2c66affSColin Finck     bi.bmiHeader.biSizeImage = 0;
288c2c66affSColin Finck     bi.bmiHeader.biXPelsPerMeter = 0;
289c2c66affSColin Finck     bi.bmiHeader.biYPelsPerMeter = 0;
290c2c66affSColin Finck     bi.bmiHeader.biClrUsed = 0;
291c2c66affSColin Finck     bi.bmiHeader.biClrImportant = 0;
292c2c66affSColin Finck 
293c2c66affSColin Finck     result = CreateDIBSection(0, &bi, DIB_RGB_COLORS, (void*)&bits, NULL, 0);
294c2c66affSColin Finck 
295c2c66affSColin Finck     bits[0].rgbReserved = alpha = (color>>24)&0xff;
296c2c66affSColin Finck     bits[0].rgbRed = ((color>>16)&0xff)*alpha/255;
297c2c66affSColin Finck     bits[0].rgbGreen = ((color>>8)&0xff)*alpha/255;
298c2c66affSColin Finck     bits[0].rgbBlue = (color&0xff)*alpha/255;
299c2c66affSColin Finck 
300c2c66affSColin Finck     return result;
301c2c66affSColin Finck }
302c2c66affSColin Finck 
303c2c66affSColin Finck /* Like atan2, but puts angle in correct quadrant if dx is 0. */
gdiplus_atan2(REAL dy,REAL dx)304c2c66affSColin Finck REAL gdiplus_atan2(REAL dy, REAL dx)
305c2c66affSColin Finck {
306c2c66affSColin Finck     if((dx == 0.0) && (dy != 0.0))
307c2c66affSColin Finck         return dy > 0.0 ? M_PI_2 : -M_PI_2;
308c2c66affSColin Finck 
309c2c66affSColin Finck     return atan2(dy, dx);
310c2c66affSColin Finck }
311c2c66affSColin Finck 
hresult_to_status(HRESULT res)312c2c66affSColin Finck GpStatus hresult_to_status(HRESULT res)
313c2c66affSColin Finck {
314c2c66affSColin Finck     switch(res){
315c2c66affSColin Finck         case S_OK:
316c2c66affSColin Finck             return Ok;
317c2c66affSColin Finck         case E_OUTOFMEMORY:
318c2c66affSColin Finck             return OutOfMemory;
319c2c66affSColin Finck         case E_INVALIDARG:
320c2c66affSColin Finck             return InvalidParameter;
321c2c66affSColin Finck         default:
322c2c66affSColin Finck             return GenericError;
323c2c66affSColin Finck     }
324c2c66affSColin Finck }
325c2c66affSColin Finck 
326c2c66affSColin Finck /* converts a given unit to its value in pixels */
units_to_pixels(REAL units,GpUnit unit,REAL dpi)327c2c66affSColin Finck REAL units_to_pixels(REAL units, GpUnit unit, REAL dpi)
328c2c66affSColin Finck {
329c2c66affSColin Finck     switch (unit)
330c2c66affSColin Finck     {
331c2c66affSColin Finck     case UnitPixel:
332c2c66affSColin Finck     case UnitWorld:
333c2c66affSColin Finck     case UnitDisplay:
334c2c66affSColin Finck         return units;
335c2c66affSColin Finck     case UnitPoint:
336c2c66affSColin Finck         return units * dpi / point_per_inch;
337c2c66affSColin Finck     case UnitInch:
338c2c66affSColin Finck         return units * dpi;
339c2c66affSColin Finck     case UnitDocument:
340c2c66affSColin Finck         return units * dpi / 300.0; /* Per MSDN */
341c2c66affSColin Finck     case UnitMillimeter:
342c2c66affSColin Finck         return units * dpi / mm_per_inch;
343c2c66affSColin Finck     default:
344c2c66affSColin Finck         FIXME("Unhandled unit type: %d\n", unit);
345c2c66affSColin Finck         return 0;
346c2c66affSColin Finck     }
347c2c66affSColin Finck }
348c2c66affSColin Finck 
349c2c66affSColin Finck /* converts value in pixels to a given unit */
pixels_to_units(REAL pixels,GpUnit unit,REAL dpi)350c2c66affSColin Finck REAL pixels_to_units(REAL pixels, GpUnit unit, REAL dpi)
351c2c66affSColin Finck {
352c2c66affSColin Finck     switch (unit)
353c2c66affSColin Finck     {
354c2c66affSColin Finck     case UnitPixel:
355c2c66affSColin Finck     case UnitWorld:
356c2c66affSColin Finck     case UnitDisplay:
357c2c66affSColin Finck         return pixels;
358c2c66affSColin Finck     case UnitPoint:
359c2c66affSColin Finck         return pixels * point_per_inch / dpi;
360c2c66affSColin Finck     case UnitInch:
361c2c66affSColin Finck         return pixels / dpi;
362c2c66affSColin Finck     case UnitDocument:
363c2c66affSColin Finck         return pixels * 300.0 / dpi;
364c2c66affSColin Finck     case UnitMillimeter:
365c2c66affSColin Finck         return pixels * mm_per_inch / dpi;
366c2c66affSColin Finck     default:
367c2c66affSColin Finck         FIXME("Unhandled unit type: %d\n", unit);
368c2c66affSColin Finck         return 0;
369c2c66affSColin Finck     }
370c2c66affSColin Finck }
371c2c66affSColin Finck 
units_scale(GpUnit from,GpUnit to,REAL dpi)372c2c66affSColin Finck REAL units_scale(GpUnit from, GpUnit to, REAL dpi)
373c2c66affSColin Finck {
374c2c66affSColin Finck     REAL pixels = units_to_pixels(1.0, from, dpi);
375c2c66affSColin Finck     return pixels_to_units(pixels, to, dpi);
376c2c66affSColin Finck }
377c2c66affSColin Finck 
378c2c66affSColin Finck /* Calculates Bezier points from cardinal spline points. */
calc_curve_bezier(const GpPointF * pts,REAL tension,REAL * x1,REAL * y1,REAL * x2,REAL * y2)379c2c66affSColin Finck void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1,
380c2c66affSColin Finck     REAL *y1, REAL *x2, REAL *y2)
381c2c66affSColin Finck {
382c2c66affSColin Finck     REAL xdiff, ydiff;
383c2c66affSColin Finck 
384c2c66affSColin Finck     /* calculate tangent */
385c2c66affSColin Finck     xdiff = pts[2].X - pts[0].X;
386c2c66affSColin Finck     ydiff = pts[2].Y - pts[0].Y;
387c2c66affSColin Finck 
388c2c66affSColin Finck     /* apply tangent to get control points */
389c2c66affSColin Finck     *x1 = pts[1].X - tension * xdiff;
390c2c66affSColin Finck     *y1 = pts[1].Y - tension * ydiff;
391c2c66affSColin Finck     *x2 = pts[1].X + tension * xdiff;
392c2c66affSColin Finck     *y2 = pts[1].Y + tension * ydiff;
393c2c66affSColin Finck }
394c2c66affSColin Finck 
395c2c66affSColin Finck /* Calculates Bezier points from cardinal spline endpoints. */
calc_curve_bezier_endp(REAL xend,REAL yend,REAL xadj,REAL yadj,REAL tension,REAL * x,REAL * y)396c2c66affSColin Finck void calc_curve_bezier_endp(REAL xend, REAL yend, REAL xadj, REAL yadj,
397c2c66affSColin Finck     REAL tension, REAL *x, REAL *y)
398c2c66affSColin Finck {
399c2c66affSColin Finck     /* tangent at endpoints is the line from the endpoint to the adjacent point */
400c2c66affSColin Finck     *x = gdip_round(tension * (xadj - xend) + xend);
401c2c66affSColin Finck     *y = gdip_round(tension * (yadj - yend) + yend);
402c2c66affSColin Finck }
403c2c66affSColin Finck 
404c2c66affSColin Finck /* make sure path has enough space for len more points */
lengthen_path(GpPath * path,INT len)405c2c66affSColin Finck BOOL lengthen_path(GpPath *path, INT len)
406c2c66affSColin Finck {
407c2c66affSColin Finck     /* initial allocation */
408c2c66affSColin Finck     if(path->datalen == 0){
409c2c66affSColin Finck         path->datalen = len * 2;
410c2c66affSColin Finck 
411c2c66affSColin Finck         path->pathdata.Points = heap_alloc_zero(path->datalen * sizeof(PointF));
412c2c66affSColin Finck         if(!path->pathdata.Points)   return FALSE;
413c2c66affSColin Finck 
414c2c66affSColin Finck         path->pathdata.Types = heap_alloc_zero(path->datalen);
415c2c66affSColin Finck         if(!path->pathdata.Types){
416c2c66affSColin Finck             heap_free(path->pathdata.Points);
417c2c66affSColin Finck             return FALSE;
418c2c66affSColin Finck         }
419c2c66affSColin Finck     }
420c2c66affSColin Finck     /* reallocation, double size of arrays */
421c2c66affSColin Finck     else if(path->datalen - path->pathdata.Count < len){
422c2c66affSColin Finck         while(path->datalen - path->pathdata.Count < len)
423c2c66affSColin Finck             path->datalen *= 2;
424c2c66affSColin Finck 
425c2c66affSColin Finck         path->pathdata.Points = heap_realloc(path->pathdata.Points, path->datalen * sizeof(PointF));
426c2c66affSColin Finck         if(!path->pathdata.Points)  return FALSE;
427c2c66affSColin Finck 
428c2c66affSColin Finck         path->pathdata.Types = heap_realloc(path->pathdata.Types, path->datalen);
429c2c66affSColin Finck         if(!path->pathdata.Types)   return FALSE;
430c2c66affSColin Finck     }
431c2c66affSColin Finck 
432c2c66affSColin Finck     return TRUE;
433c2c66affSColin Finck }
434c2c66affSColin Finck 
convert_32bppARGB_to_32bppPARGB(UINT width,UINT height,BYTE * dst_bits,INT dst_stride,const BYTE * src_bits,INT src_stride)435c2c66affSColin Finck void convert_32bppARGB_to_32bppPARGB(UINT width, UINT height,
436c2c66affSColin Finck     BYTE *dst_bits, INT dst_stride, const BYTE *src_bits, INT src_stride)
437c2c66affSColin Finck {
438c2c66affSColin Finck     INT x, y;
439c2c66affSColin Finck     for (y=0; y<height; y++)
440c2c66affSColin Finck     {
441c2c66affSColin Finck         const BYTE *src=src_bits+y*src_stride;
442c2c66affSColin Finck         BYTE *dst=dst_bits+y*dst_stride;
443c2c66affSColin Finck         for (x=0; x<width; x++)
444c2c66affSColin Finck         {
445c2c66affSColin Finck             BYTE alpha=src[3];
446c2c66affSColin Finck             *dst++ = (*src++ * alpha + 127) / 255;
447c2c66affSColin Finck             *dst++ = (*src++ * alpha + 127) / 255;
448c2c66affSColin Finck             *dst++ = (*src++ * alpha + 127) / 255;
449c2c66affSColin Finck             *dst++ = *src++;
450c2c66affSColin Finck         }
451c2c66affSColin Finck     }
452c2c66affSColin Finck }
453c2c66affSColin Finck 
454c2c66affSColin Finck /* recursive deletion of GpRegion nodes */
delete_element(region_element * element)455c2c66affSColin Finck void delete_element(region_element* element)
456c2c66affSColin Finck {
457c2c66affSColin Finck     switch(element->type)
458c2c66affSColin Finck     {
459c2c66affSColin Finck         case RegionDataRect:
460c2c66affSColin Finck             break;
461c2c66affSColin Finck         case RegionDataPath:
462c2c66affSColin Finck             GdipDeletePath(element->elementdata.path);
463c2c66affSColin Finck             break;
464c2c66affSColin Finck         case RegionDataEmptyRect:
465c2c66affSColin Finck         case RegionDataInfiniteRect:
466c2c66affSColin Finck             break;
467c2c66affSColin Finck         default:
468c2c66affSColin Finck             delete_element(element->elementdata.combine.left);
469c2c66affSColin Finck             delete_element(element->elementdata.combine.right);
470c2c66affSColin Finck             heap_free(element->elementdata.combine.left);
471c2c66affSColin Finck             heap_free(element->elementdata.combine.right);
472c2c66affSColin Finck             break;
473c2c66affSColin Finck     }
474c2c66affSColin Finck }
475c2c66affSColin Finck 
debugstr_rectf(const RectF * rc)476c2c66affSColin Finck const char *debugstr_rectf(const RectF* rc)
477c2c66affSColin Finck {
478c2c66affSColin Finck     if (!rc) return "(null)";
479c2c66affSColin Finck     return wine_dbg_sprintf("(%0.2f,%0.2f,%0.2f,%0.2f)", rc->X, rc->Y, rc->Width, rc->Height);
480c2c66affSColin Finck }
481c2c66affSColin Finck 
debugstr_pointf(const PointF * pt)482c2c66affSColin Finck const char *debugstr_pointf(const PointF* pt)
483c2c66affSColin Finck {
484c2c66affSColin Finck     if (!pt) return "(null)";
485c2c66affSColin Finck     return wine_dbg_sprintf("(%0.2f,%0.2f)", pt->X, pt->Y);
486c2c66affSColin Finck }
487