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