xref: /reactos/win32ss/gdi/gdi32/wine/mfdrv/graphics.c (revision c2c66aff)
1 /*
2  * Metafile driver graphics functions
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "mfdrv/metafiledrv.h"
29 #include "wine/debug.h"
30 
31 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
32 
33 /**********************************************************************
34  *	     MFDRV_MoveTo
35  */
MFDRV_MoveTo(PHYSDEV dev,INT x,INT y)36 BOOL MFDRV_MoveTo(PHYSDEV dev, INT x, INT y)
37 {
38     return MFDRV_MetaParam2(dev,META_MOVETO,x,y);
39 }
40 
41 /***********************************************************************
42  *           MFDRV_LineTo
43  */
MFDRV_LineTo(PHYSDEV dev,INT x,INT y)44 BOOL MFDRV_LineTo( PHYSDEV dev, INT x, INT y )
45 {
46      return MFDRV_MetaParam2(dev, META_LINETO, x, y);
47 }
48 
49 
50 /***********************************************************************
51  *           MFDRV_Arc
52  */
MFDRV_Arc(PHYSDEV dev,INT left,INT top,INT right,INT bottom,INT xstart,INT ystart,INT xend,INT yend)53 BOOL MFDRV_Arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
54                 INT xstart, INT ystart, INT xend, INT yend )
55 {
56      return MFDRV_MetaParam8(dev, META_ARC, left, top, right, bottom,
57 			     xstart, ystart, xend, yend);
58 }
59 
60 
61 /***********************************************************************
62  *           MFDRV_Pie
63  */
MFDRV_Pie(PHYSDEV dev,INT left,INT top,INT right,INT bottom,INT xstart,INT ystart,INT xend,INT yend)64 BOOL MFDRV_Pie( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
65                 INT xstart, INT ystart, INT xend, INT yend )
66 {
67     return MFDRV_MetaParam8(dev, META_PIE, left, top, right, bottom,
68 			    xstart, ystart, xend, yend);
69 }
70 
71 
72 /***********************************************************************
73  *           MFDRV_Chord
74  */
MFDRV_Chord(PHYSDEV dev,INT left,INT top,INT right,INT bottom,INT xstart,INT ystart,INT xend,INT yend)75 BOOL MFDRV_Chord( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
76                   INT xstart, INT ystart, INT xend, INT yend )
77 {
78     return MFDRV_MetaParam8(dev, META_CHORD, left, top, right, bottom,
79 			    xstart, ystart, xend, yend);
80 }
81 
82 /***********************************************************************
83  *           MFDRV_Ellipse
84  */
MFDRV_Ellipse(PHYSDEV dev,INT left,INT top,INT right,INT bottom)85 BOOL MFDRV_Ellipse( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
86 {
87     return MFDRV_MetaParam4(dev, META_ELLIPSE, left, top, right, bottom);
88 }
89 
90 /***********************************************************************
91  *           MFDRV_Rectangle
92  */
MFDRV_Rectangle(PHYSDEV dev,INT left,INT top,INT right,INT bottom)93 BOOL MFDRV_Rectangle(PHYSDEV dev, INT left, INT top, INT right, INT bottom)
94 {
95     return MFDRV_MetaParam4(dev, META_RECTANGLE, left, top, right, bottom);
96 }
97 
98 /***********************************************************************
99  *           MFDRV_RoundRect
100  */
MFDRV_RoundRect(PHYSDEV dev,INT left,INT top,INT right,INT bottom,INT ell_width,INT ell_height)101 BOOL MFDRV_RoundRect( PHYSDEV dev, INT left, INT top, INT right,
102                       INT bottom, INT ell_width, INT ell_height )
103 {
104     return MFDRV_MetaParam6(dev, META_ROUNDRECT, left, top, right, bottom,
105 			    ell_width, ell_height);
106 }
107 
108 /***********************************************************************
109  *           MFDRV_SetPixel
110  */
MFDRV_SetPixel(PHYSDEV dev,INT x,INT y,COLORREF color)111 COLORREF MFDRV_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color )
112 {
113     return MFDRV_MetaParam4(dev, META_SETPIXEL, x, y,HIWORD(color),
114 			    LOWORD(color));
115 }
116 
117 
118 /******************************************************************
119  *         MFDRV_MetaPoly - implements Polygon and Polyline
120  */
MFDRV_MetaPoly(PHYSDEV dev,short func,POINTS * pt,short count)121 static BOOL MFDRV_MetaPoly(PHYSDEV dev, short func, POINTS *pt, short count)
122 {
123     BOOL ret;
124     DWORD len;
125     METARECORD *mr;
126 
127     len = sizeof(METARECORD) + (count * 4);
128     if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len )))
129 	return FALSE;
130 
131     mr->rdSize = len / 2;
132     mr->rdFunction = func;
133     *(mr->rdParm) = count;
134     memcpy(mr->rdParm + 1, pt, count * 4);
135     ret = MFDRV_WriteRecord( dev, mr, mr->rdSize * 2);
136     HeapFree( GetProcessHeap(), 0, mr);
137     return ret;
138 }
139 
140 
141 /**********************************************************************
142  *          MFDRV_Polyline
143  */
MFDRV_Polyline(PHYSDEV dev,const POINT * pt,INT count)144 BOOL MFDRV_Polyline( PHYSDEV dev, const POINT* pt, INT count )
145 {
146     int i;
147     POINTS *pts;
148     BOOL ret;
149 
150     pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINTS)*count );
151     if(!pts) return FALSE;
152     for (i=count;i--;)
153     {
154         pts[i].x = pt[i].x;
155         pts[i].y = pt[i].y;
156     }
157     ret = MFDRV_MetaPoly(dev, META_POLYLINE, pts, count);
158 
159     HeapFree( GetProcessHeap(), 0, pts );
160     return ret;
161 }
162 
163 
164 /**********************************************************************
165  *          MFDRV_Polygon
166  */
MFDRV_Polygon(PHYSDEV dev,const POINT * pt,INT count)167 BOOL MFDRV_Polygon( PHYSDEV dev, const POINT* pt, INT count )
168 {
169     int i;
170     POINTS *pts;
171     BOOL ret;
172 
173     pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINTS)*count );
174     if(!pts) return FALSE;
175     for (i=count;i--;)
176     {
177         pts[i].x = pt[i].x;
178         pts[i].y = pt[i].y;
179     }
180     ret = MFDRV_MetaPoly(dev, META_POLYGON, pts, count);
181 
182     HeapFree( GetProcessHeap(), 0, pts );
183     return ret;
184 }
185 
186 
187 /**********************************************************************
188  *          MFDRV_PolyPolygon
189  */
MFDRV_PolyPolygon(PHYSDEV dev,const POINT * pt,const INT * counts,UINT polygons)190 BOOL MFDRV_PolyPolygon( PHYSDEV dev, const POINT* pt, const INT* counts, UINT polygons)
191 {
192     BOOL ret;
193     DWORD len;
194     METARECORD *mr;
195     unsigned int i,j;
196     POINTS *pts;
197     INT16 totalpoint16 = 0;
198     INT16 * pointcounts;
199 
200     for (i=0;i<polygons;i++) {
201          totalpoint16 += counts[i];
202     }
203 
204     /* allocate space for all points */
205     pts=HeapAlloc( GetProcessHeap(), 0, sizeof(POINTS) * totalpoint16 );
206     pointcounts = HeapAlloc( GetProcessHeap(), 0, sizeof(INT16) * totalpoint16 );
207 
208     /* copy point counts */
209     for (i=0;i<polygons;i++) {
210           pointcounts[i] = counts[i];
211     }
212 
213     /* convert all points */
214     for (j = totalpoint16; j--;){
215         pts[j].x = pt[j].x;
216         pts[j].y = pt[j].y;
217     }
218 
219     len = sizeof(METARECORD) + sizeof(WORD) + polygons*sizeof(INT16) + totalpoint16*sizeof(*pts);
220 
221     if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len ))) {
222          HeapFree( GetProcessHeap(), 0, pts );
223          HeapFree( GetProcessHeap(), 0, pointcounts );
224          return FALSE;
225     }
226 
227     mr->rdSize = len /2;
228     mr->rdFunction = META_POLYPOLYGON;
229     *(mr->rdParm) = polygons;
230     memcpy(mr->rdParm + 1, pointcounts, polygons*sizeof(INT16));
231     memcpy(mr->rdParm + 1+polygons, pts , totalpoint16*sizeof(*pts));
232     ret = MFDRV_WriteRecord( dev, mr, mr->rdSize * 2);
233 
234     HeapFree( GetProcessHeap(), 0, pts );
235     HeapFree( GetProcessHeap(), 0, pointcounts );
236     HeapFree( GetProcessHeap(), 0, mr);
237     return ret;
238 }
239 
240 
241 /**********************************************************************
242  *          MFDRV_ExtFloodFill
243  */
MFDRV_ExtFloodFill(PHYSDEV dev,INT x,INT y,COLORREF color,UINT fillType)244 BOOL MFDRV_ExtFloodFill( PHYSDEV dev, INT x, INT y, COLORREF color, UINT fillType )
245 {
246     return MFDRV_MetaParam4(dev,META_FLOODFILL,x,y,HIWORD(color),
247 			    LOWORD(color));
248 }
249 
250 
251 /******************************************************************
252  *         MFDRV_CreateRegion
253  *
254  * For explanation of the format of the record see MF_Play_MetaCreateRegion in
255  * objects/metafile.c
256  */
MFDRV_CreateRegion(PHYSDEV dev,HRGN hrgn)257 static INT16 MFDRV_CreateRegion(PHYSDEV dev, HRGN hrgn)
258 {
259     DWORD len;
260     METARECORD *mr;
261     RGNDATA *rgndata;
262     RECT *pCurRect, *pEndRect;
263     WORD Bands = 0, MaxBands = 0;
264     WORD *Param, *StartBand;
265     BOOL ret;
266 
267     if (!(len = GetRegionData( hrgn, 0, NULL ))) return -1;
268     if( !(rgndata = HeapAlloc( GetProcessHeap(), 0, len )) ) {
269         WARN("Can't alloc rgndata buffer\n");
270 	return -1;
271     }
272     GetRegionData( hrgn, len, rgndata );
273 
274     /* Overestimate of length:
275      * Assume every rect is a separate band -> 6 WORDs per rect
276      */
277     len = sizeof(METARECORD) + 20 + (rgndata->rdh.nCount * 12);
278     if( !(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len )) ) {
279         WARN("Can't alloc METARECORD buffer\n");
280 	HeapFree( GetProcessHeap(), 0, rgndata );
281 	return -1;
282     }
283 
284     Param = mr->rdParm + 11;
285     StartBand = NULL;
286 
287     pEndRect = (RECT *)rgndata->Buffer + rgndata->rdh.nCount;
288     for(pCurRect = (RECT *)rgndata->Buffer; pCurRect < pEndRect; pCurRect++)
289     {
290         if( StartBand && pCurRect->top == *(StartBand + 1) )
291         {
292 	    *Param++ = pCurRect->left;
293 	    *Param++ = pCurRect->right;
294 	}
295 	else
296 	{
297 	    if(StartBand)
298 	    {
299 	        *StartBand = Param - StartBand - 3;
300 		*Param++ = *StartBand;
301 		if(*StartBand > MaxBands)
302 		    MaxBands = *StartBand;
303 		Bands++;
304 	    }
305 	    StartBand = Param++;
306 	    *Param++ = pCurRect->top;
307 	    *Param++ = pCurRect->bottom;
308 	    *Param++ = pCurRect->left;
309 	    *Param++ = pCurRect->right;
310 	}
311     }
312 
313     if (StartBand)
314     {
315         *StartBand = Param - StartBand - 3;
316         *Param++ = *StartBand;
317         if(*StartBand > MaxBands)
318             MaxBands = *StartBand;
319         Bands++;
320     }
321 
322     mr->rdParm[0] = 0;
323     mr->rdParm[1] = 6;
324     mr->rdParm[2] = 0x2f6;
325     mr->rdParm[3] = 0;
326     mr->rdParm[4] = (Param - &mr->rdFunction) * sizeof(WORD);
327     mr->rdParm[5] = Bands;
328     mr->rdParm[6] = MaxBands;
329     mr->rdParm[7] = rgndata->rdh.rcBound.left;
330     mr->rdParm[8] = rgndata->rdh.rcBound.top;
331     mr->rdParm[9] = rgndata->rdh.rcBound.right;
332     mr->rdParm[10] = rgndata->rdh.rcBound.bottom;
333     mr->rdFunction = META_CREATEREGION;
334     mr->rdSize = Param - (WORD *)mr;
335     ret = MFDRV_WriteRecord( dev, mr, mr->rdSize * 2 );
336     HeapFree( GetProcessHeap(), 0, mr );
337     HeapFree( GetProcessHeap(), 0, rgndata );
338     if(!ret)
339     {
340         WARN("MFDRV_WriteRecord failed\n");
341 	return -1;
342     }
343     return MFDRV_AddHandle( dev, hrgn );
344 }
345 
346 
347 /**********************************************************************
348  *          MFDRV_PaintRgn
349  */
MFDRV_PaintRgn(PHYSDEV dev,HRGN hrgn)350 BOOL MFDRV_PaintRgn( PHYSDEV dev, HRGN hrgn )
351 {
352     INT16 index;
353     index = MFDRV_CreateRegion( dev, hrgn );
354     if(index == -1)
355         return FALSE;
356     return MFDRV_MetaParam1( dev, META_PAINTREGION, index );
357 }
358 
359 
360 /**********************************************************************
361  *          MFDRV_InvertRgn
362  */
MFDRV_InvertRgn(PHYSDEV dev,HRGN hrgn)363 BOOL MFDRV_InvertRgn( PHYSDEV dev, HRGN hrgn )
364 {
365     INT16 index;
366     index = MFDRV_CreateRegion( dev, hrgn );
367     if(index == -1)
368         return FALSE;
369     return MFDRV_MetaParam1( dev, META_INVERTREGION, index );
370 }
371 
372 
373 /**********************************************************************
374  *          MFDRV_FillRgn
375  */
MFDRV_FillRgn(PHYSDEV dev,HRGN hrgn,HBRUSH hbrush)376 BOOL MFDRV_FillRgn( PHYSDEV dev, HRGN hrgn, HBRUSH hbrush )
377 {
378     INT16 iRgn, iBrush;
379     iRgn = MFDRV_CreateRegion( dev, hrgn );
380     if(iRgn == -1)
381         return FALSE;
382     iBrush = MFDRV_CreateBrushIndirect( dev, hbrush );
383     if(!iBrush)
384         return FALSE;
385     return MFDRV_MetaParam2( dev, META_FILLREGION, iRgn, iBrush );
386 }
387 
388 /**********************************************************************
389  *          MFDRV_FrameRgn
390  */
MFDRV_FrameRgn(PHYSDEV dev,HRGN hrgn,HBRUSH hbrush,INT x,INT y)391 BOOL MFDRV_FrameRgn( PHYSDEV dev, HRGN hrgn, HBRUSH hbrush, INT x, INT y )
392 {
393     INT16 iRgn, iBrush;
394     iRgn = MFDRV_CreateRegion( dev, hrgn );
395     if(iRgn == -1)
396         return FALSE;
397     iBrush = MFDRV_CreateBrushIndirect( dev, hbrush );
398     if(!iBrush)
399         return FALSE;
400     return MFDRV_MetaParam4( dev, META_FRAMEREGION, iRgn, iBrush, x, y );
401 }
402 
403 
404 /**********************************************************************
405  *          MFDRV_ExtSelectClipRgn
406  */
MFDRV_ExtSelectClipRgn(PHYSDEV dev,HRGN hrgn,INT mode)407 INT MFDRV_ExtSelectClipRgn( PHYSDEV dev, HRGN hrgn, INT mode )
408 {
409     INT16 iRgn;
410     INT ret;
411 
412     if (mode != RGN_COPY) return ERROR;
413     if (!hrgn) return NULLREGION;
414     iRgn = MFDRV_CreateRegion( dev, hrgn );
415     if(iRgn == -1) return ERROR;
416     ret = MFDRV_MetaParam1( dev, META_SELECTOBJECT, iRgn ) ? NULLREGION : ERROR;
417     MFDRV_MetaParam1( dev, META_DELETEOBJECT, iRgn );
418     MFDRV_RemoveHandle( dev, iRgn );
419     return ret;
420 }
421 
422 
423 /**********************************************************************
424  *          MFDRV_PolyBezier
425  * Since MetaFiles don't record Beziers and they don't even record
426  * approximations to them using lines, we need this stub function.
427  */
MFDRV_PolyBezier(PHYSDEV dev,const POINT * pts,DWORD count)428 BOOL MFDRV_PolyBezier( PHYSDEV dev, const POINT *pts, DWORD count )
429 {
430     return FALSE;
431 }
432 
433 /**********************************************************************
434  *          MFDRV_PolyBezierTo
435  * Since MetaFiles don't record Beziers and they don't even record
436  * approximations to them using lines, we need this stub function.
437  */
MFDRV_PolyBezierTo(PHYSDEV dev,const POINT * pts,DWORD count)438 BOOL MFDRV_PolyBezierTo( PHYSDEV dev, const POINT *pts, DWORD count )
439 {
440     return FALSE;
441 }
442