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