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