msxml3: Release IDispatchEx dynamic data properly.
[wine] / dlls / gdi32 / dibdrv / graphics.c
1 /*
2  * DIB driver graphics operations.
3  *
4  * Copyright 2011 Huw Davies
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 "gdi_private.h"
22 #include "dibdrv.h"
23
24 #include "wine/debug.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(dib);
27
28 static RECT get_device_rect( HDC hdc, int left, int top, int right, int bottom, BOOL rtl_correction )
29 {
30     RECT rect;
31
32     rect.left   = left;
33     rect.top    = top;
34     rect.right  = right;
35     rect.bottom = bottom;
36     if (rtl_correction && GetLayout( hdc ) & LAYOUT_RTL)
37     {
38         /* shift the rectangle so that the right border is included after mirroring */
39         /* it would be more correct to do this after LPtoDP but that's not what Windows does */
40         rect.left--;
41         rect.right--;
42     }
43     LPtoDP( hdc, (POINT *)&rect, 2 );
44     if (rect.left > rect.right)
45     {
46         int tmp = rect.left;
47         rect.left = rect.right;
48         rect.right = tmp;
49     }
50     if (rect.top > rect.bottom)
51     {
52         int tmp = rect.top;
53         rect.top = rect.bottom;
54         rect.bottom = tmp;
55     }
56     return rect;
57 }
58
59 /***********************************************************************
60  *           dibdrv_GetPixel
61  */
62 COLORREF dibdrv_GetPixel( PHYSDEV dev, INT x, INT y )
63 {
64     dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
65     POINT pt;
66     DWORD pixel;
67
68     TRACE( "(%p, %d, %d)\n", dev, x, y );
69
70     pt.x = x;
71     pt.y = y;
72     LPtoDP( dev->hdc, &pt, 1 );
73
74     if (pt.x < 0 || pt.x >= pdev->dib.width ||
75         pt.y < 0 || pt.y >= pdev->dib.height)
76         return CLR_INVALID;
77
78     pixel = pdev->dib.funcs->get_pixel( &pdev->dib, &pt );
79     return pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
80 }
81
82 /***********************************************************************
83  *           dibdrv_LineTo
84  */
85 BOOL dibdrv_LineTo( PHYSDEV dev, INT x, INT y )
86 {
87     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pLineTo );
88     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
89     POINT pts[2];
90
91     GetCurrentPositionEx(dev->hdc, pts);
92     pts[1].x = x;
93     pts[1].y = y;
94
95     LPtoDP(dev->hdc, pts, 2);
96
97     reset_dash_origin(pdev);
98
99     if(defer_pen(pdev) || !pdev->pen_lines(pdev, 2, pts))
100         return next->funcs->pLineTo( next, x, y );
101
102     return TRUE;
103 }
104
105 /***********************************************************************
106  *           get_rop2_from_rop
107  *
108  * Returns the binary rop that is equivalent to the provided ternary rop
109  * if the src bits are ignored.
110  */
111 static inline INT get_rop2_from_rop(INT rop)
112 {
113     return (((rop >> 18) & 0x0c) | ((rop >> 16) & 0x03)) + 1;
114 }
115
116 /***********************************************************************
117  *           dibdrv_PatBlt
118  */
119 BOOL dibdrv_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
120 {
121     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPatBlt );
122     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
123     INT rop2 = get_rop2_from_rop(rop);
124     BOOL done;
125
126     TRACE("(%p, %d, %d, %d, %d, %06x)\n", dev, dst->x, dst->y, dst->width, dst->height, rop);
127
128     if(defer_brush(pdev))
129         return next->funcs->pPatBlt( next, dst, rop );
130
131     update_brush_rop( pdev, rop2 );
132
133     done = brush_rects( pdev, 1, &dst->visrect );
134
135     update_brush_rop( pdev, GetROP2(dev->hdc) );
136
137     if(!done)
138         return next->funcs->pPatBlt( next, dst, rop );
139
140     return TRUE;
141 }
142
143 /***********************************************************************
144  *           dibdrv_PaintRgn
145  */
146 BOOL dibdrv_PaintRgn( PHYSDEV dev, HRGN rgn )
147 {
148     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPaintRgn );
149     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
150     const WINEREGION *region;
151     int i;
152     RECT rect;
153
154     TRACE("%p, %p\n", dev, rgn);
155
156     if(defer_brush(pdev)) return next->funcs->pPaintRgn( next, rgn );
157
158     region = get_wine_region( rgn );
159     if(!region) return FALSE;
160
161     for(i = 0; i < region->numRects; i++)
162     {
163         rect = get_device_rect( dev->hdc, region->rects[i].left, region->rects[i].top,
164                                 region->rects[i].right, region->rects[i].bottom, FALSE );
165         brush_rects( pdev, 1, &rect );
166     }
167
168     release_wine_region( rgn );
169     return TRUE;
170 }
171
172 /***********************************************************************
173  *           dibdrv_PolyPolyline
174  */
175 BOOL dibdrv_PolyPolyline( PHYSDEV dev, const POINT* pt, const DWORD* counts, DWORD polylines )
176 {
177     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
178     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPolyPolyline );
179     DWORD max_points = 0, i;
180     POINT *points;
181
182     if (defer_pen( pdev )) return next->funcs->pPolyPolyline( next, pt, counts, polylines );
183
184     for (i = 0; i < polylines; i++) max_points = max( counts[i], max_points );
185
186     points = HeapAlloc( GetProcessHeap(), 0, max_points * sizeof(*pt) );
187     if (!points) return FALSE;
188
189     for (i = 0; i < polylines; i++)
190     {
191         memcpy( points, pt, counts[i] * sizeof(*pt) );
192         pt += counts[i];
193         LPtoDP( dev->hdc, points, counts[i] );
194
195         reset_dash_origin( pdev );
196         pdev->pen_lines( pdev, counts[i], points );
197     }
198
199     HeapFree( GetProcessHeap(), 0, points );
200     return TRUE;
201 }
202
203 /***********************************************************************
204  *           dibdrv_Polyline
205  */
206 BOOL dibdrv_Polyline( PHYSDEV dev, const POINT* pt, INT count )
207 {
208     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
209     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPolyline );
210     POINT *points;
211
212     if (defer_pen( pdev )) return next->funcs->pPolyline( next, pt, count );
213
214     points = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pt) );
215     if (!points) return FALSE;
216
217     memcpy( points, pt, count * sizeof(*pt) );
218     LPtoDP( dev->hdc, points, count );
219
220     reset_dash_origin( pdev );
221     pdev->pen_lines( pdev, count, points );
222
223     HeapFree( GetProcessHeap(), 0, points );
224     return TRUE;
225 }
226
227 /***********************************************************************
228  *           dibdrv_Rectangle
229  */
230 BOOL dibdrv_Rectangle( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
231 {
232     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pRectangle );
233     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
234     RECT rect = get_device_rect( dev->hdc, left, top, right, bottom, TRUE );
235     POINT pts[5];
236
237     TRACE("(%p, %d, %d, %d, %d)\n", dev, left, top, right, bottom);
238
239     if(rect.left == rect.right || rect.top == rect.bottom) return TRUE;
240
241     if(defer_pen(pdev) || defer_brush(pdev))
242         return next->funcs->pRectangle( next, left, top, right, bottom );
243
244     reset_dash_origin(pdev);
245
246     /* 4 pts going anti-clockwise starting from top-right */
247     pts[0].x = pts[3].x = rect.right - 1;
248     pts[0].y = pts[1].y = rect.top;
249     pts[1].x = pts[2].x = rect.left;
250     pts[2].y = pts[3].y = rect.bottom - 1;
251     pts[4] = pts[0];
252
253     pdev->pen_lines(pdev, 5, pts);
254
255     /* FIXME: Will need updating when we support wide pens */
256
257     rect.left   += 1;
258     rect.top    += 1;
259     rect.right  -= 1;
260     rect.bottom -= 1;
261
262     brush_rects(pdev, 1, &rect);
263
264     return TRUE;
265 }
266
267 /***********************************************************************
268  *           dibdrv_SetPixel
269  */
270 COLORREF dibdrv_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color )
271 {
272     dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
273     int i;
274     POINT pt;
275     DWORD pixel;
276     const WINEREGION *clip = get_wine_region( pdev->clip );
277
278     TRACE( "(%p, %d, %d, %08x)\n", dev, x, y, color );
279
280     pt.x = x;
281     pt.y = y;
282     LPtoDP( dev->hdc, &pt, 1 );
283
284     /* SetPixel doesn't do the 1bpp massaging like other fg colors */
285     pixel = get_pixel_color( pdev, color, FALSE );
286     color = pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
287
288     for (i = 0; i < clip->numRects; i++)
289     {
290         if (pt_in_rect( clip->rects + i, pt ))
291         {
292             RECT rect;
293             rect.left = pt.x;
294             rect.top =  pt.y;
295             rect.right = rect.left + 1;
296             rect.bottom = rect.top + 1;
297
298             pdev->dib.funcs->solid_rects( &pdev->dib, 1, &rect, 0, pixel );
299             break;
300         }
301     }
302
303     release_wine_region( pdev->clip );
304     return color;
305 }