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