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"
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
)
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 */
43 LPtoDP( hdc
, (POINT
*)&rect
, 2 );
44 if (rect
.left
> rect
.right
)
47 rect
.left
= rect
.right
;
50 if (rect
.top
> rect
.bottom
)
53 rect
.top
= rect
.bottom
;
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] =
64 0x8c, 0x9a, 0xa7, 0xb2,
65 0xbd, 0xc7, 0xd0, 0xd9,
66 0xe1, 0xe9, 0xf0, 0xf8,
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
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
)
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
)
115 if (pdev
->dib
.bit_count
!= 1)
116 mask
->xor = pdev
->bkgnd_color
;
119 mask
->xor = ~pdev
->text_color
;
120 if (GetTextColor( pdev
->dev
.hdc
) == GetBkColor( pdev
->dev
.hdc
))
121 mask
->xor = pdev
->text_color
;
125 /***********************************************************************
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 /***********************************************************************
150 COLORREF
dibdrv_GetPixel( PHYSDEV dev
, INT x
, INT y
)
152 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
156 TRACE( "(%p, %d, %d)\n", dev
, x
, 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
)
166 pixel
= pdev
->dib
.funcs
->get_pixel( &pdev
->dib
, &pt
);
167 return pdev
->dib
.funcs
->pixel_to_colorref( &pdev
->dib
, pixel
);
170 /***********************************************************************
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
);
179 GetCurrentPositionEx(dev
->hdc
, pts
);
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
);
193 /***********************************************************************
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 /***********************************************************************
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
);
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
) );
226 return next
->funcs
->pPatBlt( next
, dst
, rop
);
231 /***********************************************************************
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
;
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
);
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
;
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
) );
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
);
291 /***********************************************************************
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
);
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
);
315 /***********************************************************************
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
);
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;
341 pdev
->pen_lines(pdev
, 5, pts
);
343 /* FIXME: Will need updating when we support wide pens */
350 brush_rects(pdev
, 1, &rect
);
355 /***********************************************************************
358 COLORREF
dibdrv_SetPixel( PHYSDEV dev
, INT x
, INT y
, COLORREF color
)
360 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
364 const WINEREGION
*clip
= get_wine_region( pdev
->clip
);
366 TRACE( "(%p, %d, %d, %08x)\n", dev
, x
, y
, color
);
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
))
383 rect
.right
= rect
.left
+ 1;
384 rect
.bottom
= rect
.top
+ 1;
386 pdev
->dib
.funcs
->solid_rects( &pdev
->dib
, 1, &rect
, 0, pixel
);
391 release_wine_region( pdev
->clip
);