xref: /reactos/win32ss/gdi/gdi32/wine/emfdrv.c (revision fc16259f)
1 /*
2  * Enhanced MetaFile driver
3  *
4  * Copyright 1999 Huw D M Davies
5  * Copyright 2021 Jacek Caban for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 //#include "ntgdi_private.h"
23 #include "wine/config.h"
24 
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winnls.h"
33 #include "winerror.h"
34 #include "gdi_private.h"
35 #ifdef __REACTOS__
36 #include "wine/winternl.h"
37 #else
38 #include "winternl.h"
39 #endif
40 #include "wine/wingdi16.h"
41 #include "wine/debug.h"
42 
43 #define M_PI 3.14159265358979323846
44 #define M_PI_2 1.570796326794896619
45 
emfdrv_update_bounds(WINEDC * dc,RECTL * rect)46 static void emfdrv_update_bounds( WINEDC *dc, RECTL *rect )
47 {
48     RECTL *bounds = &dc->emf_bounds;
49     RECTL vport_rect = *rect;
50 
51     //lp_to_dp( dc, (POINT *)&vport_rect, 2 );
52     LPtoDP(dc->hdc, (POINT *)&vport_rect, 2 );
53 
54     /* The coordinate systems may be mirrored
55        (LPtoDP handles points, not rectangles) */
56     if (vport_rect.left > vport_rect.right)
57     {
58         LONG temp = vport_rect.right;
59         vport_rect.right = vport_rect.left;
60         vport_rect.left = temp;
61     }
62     if (vport_rect.top > vport_rect.bottom)
63     {
64         LONG temp = vport_rect.bottom;
65         vport_rect.bottom = vport_rect.top;
66         vport_rect.top = temp;
67     }
68 
69     if (bounds->left > bounds->right)
70     {
71         /* first bounding rectangle */
72         *bounds = vport_rect;
73     }
74     else
75     {
76         bounds->left   = min( bounds->left,   vport_rect.left );
77         bounds->top    = min( bounds->top,    vport_rect.top );
78         bounds->right  = max( bounds->right,  vport_rect.right );
79         bounds->bottom = max( bounds->bottom, vport_rect.bottom );
80     }
81 }
82 
EMFDRV_LineTo(WINEDC * dc,INT x,INT y)83 BOOL EMFDRV_LineTo( WINEDC *dc, INT x, INT y )
84 {
85     RECTL bounds;
86     POINT pt;
87 
88     //pt = dc->attr->cur_pos;
89     GetCurrentPositionEx(dc->hdc, &pt);
90 
91     bounds.left   = min( x, pt.x );
92     bounds.top    = min( y, pt.y );
93     bounds.right  = max( x, pt.x );
94     bounds.bottom = max( y, pt.y );
95     emfdrv_update_bounds( dc, &bounds );
96     return TRUE;
97 }
98 
EMFDRV_RoundRect(WINEDC * dc,INT left,INT top,INT right,INT bottom,INT ell_width,INT ell_height)99 BOOL EMFDRV_RoundRect( WINEDC *dc, INT left, INT top, INT right,
100                                     INT bottom, INT ell_width, INT ell_height )
101 {
102     RECTL bounds;
103 
104     if (left == right || top == bottom) return FALSE;
105 
106     bounds.left   = min( left, right );
107     bounds.top    = min( top, bottom );
108     bounds.right  = max( left, right );
109     bounds.bottom = max( top, bottom );
110     if (GetGraphicsMode(dc->hdc) == GM_COMPATIBLE)//dc->attr->graphics_mode == GM_COMPATIBLE)
111     {
112         bounds.right--;
113         bounds.bottom--;
114     }
115 
116     emfdrv_update_bounds( dc, &bounds );
117     return TRUE;
118 }
119 
EMFDRV_ArcChordPie(WINEDC * dc,INT left,INT top,INT right,INT bottom,INT xstart,INT ystart,INT xend,INT yend,DWORD type)120 BOOL EMFDRV_ArcChordPie( WINEDC *dc, INT left, INT top, INT right, INT bottom,
121                                 INT xstart, INT ystart, INT xend, INT yend, DWORD type )
122 {
123     INT temp, x_centre, y_centre, i;
124     double angle_start, angle_end;
125     double xinter_start, yinter_start, xinter_end, yinter_end;
126     EMRARC emr;
127     RECTL bounds;
128 
129     if (left == right || top == bottom) return FALSE;
130 
131     if (left > right) { temp = left; left = right; right = temp; }
132     if (top > bottom) { temp = top; top = bottom; bottom = temp; }
133 
134     if (GetGraphicsMode(dc->hdc) == GM_COMPATIBLE)//dc->attr->graphics_mode == GM_COMPATIBLE)
135     {
136         right--;
137         bottom--;
138     }
139 
140     emr.emr.iType     = type;
141     emr.emr.nSize     = sizeof(emr);
142     emr.rclBox.left   = left;
143     emr.rclBox.top    = top;
144     emr.rclBox.right  = right;
145     emr.rclBox.bottom = bottom;
146     emr.ptlStart.x    = xstart;
147     emr.ptlStart.y    = ystart;
148     emr.ptlEnd.x      = xend;
149     emr.ptlEnd.y      = yend;
150 
151     /* Now calculate the BBox */
152     x_centre = (left + right + 1) / 2;
153     y_centre = (top + bottom + 1) / 2;
154 
155     xstart -= x_centre;
156     ystart -= y_centre;
157     xend   -= x_centre;
158     yend   -= y_centre;
159 
160     /* invert y co-ords to get angle anti-clockwise from x-axis */
161     angle_start = atan2( -(double)ystart, (double)xstart );
162     angle_end   = atan2( -(double)yend, (double)xend );
163 
164     /* These are the intercepts of the start/end lines with the arc */
165     xinter_start = (right - left + 1)/2 * cos(angle_start) + x_centre;
166     yinter_start = -(bottom - top + 1)/2 * sin(angle_start) + y_centre;
167     xinter_end   = (right - left + 1)/2 * cos(angle_end) + x_centre;
168     yinter_end   = -(bottom - top + 1)/2 * sin(angle_end) + y_centre;
169 
170     if (angle_start < 0) angle_start += 2 * M_PI;
171     if (angle_end < 0) angle_end += 2 * M_PI;
172     if (angle_end < angle_start) angle_end += 2 * M_PI;
173 
174     bounds.left   = min( xinter_start, xinter_end );
175     bounds.top    = min( yinter_start, yinter_end );
176     bounds.right  = max( xinter_start, xinter_end );
177     bounds.bottom = max( yinter_start, yinter_end );
178 
179     for (i = 0; i <= 8; i++)
180     {
181         if(i * M_PI / 2 < angle_start) /* loop until we're past start */
182 	    continue;
183 	if(i * M_PI / 2 > angle_end)   /* if we're past end we're finished */
184 	    break;
185 
186 	/* the arc touches the rectangle at the start of quadrant i, so adjust
187 	   BBox to reflect this. */
188 
189 	switch(i % 4) {
190 	case 0:
191 	    bounds.right = right;
192 	    break;
193 	case 1:
194 	    bounds.top = top;
195 	    break;
196 	case 2:
197 	    bounds.left = left;
198 	    break;
199 	case 3:
200 	    bounds.bottom = bottom;
201 	    break;
202 	}
203     }
204 
205     /* If we're drawing a pie then make sure we include the centre */
206     if (type == EMR_PIE)
207     {
208         if (bounds.left > x_centre) bounds.left = x_centre;
209 	else if (bounds.right < x_centre) bounds.right = x_centre;
210 	if (bounds.top > y_centre) bounds.top = y_centre;
211 	else if (bounds.bottom < y_centre) bounds.bottom = y_centre;
212     }
213     else if (type == EMR_ARCTO)
214     {
215         POINT pt;
216         //pt = dc->attr->cur_pos;
217         GetCurrentPositionEx(dc->hdc, &pt);
218         bounds.left   = min( bounds.left, pt.x );
219         bounds.top    = min( bounds.top, pt.y );
220         bounds.right  = max( bounds.right, pt.x );
221         bounds.bottom = max( bounds.bottom, pt.y );
222     }
223     emfdrv_update_bounds( dc, &bounds );
224     return TRUE;
225 }
226 
EMFDRV_Arc(WINEDC * dc,INT left,INT top,INT right,INT bottom,INT xstart,INT ystart,INT xend,INT yend)227 BOOL EMFDRV_Arc( WINEDC *dc, INT left, INT top, INT right, INT bottom,
228                               INT xstart, INT ystart, INT xend, INT yend )
229 {
230     return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
231                                xend, yend, EMR_ARC );
232 }
233 
EMFDRV_ArcTo(WINEDC * dc,INT left,INT top,INT right,INT bottom,INT xstart,INT ystart,INT xend,INT yend)234 BOOL EMFDRV_ArcTo( WINEDC *dc, INT left, INT top, INT right, INT bottom,
235                                 INT xstart, INT ystart, INT xend, INT yend )
236 {
237     return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
238                                xend, yend, EMR_ARCTO );
239 }
240 
EMFDRV_Pie(WINEDC * dc,INT left,INT top,INT right,INT bottom,INT xstart,INT ystart,INT xend,INT yend)241 BOOL EMFDRV_Pie( WINEDC *dc, INT left, INT top, INT right, INT bottom,
242                               INT xstart, INT ystart, INT xend, INT yend )
243 {
244     return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
245                                xend, yend, EMR_PIE );
246 }
247 
EMFDRV_Chord(WINEDC * dc,INT left,INT top,INT right,INT bottom,INT xstart,INT ystart,INT xend,INT yend)248 BOOL EMFDRV_Chord( WINEDC *dc, INT left, INT top, INT right, INT bottom,
249                                 INT xstart, INT ystart, INT xend, INT yend )
250 {
251     return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
252                                xend, yend, EMR_CHORD );
253 }
254 
EMFDRV_Ellipse(WINEDC * dc,INT left,INT top,INT right,INT bottom)255 BOOL EMFDRV_Ellipse( WINEDC *dc, INT left, INT top, INT right, INT bottom )
256 {
257     RECTL bounds;
258 
259     if (left == right || top == bottom) return FALSE;
260 
261     bounds.left   = min( left, right );
262     bounds.top    = min( top, bottom );
263     bounds.right  = max( left, right );
264     bounds.bottom = max( top, bottom );
265     if (GetGraphicsMode(dc->hdc) == GM_COMPATIBLE)//dc->attr->graphics_mode == GM_COMPATIBLE)
266     {
267         bounds.right--;
268         bounds.bottom--;
269     }
270 
271     emfdrv_update_bounds( dc, &bounds );
272     return TRUE;
273 }
274 
EMFDRV_Rectangle(WINEDC * dc,INT left,INT top,INT right,INT bottom)275 BOOL EMFDRV_Rectangle( WINEDC *dc, INT left, INT top, INT right, INT bottom )
276 {
277     RECTL bounds;
278 
279     if (left == right || top == bottom) return FALSE;
280 
281     bounds.left   = min( left, right );
282     bounds.top    = min( top, bottom );
283     bounds.right  = max( left, right );
284     bounds.bottom = max( top, bottom );
285     if (GetGraphicsMode(dc->hdc) == GM_COMPATIBLE)//dc->attr->graphics_mode == GM_COMPATIBLE)
286     {
287         bounds.right--;
288         bounds.bottom--;
289     }
290 
291     emfdrv_update_bounds( dc, &bounds );
292     return TRUE;
293 }
294 
EMFDRV_SetPixel(WINEDC * dc,INT x,INT y,COLORREF color)295 COLORREF EMFDRV_SetPixel( WINEDC *dc, INT x, INT y, COLORREF color )
296 {
297     RECTL bounds;
298 
299     bounds.left = bounds.right = x;
300     bounds.top = bounds.bottom = y;
301     emfdrv_update_bounds( dc, &bounds );
302     return CLR_INVALID;
303 }
304 
EMFDRV_PolylineTo(WINEDC * dc,const POINT * pt,INT count)305 BOOL EMFDRV_PolylineTo( WINEDC *dc, const POINT *pt, INT count )
306 {
307     /* FIXME: update bounding rect */
308     return TRUE;
309 }
310 
EMFDRV_PolyBezier(WINEDC * dc,const POINT * pts,DWORD count)311 BOOL EMFDRV_PolyBezier( WINEDC *dc, const POINT *pts, DWORD count )
312 {
313     /* FIXME: update bounding rect */
314     return TRUE;
315 }
316 
EMFDRV_PolyBezierTo(WINEDC * dc,const POINT * pts,DWORD count)317 BOOL EMFDRV_PolyBezierTo( WINEDC *dc, const POINT *pts, DWORD count )
318 {
319     /* FIXME: update bounding rect */
320     return TRUE;
321 }
322 
EMFDRV_PolyPolyline(WINEDC * dc,const POINT * pt,const DWORD * counts,UINT polys)323 BOOL EMFDRV_PolyPolyline( WINEDC *dc, const POINT *pt,
324                                        const DWORD *counts, UINT polys )
325 {
326     /* FIXME: update bounding rect */
327     return TRUE;
328 }
329 
EMFDRV_PolyPolygon(WINEDC * dc,const POINT * pt,const INT * counts,UINT polys)330 BOOL EMFDRV_PolyPolygon( WINEDC *dc, const POINT *pt,
331                                       const INT *counts, UINT polys )
332 {
333     /* FIXME: update bounding rect */
334     return TRUE;
335 }
336 
EMFDRV_PolyDraw(WINEDC * dc,const POINT * pts,const BYTE * types,DWORD count)337 BOOL EMFDRV_PolyDraw( WINEDC *dc, const POINT *pts,
338                                    const BYTE *types, DWORD count )
339 {
340     /* FIXME: update bounding rect */
341     return TRUE;
342 }
343 
EMFDRV_FillRgn(WINEDC * dc,HRGN hrgn,HBRUSH hbrush)344 BOOL EMFDRV_FillRgn( WINEDC *dc, HRGN hrgn, HBRUSH hbrush )
345 {
346     /* FIXME: update bounding rect */
347     return TRUE;
348 }
349 
EMFDRV_FrameRgn(WINEDC * dc,HRGN hrgn,HBRUSH hbrush,INT width,INT height)350 BOOL EMFDRV_FrameRgn( WINEDC *dc, HRGN hrgn, HBRUSH hbrush, INT width, INT height )
351 {
352     /* FIXME: update bounding rect */
353     return TRUE;
354 }
355 
EMFDRV_InvertRgn(WINEDC * dc,HRGN hrgn)356 BOOL EMFDRV_InvertRgn( WINEDC *dc, HRGN hrgn )
357 {
358     /* FIXME: update bounding rect */
359     return TRUE;
360 }
361 
EMFDRV_ExtTextOut(WINEDC * dc,INT x,INT y,UINT flags,const RECT * lprect,LPCWSTR str,UINT count,const INT * lpDx)362 BOOL EMFDRV_ExtTextOut( WINEDC *dc, INT x, INT y, UINT flags, const RECT *lprect,
363                                      LPCWSTR str, UINT count, const INT *lpDx )
364 {
365     /* FIXME: update bounding rect */
366     return TRUE;
367 }
368 
EMFDRV_GradientFill(WINEDC * dc,TRIVERTEX * vert_array,ULONG nvert,void * grad_array,ULONG ngrad,ULONG mode)369 BOOL EMFDRV_GradientFill( WINEDC *dc, TRIVERTEX *vert_array, ULONG nvert,
370                                        void *grad_array, ULONG ngrad, ULONG mode )
371 {
372     /* FIXME: update bounding rect */
373     return TRUE;
374 }
375 
EMFDRV_FillPath(WINEDC * dc)376 BOOL EMFDRV_FillPath( WINEDC *dc )
377 {
378     /* FIXME: update bound rect */
379     return TRUE;
380 }
381 
EMFDRV_StrokeAndFillPath(WINEDC * dc)382 BOOL EMFDRV_StrokeAndFillPath( WINEDC *dc )
383 {
384     /* FIXME: update bound rect */
385     return TRUE;
386 }
387 
EMFDRV_StrokePath(WINEDC * dc)388 BOOL EMFDRV_StrokePath( WINEDC *dc )
389 {
390     /* FIXME: update bound rect */
391     return TRUE;
392 }
393 
EMFDRV_AlphaBlend(WINEDC * dc_dst,INT x_dst,INT y_dst,INT width_dst,INT height_dst,HDC dc_src,INT x_src,INT y_src,INT width_src,INT height_src,BLENDFUNCTION func)394 BOOL EMFDRV_AlphaBlend( WINEDC *dc_dst, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
395                                      HDC dc_src, INT x_src, INT y_src, INT width_src, INT height_src,
396                                      BLENDFUNCTION func )
397 {
398     /* FIXME: update bound rect */
399     return TRUE;
400 }
401 
EMFDRV_PatBlt(WINEDC * dc,INT left,INT top,INT width,INT height,DWORD rop)402 BOOL EMFDRV_PatBlt( WINEDC *dc, INT left, INT top, INT width, INT height, DWORD rop )
403 {
404     /* FIXME: update bound rect */
405     return TRUE;
406 }
407 
EMFDRV_StretchDIBits(WINEDC * dc,INT x_dst,INT y_dst,INT width_dst,INT height_dst,INT x_src,INT y_src,INT width_src,INT height_src,const void * bits,BITMAPINFO * info,UINT wUsage,DWORD dwRop)408 INT EMFDRV_StretchDIBits( WINEDC *dc, INT x_dst, INT y_dst, INT width_dst,
409                                        INT height_dst, INT x_src, INT y_src, INT width_src,
410                                        INT height_src, const void *bits, BITMAPINFO *info,
411                                        UINT wUsage, DWORD dwRop )
412 {
413     /* FIXME: Update bound rect */
414     return height_src;
415 }
416 
EMFDRV_SetDIBitsToDevice(WINEDC * dc,INT x_dst,INT y_dst,DWORD width,DWORD height,INT x_src,INT y_src,UINT startscan,UINT lines,const void * bits,BITMAPINFO * info,UINT usage)417 INT EMFDRV_SetDIBitsToDevice( WINEDC *dc, INT x_dst, INT y_dst, DWORD width,
418                                            DWORD height, INT x_src, INT y_src, UINT startscan,
419                                            UINT lines, const void *bits, BITMAPINFO *info,
420                                            UINT usage )
421 {
422     /* FIXME: Update bound rect */
423     return lines;
424 }
425 
EMFDRV_SelectBitmap(WINEDC * dc,HBITMAP hbitmap)426 HBITMAP EMFDRV_SelectBitmap( WINEDC *dc, HBITMAP hbitmap )
427 {
428     return 0;
429 }
430 
431