gdi32: Calculate the min/max color component intensities for 17 glyph levels.
[wine/multimedia.git] / dlls / gdi32 / dibdrv / graphics.c
blob343dd0d3306a96bde936dae022bcc733db027f4e
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 /* Intensities of the 17 glyph levels when drawn with text component of 0xff on a
60 black bkgnd. [A log-log plot of these data gives: y = 77.05 * x^0.4315]. */
61 static const BYTE ramp[17] =
63 0, 0x4d, 0x68, 0x7c,
64 0x8c, 0x9a, 0xa7, 0xb2,
65 0xbd, 0xc7, 0xd0, 0xd9,
66 0xe1, 0xe9, 0xf0, 0xf8,
67 0xff
70 /* For a give text-color component and a glyph level, calculate the
71 range of dst intensities, the min/max corresponding to 0/0xff bkgnd
72 components respectively.
74 The minimum is a linear interpolation between 0 and the value in
75 the ramp table.
77 The maximum is a linear interpolation between the value from the
78 ramp table read in reverse and 0xff.
80 To find the resulting pixel intensity, we note that if the text and
81 bkgnd intensities are the same then the result must be that
82 intensity. Otherwise we linearly interpolate between either the
83 min or the max value and this intermediate value depending on which
84 side of the inequality we lie.
87 static inline void get_range( BYTE aa, DWORD text_comp, BYTE *min_comp, BYTE *max_comp )
89 *min_comp = (ramp[aa] * text_comp) / 0xff;
90 *max_comp = ramp[16 - aa] + ((0xff - ramp[16 - aa]) * text_comp) / 0xff;
93 void update_aa_ranges( dibdrv_physdev *pdev )
95 int i;
96 COLORREF text = pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pdev->text_color );
98 for (i = 0; i < 17; i++)
100 get_range( i, GetRValue(text), &pdev->glyph_intensities[i].r_min, &pdev->glyph_intensities[i].r_max );
101 get_range( i, GetGValue(text), &pdev->glyph_intensities[i].g_min, &pdev->glyph_intensities[i].g_max );
102 get_range( i, GetBValue(text), &pdev->glyph_intensities[i].b_min, &pdev->glyph_intensities[i].b_max );
106 /**********************************************************************
107 * get_text_bkgnd_masks
109 * See the comment above get_pen_bkgnd_masks
111 static inline void get_text_bkgnd_masks( const dibdrv_physdev *pdev, rop_mask *mask )
113 mask->and = 0;
115 if (pdev->dib.bit_count != 1)
116 mask->xor = pdev->bkgnd_color;
117 else
119 mask->xor = ~pdev->text_color;
120 if (GetTextColor( pdev->dev.hdc ) == GetBkColor( pdev->dev.hdc ))
121 mask->xor = pdev->text_color;
125 /***********************************************************************
126 * dibdrv_ExtTextOut
128 BOOL dibdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
129 const RECT *rect, LPCWSTR str, UINT count, const INT *dx )
131 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pExtTextOut );
132 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
134 if (flags & ETO_OPAQUE)
136 rop_mask bkgnd_color;
137 get_text_bkgnd_masks( pdev, &bkgnd_color );
138 solid_rects( &pdev->dib, 1, rect, &bkgnd_color, pdev->clip );
141 if (count == 0) return TRUE;
143 flags &= ~ETO_OPAQUE;
144 return next->funcs->pExtTextOut( next, x, y, flags, rect, str, count, dx );
147 /***********************************************************************
148 * dibdrv_GetPixel
150 COLORREF dibdrv_GetPixel( PHYSDEV dev, INT x, INT y )
152 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
153 POINT pt;
154 DWORD pixel;
156 TRACE( "(%p, %d, %d)\n", dev, x, y );
158 pt.x = x;
159 pt.y = y;
160 LPtoDP( dev->hdc, &pt, 1 );
162 if (pt.x < 0 || pt.x >= pdev->dib.width ||
163 pt.y < 0 || pt.y >= pdev->dib.height)
164 return CLR_INVALID;
166 pixel = pdev->dib.funcs->get_pixel( &pdev->dib, &pt );
167 return pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
170 /***********************************************************************
171 * dibdrv_LineTo
173 BOOL dibdrv_LineTo( PHYSDEV dev, INT x, INT y )
175 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pLineTo );
176 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
177 POINT pts[2];
179 GetCurrentPositionEx(dev->hdc, pts);
180 pts[1].x = x;
181 pts[1].y = y;
183 LPtoDP(dev->hdc, pts, 2);
185 reset_dash_origin(pdev);
187 if(defer_pen(pdev) || !pdev->pen_lines(pdev, 2, pts))
188 return next->funcs->pLineTo( next, x, y );
190 return TRUE;
193 /***********************************************************************
194 * get_rop2_from_rop
196 * Returns the binary rop that is equivalent to the provided ternary rop
197 * if the src bits are ignored.
199 static inline INT get_rop2_from_rop(INT rop)
201 return (((rop >> 18) & 0x0c) | ((rop >> 16) & 0x03)) + 1;
204 /***********************************************************************
205 * dibdrv_PatBlt
207 BOOL dibdrv_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
209 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPatBlt );
210 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
211 INT rop2 = get_rop2_from_rop(rop);
212 BOOL done;
214 TRACE("(%p, %d, %d, %d, %d, %06x)\n", dev, dst->x, dst->y, dst->width, dst->height, rop);
216 if(defer_brush(pdev))
217 return next->funcs->pPatBlt( next, dst, rop );
219 update_brush_rop( pdev, rop2 );
221 done = brush_rects( pdev, 1, &dst->visrect );
223 update_brush_rop( pdev, GetROP2(dev->hdc) );
225 if(!done)
226 return next->funcs->pPatBlt( next, dst, rop );
228 return TRUE;
231 /***********************************************************************
232 * dibdrv_PaintRgn
234 BOOL dibdrv_PaintRgn( PHYSDEV dev, HRGN rgn )
236 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPaintRgn );
237 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
238 const WINEREGION *region;
239 int i;
240 RECT rect;
242 TRACE("%p, %p\n", dev, rgn);
244 if(defer_brush(pdev)) return next->funcs->pPaintRgn( next, rgn );
246 region = get_wine_region( rgn );
247 if(!region) return FALSE;
249 for(i = 0; i < region->numRects; i++)
251 rect = get_device_rect( dev->hdc, region->rects[i].left, region->rects[i].top,
252 region->rects[i].right, region->rects[i].bottom, FALSE );
253 brush_rects( pdev, 1, &rect );
256 release_wine_region( rgn );
257 return TRUE;
260 /***********************************************************************
261 * dibdrv_PolyPolyline
263 BOOL dibdrv_PolyPolyline( PHYSDEV dev, const POINT* pt, const DWORD* counts, DWORD polylines )
265 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
266 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPolyPolyline );
267 DWORD max_points = 0, i;
268 POINT *points;
270 if (defer_pen( pdev )) return next->funcs->pPolyPolyline( next, pt, counts, polylines );
272 for (i = 0; i < polylines; i++) max_points = max( counts[i], max_points );
274 points = HeapAlloc( GetProcessHeap(), 0, max_points * sizeof(*pt) );
275 if (!points) return FALSE;
277 for (i = 0; i < polylines; i++)
279 memcpy( points, pt, counts[i] * sizeof(*pt) );
280 pt += counts[i];
281 LPtoDP( dev->hdc, points, counts[i] );
283 reset_dash_origin( pdev );
284 pdev->pen_lines( pdev, counts[i], points );
287 HeapFree( GetProcessHeap(), 0, points );
288 return TRUE;
291 /***********************************************************************
292 * dibdrv_Polyline
294 BOOL dibdrv_Polyline( PHYSDEV dev, const POINT* pt, INT count )
296 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
297 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pPolyline );
298 POINT *points;
300 if (defer_pen( pdev )) return next->funcs->pPolyline( next, pt, count );
302 points = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*pt) );
303 if (!points) return FALSE;
305 memcpy( points, pt, count * sizeof(*pt) );
306 LPtoDP( dev->hdc, points, count );
308 reset_dash_origin( pdev );
309 pdev->pen_lines( pdev, count, points );
311 HeapFree( GetProcessHeap(), 0, points );
312 return TRUE;
315 /***********************************************************************
316 * dibdrv_Rectangle
318 BOOL dibdrv_Rectangle( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
320 PHYSDEV next = GET_NEXT_PHYSDEV( dev, pRectangle );
321 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
322 RECT rect = get_device_rect( dev->hdc, left, top, right, bottom, TRUE );
323 POINT pts[5];
325 TRACE("(%p, %d, %d, %d, %d)\n", dev, left, top, right, bottom);
327 if(rect.left == rect.right || rect.top == rect.bottom) return TRUE;
329 if(defer_pen(pdev) || defer_brush(pdev))
330 return next->funcs->pRectangle( next, left, top, right, bottom );
332 reset_dash_origin(pdev);
334 /* 4 pts going anti-clockwise starting from top-right */
335 pts[0].x = pts[3].x = rect.right - 1;
336 pts[0].y = pts[1].y = rect.top;
337 pts[1].x = pts[2].x = rect.left;
338 pts[2].y = pts[3].y = rect.bottom - 1;
339 pts[4] = pts[0];
341 pdev->pen_lines(pdev, 5, pts);
343 /* FIXME: Will need updating when we support wide pens */
345 rect.left += 1;
346 rect.top += 1;
347 rect.right -= 1;
348 rect.bottom -= 1;
350 brush_rects(pdev, 1, &rect);
352 return TRUE;
355 /***********************************************************************
356 * dibdrv_SetPixel
358 COLORREF dibdrv_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color )
360 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
361 int i;
362 POINT pt;
363 DWORD pixel;
364 const WINEREGION *clip = get_wine_region( pdev->clip );
366 TRACE( "(%p, %d, %d, %08x)\n", dev, x, y, color );
368 pt.x = x;
369 pt.y = y;
370 LPtoDP( dev->hdc, &pt, 1 );
372 /* SetPixel doesn't do the 1bpp massaging like other fg colors */
373 pixel = get_pixel_color( pdev, color, FALSE );
374 color = pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
376 for (i = 0; i < clip->numRects; i++)
378 if (pt_in_rect( clip->rects + i, pt ))
380 RECT rect;
381 rect.left = pt.x;
382 rect.top = pt.y;
383 rect.right = rect.left + 1;
384 rect.bottom = rect.top + 1;
386 pdev->dib.funcs->solid_rects( &pdev->dib, 1, &rect, 0, pixel );
387 break;
391 release_wine_region( pdev->clip );
392 return color;