gdi32: Implement SetPixel.
[wine.git] / dlls / gdi32 / dibdrv / graphics.c
blobb68b17e277c1e77decaca0a69027f7b0f5750d1a
1 /*
2 * DIB driver graphics operations.
4 * Copyright 2011 Huw Davies
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.
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.
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
21 #include "gdi_private.h"
22 #include "dibdrv.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dib);
28 static RECT get_device_rect( HDC hdc, int left, int top, int right, int bottom, BOOL rtl_correction )
30 RECT rect;
32 rect.left = left;
33 rect.top = top;
34 rect.right = right;
35 rect.bottom = bottom;
36 if (rtl_correction && GetLayout( hdc ) & LAYOUT_RTL)
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--;
43 LPtoDP( hdc, (POINT *)&rect, 2 );
44 if (rect.left > rect.right)
46 int tmp = rect.left;
47 rect.left = rect.right;
48 rect.right = tmp;
50 if (rect.top > rect.bottom)
52 int tmp = rect.top;
53 rect.top = rect.bottom;
54 rect.bottom = tmp;
56 return rect;
59 /***********************************************************************
60 * dibdrv_LineTo
62 BOOL dibdrv_LineTo( PHYSDEV dev, INT x, INT y )
64 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pLineTo );
65 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
66 POINT pts[2];
68 GetCurrentPositionEx(dev->hdc, pts);
69 pts[1].x = x;
70 pts[1].y = y;
72 LPtoDP(dev->hdc, pts, 2);
74 reset_dash_origin(pdev);
76 if(defer_pen(pdev) || !pdev->pen_lines(pdev, 2, pts))
77 return next->funcs->pLineTo( next, x, y );
79 return TRUE;
82 /***********************************************************************
83 * get_rop2_from_rop
85 * Returns the binary rop that is equivalent to the provided ternary rop
86 * if the src bits are ignored.
88 static inline INT get_rop2_from_rop(INT rop)
90 return (((rop >> 18) & 0x0c) | ((rop >> 16) & 0x03)) + 1;
93 /***********************************************************************
94 * dibdrv_PatBlt
96 BOOL dibdrv_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
98 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPatBlt );
99 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
100 INT rop2 = get_rop2_from_rop(rop);
101 BOOL done;
103 TRACE("(%p, %d, %d, %d, %d, %06x)\n", dev, dst->x, dst->y, dst->width, dst->height, rop);
105 if(defer_brush(pdev))
106 return next->funcs->pPatBlt( next, dst, rop );
108 update_brush_rop( pdev, rop2 );
110 done = brush_rects( pdev, 1, &dst->visrect );
112 update_brush_rop( pdev, GetROP2(dev->hdc) );
114 if(!done)
115 return next->funcs->pPatBlt( next, dst, rop );
117 return TRUE;
120 /***********************************************************************
121 * dibdrv_PaintRgn
123 BOOL dibdrv_PaintRgn( PHYSDEV dev, HRGN rgn )
125 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPaintRgn );
126 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
127 const WINEREGION *region;
128 int i;
129 RECT rect;
131 TRACE("%p, %p\n", dev, rgn);
133 if(defer_brush(pdev)) return next->funcs->pPaintRgn( next, rgn );
135 region = get_wine_region( rgn );
136 if(!region) return FALSE;
138 for(i = 0; i < region->numRects; i++)
140 rect = get_device_rect( dev->hdc, region->rects[i].left, region->rects[i].top,
141 region->rects[i].right, region->rects[i].bottom, FALSE );
142 brush_rects( pdev, 1, &rect );
145 release_wine_region( rgn );
146 return TRUE;
149 /***********************************************************************
150 * dibdrv_PolyPolyline
152 BOOL dibdrv_PolyPolyline( PHYSDEV dev, const POINT* pt, const DWORD* counts, DWORD polylines )
154 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
155 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPolyPolyline );
156 DWORD max_points = 0, i;
157 POINT *points;
159 if (defer_pen( pdev )) return next->funcs->pPolyPolyline( next, pt, counts, polylines );
161 for (i = 0; i < polylines; i++) max_points = max( counts[i], max_points );
163 points = HeapAlloc( GetProcessHeap(), 0, max_points * sizeof(*pt) );
164 if (!points) return FALSE;
166 for (i = 0; i < polylines; i++)
168 memcpy( points, pt, counts[i] * sizeof(*pt) );
169 pt += counts[i];
170 LPtoDP( dev->hdc, points, counts[i] );
172 reset_dash_origin( pdev );
173 pdev->pen_lines( pdev, counts[i], points );
176 HeapFree( GetProcessHeap(), 0, points );
177 return TRUE;
180 /***********************************************************************
181 * dibdrv_Polyline
183 BOOL dibdrv_Polyline( PHYSDEV dev, const POINT* pt, INT count )
185 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
186 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPolyline );
187 POINT *points;
189 if (defer_pen( pdev )) return next->funcs->pPolyline( next, pt, count );
191 points = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pt) );
192 if (!points) return FALSE;
194 memcpy( points, pt, count * sizeof(*pt) );
195 LPtoDP( dev->hdc, points, count );
197 reset_dash_origin( pdev );
198 pdev->pen_lines( pdev, count, points );
200 HeapFree( GetProcessHeap(), 0, points );
201 return TRUE;
204 /***********************************************************************
205 * dibdrv_Rectangle
207 BOOL dibdrv_Rectangle( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
209 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pRectangle );
210 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
211 RECT rect = get_device_rect( dev->hdc, left, top, right, bottom, TRUE );
212 POINT pts[5];
214 TRACE("(%p, %d, %d, %d, %d)\n", dev, left, top, right, bottom);
216 if(rect.left == rect.right || rect.top == rect.bottom) return TRUE;
218 if(defer_pen(pdev) || defer_brush(pdev))
219 return next->funcs->pRectangle( next, left, top, right, bottom );
221 reset_dash_origin(pdev);
223 /* 4 pts going anti-clockwise starting from top-right */
224 pts[0].x = pts[3].x = rect.right - 1;
225 pts[0].y = pts[1].y = rect.top;
226 pts[1].x = pts[2].x = rect.left;
227 pts[2].y = pts[3].y = rect.bottom - 1;
228 pts[4] = pts[0];
230 pdev->pen_lines(pdev, 5, pts);
232 /* FIXME: Will need updating when we support wide pens */
234 rect.left += 1;
235 rect.top += 1;
236 rect.right -= 1;
237 rect.bottom -= 1;
239 brush_rects(pdev, 1, &rect);
241 return TRUE;
244 /***********************************************************************
245 * dibdrv_SetPixel
247 COLORREF dibdrv_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color )
249 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
250 int i;
251 POINT pt;
252 DWORD pixel;
253 const WINEREGION *clip = get_wine_region( pdev->clip );
255 TRACE( "(%p, %d, %d, %08x)\n", dev, x, y, color );
257 pt.x = x;
258 pt.y = y;
259 LPtoDP( dev->hdc, &pt, 1 );
261 /* SetPixel doesn't do the 1bpp massaging like other fg colors */
262 pixel = get_pixel_color( pdev, color, FALSE );
263 color = pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
265 for (i = 0; i < clip->numRects; i++)
267 if (pt_in_rect( clip->rects + i, pt ))
269 RECT rect;
270 rect.left = pt.x;
271 rect.top = pt.y;
272 rect.right = rect.left + 1;
273 rect.bottom = rect.top + 1;
275 pdev->dib.funcs->solid_rects( &pdev->dib, 1, &rect, 0, pixel );
276 break;
280 release_wine_region( pdev->clip );
281 return color;