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
22 #include "gdi_private.h"
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(dib
);
29 static RECT
get_device_rect( HDC hdc
, int left
, int top
, int right
, int bottom
, BOOL rtl_correction
)
37 if (rtl_correction
&& GetLayout( hdc
) & LAYOUT_RTL
)
39 /* shift the rectangle so that the right border is included after mirroring */
40 /* it would be more correct to do this after LPtoDP but that's not what Windows does */
44 LPtoDP( hdc
, (POINT
*)&rect
, 2 );
45 if (rect
.left
> rect
.right
)
48 rect
.left
= rect
.right
;
51 if (rect
.top
> rect
.bottom
)
54 rect
.top
= rect
.bottom
;
60 /* Intensities of the 17 glyph levels when drawn with text component of 0xff on a
61 black bkgnd. [A log-log plot of these data gives: y = 77.05 * x^0.4315]. */
62 static const BYTE ramp
[17] =
65 0x8c, 0x9a, 0xa7, 0xb2,
66 0xbd, 0xc7, 0xd0, 0xd9,
67 0xe1, 0xe9, 0xf0, 0xf8,
71 /* For a give text-color component and a glyph level, calculate the
72 range of dst intensities, the min/max corresponding to 0/0xff bkgnd
73 components respectively.
75 The minimum is a linear interpolation between 0 and the value in
78 The maximum is a linear interpolation between the value from the
79 ramp table read in reverse and 0xff.
81 To find the resulting pixel intensity, we note that if the text and
82 bkgnd intensities are the same then the result must be that
83 intensity. Otherwise we linearly interpolate between either the
84 min or the max value and this intermediate value depending on which
85 side of the inequality we lie.
88 static inline void get_range( BYTE aa
, DWORD text_comp
, BYTE
*min_comp
, BYTE
*max_comp
)
90 *min_comp
= (ramp
[aa
] * text_comp
) / 0xff;
91 *max_comp
= ramp
[16 - aa
] + ((0xff - ramp
[16 - aa
]) * text_comp
) / 0xff;
94 static inline void get_aa_ranges( COLORREF col
, struct intensity_range intensities
[17] )
98 for (i
= 0; i
< 17; i
++)
100 get_range( i
, GetRValue(col
), &intensities
[i
].r_min
, &intensities
[i
].r_max
);
101 get_range( i
, GetGValue(col
), &intensities
[i
].g_min
, &intensities
[i
].g_max
);
102 get_range( i
, GetBValue(col
), &intensities
[i
].b_min
, &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( dibdrv_physdev
*pdev
, rop_mask
*mask
)
113 COLORREF bg
= GetBkColor( pdev
->dev
.hdc
);
117 if (pdev
->dib
.bit_count
!= 1)
118 mask
->xor = get_pixel_color( pdev
, bg
, FALSE
);
121 COLORREF fg
= GetTextColor( pdev
->dev
.hdc
);
122 mask
->xor = get_pixel_color( pdev
, fg
, TRUE
);
123 if (fg
!= bg
) mask
->xor = ~mask
->xor;
127 static void draw_glyph( dibdrv_physdev
*pdev
, const POINT
*origin
, const GLYPHMETRICS
*metrics
,
128 const struct gdi_image_bits
*image
, DWORD text_color
,
129 const struct intensity_range
*ranges
, const struct clipped_rects
*clipped_rects
)
132 RECT rect
, clipped_rect
;
136 glyph_dib
.bit_count
= 8;
137 glyph_dib
.width
= metrics
->gmBlackBoxX
;
138 glyph_dib
.height
= metrics
->gmBlackBoxY
;
139 glyph_dib
.stride
= get_dib_stride( metrics
->gmBlackBoxX
, 8 );
140 glyph_dib
.bits
= *image
;
142 rect
.left
= origin
->x
+ metrics
->gmptGlyphOrigin
.x
;
143 rect
.top
= origin
->y
- metrics
->gmptGlyphOrigin
.y
;
144 rect
.right
= rect
.left
+ metrics
->gmBlackBoxX
;
145 rect
.bottom
= rect
.top
+ metrics
->gmBlackBoxY
;
147 for (i
= 0; i
< clipped_rects
->count
; i
++)
149 if (intersect_rect( &clipped_rect
, &rect
, clipped_rects
->rects
+ i
))
151 src_origin
.x
= clipped_rect
.left
- rect
.left
;
152 src_origin
.y
= clipped_rect
.top
- rect
.top
;
154 pdev
->dib
.funcs
->draw_glyph( &pdev
->dib
, &clipped_rect
, &glyph_dib
, &src_origin
,
155 text_color
, ranges
);
160 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
161 static const int padding
[4] = {0, 3, 2, 1};
163 /***********************************************************************
166 * Retrieve a 17-level bitmap for the appropiate glyph.
168 * For non-antialiased bitmaps convert them to the 17-level format
169 * using only values 0 or 16.
171 static DWORD
get_glyph_bitmap( HDC hdc
, UINT index
, UINT aa_flags
, GLYPHMETRICS
*metrics
,
172 struct gdi_image_bits
*image
)
174 UINT ggo_flags
= aa_flags
| GGO_GLYPH_INDEX
;
175 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
176 UINT indices
[3] = {0, 0, 0x20};
179 BYTE
*buf
, *dst
, *src
;
183 image
->is_copy
= FALSE
;
184 image
->free
= free_heap_bits
;
189 for (i
= 0; i
< sizeof(indices
) / sizeof(indices
[0]); i
++)
192 ret
= GetGlyphOutlineW( hdc
, index
, ggo_flags
, metrics
, 0, NULL
, &identity
);
193 if (ret
!= GDI_ERROR
) break;
196 if (ret
== GDI_ERROR
) return ERROR_NOT_FOUND
;
197 if (!ret
) return ERROR_SUCCESS
; /* empty glyph */
199 /* We'll convert non-antialiased 1-bpp bitmaps to 8-bpp, so these sizes relate to 8-bpp */
200 pad
= padding
[ metrics
->gmBlackBoxX
% 4 ];
201 stride
= get_dib_stride( metrics
->gmBlackBoxX
, 8 );
202 size
= metrics
->gmBlackBoxY
* stride
;
204 buf
= HeapAlloc( GetProcessHeap(), 0, size
);
205 if (!buf
) return ERROR_OUTOFMEMORY
;
207 ret
= GetGlyphOutlineW( hdc
, index
, ggo_flags
, metrics
, size
, buf
, &identity
);
208 if (ret
== GDI_ERROR
)
210 HeapFree( GetProcessHeap(), 0, buf
);
211 return ERROR_NOT_FOUND
;
214 if (aa_flags
== GGO_BITMAP
)
216 for (y
= metrics
->gmBlackBoxY
- 1; y
>= 0; y
--)
218 src
= buf
+ y
* get_dib_stride( metrics
->gmBlackBoxX
, 1 );
219 dst
= buf
+ y
* stride
;
221 if (pad
) memset( dst
+ metrics
->gmBlackBoxX
, 0, pad
);
223 for (x
= metrics
->gmBlackBoxX
- 1; x
>= 0; x
--)
224 dst
[x
] = (src
[x
/ 8] & masks
[x
% 8]) ? 0x10 : 0;
229 for (y
= 0, dst
= buf
; y
< metrics
->gmBlackBoxY
; y
++, dst
+= stride
)
230 memset( dst
+ metrics
->gmBlackBoxX
, 0, pad
);
234 return ERROR_SUCCESS
;
237 BOOL
render_aa_text_bitmapinfo( HDC hdc
, BITMAPINFO
*info
, struct gdi_image_bits
*bits
,
238 struct bitblt_coords
*src
, INT x
, INT y
, UINT flags
,
239 UINT aa_flags
, LPCWSTR str
, UINT count
, const INT
*dx
)
246 DWORD fg_pixel
, bg_pixel
;
247 struct intensity_range glyph_intensities
[17];
249 assert( info
->bmiHeader
.biBitCount
> 8 ); /* mono and indexed formats don't support anti-aliasing */
251 init_dib_info_from_bitmapinfo( &dib
, info
, bits
->ptr
, 0 );
253 fg
= make_rgb_colorref( hdc
, &dib
, GetTextColor( hdc
), &got_pixel
, &fg_pixel
);
254 if (!got_pixel
) fg_pixel
= dib
.funcs
->colorref_to_pixel( &dib
, fg
);
256 get_aa_ranges( fg
, glyph_intensities
);
258 if (flags
& ETO_OPAQUE
)
260 rop_mask bkgnd_color
;
262 bg
= make_rgb_colorref( hdc
, &dib
, GetBkColor( hdc
), &got_pixel
, &bg_pixel
);
263 if (!got_pixel
) bg_pixel
= dib
.funcs
->colorref_to_pixel( &dib
, bg
);
266 bkgnd_color
.xor = bg_pixel
;
267 dib
.funcs
->solid_rects( &dib
, 1, &src
->visrect
, bkgnd_color
.and, bkgnd_color
.xor );
270 for (i
= 0; i
< count
; i
++)
272 GLYPHMETRICS metrics
;
273 struct gdi_image_bits image
;
275 err
= get_glyph_bitmap( hdc
, (UINT
)str
[i
], aa_flags
, &metrics
, &image
);
280 RECT rect
, clipped_rect
;
284 glyph_dib
.bit_count
= 8;
285 glyph_dib
.width
= metrics
.gmBlackBoxX
;
286 glyph_dib
.height
= metrics
.gmBlackBoxY
;
287 glyph_dib
.stride
= get_dib_stride( metrics
.gmBlackBoxX
, 8 );
288 glyph_dib
.bits
= image
;
290 rect
.left
= x
+ metrics
.gmptGlyphOrigin
.x
;
291 rect
.top
= y
- metrics
.gmptGlyphOrigin
.y
;
292 rect
.right
= rect
.left
+ metrics
.gmBlackBoxX
;
293 rect
.bottom
= rect
.top
+ metrics
.gmBlackBoxY
;
295 if (intersect_rect( &clipped_rect
, &rect
, &src
->visrect
))
297 src_origin
.x
= clipped_rect
.left
- rect
.left
;
298 src_origin
.y
= clipped_rect
.top
- rect
.top
;
300 dib
.funcs
->draw_glyph( &dib
, &clipped_rect
, &glyph_dib
, &src_origin
,
301 fg_pixel
, glyph_intensities
);
304 if (image
.free
) image
.free( &image
);
318 x
+= metrics
.gmCellIncX
;
319 y
+= metrics
.gmCellIncY
;
325 /***********************************************************************
328 BOOL
dibdrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
,
329 const RECT
*rect
, LPCWSTR str
, UINT count
, const INT
*dx
)
331 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
332 struct clipped_rects clipped_rects
;
335 DWORD text_color
, err
;
336 struct intensity_range ranges
[17];
338 init_clipped_rects( &clipped_rects
);
340 if (flags
& ETO_OPAQUE
)
342 rop_mask bkgnd_color
;
343 get_text_bkgnd_masks( pdev
, &bkgnd_color
);
344 get_clipped_rects( &pdev
->dib
, rect
, pdev
->clip
, &clipped_rects
);
345 pdev
->dib
.funcs
->solid_rects( &pdev
->dib
, clipped_rects
.count
, clipped_rects
.rects
,
346 bkgnd_color
.and, bkgnd_color
.xor );
349 if (count
== 0) goto done
;
351 if (flags
& ETO_CLIPPED
)
353 if (!(flags
& ETO_OPAQUE
)) /* otherwise we have done it already */
354 get_clipped_rects( &pdev
->dib
, rect
, pdev
->clip
, &clipped_rects
);
358 free_clipped_rects( &clipped_rects
);
359 get_clipped_rects( &pdev
->dib
, NULL
, pdev
->clip
, &clipped_rects
);
361 if (!clipped_rects
.count
) return TRUE
;
363 text_color
= get_pixel_color( pdev
, GetTextColor( pdev
->dev
.hdc
), TRUE
);
364 get_aa_ranges( pdev
->dib
.funcs
->pixel_to_colorref( &pdev
->dib
, text_color
), ranges
);
366 aa_flags
= get_font_aa_flags( dev
->hdc
);
369 for (i
= 0; i
< count
; i
++)
371 GLYPHMETRICS metrics
;
372 struct gdi_image_bits image
;
374 err
= get_glyph_bitmap( dev
->hdc
, (UINT
)str
[i
], aa_flags
, &metrics
, &image
);
377 if (image
.ptr
) draw_glyph( pdev
, &origin
, &metrics
, &image
, text_color
, ranges
, &clipped_rects
);
378 if (image
.free
) image
.free( &image
);
384 origin
.x
+= dx
[ i
* 2 ];
385 origin
.y
+= dx
[ i
* 2 + 1];
392 origin
.x
+= metrics
.gmCellIncX
;
393 origin
.y
+= metrics
.gmCellIncY
;
398 free_clipped_rects( &clipped_rects
);
402 /***********************************************************************
403 * dibdrv_GetNearestColor
405 COLORREF
dibdrv_GetNearestColor( PHYSDEV dev
, COLORREF color
)
407 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
410 TRACE( "(%p, %08x)\n", dev
, color
);
412 pixel
= get_pixel_color( pdev
, color
, FALSE
);
413 return pdev
->dib
.funcs
->pixel_to_colorref( &pdev
->dib
, pixel
);
416 /***********************************************************************
419 COLORREF
dibdrv_GetPixel( PHYSDEV dev
, INT x
, INT y
)
421 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
425 TRACE( "(%p, %d, %d)\n", dev
, x
, y
);
429 LPtoDP( dev
->hdc
, &pt
, 1 );
431 if (pt
.x
< 0 || pt
.x
>= pdev
->dib
.width
||
432 pt
.y
< 0 || pt
.y
>= pdev
->dib
.height
)
435 pixel
= pdev
->dib
.funcs
->get_pixel( &pdev
->dib
, &pt
);
436 return pdev
->dib
.funcs
->pixel_to_colorref( &pdev
->dib
, pixel
);
439 /***********************************************************************
442 BOOL
dibdrv_LineTo( PHYSDEV dev
, INT x
, INT y
)
444 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pLineTo
);
445 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
450 if(defer_pen(pdev
)) return next
->funcs
->pLineTo( next
, x
, y
);
452 GetCurrentPositionEx(dev
->hdc
, pts
);
456 LPtoDP(dev
->hdc
, pts
, 2);
458 if (pdev
->pen_uses_region
&& !(region
= CreateRectRgn( 0, 0, 0, 0 ))) return FALSE
;
460 reset_dash_origin(pdev
);
462 ret
= pdev
->pen_lines(pdev
, 2, pts
, FALSE
, region
);
466 if (pdev
->clip
) CombineRgn( region
, region
, pdev
->clip
, RGN_AND
);
467 ret
= pen_rect( pdev
, NULL
, region
, GetROP2(dev
->hdc
) );
468 DeleteObject( region
);
473 /***********************************************************************
476 * Returns the binary rop that is equivalent to the provided ternary rop
477 * if the src bits are ignored.
479 static inline INT
get_rop2_from_rop(INT rop
)
481 return (((rop
>> 18) & 0x0c) | ((rop
>> 16) & 0x03)) + 1;
484 /***********************************************************************
487 BOOL
dibdrv_PatBlt( PHYSDEV dev
, struct bitblt_coords
*dst
, DWORD rop
)
489 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
491 TRACE("(%p, %d, %d, %d, %d, %06x)\n", dev
, dst
->x
, dst
->y
, dst
->width
, dst
->height
, rop
);
493 return brush_rect( pdev
, &dst
->visrect
, pdev
->clip
, get_rop2_from_rop(rop
) );
496 /***********************************************************************
499 BOOL
dibdrv_PaintRgn( PHYSDEV dev
, HRGN rgn
)
501 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
502 const WINEREGION
*region
;
506 TRACE("%p, %p\n", dev
, rgn
);
508 region
= get_wine_region( rgn
);
509 if(!region
) return FALSE
;
511 for(i
= 0; i
< region
->numRects
; i
++)
513 rect
= get_device_rect( dev
->hdc
, region
->rects
[i
].left
, region
->rects
[i
].top
,
514 region
->rects
[i
].right
, region
->rects
[i
].bottom
, FALSE
);
515 brush_rect( pdev
, &rect
, pdev
->clip
, GetROP2( dev
->hdc
) );
518 release_wine_region( rgn
);
522 /***********************************************************************
525 BOOL
dibdrv_PolyPolygon( PHYSDEV dev
, const POINT
*pt
, const INT
*counts
, DWORD polygons
)
527 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
528 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pPolyPolygon
);
532 INT rop
= GetROP2( dev
->hdc
);
533 HRGN outline
= 0, interior
;
535 if (defer_pen( pdev
)) return next
->funcs
->pPolyPolygon( next
, pt
, counts
, polygons
);
537 for (i
= total
= 0; i
< polygons
; i
++)
539 if (counts
[i
] < 2) return FALSE
;
543 points
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(*pt
) );
544 if (!points
) return FALSE
;
545 memcpy( points
, pt
, total
* sizeof(*pt
) );
546 LPtoDP( dev
->hdc
, points
, total
);
548 if (!(interior
= CreatePolyPolygonRgn( points
, counts
, polygons
, GetPolyFillMode( dev
->hdc
))))
550 HeapFree( GetProcessHeap(), 0, points
);
554 if (pdev
->clip
) CombineRgn( interior
, interior
, pdev
->clip
, RGN_AND
);
556 /* if not using a region, paint the interior first so the outline can overlap it */
557 if (!pdev
->pen_uses_region
|| !(outline
= CreateRectRgn( 0, 0, 0, 0 )))
558 ret
= brush_rect( pdev
, NULL
, interior
, rop
);
560 for (i
= pos
= 0; i
< polygons
; i
++)
562 reset_dash_origin( pdev
);
563 pdev
->pen_lines( pdev
, counts
[i
], points
+ pos
, TRUE
, outline
);
569 if (pdev
->clip
) CombineRgn( outline
, outline
, pdev
->clip
, RGN_AND
);
570 CombineRgn( interior
, interior
, outline
, RGN_DIFF
);
571 ret
= pen_rect( pdev
, NULL
, outline
, rop
) && brush_rect( pdev
, NULL
, interior
, rop
);
572 DeleteObject( outline
);
575 DeleteObject( interior
);
576 HeapFree( GetProcessHeap(), 0, points
);
580 /***********************************************************************
581 * dibdrv_PolyPolyline
583 BOOL
dibdrv_PolyPolyline( PHYSDEV dev
, const POINT
* pt
, const DWORD
* counts
, DWORD polylines
)
585 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
586 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pPolyPolyline
);
587 DWORD max_points
= 0, i
;
590 INT rop
= GetROP2( dev
->hdc
);
593 if (defer_pen( pdev
)) return next
->funcs
->pPolyPolyline( next
, pt
, counts
, polylines
);
595 for (i
= 0; i
< polylines
; i
++)
597 if (counts
[i
] < 2) return FALSE
;
598 max_points
= max( counts
[i
], max_points
);
601 points
= HeapAlloc( GetProcessHeap(), 0, max_points
* sizeof(*pt
) );
602 if (!points
) return FALSE
;
604 if (pdev
->pen_uses_region
&& !(outline
= CreateRectRgn( 0, 0, 0, 0 )))
606 HeapFree( GetProcessHeap(), 0, points
);
610 for (i
= 0; i
< polylines
; i
++)
612 memcpy( points
, pt
, counts
[i
] * sizeof(*pt
) );
614 LPtoDP( dev
->hdc
, points
, counts
[i
] );
616 reset_dash_origin( pdev
);
617 pdev
->pen_lines( pdev
, counts
[i
], points
, FALSE
, outline
);
622 if (pdev
->clip
) CombineRgn( outline
, outline
, pdev
->clip
, RGN_AND
);
623 ret
= pen_rect( pdev
, NULL
, outline
, rop
);
624 DeleteObject( outline
);
627 HeapFree( GetProcessHeap(), 0, points
);
631 /***********************************************************************
634 BOOL
dibdrv_Polygon( PHYSDEV dev
, const POINT
*pt
, INT count
)
636 INT counts
[1] = { count
};
638 return dibdrv_PolyPolygon( dev
, pt
, counts
, 1 );
641 /***********************************************************************
644 BOOL
dibdrv_Polyline( PHYSDEV dev
, const POINT
* pt
, INT count
)
646 DWORD counts
[1] = { count
};
648 if (count
< 0) return FALSE
;
649 return dibdrv_PolyPolyline( dev
, pt
, counts
, 1 );
652 /***********************************************************************
655 BOOL
dibdrv_Rectangle( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
)
657 PHYSDEV next
= GET_NEXT_PHYSDEV( dev
, pRectangle
);
658 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
659 RECT rect
= get_device_rect( dev
->hdc
, left
, top
, right
, bottom
, TRUE
);
662 INT rop
= GetROP2( dev
->hdc
);
665 TRACE("(%p, %d, %d, %d, %d)\n", dev
, left
, top
, right
, bottom
);
667 if(rect
.left
== rect
.right
|| rect
.top
== rect
.bottom
) return TRUE
;
670 return next
->funcs
->pRectangle( next
, left
, top
, right
, bottom
);
672 if (pdev
->pen_style
== PS_INSIDEFRAME
)
674 rect
.left
+= pdev
->pen_width
/ 2;
675 rect
.top
+= pdev
->pen_width
/ 2;
676 rect
.right
-= (pdev
->pen_width
- 1) / 2;
677 rect
.bottom
-= (pdev
->pen_width
- 1) / 2;
680 if (pdev
->pen_uses_region
&& !(outline
= CreateRectRgn( 0, 0, 0, 0 ))) return FALSE
;
684 reset_dash_origin(pdev
);
686 /* 4 pts going anti-clockwise starting from top-right */
687 pts
[0].x
= pts
[3].x
= rect
.right
;
688 pts
[0].y
= pts
[1].y
= rect
.top
;
689 pts
[1].x
= pts
[2].x
= rect
.left
;
690 pts
[2].y
= pts
[3].y
= rect
.bottom
;
692 pdev
->pen_lines(pdev
, 4, pts
, TRUE
, outline
);
696 HRGN interior
= CreateRectRgnIndirect( &rect
);
698 CombineRgn( interior
, interior
, outline
, RGN_DIFF
);
701 CombineRgn( outline
, outline
, pdev
->clip
, RGN_AND
);
702 CombineRgn( interior
, interior
, pdev
->clip
, RGN_AND
);
704 ret
= pen_rect( pdev
, NULL
, outline
, rop
) && brush_rect( pdev
, NULL
, interior
, rop
);
705 DeleteObject( outline
);
706 DeleteObject( interior
);
710 rect
.left
+= (pdev
->pen_width
+ 1) / 2;
711 rect
.top
+= (pdev
->pen_width
+ 1) / 2;
712 rect
.right
-= pdev
->pen_width
/ 2;
713 rect
.bottom
-= pdev
->pen_width
/ 2;
714 ret
= brush_rect( pdev
, &rect
, pdev
->clip
, rop
);
719 /***********************************************************************
722 COLORREF
dibdrv_SetPixel( PHYSDEV dev
, INT x
, INT y
, COLORREF color
)
724 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
725 struct clipped_rects clipped_rects
;
730 TRACE( "(%p, %d, %d, %08x)\n", dev
, x
, y
, color
);
734 LPtoDP( dev
->hdc
, &pt
, 1 );
737 rect
.right
= rect
.left
+ 1;
738 rect
.bottom
= rect
.top
+ 1;
740 /* SetPixel doesn't do the 1bpp massaging like other fg colors */
741 pixel
= get_pixel_color( pdev
, color
, FALSE
);
742 color
= pdev
->dib
.funcs
->pixel_to_colorref( &pdev
->dib
, pixel
);
744 if (!get_clipped_rects( &pdev
->dib
, &rect
, pdev
->clip
, &clipped_rects
)) return color
;
745 pdev
->dib
.funcs
->solid_rects( &pdev
->dib
, clipped_rects
.count
, clipped_rects
.rects
, 0, pixel
);
746 free_clipped_rects( &clipped_rects
);