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