mstask: Implement GetTargetComputer.
[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 <assert.h>
22 #include "gdi_private.h"
23 #include "dibdrv.h"
24
25 #include "wine/debug.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(dib);
28
29 static BOOL brush_rect( dibdrv_physdev *pdev, dib_brush *brush, const RECT *rect, HRGN clip )
30 {
31     struct clipped_rects clipped_rects;
32     BOOL ret;
33
34     if (!get_clipped_rects( &pdev->dib, rect, clip, &clipped_rects )) return TRUE;
35     ret = brush->rects( pdev, brush, &pdev->dib, clipped_rects.count, clipped_rects.rects,
36                         GetROP2( pdev->dev.hdc ));
37     free_clipped_rects( &clipped_rects );
38     return ret;
39 }
40
41 /* paint a region with the brush (note: the region can be modified) */
42 static BOOL brush_region( dibdrv_physdev *pdev, HRGN region )
43 {
44     if (pdev->clip) CombineRgn( region, region, pdev->clip, RGN_AND );
45     return brush_rect( pdev, &pdev->brush, NULL, region );
46 }
47
48 /* paint a region with the pen (note: the region can be modified) */
49 static BOOL pen_region( dibdrv_physdev *pdev, HRGN region )
50 {
51     if (pdev->clip) CombineRgn( region, region, pdev->clip, RGN_AND );
52     return brush_rect( pdev, &pdev->pen_brush, NULL, region );
53 }
54
55 static RECT get_device_rect( HDC hdc, int left, int top, int right, int bottom, BOOL rtl_correction )
56 {
57     RECT rect;
58
59     rect.left   = left;
60     rect.top    = top;
61     rect.right  = right;
62     rect.bottom = bottom;
63     if (rtl_correction && GetLayout( hdc ) & LAYOUT_RTL)
64     {
65         /* shift the rectangle so that the right border is included after mirroring */
66         /* it would be more correct to do this after LPtoDP but that's not what Windows does */
67         rect.left--;
68         rect.right--;
69     }
70     LPtoDP( hdc, (POINT *)&rect, 2 );
71     if (rect.left > rect.right)
72     {
73         int tmp = rect.left;
74         rect.left = rect.right;
75         rect.right = tmp;
76     }
77     if (rect.top > rect.bottom)
78     {
79         int tmp = rect.top;
80         rect.top = rect.bottom;
81         rect.bottom = tmp;
82     }
83     return rect;
84 }
85
86 static BOOL get_pen_device_rect( dibdrv_physdev *dev, RECT *rect, int left, int top, int right, int bottom )
87 {
88     *rect = get_device_rect( dev->dev.hdc, left, top, right, bottom, TRUE );
89     if (rect->left == rect->right || rect->top == rect->bottom) return FALSE;
90
91     if (dev->pen_style == PS_INSIDEFRAME)
92     {
93         rect->left   += dev->pen_width / 2;
94         rect->top    += dev->pen_width / 2;
95         rect->right  -= (dev->pen_width - 1) / 2;
96         rect->bottom -= (dev->pen_width - 1) / 2;
97     }
98     return TRUE;
99 }
100
101 static void add_pen_lines_bounds( dibdrv_physdev *dev, int count, const POINT *points, HRGN rgn )
102 {
103     const WINEREGION *region;
104     RECT bounds, rect;
105     int width = 0;
106
107     if (!dev->bounds) return;
108     reset_bounds( &bounds );
109
110     if (dev->pen_uses_region)
111     {
112         /* Windows uses some heuristics to estimate the distance from the point that will be painted */
113         width = dev->pen_width + 2;
114         if (dev->pen_join == PS_JOIN_MITER)
115         {
116             width *= 5;
117             if (dev->pen_endcap == PS_ENDCAP_SQUARE) width = (width * 3 + 1) / 2;
118         }
119         else
120         {
121             if (dev->pen_endcap == PS_ENDCAP_SQUARE) width -= width / 4;
122             else width = (width + 1) / 2;
123         }
124
125         /* in case the heuristics are wrong, add the actual region too */
126         if ((region = get_wine_region( rgn )))
127         {
128             add_bounds_rect( &bounds, &region->extents );
129             release_wine_region( rgn );
130         }
131     }
132
133     while (count-- > 0)
134     {
135         rect.left   = points->x - width;
136         rect.top    = points->y - width;
137         rect.right  = points->x + width + 1;
138         rect.bottom = points->y + width + 1;
139         add_bounds_rect( &bounds, &rect );
140         points++;
141     }
142
143     add_clipped_bounds( dev, &bounds, dev->clip );
144 }
145
146 /* compute the points for the first quadrant of an ellipse, counterclockwise from the x axis */
147 /* 'data' must contain enough space, (width+height)/2 is a reasonable upper bound */
148 static int ellipse_first_quadrant( int width, int height, POINT *data )
149 {
150     const int a = width - 1;
151     const int b = height - 1;
152     const INT64 asq = (INT64)8 * a * a;
153     const INT64 bsq = (INT64)8 * b * b;
154     INT64 dx  = (INT64)4 * b * b * (1 - a);
155     INT64 dy  = (INT64)4 * a * a * (1 + (b % 2));
156     INT64 err = dx + dy + a * a * (b % 2);
157     int pos = 0;
158     POINT pt;
159
160     pt.x = a;
161     pt.y = height / 2;
162
163     /* based on an algorithm by Alois Zingl */
164
165     while (pt.x >= width / 2)
166     {
167         INT64 e2 = 2 * err;
168         data[pos++] = pt;
169         if (e2 >= dx)
170         {
171             pt.x--;
172             err += dx += bsq;
173         }
174         if (e2 <= dy)
175         {
176             pt.y++;
177             err += dy += asq;
178         }
179     }
180     return pos;
181 }
182
183 static int find_intersection( const POINT *points, int x, int y, int count )
184 {
185     int i;
186
187     if (y >= 0)
188     {
189         if (x >= 0)  /* first quadrant */
190         {
191             for (i = 0; i < count; i++) if (points[i].x * y <= points[i].y * x) break;
192             return i;
193         }
194         /* second quadrant */
195         for (i = 0; i < count; i++) if (points[i].x * y < points[i].y * -x) break;
196         return 2 * count - i;
197     }
198     if (x >= 0)  /* fourth quadrant */
199     {
200         for (i = 0; i < count; i++) if (points[i].x * -y <= points[i].y * x) break;
201         return 4 * count - i;
202     }
203     /* third quadrant */
204     for (i = 0; i < count; i++) if (points[i].x * -y < points[i].y * -x) break;
205     return 2 * count + i;
206 }
207
208 static int get_arc_points( PHYSDEV dev, const RECT *rect, POINT start, POINT end, POINT *points )
209 {
210     int i, pos, count, start_pos, end_pos;
211     int width = rect->right - rect->left;
212     int height = rect->bottom - rect->top;
213
214     count = ellipse_first_quadrant( width, height, points );
215     for (i = 0; i < count; i++)
216     {
217         points[i].x -= width / 2;
218         points[i].y -= height / 2;
219     }
220     if (GetArcDirection( dev->hdc ) != AD_CLOCKWISE)
221     {
222         start.y = -start.y;
223         end.y = -end.y;
224     }
225     start_pos = find_intersection( points, start.x, start.y, count );
226     end_pos = find_intersection( points, end.x, end.y, count );
227     if (end_pos <= start_pos) end_pos += 4 * count;
228
229     pos = count;
230     if (GetArcDirection( dev->hdc ) == AD_CLOCKWISE)
231     {
232         for (i = start_pos; i < end_pos; i++, pos++)
233         {
234             switch ((i / count) % 4)
235             {
236             case 0:
237                 points[pos].x = rect->left + width/2 + points[i % count].x;
238                 points[pos].y = rect->top + height/2 + points[i % count].y;
239                 break;
240             case 1:
241                 points[pos].x = rect->left + width/2 - points[count - 1 - i % count].x;
242                 points[pos].y = rect->top + height/2 + points[count - 1 - i % count].y;
243                 break;
244             case 2:
245                 points[pos].x = rect->left + width/2 - points[i % count].x;
246                 points[pos].y = rect->top + height/2 - points[i % count].y;
247                 break;
248             case 3:
249                 points[pos].x = rect->left + width/2 + points[count - 1 - i % count].x;
250                 points[pos].y = rect->top + height/2 - points[count - 1 - i % count].y;
251                 break;
252             }
253         }
254     }
255     else
256     {
257         for (i = start_pos; i < end_pos; i++, pos++)
258         {
259             switch ((i / count) % 4)
260             {
261             case 0:
262                 points[pos].x = rect->left + width/2 + points[i % count].x;
263                 points[pos].y = rect->top + height/2 - points[i % count].y;
264                 break;
265             case 1:
266                 points[pos].x = rect->left + width/2 - points[count - 1 - i % count].x;
267                 points[pos].y = rect->top + height/2 - points[count - 1 - i % count].y;
268                 break;
269             case 2:
270                 points[pos].x = rect->left + width/2 - points[i % count].x;
271                 points[pos].y = rect->top + height/2 + points[i % count].y;
272                 break;
273             case 3:
274                 points[pos].x = rect->left + width/2 + points[count - 1 - i % count].x;
275                 points[pos].y = rect->top + height/2 + points[count - 1 - i % count].y;
276                 break;
277             }
278         }
279     }
280
281     memmove( points, points + count, (pos - count) * sizeof(POINT) );
282     return pos - count;
283 }
284
285 /* backend for arc functions; extra_lines is -1 for ArcTo, 0 for Arc, 1 for Chord, 2 for Pie */
286 static BOOL draw_arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
287                       INT start_x, INT start_y, INT end_x, INT end_y, INT extra_lines )
288 {
289     dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
290     RECT rect;
291     POINT pt[2], *points;
292     int width, height, count;
293     BOOL ret = TRUE;
294     HRGN outline = 0, interior = 0;
295
296     if (!get_pen_device_rect( pdev, &rect, left, top, right, bottom )) return TRUE;
297
298     width = rect.right - rect.left;
299     height = rect.bottom - rect.top;
300
301     pt[0].x = start_x;
302     pt[0].y = start_y;
303     pt[1].x = end_x;
304     pt[1].y = end_y;
305     LPtoDP( dev->hdc, pt, 2 );
306     /* make them relative to the ellipse center */
307     pt[0].x -= left + width / 2;
308     pt[0].y -= top + height / 2;
309     pt[1].x -= left + width / 2;
310     pt[1].y -= top + height / 2;
311
312     points = HeapAlloc( GetProcessHeap(), 0, (width + height) * 3 * sizeof(*points) );
313     if (!points) return FALSE;
314
315     if (extra_lines == -1)
316     {
317         GetCurrentPositionEx( dev->hdc, points );
318         LPtoDP( dev->hdc, points, 1 );
319         count = 1 + get_arc_points( dev, &rect, pt[0], pt[1], points + 1 );
320     }
321     else count = get_arc_points( dev, &rect, pt[0], pt[1], points );
322
323     if (extra_lines == 2)
324     {
325         points[count].x = rect.left + width / 2;
326         points[count].y = rect.top + height / 2;
327         count++;
328     }
329     if (count < 2)
330     {
331         HeapFree( GetProcessHeap(), 0, points );
332         return TRUE;
333     }
334
335     if (pdev->pen_uses_region && !(outline = CreateRectRgn( 0, 0, 0, 0 )))
336     {
337         HeapFree( GetProcessHeap(), 0, points );
338         return FALSE;
339     }
340
341     if (pdev->brush.style != BS_NULL && extra_lines > 0 &&
342         !(interior = CreatePolygonRgn( points, count, WINDING )))
343     {
344         HeapFree( GetProcessHeap(), 0, points );
345         if (outline) DeleteObject( outline );
346         return FALSE;
347     }
348
349     /* if not using a region, paint the interior first so the outline can overlap it */
350     if (interior && !outline)
351     {
352         ret = brush_region( pdev, interior );
353         DeleteObject( interior );
354         interior = 0;
355     }
356
357     reset_dash_origin( pdev );
358     pdev->pen_lines( pdev, count, points, extra_lines > 0, outline );
359     add_pen_lines_bounds( pdev, count, points, outline );
360
361     if (interior)
362     {
363         CombineRgn( interior, interior, outline, RGN_DIFF );
364         ret = brush_region( pdev, interior );
365         DeleteObject( interior );
366     }
367     if (outline)
368     {
369         if (ret) ret = pen_region( pdev, outline );
370         DeleteObject( outline );
371     }
372     HeapFree( GetProcessHeap(), 0, points );
373     return ret;
374 }
375
376 /* Intensities of the 17 glyph levels when drawn with text component of 0xff on a
377    black bkgnd.  [A log-log plot of these data gives: y = 77.05 * x^0.4315]. */
378 static const BYTE ramp[17] =
379 {
380     0,    0x4d, 0x68, 0x7c,
381     0x8c, 0x9a, 0xa7, 0xb2,
382     0xbd, 0xc7, 0xd0, 0xd9,
383     0xe1, 0xe9, 0xf0, 0xf8,
384     0xff
385 };
386
387 /* For a give text-color component and a glyph level, calculate the
388    range of dst intensities, the min/max corresponding to 0/0xff bkgnd
389    components respectively.
390
391    The minimum is a linear interpolation between 0 and the value in
392    the ramp table.
393
394    The maximum is a linear interpolation between the value from the
395    ramp table read in reverse and 0xff.
396
397    To find the resulting pixel intensity, we note that if the text and
398    bkgnd intensities are the same then the result must be that
399    intensity.  Otherwise we linearly interpolate between either the
400    min or the max value and this intermediate value depending on which
401    side of the inequality we lie.
402 */
403
404 static inline void get_range( BYTE aa, DWORD text_comp, BYTE *min_comp, BYTE *max_comp )
405 {
406     *min_comp = (ramp[aa] * text_comp) / 0xff;
407     *max_comp = ramp[16 - aa] + ((0xff - ramp[16 - aa]) * text_comp) / 0xff;
408 }
409
410 static inline void get_aa_ranges( COLORREF col, struct intensity_range intensities[17] )
411 {
412     int i;
413
414     for (i = 0; i < 17; i++)
415     {
416         get_range( i, GetRValue(col), &intensities[i].r_min, &intensities[i].r_max );
417         get_range( i, GetGValue(col), &intensities[i].g_min, &intensities[i].g_max );
418         get_range( i, GetBValue(col), &intensities[i].b_min, &intensities[i].b_max );
419     }
420 }
421
422 /**********************************************************************
423  *                 get_text_bkgnd_masks
424  *
425  * See the comment above get_pen_bkgnd_masks
426  */
427 static inline void get_text_bkgnd_masks( dibdrv_physdev *pdev, rop_mask *mask )
428 {
429     COLORREF bg = GetBkColor( pdev->dev.hdc );
430
431     mask->and = 0;
432
433     if (pdev->dib.bit_count != 1)
434         mask->xor = get_pixel_color( pdev, bg, FALSE );
435     else
436     {
437         COLORREF fg = GetTextColor( pdev->dev.hdc );
438         mask->xor = get_pixel_color( pdev, fg, TRUE );
439         if (fg != bg) mask->xor = ~mask->xor;
440     }
441 }
442
443 static void draw_glyph( dib_info *dib, int x, int y, const GLYPHMETRICS *metrics,
444                         const dib_info *glyph_dib, DWORD text_color,
445                         const struct intensity_range *ranges, const struct clipped_rects *clipped_rects,
446                         RECT *bounds )
447 {
448     int i;
449     RECT rect, clipped_rect;
450     POINT src_origin;
451
452     rect.left   = x          + metrics->gmptGlyphOrigin.x;
453     rect.top    = y          - metrics->gmptGlyphOrigin.y;
454     rect.right  = rect.left  + metrics->gmBlackBoxX;
455     rect.bottom = rect.top   + metrics->gmBlackBoxY;
456     if (bounds) add_bounds_rect( bounds, &rect );
457
458     for (i = 0; i < clipped_rects->count; i++)
459     {
460         if (intersect_rect( &clipped_rect, &rect, clipped_rects->rects + i ))
461         {
462             src_origin.x = clipped_rect.left - rect.left;
463             src_origin.y = clipped_rect.top  - rect.top;
464
465             if (glyph_dib->bit_count == 32)
466                 dib->funcs->draw_subpixel_glyph( dib, &clipped_rect, glyph_dib, &src_origin,
467                                                  text_color );
468             else
469                 dib->funcs->draw_glyph( dib, &clipped_rect, glyph_dib, &src_origin,
470                                         text_color, ranges );
471         }
472     }
473 }
474
475 static int get_glyph_depth( UINT aa_flags )
476 {
477     switch (aa_flags)
478     {
479     case GGO_BITMAP: return 1;
480
481     case GGO_GRAY2_BITMAP:
482     case GGO_GRAY4_BITMAP:
483     case GGO_GRAY8_BITMAP:
484     case WINE_GGO_GRAY16_BITMAP: return 8;
485
486     case WINE_GGO_HRGB_BITMAP:
487     case WINE_GGO_HBGR_BITMAP:
488     case WINE_GGO_VRGB_BITMAP:
489     case WINE_GGO_VBGR_BITMAP: return 32;
490
491     default:
492         ERR("Unexpected flags %08x\n", aa_flags);
493         return 0;
494     }
495 }
496
497 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
498 static const int padding[4] = {0, 3, 2, 1};
499
500 /***********************************************************************
501  *         get_glyph_bitmap
502  *
503  * Retrieve a 17-level bitmap for the appropriate glyph.
504  *
505  * For non-antialiased bitmaps convert them to the 17-level format
506  * using only values 0 or 16.
507  */
508 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT aa_flags, GLYPHMETRICS *metrics,
509                                dib_info *glyph_dib )
510 {
511     UINT ggo_flags = aa_flags | GGO_GLYPH_INDEX;
512     static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
513     UINT indices[3] = {0, 0, 0x20};
514     int i, x, y;
515     DWORD ret, size;
516     BYTE *buf, *dst, *src;
517     int pad = 0, depth = get_glyph_depth( aa_flags );
518
519     glyph_dib->bits.ptr = NULL;
520     glyph_dib->bits.is_copy = FALSE;
521     glyph_dib->bits.free = free_heap_bits;
522     glyph_dib->bits.param = NULL;
523
524     indices[0] = index;
525
526     for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
527     {
528         index = indices[i];
529         ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, 0, NULL, &identity );
530         if (ret != GDI_ERROR) break;
531     }
532
533     if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
534     if (!ret) return ERROR_SUCCESS; /* empty glyph */
535
536     /* We'll convert non-antialiased 1-bpp bitmaps to 8-bpp, so these sizes relate to 8-bpp */
537     glyph_dib->bit_count   = depth == 1 ? 8 : depth;
538     glyph_dib->width       = metrics->gmBlackBoxX;
539     glyph_dib->height      = metrics->gmBlackBoxY;
540     glyph_dib->rect.left   = 0;
541     glyph_dib->rect.top    = 0;
542     glyph_dib->rect.right  = metrics->gmBlackBoxX;
543     glyph_dib->rect.bottom = metrics->gmBlackBoxY;
544     glyph_dib->stride      = get_dib_stride( metrics->gmBlackBoxX, glyph_dib->bit_count );
545
546     if (glyph_dib->bit_count == 8) pad = padding[ metrics->gmBlackBoxX % 4 ];
547     size = metrics->gmBlackBoxY * glyph_dib->stride;
548
549     buf = HeapAlloc( GetProcessHeap(), 0, size );
550     if (!buf) return ERROR_OUTOFMEMORY;
551
552     ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, size, buf, &identity );
553     if (ret == GDI_ERROR)
554     {
555         HeapFree( GetProcessHeap(), 0, buf );
556         return ERROR_NOT_FOUND;
557     }
558
559     if (aa_flags == GGO_BITMAP)
560     {
561         for (y = metrics->gmBlackBoxY - 1; y >= 0; y--)
562         {
563             src = buf + y * get_dib_stride( metrics->gmBlackBoxX, 1 );
564             dst = buf + y * glyph_dib->stride;
565
566             if (pad) memset( dst + metrics->gmBlackBoxX, 0, pad );
567
568             for (x = metrics->gmBlackBoxX - 1; x >= 0; x--)
569                 dst[x] = (src[x / 8] & masks[x % 8]) ? 0x10 : 0;
570         }
571     }
572     else if (pad)
573     {
574         for (y = 0, dst = buf; y < metrics->gmBlackBoxY; y++, dst += glyph_dib->stride)
575             memset( dst + metrics->gmBlackBoxX, 0, pad );
576     }
577
578     glyph_dib->bits.ptr = buf;
579     return ERROR_SUCCESS;
580 }
581
582 static void render_string( HDC hdc, dib_info *dib, INT x, INT y, UINT flags, UINT aa_flags,
583                            const WCHAR *str, UINT count, const INT *dx, DWORD text_color,
584                            const struct intensity_range *ranges, const struct clipped_rects *clipped_rects,
585                            RECT *bounds )
586 {
587     UINT i;
588     DWORD err;
589     GLYPHMETRICS metrics;
590     dib_info glyph_dib;
591
592     for (i = 0; i < count; i++)
593     {
594         err = get_glyph_bitmap( hdc, (UINT)str[i], aa_flags, &metrics, &glyph_dib );
595         if (err) continue;
596
597         if (glyph_dib.bits.ptr)
598             draw_glyph( dib, x, y, &metrics, &glyph_dib, text_color, ranges, clipped_rects, bounds );
599
600         free_dib_info( &glyph_dib );
601
602         if (dx)
603         {
604             if (flags & ETO_PDY)
605             {
606                 x += dx[ i * 2 ];
607                 y += dx[ i * 2 + 1];
608             }
609             else
610                 x += dx[ i ];
611         }
612         else
613         {
614             x += metrics.gmCellIncX;
615             y += metrics.gmCellIncY;
616         }
617     }
618 }
619
620 BOOL render_aa_text_bitmapinfo( HDC hdc, BITMAPINFO *info, struct gdi_image_bits *bits,
621                                 struct bitblt_coords *src, INT x, INT y, UINT flags,
622                                 UINT aa_flags, LPCWSTR str, UINT count, const INT *dx )
623 {
624     dib_info dib;
625     BOOL got_pixel;
626     COLORREF fg, bg;
627     DWORD fg_pixel, bg_pixel;
628     struct intensity_range glyph_intensities[17];
629     struct clipped_rects visrect;
630
631     assert( info->bmiHeader.biBitCount > 8 ); /* mono and indexed formats don't support anti-aliasing */
632
633     init_dib_info_from_bitmapinfo( &dib, info, bits->ptr );
634
635     visrect.count = 1;
636     visrect.rects = &src->visrect;
637
638     fg = make_rgb_colorref( hdc, &dib, GetTextColor( hdc ), &got_pixel, &fg_pixel);
639     if (!got_pixel) fg_pixel = dib.funcs->colorref_to_pixel( &dib, fg );
640
641     get_aa_ranges( fg, glyph_intensities );
642
643     if (flags & ETO_OPAQUE)
644     {
645         rop_mask bkgnd_color;
646
647         bg = make_rgb_colorref( hdc, &dib, GetBkColor( hdc ), &got_pixel, &bg_pixel);
648         if (!got_pixel) bg_pixel = dib.funcs->colorref_to_pixel( &dib, bg );
649
650         bkgnd_color.and = 0;
651         bkgnd_color.xor = bg_pixel;
652         dib.funcs->solid_rects( &dib, 1, &src->visrect, bkgnd_color.and, bkgnd_color.xor );
653     }
654
655     render_string( hdc, &dib, x, y, flags, aa_flags, str, count, dx,
656                    fg_pixel, glyph_intensities, &visrect, NULL );
657     return TRUE;
658 }
659
660 /***********************************************************************
661  *           dibdrv_ExtTextOut
662  */
663 BOOL dibdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
664                         const RECT *rect, LPCWSTR str, UINT count, const INT *dx )
665 {
666     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
667     struct clipped_rects clipped_rects;
668     DC *dc;
669     RECT bounds;
670     DWORD text_color;
671     struct intensity_range ranges[17];
672
673     init_clipped_rects( &clipped_rects );
674     reset_bounds( &bounds );
675
676     if (flags & ETO_OPAQUE)
677     {
678         rop_mask bkgnd_color;
679         get_text_bkgnd_masks( pdev, &bkgnd_color );
680         add_bounds_rect( &bounds, rect );
681         get_clipped_rects( &pdev->dib, rect, pdev->clip, &clipped_rects );
682         pdev->dib.funcs->solid_rects( &pdev->dib, clipped_rects.count, clipped_rects.rects,
683                                       bkgnd_color.and, bkgnd_color.xor );
684     }
685
686     if (count == 0) goto done;
687
688     if (flags & ETO_CLIPPED)
689     {
690         if (!(flags & ETO_OPAQUE))  /* otherwise we have done it already */
691             get_clipped_rects( &pdev->dib, rect, pdev->clip, &clipped_rects );
692     }
693     else
694     {
695         free_clipped_rects( &clipped_rects );
696         get_clipped_rects( &pdev->dib, NULL, pdev->clip, &clipped_rects );
697     }
698     if (!clipped_rects.count) goto done;
699
700     text_color = get_pixel_color( pdev, GetTextColor( pdev->dev.hdc ), TRUE );
701     get_aa_ranges( pdev->dib.funcs->pixel_to_colorref( &pdev->dib, text_color ), ranges );
702
703     dc = get_dc_ptr( dev->hdc );
704     render_string( dev->hdc, &pdev->dib, x, y, flags, dc->aa_flags, str, count, dx,
705                    text_color, ranges, &clipped_rects, &bounds );
706     release_dc_ptr( dc );
707
708 done:
709     add_clipped_bounds( pdev, &bounds, pdev->clip );
710     free_clipped_rects( &clipped_rects );
711     return TRUE;
712 }
713
714 /***********************************************************************
715  *           dibdrv_SelectFont
716  */
717 HFONT dibdrv_SelectFont( PHYSDEV dev, HFONT font, UINT *aa_flags )
718 {
719     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
720
721     if (pdev->dib.bit_count <= 8) *aa_flags = GGO_BITMAP;  /* no anti-aliasing on <= 8bpp */
722
723     dev = GET_NEXT_PHYSDEV( dev, pSelectFont );
724     return dev->funcs->pSelectFont( dev, font, aa_flags );
725 }
726
727 /***********************************************************************
728  *           dibdrv_Arc
729  */
730 BOOL dibdrv_Arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
731                  INT start_x, INT start_y, INT end_x, INT end_y )
732 {
733     return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, 0 );
734 }
735
736 /***********************************************************************
737  *           dibdrv_ArcTo
738  */
739 BOOL dibdrv_ArcTo( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
740                    INT start_x, INT start_y, INT end_x, INT end_y )
741 {
742     return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, -1 );
743 }
744
745 /***********************************************************************
746  *           dibdrv_Chord
747  */
748 BOOL dibdrv_Chord( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
749                    INT start_x, INT start_y, INT end_x, INT end_y )
750 {
751     return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, 1 );
752 }
753
754 /***********************************************************************
755  *           dibdrv_Ellipse
756  */
757 BOOL dibdrv_Ellipse( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
758 {
759     return dibdrv_RoundRect( dev, left, top, right, bottom, right - left, bottom - top );
760 }
761
762 static inline BOOL is_interior( dib_info *dib, HRGN clip, int x, int y, DWORD pixel, UINT type)
763 {
764     /* the clip rgn stops the flooding */
765     if (clip && !PtInRegion( clip, x, y )) return FALSE;
766
767     if (type == FLOODFILLBORDER)
768         return dib->funcs->get_pixel( dib, x, y ) != pixel;
769     else
770         return dib->funcs->get_pixel( dib, x, y ) == pixel;
771 }
772
773 static void fill_row( dib_info *dib, HRGN clip, RECT *row, DWORD pixel, UINT type, HRGN rgn );
774
775 static inline void do_next_row( dib_info *dib, HRGN clip, const RECT *row, int offset, DWORD pixel, UINT type, HRGN rgn )
776 {
777     RECT next;
778
779     next.top = row->top + offset;
780     next.bottom = next.top + 1;
781     next.left = next.right = row->left;
782     while (next.right < row->right)
783     {
784         if (is_interior( dib, clip, next.right, next.top, pixel, type)) next.right++;
785         else
786         {
787             if (next.left != next.right && !PtInRegion( rgn, next.left, next.top ))
788                 fill_row( dib, clip, &next, pixel, type, rgn );
789             next.left = ++next.right;
790         }
791     }
792     if (next.left != next.right && !PtInRegion( rgn, next.left, next.top ))
793         fill_row( dib, clip, &next, pixel, type, rgn );
794 }
795
796 static void fill_row( dib_info *dib, HRGN clip, RECT *row, DWORD pixel, UINT type, HRGN rgn )
797 {
798     while (row->left > 0 && is_interior( dib, clip, row->left - 1, row->top, pixel, type)) row->left--;
799     while (row->right < dib->rect.right - dib->rect.left &&
800            is_interior( dib, clip, row->right, row->top, pixel, type))
801         row->right++;
802
803     add_rect_to_region( rgn, row );
804
805     if (row->top > 0) do_next_row( dib, clip, row, -1, pixel, type, rgn );
806     if (row->top < dib->rect.bottom - dib->rect.top - 1)
807         do_next_row( dib, clip, row, 1, pixel, type, rgn );
808 }
809
810 /***********************************************************************
811  *           dibdrv_ExtFloodFill
812  */
813 BOOL dibdrv_ExtFloodFill( PHYSDEV dev, INT x, INT y, COLORREF color, UINT type )
814 {
815     dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
816     DWORD pixel = get_pixel_color( pdev, color, FALSE );
817     RECT row;
818     HRGN rgn;
819
820     TRACE( "(%p, %d, %d, %08x, %d)\n", pdev, x, y, color, type );
821
822     if (!is_interior( &pdev->dib, pdev->clip, x, y, pixel, type )) return FALSE;
823
824     if (!(rgn = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
825     row.left = x;
826     row.right = x + 1;
827     row.top = y;
828     row.bottom = y + 1;
829
830     fill_row( &pdev->dib, pdev->clip, &row, pixel, type, rgn );
831
832     add_clipped_bounds( pdev, NULL, rgn );
833     brush_region( pdev, rgn );
834
835     DeleteObject( rgn );
836     return TRUE;
837 }
838
839 /***********************************************************************
840  *           dibdrv_GetNearestColor
841  */
842 COLORREF dibdrv_GetNearestColor( PHYSDEV dev, COLORREF color )
843 {
844     dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
845     DWORD pixel;
846
847     TRACE( "(%p, %08x)\n", dev, color );
848
849     pixel = get_pixel_color( pdev, color, FALSE );
850     return pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
851 }
852
853 /***********************************************************************
854  *           dibdrv_GetPixel
855  */
856 COLORREF dibdrv_GetPixel( PHYSDEV dev, INT x, INT y )
857 {
858     dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
859     POINT pt;
860     DWORD pixel;
861
862     TRACE( "(%p, %d, %d)\n", dev, x, y );
863
864     pt.x = x;
865     pt.y = y;
866     LPtoDP( dev->hdc, &pt, 1 );
867
868     if (pt.x < 0 || pt.x >= pdev->dib.rect.right - pdev->dib.rect.left ||
869         pt.y < 0 || pt.y >= pdev->dib.rect.bottom - pdev->dib.rect.top)
870         return CLR_INVALID;
871
872     pixel = pdev->dib.funcs->get_pixel( &pdev->dib, pt.x, pt.y );
873     return pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
874 }
875
876 /***********************************************************************
877  *           dibdrv_LineTo
878  */
879 BOOL dibdrv_LineTo( PHYSDEV dev, INT x, INT y )
880 {
881     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
882     POINT pts[2];
883     HRGN region = 0;
884     BOOL ret;
885
886     GetCurrentPositionEx(dev->hdc, pts);
887     pts[1].x = x;
888     pts[1].y = y;
889
890     LPtoDP(dev->hdc, pts, 2);
891
892     if (pdev->pen_uses_region && !(region = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
893
894     reset_dash_origin(pdev);
895
896     ret = pdev->pen_lines(pdev, 2, pts, FALSE, region);
897     add_pen_lines_bounds( pdev, 2, pts, region );
898
899     if (region)
900     {
901         ret = pen_region( pdev, region );
902         DeleteObject( region );
903     }
904     return ret;
905 }
906
907 /***********************************************************************
908  *           get_rop2_from_rop
909  *
910  * Returns the binary rop that is equivalent to the provided ternary rop
911  * if the src bits are ignored.
912  */
913 static inline INT get_rop2_from_rop(INT rop)
914 {
915     return (((rop >> 18) & 0x0c) | ((rop >> 16) & 0x03)) + 1;
916 }
917
918 /***********************************************************************
919  *           dibdrv_PatBlt
920  */
921 BOOL dibdrv_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
922 {
923     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
924     dib_brush *brush = &pdev->brush;
925     int rop2 = get_rop2_from_rop( rop );
926     struct clipped_rects clipped_rects;
927     DWORD and = 0, xor = 0;
928     BOOL ret = TRUE;
929
930     TRACE("(%p, %d, %d, %d, %d, %06x)\n", dev, dst->x, dst->y, dst->width, dst->height, rop);
931
932     add_clipped_bounds( pdev, &dst->visrect, 0 );
933     if (!get_clipped_rects( &pdev->dib, &dst->visrect, pdev->clip, &clipped_rects )) return TRUE;
934
935     switch (rop2)  /* shortcuts for rops that don't involve the brush */
936     {
937     case R2_NOT:   and = ~0u;
938         /* fall through */
939     case R2_WHITE: xor = ~0u;
940         /* fall through */
941     case R2_BLACK:
942         pdev->dib.funcs->solid_rects( &pdev->dib, clipped_rects.count, clipped_rects.rects, and, xor );
943         /* fall through */
944     case R2_NOP:
945         break;
946     default:
947         ret = brush->rects( pdev, brush, &pdev->dib, clipped_rects.count, clipped_rects.rects, rop2 );
948         break;
949     }
950     free_clipped_rects( &clipped_rects );
951     return ret;
952 }
953
954 /***********************************************************************
955  *           dibdrv_PaintRgn
956  */
957 BOOL dibdrv_PaintRgn( PHYSDEV dev, HRGN rgn )
958 {
959     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
960     const WINEREGION *region;
961     int i;
962     RECT rect, bounds;
963
964     TRACE("%p, %p\n", dev, rgn);
965
966     reset_bounds( &bounds );
967
968     region = get_wine_region( rgn );
969     if(!region) return FALSE;
970
971     for(i = 0; i < region->numRects; i++)
972     {
973         rect = get_device_rect( dev->hdc, region->rects[i].left, region->rects[i].top,
974                                 region->rects[i].right, region->rects[i].bottom, FALSE );
975         add_bounds_rect( &bounds, &rect );
976         brush_rect( pdev, &pdev->brush, &rect, pdev->clip );
977     }
978
979     release_wine_region( rgn );
980     add_clipped_bounds( pdev, &bounds, pdev->clip );
981     return TRUE;
982 }
983
984 /***********************************************************************
985  *           dibdrv_PolyPolygon
986  */
987 BOOL dibdrv_PolyPolygon( PHYSDEV dev, const POINT *pt, const INT *counts, DWORD polygons )
988 {
989     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
990     DWORD total, i, pos;
991     BOOL ret = TRUE;
992     POINT *points;
993     HRGN outline = 0, interior = 0;
994
995     for (i = total = 0; i < polygons; i++)
996     {
997         if (counts[i] < 2) return FALSE;
998         total += counts[i];
999     }
1000
1001     points = HeapAlloc( GetProcessHeap(), 0, total * sizeof(*pt) );
1002     if (!points) return FALSE;
1003     memcpy( points, pt, total * sizeof(*pt) );
1004     LPtoDP( dev->hdc, points, total );
1005
1006     if (pdev->brush.style != BS_NULL &&
1007         !(interior = CreatePolyPolygonRgn( points, counts, polygons, GetPolyFillMode( dev->hdc ))))
1008     {
1009         HeapFree( GetProcessHeap(), 0, points );
1010         return FALSE;
1011     }
1012
1013     if (pdev->pen_uses_region) outline = CreateRectRgn( 0, 0, 0, 0 );
1014
1015     /* if not using a region, paint the interior first so the outline can overlap it */
1016     if (interior && !outline)
1017     {
1018         ret = brush_region( pdev, interior );
1019         DeleteObject( interior );
1020         interior = 0;
1021     }
1022
1023     for (i = pos = 0; i < polygons; i++)
1024     {
1025         reset_dash_origin( pdev );
1026         pdev->pen_lines( pdev, counts[i], points + pos, TRUE, outline );
1027         pos += counts[i];
1028     }
1029     add_pen_lines_bounds( pdev, total, points, outline );
1030
1031     if (interior)
1032     {
1033         CombineRgn( interior, interior, outline, RGN_DIFF );
1034         ret = brush_region( pdev, interior );
1035         DeleteObject( interior );
1036     }
1037     if (outline)
1038     {
1039         if (ret) ret = pen_region( pdev, outline );
1040         DeleteObject( outline );
1041     }
1042     HeapFree( GetProcessHeap(), 0, points );
1043     return ret;
1044 }
1045
1046 /***********************************************************************
1047  *           dibdrv_PolyPolyline
1048  */
1049 BOOL dibdrv_PolyPolyline( PHYSDEV dev, const POINT* pt, const DWORD* counts, DWORD polylines )
1050 {
1051     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
1052     DWORD total, pos, i;
1053     POINT *points;
1054     BOOL ret = TRUE;
1055     HRGN outline = 0;
1056
1057     for (i = total = 0; i < polylines; i++)
1058     {
1059         if (counts[i] < 2) return FALSE;
1060         total += counts[i];
1061     }
1062
1063     points = HeapAlloc( GetProcessHeap(), 0, total * sizeof(*pt) );
1064     if (!points) return FALSE;
1065     memcpy( points, pt, total * sizeof(*pt) );
1066     LPtoDP( dev->hdc, points, total );
1067
1068     if (pdev->pen_uses_region && !(outline = CreateRectRgn( 0, 0, 0, 0 )))
1069     {
1070         HeapFree( GetProcessHeap(), 0, points );
1071         return FALSE;
1072     }
1073
1074     for (i = pos = 0; i < polylines; i++)
1075     {
1076         reset_dash_origin( pdev );
1077         pdev->pen_lines( pdev, counts[i], points + pos, FALSE, outline );
1078         pos += counts[i];
1079     }
1080     add_pen_lines_bounds( pdev, total, points, outline );
1081
1082     if (outline)
1083     {
1084         ret = pen_region( pdev, outline );
1085         DeleteObject( outline );
1086     }
1087
1088     HeapFree( GetProcessHeap(), 0, points );
1089     return ret;
1090 }
1091
1092 /***********************************************************************
1093  *           dibdrv_Polygon
1094  */
1095 BOOL dibdrv_Polygon( PHYSDEV dev, const POINT *pt, INT count )
1096 {
1097     INT counts[1] = { count };
1098
1099     return dibdrv_PolyPolygon( dev, pt, counts, 1 );
1100 }
1101
1102 /***********************************************************************
1103  *           dibdrv_Polyline
1104  */
1105 BOOL dibdrv_Polyline( PHYSDEV dev, const POINT* pt, INT count )
1106 {
1107     DWORD counts[1] = { count };
1108
1109     if (count < 0) return FALSE;
1110     return dibdrv_PolyPolyline( dev, pt, counts, 1 );
1111 }
1112
1113 /***********************************************************************
1114  *           dibdrv_Rectangle
1115  */
1116 BOOL dibdrv_Rectangle( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
1117 {
1118     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
1119     RECT rect;
1120     POINT pts[4];
1121     BOOL ret;
1122     HRGN outline = 0;
1123
1124     TRACE("(%p, %d, %d, %d, %d)\n", dev, left, top, right, bottom);
1125
1126     if (!get_pen_device_rect( pdev, &rect, left, top, right, bottom )) return TRUE;
1127
1128     if (pdev->pen_uses_region && !(outline = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
1129
1130     rect.right--;
1131     rect.bottom--;
1132     reset_dash_origin(pdev);
1133
1134     if (GetArcDirection( dev->hdc ) == AD_CLOCKWISE)
1135     {
1136         /* 4 pts going clockwise starting from bottom-right */
1137         pts[0].x = pts[3].x = rect.right;
1138         pts[0].y = pts[1].y = rect.bottom;
1139         pts[1].x = pts[2].x = rect.left;
1140         pts[2].y = pts[3].y = rect.top;
1141     }
1142     else
1143     {
1144         /* 4 pts going anti-clockwise starting from top-right */
1145         pts[0].x = pts[3].x = rect.right;
1146         pts[0].y = pts[1].y = rect.top;
1147         pts[1].x = pts[2].x = rect.left;
1148         pts[2].y = pts[3].y = rect.bottom;
1149     }
1150
1151     pdev->pen_lines(pdev, 4, pts, TRUE, outline);
1152     add_pen_lines_bounds( pdev, 4, pts, outline );
1153
1154     if (outline)
1155     {
1156         if (pdev->brush.style != BS_NULL)
1157         {
1158             HRGN interior = CreateRectRgnIndirect( &rect );
1159
1160             CombineRgn( interior, interior, outline, RGN_DIFF );
1161             brush_region( pdev, interior );
1162             DeleteObject( interior );
1163         }
1164         ret = pen_region( pdev, outline );
1165         DeleteObject( outline );
1166     }
1167     else
1168     {
1169         rect.left   += (pdev->pen_width + 1) / 2;
1170         rect.top    += (pdev->pen_width + 1) / 2;
1171         rect.right  -= pdev->pen_width / 2;
1172         rect.bottom -= pdev->pen_width / 2;
1173         ret = brush_rect( pdev, &pdev->brush, &rect, pdev->clip );
1174     }
1175     return ret;
1176 }
1177
1178 /***********************************************************************
1179  *           dibdrv_RoundRect
1180  */
1181 BOOL dibdrv_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
1182                        INT ellipse_width, INT ellipse_height )
1183 {
1184     dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
1185     RECT rect;
1186     POINT pt[2], *points;
1187     int i, end, count;
1188     BOOL ret = TRUE;
1189     HRGN outline = 0, interior = 0;
1190
1191     if (!get_pen_device_rect( pdev, &rect, left, top, right, bottom )) return TRUE;
1192
1193     pt[0].x = pt[0].y = 0;
1194     pt[1].x = ellipse_width;
1195     pt[1].y = ellipse_height;
1196     LPtoDP( dev->hdc, pt, 2 );
1197     ellipse_width = min( rect.right - rect.left, abs( pt[1].x - pt[0].x ));
1198     ellipse_height = min( rect.bottom - rect.top, abs( pt[1].y - pt[0].y ));
1199     if (ellipse_width <= 2|| ellipse_height <= 2)
1200         return dibdrv_Rectangle( dev, left, top, right, bottom );
1201
1202     points = HeapAlloc( GetProcessHeap(), 0, (ellipse_width + ellipse_height) * 2 * sizeof(*points) );
1203     if (!points) return FALSE;
1204
1205     if (pdev->pen_uses_region && !(outline = CreateRectRgn( 0, 0, 0, 0 )))
1206     {
1207         HeapFree( GetProcessHeap(), 0, points );
1208         return FALSE;
1209     }
1210
1211     if (pdev->brush.style != BS_NULL &&
1212         !(interior = CreateRoundRectRgn( rect.left, rect.top, rect.right + 1, rect.bottom + 1,
1213                                          ellipse_width, ellipse_height )))
1214     {
1215         HeapFree( GetProcessHeap(), 0, points );
1216         if (outline) DeleteObject( outline );
1217         return FALSE;
1218     }
1219
1220     /* if not using a region, paint the interior first so the outline can overlap it */
1221     if (interior && !outline)
1222     {
1223         ret = brush_region( pdev, interior );
1224         DeleteObject( interior );
1225         interior = 0;
1226     }
1227
1228     count = ellipse_first_quadrant( ellipse_width, ellipse_height, points );
1229
1230     if (GetArcDirection( dev->hdc ) == AD_CLOCKWISE)
1231     {
1232         for (i = 0; i < count; i++)
1233         {
1234             points[i].x = rect.right - ellipse_width + points[i].x;
1235             points[i].y = rect.bottom - ellipse_height + points[i].y;
1236         }
1237     }
1238     else
1239     {
1240         for (i = 0; i < count; i++)
1241         {
1242             points[i].x = rect.right - ellipse_width + points[i].x;
1243             points[i].y = rect.top + ellipse_height - 1 - points[i].y;
1244         }
1245     }
1246
1247     /* horizontal symmetry */
1248
1249     end = 2 * count - 1;
1250     /* avoid duplicating the midpoint */
1251     if (ellipse_width % 2 && ellipse_width == rect.right - rect.left) end--;
1252     for (i = 0; i < count; i++)
1253     {
1254         points[end - i].x = rect.left + rect.right - 1 - points[i].x;
1255         points[end - i].y = points[i].y;
1256     }
1257     count = end + 1;
1258
1259     /* vertical symmetry */
1260
1261     end = 2 * count - 1;
1262     /* avoid duplicating the midpoint */
1263     if (ellipse_height % 2 && ellipse_height == rect.bottom - rect.top) end--;
1264     for (i = 0; i < count; i++)
1265     {
1266         points[end - i].x = points[i].x;
1267         points[end - i].y = rect.top + rect.bottom - 1 - points[i].y;
1268     }
1269     count = end + 1;
1270
1271     reset_dash_origin( pdev );
1272     pdev->pen_lines( pdev, count, points, TRUE, outline );
1273     add_pen_lines_bounds( pdev, count, points, outline );
1274
1275     if (interior)
1276     {
1277         CombineRgn( interior, interior, outline, RGN_DIFF );
1278         ret = brush_region( pdev, interior );
1279         DeleteObject( interior );
1280     }
1281     if (outline)
1282     {
1283         if (ret) ret = pen_region( pdev, outline );
1284         DeleteObject( outline );
1285     }
1286     HeapFree( GetProcessHeap(), 0, points );
1287     return ret;
1288 }
1289
1290 /***********************************************************************
1291  *           dibdrv_Pie
1292  */
1293 BOOL dibdrv_Pie( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
1294                  INT start_x, INT start_y, INT end_x, INT end_y )
1295 {
1296     return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, 2 );
1297 }
1298
1299 /***********************************************************************
1300  *           dibdrv_SetPixel
1301  */
1302 COLORREF dibdrv_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color )
1303 {
1304     dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
1305     struct clipped_rects clipped_rects;
1306     RECT rect;
1307     POINT pt;
1308     DWORD pixel;
1309
1310     TRACE( "(%p, %d, %d, %08x)\n", dev, x, y, color );
1311
1312     pt.x = x;
1313     pt.y = y;
1314     LPtoDP( dev->hdc, &pt, 1 );
1315     rect.left = pt.x;
1316     rect.top =  pt.y;
1317     rect.right = rect.left + 1;
1318     rect.bottom = rect.top + 1;
1319     add_clipped_bounds( pdev, &rect, pdev->clip );
1320
1321     /* SetPixel doesn't do the 1bpp massaging like other fg colors */
1322     pixel = get_pixel_color( pdev, color, FALSE );
1323     color = pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
1324
1325     if (!get_clipped_rects( &pdev->dib, &rect, pdev->clip, &clipped_rects )) return color;
1326     pdev->dib.funcs->solid_rects( &pdev->dib, clipped_rects.count, clipped_rects.rects, 0, pixel );
1327     free_clipped_rects( &clipped_rects );
1328     return color;
1329 }