2 * DIB driver graphics operations.
4 * Copyright 2011 Huw Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "gdi_private.h"
25 #include "wine/unicode.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(dib
);
43 #define GLYPH_CACHE_PAGE_SIZE 0x100
44 #define GLYPH_CACHE_PAGES (0x10000 / GLYPH_CACHE_PAGE_SIZE)
54 struct cached_glyph
**glyphs
[GLYPH_NBTYPES
][GLYPH_CACHE_PAGES
];
57 static struct list font_cache
= LIST_INIT( font_cache
);
59 static CRITICAL_SECTION font_cache_cs
;
60 static CRITICAL_SECTION_DEBUG critsect_debug
=
63 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
64 0, 0, { (DWORD_PTR
)(__FILE__
": font_cache_cs") }
66 static CRITICAL_SECTION font_cache_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
69 static BOOL
brush_rect( dibdrv_physdev
*pdev
, dib_brush
*brush
, const RECT
*rect
, HRGN clip
)
71 struct clipped_rects clipped_rects
;
74 if (!get_clipped_rects( &pdev
->dib
, rect
, clip
, &clipped_rects
)) return TRUE
;
75 ret
= brush
->rects( pdev
, brush
, &pdev
->dib
, clipped_rects
.count
, clipped_rects
.rects
,
76 GetROP2( pdev
->dev
.hdc
));
77 free_clipped_rects( &clipped_rects
);
81 /* paint a region with the brush (note: the region can be modified) */
82 static BOOL
brush_region( dibdrv_physdev
*pdev
, HRGN region
)
84 if (pdev
->clip
) CombineRgn( region
, region
, pdev
->clip
, RGN_AND
);
85 return brush_rect( pdev
, &pdev
->brush
, NULL
, region
);
88 /* paint a region with the pen (note: the region can be modified) */
89 static BOOL
pen_region( dibdrv_physdev
*pdev
, HRGN region
)
91 if (pdev
->clip
) CombineRgn( region
, region
, pdev
->clip
, RGN_AND
);
92 return brush_rect( pdev
, &pdev
->pen_brush
, NULL
, region
);
95 static RECT
get_device_rect( HDC hdc
, int left
, int top
, int right
, int bottom
, BOOL rtl_correction
)
102 rect
.bottom
= bottom
;
103 if (rtl_correction
&& GetLayout( hdc
) & LAYOUT_RTL
)
105 /* shift the rectangle so that the right border is included after mirroring */
106 /* it would be more correct to do this after LPtoDP but that's not what Windows does */
110 LPtoDP( hdc
, (POINT
*)&rect
, 2 );
115 static BOOL
get_pen_device_rect( dibdrv_physdev
*dev
, RECT
*rect
, int left
, int top
, int right
, int bottom
)
117 *rect
= get_device_rect( dev
->dev
.hdc
, left
, top
, right
, bottom
, TRUE
);
118 if (rect
->left
== rect
->right
|| rect
->top
== rect
->bottom
) return FALSE
;
120 if (dev
->pen_style
== PS_INSIDEFRAME
)
122 rect
->left
+= dev
->pen_width
/ 2;
123 rect
->top
+= dev
->pen_width
/ 2;
124 rect
->right
-= (dev
->pen_width
- 1) / 2;
125 rect
->bottom
-= (dev
->pen_width
- 1) / 2;
130 static void add_pen_lines_bounds( dibdrv_physdev
*dev
, int count
, const POINT
*points
, HRGN rgn
)
132 const WINEREGION
*region
;
136 if (!dev
->bounds
) return;
137 reset_bounds( &bounds
);
139 if (dev
->pen_uses_region
)
141 /* Windows uses some heuristics to estimate the distance from the point that will be painted */
142 width
= dev
->pen_width
+ 2;
143 if (dev
->pen_join
== PS_JOIN_MITER
)
146 if (dev
->pen_endcap
== PS_ENDCAP_SQUARE
) width
= (width
* 3 + 1) / 2;
150 if (dev
->pen_endcap
== PS_ENDCAP_SQUARE
) width
-= width
/ 4;
151 else width
= (width
+ 1) / 2;
154 /* in case the heuristics are wrong, add the actual region too */
155 if ((region
= get_wine_region( rgn
)))
157 add_bounds_rect( &bounds
, ®ion
->extents
);
158 release_wine_region( rgn
);
164 rect
.left
= points
->x
- width
;
165 rect
.top
= points
->y
- width
;
166 rect
.right
= points
->x
+ width
+ 1;
167 rect
.bottom
= points
->y
+ width
+ 1;
168 add_bounds_rect( &bounds
, &rect
);
172 add_clipped_bounds( dev
, &bounds
, dev
->clip
);
175 /* compute the points for the first quadrant of an ellipse, counterclockwise from the x axis */
176 /* 'data' must contain enough space, (width+height)/2 is a reasonable upper bound */
177 static int ellipse_first_quadrant( int width
, int height
, POINT
*data
)
179 const int a
= width
- 1;
180 const int b
= height
- 1;
181 const INT64 asq
= (INT64
)8 * a
* a
;
182 const INT64 bsq
= (INT64
)8 * b
* b
;
183 INT64 dx
= (INT64
)4 * b
* b
* (1 - a
);
184 INT64 dy
= (INT64
)4 * a
* a
* (1 + (b
% 2));
185 INT64 err
= dx
+ dy
+ a
* a
* (b
% 2);
192 /* based on an algorithm by Alois Zingl */
194 while (pt
.x
>= width
/ 2)
212 static int find_intersection( const POINT
*points
, int x
, int y
, int count
)
218 if (x
>= 0) /* first quadrant */
220 for (i
= 0; i
< count
; i
++) if (points
[i
].x
* y
<= points
[i
].y
* x
) break;
223 /* second quadrant */
224 for (i
= 0; i
< count
; i
++) if (points
[i
].x
* y
< points
[i
].y
* -x
) break;
225 return 2 * count
- i
;
227 if (x
>= 0) /* fourth quadrant */
229 for (i
= 0; i
< count
; i
++) if (points
[i
].x
* -y
<= points
[i
].y
* x
) break;
230 return 4 * count
- i
;
233 for (i
= 0; i
< count
; i
++) if (points
[i
].x
* -y
< points
[i
].y
* -x
) break;
234 return 2 * count
+ i
;
237 static int get_arc_points( PHYSDEV dev
, const RECT
*rect
, POINT start
, POINT end
, POINT
*points
)
239 int i
, pos
, count
, start_pos
, end_pos
;
240 int width
= rect
->right
- rect
->left
;
241 int height
= rect
->bottom
- rect
->top
;
243 count
= ellipse_first_quadrant( width
, height
, points
);
244 for (i
= 0; i
< count
; i
++)
246 points
[i
].x
-= width
/ 2;
247 points
[i
].y
-= height
/ 2;
249 if (GetArcDirection( dev
->hdc
) != AD_CLOCKWISE
)
254 start_pos
= find_intersection( points
, start
.x
, start
.y
, count
);
255 end_pos
= find_intersection( points
, end
.x
, end
.y
, count
);
256 if (end_pos
<= start_pos
) end_pos
+= 4 * count
;
259 if (GetArcDirection( dev
->hdc
) == AD_CLOCKWISE
)
261 for (i
= start_pos
; i
< end_pos
; i
++, pos
++)
263 switch ((i
/ count
) % 4)
266 points
[pos
].x
= rect
->left
+ width
/2 + points
[i
% count
].x
;
267 points
[pos
].y
= rect
->top
+ height
/2 + points
[i
% count
].y
;
270 points
[pos
].x
= rect
->right
-1 - width
/2 - points
[count
- 1 - i
% count
].x
;
271 points
[pos
].y
= rect
->top
+ height
/2 + points
[count
- 1 - i
% count
].y
;
274 points
[pos
].x
= rect
->right
-1 - width
/2 - points
[i
% count
].x
;
275 points
[pos
].y
= rect
->bottom
-1 - height
/2 - points
[i
% count
].y
;
278 points
[pos
].x
= rect
->left
+ width
/2 + points
[count
- 1 - i
% count
].x
;
279 points
[pos
].y
= rect
->bottom
-1 - height
/2 - points
[count
- 1 - i
% count
].y
;
286 for (i
= start_pos
; i
< end_pos
; i
++, pos
++)
288 switch ((i
/ count
) % 4)
291 points
[pos
].x
= rect
->left
+ width
/2 + points
[i
% count
].x
;
292 points
[pos
].y
= rect
->bottom
-1 - height
/2 - points
[i
% count
].y
;
295 points
[pos
].x
= rect
->right
-1 - width
/2 - points
[count
- 1 - i
% count
].x
;
296 points
[pos
].y
= rect
->bottom
-1 - height
/2 - points
[count
- 1 - i
% count
].y
;
299 points
[pos
].x
= rect
->right
-1 - width
/2 - points
[i
% count
].x
;
300 points
[pos
].y
= rect
->top
+ height
/2 + points
[i
% count
].y
;
303 points
[pos
].x
= rect
->left
+ width
/2 + points
[count
- 1 - i
% count
].x
;
304 points
[pos
].y
= rect
->top
+ height
/2 + points
[count
- 1 - i
% count
].y
;
310 memmove( points
, points
+ count
, (pos
- count
) * sizeof(POINT
) );
314 /* backend for arc functions; extra_lines is -1 for ArcTo, 0 for Arc, 1 for Chord, 2 for Pie */
315 static BOOL
draw_arc( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
316 INT start_x
, INT start_y
, INT end_x
, INT end_y
, INT extra_lines
)
318 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
320 POINT pt
[2], *points
;
321 int width
, height
, count
;
323 HRGN outline
= 0, interior
= 0;
325 if (!get_pen_device_rect( pdev
, &rect
, left
, top
, right
, bottom
)) return TRUE
;
327 width
= rect
.right
- rect
.left
;
328 height
= rect
.bottom
- rect
.top
;
334 LPtoDP( dev
->hdc
, pt
, 2 );
335 /* make them relative to the ellipse center */
336 pt
[0].x
-= rect
.left
+ width
/ 2;
337 pt
[0].y
-= rect
.top
+ height
/ 2;
338 pt
[1].x
-= rect
.left
+ width
/ 2;
339 pt
[1].y
-= rect
.top
+ height
/ 2;
341 points
= HeapAlloc( GetProcessHeap(), 0, (width
+ height
) * 3 * sizeof(*points
) );
342 if (!points
) return FALSE
;
344 if (extra_lines
== -1)
346 GetCurrentPositionEx( dev
->hdc
, points
);
347 LPtoDP( dev
->hdc
, points
, 1 );
348 count
= 1 + get_arc_points( dev
, &rect
, pt
[0], pt
[1], points
+ 1 );
350 else count
= get_arc_points( dev
, &rect
, pt
[0], pt
[1], points
);
352 if (extra_lines
== 2)
354 points
[count
].x
= rect
.left
+ width
/ 2;
355 points
[count
].y
= rect
.top
+ height
/ 2;
360 HeapFree( GetProcessHeap(), 0, points
);
364 if (pdev
->pen_uses_region
&& !(outline
= CreateRectRgn( 0, 0, 0, 0 )))
366 HeapFree( GetProcessHeap(), 0, points
);
370 if (pdev
->brush
.style
!= BS_NULL
&& extra_lines
> 0 &&
371 !(interior
= CreatePolygonRgn( points
, count
, WINDING
)))
373 HeapFree( GetProcessHeap(), 0, points
);
374 if (outline
) DeleteObject( outline
);
378 /* if not using a region, paint the interior first so the outline can overlap it */
379 if (interior
&& !outline
)
381 ret
= brush_region( pdev
, interior
);
382 DeleteObject( interior
);
386 reset_dash_origin( pdev
);
387 pdev
->pen_lines( pdev
, count
, points
, extra_lines
> 0, outline
);
388 add_pen_lines_bounds( pdev
, count
, points
, outline
);
392 CombineRgn( interior
, interior
, outline
, RGN_DIFF
);
393 ret
= brush_region( pdev
, interior
);
394 DeleteObject( interior
);
398 if (ret
) ret
= pen_region( pdev
, outline
);
399 DeleteObject( outline
);
401 HeapFree( GetProcessHeap(), 0, points
);
405 /* Intensities of the 17 glyph levels when drawn with text component of 0xff on a
406 black bkgnd. [A log-log plot of these data gives: y = 77.05 * x^0.4315]. */
407 static const BYTE ramp
[17] =
410 0x8c, 0x9a, 0xa7, 0xb2,
411 0xbd, 0xc7, 0xd0, 0xd9,
412 0xe1, 0xe9, 0xf0, 0xf8,
416 /* For a give text-color component and a glyph level, calculate the
417 range of dst intensities, the min/max corresponding to 0/0xff bkgnd
418 components respectively.
420 The minimum is a linear interpolation between 0 and the value in
423 The maximum is a linear interpolation between the value from the
424 ramp table read in reverse and 0xff.
426 To find the resulting pixel intensity, we note that if the text and
427 bkgnd intensities are the same then the result must be that
428 intensity. Otherwise we linearly interpolate between either the
429 min or the max value and this intermediate value depending on which
430 side of the inequality we lie.
433 static inline void get_range( BYTE aa
, DWORD text_comp
, BYTE
*min_comp
, BYTE
*max_comp
)
435 *min_comp
= (ramp
[aa
] * text_comp
) / 0xff;
436 *max_comp
= ramp
[16 - aa
] + ((0xff - ramp
[16 - aa
]) * text_comp
) / 0xff;
439 static inline void get_aa_ranges( COLORREF col
, struct intensity_range intensities
[17] )
443 for (i
= 0; i
< 17; i
++)
445 get_range( i
, GetRValue(col
), &intensities
[i
].r_min
, &intensities
[i
].r_max
);
446 get_range( i
, GetGValue(col
), &intensities
[i
].g_min
, &intensities
[i
].g_max
);
447 get_range( i
, GetBValue(col
), &intensities
[i
].b_min
, &intensities
[i
].b_max
);
451 static DWORD
font_cache_hash( struct cached_font
*font
)
453 DWORD hash
= 0, *ptr
, two_chars
;
457 hash
^= font
->aa_flags
;
458 for(i
= 0, ptr
= (DWORD
*)&font
->xform
; i
< sizeof(XFORM
)/sizeof(DWORD
); i
++, ptr
++)
460 for(i
= 0, ptr
= (DWORD
*)&font
->lf
; i
< 7; i
++, ptr
++)
462 for(i
= 0, ptr
= (DWORD
*)font
->lf
.lfFaceName
; i
< LF_FACESIZE
/2; i
++, ptr
++) {
464 pwc
= (WCHAR
*)&two_chars
;
466 *pwc
= toupperW(*pwc
);
468 *pwc
= toupperW(*pwc
);
475 static int font_cache_cmp( const struct cached_font
*p1
, const struct cached_font
*p2
)
477 int ret
= p1
->hash
- p2
->hash
;
478 if (!ret
) ret
= p1
->aa_flags
- p2
->aa_flags
;
479 if (!ret
) ret
= memcmp( &p1
->xform
, &p2
->xform
, sizeof(p1
->xform
) );
480 if (!ret
) ret
= memcmp( &p1
->lf
, &p2
->lf
, FIELD_OFFSET( LOGFONTW
, lfFaceName
));
481 if (!ret
) ret
= strcmpiW( p1
->lf
.lfFaceName
, p2
->lf
.lfFaceName
);
485 static struct cached_font
*add_cached_font( HDC hdc
, HFONT hfont
, UINT aa_flags
)
487 struct cached_font font
, *ptr
, *last_unused
= NULL
;
490 GetObjectW( hfont
, sizeof(font
.lf
), &font
.lf
);
491 GetTransform( hdc
, 0x204, &font
.xform
);
492 font
.xform
.eDx
= font
.xform
.eDy
= 0; /* unused, would break hashing */
493 if (GetGraphicsMode( hdc
) == GM_COMPATIBLE
)
495 font
.lf
.lfOrientation
= font
.lf
.lfEscapement
;
496 if (font
.xform
.eM11
* font
.xform
.eM22
< 0)
497 font
.lf
.lfOrientation
= -font
.lf
.lfOrientation
;
499 font
.lf
.lfWidth
= abs( font
.lf
.lfWidth
);
500 font
.aa_flags
= aa_flags
;
501 font
.hash
= font_cache_hash( &font
);
503 EnterCriticalSection( &font_cache_cs
);
504 LIST_FOR_EACH_ENTRY( ptr
, &font_cache
, struct cached_font
, entry
)
506 if (!font_cache_cmp( &font
, ptr
))
508 InterlockedIncrement( &ptr
->ref
);
509 list_remove( &ptr
->entry
);
519 if (i
> 5) /* keep at least 5 of the most-recently used fonts around */
522 for (i
= 0; i
< GLYPH_NBTYPES
; i
++)
524 for (j
= 0; j
< GLYPH_CACHE_PAGES
; j
++)
526 if (!ptr
->glyphs
[i
][j
]) continue;
527 for (k
= 0; k
< GLYPH_CACHE_PAGE_SIZE
; k
++)
528 HeapFree( GetProcessHeap(), 0, ptr
->glyphs
[i
][j
][k
] );
529 HeapFree( GetProcessHeap(), 0, ptr
->glyphs
[i
][j
] );
532 list_remove( &ptr
->entry
);
534 else if (!(ptr
= HeapAlloc( GetProcessHeap(), 0, sizeof(*ptr
) )))
536 LeaveCriticalSection( &font_cache_cs
);
542 memset( ptr
->glyphs
, 0, sizeof(ptr
->glyphs
) );
544 list_add_head( &font_cache
, &ptr
->entry
);
545 LeaveCriticalSection( &font_cache_cs
);
546 TRACE( "%d %s -> %p\n", ptr
->lf
.lfHeight
, debugstr_w(ptr
->lf
.lfFaceName
), ptr
);
550 void release_cached_font( struct cached_font
*font
)
552 if (font
) InterlockedDecrement( &font
->ref
);
555 static struct cached_glyph
*add_cached_glyph( struct cached_font
*font
, UINT index
, UINT flags
,
556 struct cached_glyph
*glyph
)
558 struct cached_glyph
*ret
;
559 enum glyph_type type
= (flags
& ETO_GLYPH_INDEX
) ? GLYPH_INDEX
: GLYPH_WCHAR
;
560 UINT page
= index
/ GLYPH_CACHE_PAGE_SIZE
;
561 UINT entry
= index
% GLYPH_CACHE_PAGE_SIZE
;
563 if (!font
->glyphs
[type
][page
])
565 struct cached_glyph
**ptr
;
567 ptr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, GLYPH_CACHE_PAGE_SIZE
* sizeof(*ptr
) );
570 HeapFree( GetProcessHeap(), 0, glyph
);
573 if (InterlockedCompareExchangePointer( (void **)&font
->glyphs
[type
][page
], ptr
, NULL
))
574 HeapFree( GetProcessHeap(), 0, ptr
);
576 ret
= InterlockedCompareExchangePointer( (void **)&font
->glyphs
[type
][page
][entry
], glyph
, NULL
);
577 if (!ret
) ret
= glyph
;
578 else HeapFree( GetProcessHeap(), 0, glyph
);
582 static struct cached_glyph
*get_cached_glyph( struct cached_font
*font
, UINT index
, UINT flags
)
584 enum glyph_type type
= (flags
& ETO_GLYPH_INDEX
) ? GLYPH_INDEX
: GLYPH_WCHAR
;
585 UINT page
= index
/ GLYPH_CACHE_PAGE_SIZE
;
587 if (!font
->glyphs
[type
][page
]) return NULL
;
588 return font
->glyphs
[type
][page
][index
% GLYPH_CACHE_PAGE_SIZE
];
591 /**********************************************************************
592 * get_text_bkgnd_masks
594 * See the comment above get_pen_bkgnd_masks
596 static inline void get_text_bkgnd_masks( HDC hdc
, const dib_info
*dib
, rop_mask
*mask
)
598 COLORREF bg
= GetBkColor( hdc
);
602 if (dib
->bit_count
!= 1)
603 mask
->xor = get_pixel_color( hdc
, dib
, bg
, FALSE
);
606 COLORREF fg
= GetTextColor( hdc
);
607 mask
->xor = get_pixel_color( hdc
, dib
, fg
, TRUE
);
608 if (fg
!= bg
) mask
->xor = ~mask
->xor;
612 static void draw_glyph( dib_info
*dib
, int x
, int y
, const GLYPHMETRICS
*metrics
,
613 const dib_info
*glyph_dib
, DWORD text_color
,
614 const struct intensity_range
*ranges
, const struct clipped_rects
*clipped_rects
,
618 RECT rect
, clipped_rect
;
621 rect
.left
= x
+ metrics
->gmptGlyphOrigin
.x
;
622 rect
.top
= y
- metrics
->gmptGlyphOrigin
.y
;
623 rect
.right
= rect
.left
+ metrics
->gmBlackBoxX
;
624 rect
.bottom
= rect
.top
+ metrics
->gmBlackBoxY
;
625 if (bounds
) add_bounds_rect( bounds
, &rect
);
627 for (i
= 0; i
< clipped_rects
->count
; i
++)
629 if (intersect_rect( &clipped_rect
, &rect
, clipped_rects
->rects
+ i
))
631 src_origin
.x
= clipped_rect
.left
- rect
.left
;
632 src_origin
.y
= clipped_rect
.top
- rect
.top
;
634 if (glyph_dib
->bit_count
== 32)
635 dib
->funcs
->draw_subpixel_glyph( dib
, &clipped_rect
, glyph_dib
, &src_origin
,
638 dib
->funcs
->draw_glyph( dib
, &clipped_rect
, glyph_dib
, &src_origin
,
639 text_color
, ranges
);
644 static int get_glyph_depth( UINT aa_flags
)
648 case GGO_BITMAP
: /* we'll convert non-antialiased 1-bpp bitmaps to 8-bpp */
649 case GGO_GRAY2_BITMAP
:
650 case GGO_GRAY4_BITMAP
:
651 case GGO_GRAY8_BITMAP
:
652 case WINE_GGO_GRAY16_BITMAP
: return 8;
654 case WINE_GGO_HRGB_BITMAP
:
655 case WINE_GGO_HBGR_BITMAP
:
656 case WINE_GGO_VRGB_BITMAP
:
657 case WINE_GGO_VBGR_BITMAP
: return 32;
660 ERR("Unexpected flags %08x\n", aa_flags
);
665 static const BYTE masks
[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
666 static const int padding
[4] = {0, 3, 2, 1};
668 /***********************************************************************
671 * Retrieve a 17-level bitmap for the appropriate glyph.
673 * For non-antialiased bitmaps convert them to the 17-level format
674 * using only values 0 or 16.
676 static struct cached_glyph
*cache_glyph_bitmap( HDC hdc
, struct cached_font
*font
, UINT index
, UINT flags
)
678 UINT ggo_flags
= font
->aa_flags
;
679 static const MAT2 identity
= { {0,1}, {0,0}, {0,0}, {0,1} };
680 UINT indices
[3] = {0, 0, 0x20};
684 int pad
= 0, stride
, bit_count
;
685 GLYPHMETRICS metrics
;
686 struct cached_glyph
*glyph
;
688 if (flags
& ETO_GLYPH_INDEX
) ggo_flags
|= GGO_GLYPH_INDEX
;
690 for (i
= 0; i
< sizeof(indices
) / sizeof(indices
[0]); i
++)
693 ret
= GetGlyphOutlineW( hdc
, index
, ggo_flags
, &metrics
, 0, NULL
, &identity
);
694 if (ret
!= GDI_ERROR
) break;
696 if (ret
== GDI_ERROR
) return NULL
;
697 if (!ret
) metrics
.gmBlackBoxX
= metrics
.gmBlackBoxY
= 0; /* empty glyph */
699 bit_count
= get_glyph_depth( font
->aa_flags
);
700 stride
= get_dib_stride( metrics
.gmBlackBoxX
, bit_count
);
701 size
= metrics
.gmBlackBoxY
* stride
;
702 glyph
= HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( struct cached_glyph
, bits
[size
] ));
703 if (!glyph
) return NULL
;
704 if (!size
) goto done
; /* empty glyph */
706 if (bit_count
== 8) pad
= padding
[ metrics
.gmBlackBoxX
% 4 ];
708 ret
= GetGlyphOutlineW( hdc
, index
, ggo_flags
, &metrics
, size
, glyph
->bits
, &identity
);
709 if (ret
== GDI_ERROR
)
711 HeapFree( GetProcessHeap(), 0, glyph
);
714 assert( ret
<= size
);
715 if (font
->aa_flags
== GGO_BITMAP
)
717 for (y
= metrics
.gmBlackBoxY
- 1; y
>= 0; y
--)
719 src
= glyph
->bits
+ y
* get_dib_stride( metrics
.gmBlackBoxX
, 1 );
720 dst
= glyph
->bits
+ y
* stride
;
722 if (pad
) memset( dst
+ metrics
.gmBlackBoxX
, 0, pad
);
724 for (x
= metrics
.gmBlackBoxX
- 1; x
>= 0; x
--)
725 dst
[x
] = (src
[x
/ 8] & masks
[x
% 8]) ? 0x10 : 0;
730 for (y
= 0, dst
= glyph
->bits
; y
< metrics
.gmBlackBoxY
; y
++, dst
+= stride
)
731 memset( dst
+ metrics
.gmBlackBoxX
, 0, pad
);
735 glyph
->metrics
= metrics
;
736 return add_cached_glyph( font
, index
, flags
, glyph
);
739 static void render_string( HDC hdc
, dib_info
*dib
, struct cached_font
*font
, INT x
, INT y
,
740 UINT flags
, const WCHAR
*str
, UINT count
, const INT
*dx
,
741 const struct clipped_rects
*clipped_rects
, RECT
*bounds
)
744 struct cached_glyph
*glyph
;
747 struct intensity_range ranges
[17];
749 glyph_dib
.bit_count
= get_glyph_depth( font
->aa_flags
);
750 glyph_dib
.rect
.left
= 0;
751 glyph_dib
.rect
.top
= 0;
752 glyph_dib
.bits
.is_copy
= FALSE
;
753 glyph_dib
.bits
.free
= NULL
;
755 text_color
= get_pixel_color( hdc
, dib
, GetTextColor( hdc
), TRUE
);
757 if (glyph_dib
.bit_count
== 8)
758 get_aa_ranges( dib
->funcs
->pixel_to_colorref( dib
, text_color
), ranges
);
760 for (i
= 0; i
< count
; i
++)
762 if (!(glyph
= get_cached_glyph( font
, str
[i
], flags
)) &&
763 !(glyph
= cache_glyph_bitmap( hdc
, font
, str
[i
], flags
))) continue;
765 glyph_dib
.width
= glyph
->metrics
.gmBlackBoxX
;
766 glyph_dib
.height
= glyph
->metrics
.gmBlackBoxY
;
767 glyph_dib
.rect
.right
= glyph
->metrics
.gmBlackBoxX
;
768 glyph_dib
.rect
.bottom
= glyph
->metrics
.gmBlackBoxY
;
769 glyph_dib
.stride
= get_dib_stride( glyph
->metrics
.gmBlackBoxX
, glyph_dib
.bit_count
);
770 glyph_dib
.bits
.ptr
= glyph
->bits
;
772 draw_glyph( dib
, x
, y
, &glyph
->metrics
, &glyph_dib
, text_color
, ranges
, clipped_rects
, bounds
);
786 x
+= glyph
->metrics
.gmCellIncX
;
787 y
+= glyph
->metrics
.gmCellIncY
;
792 BOOL
render_aa_text_bitmapinfo( HDC hdc
, BITMAPINFO
*info
, struct gdi_image_bits
*bits
,
793 struct bitblt_coords
*src
, INT x
, INT y
, UINT flags
,
794 UINT aa_flags
, LPCWSTR str
, UINT count
, const INT
*dx
)
797 struct clipped_rects visrect
;
798 struct cached_font
*font
;
800 assert( info
->bmiHeader
.biBitCount
> 8 ); /* mono and indexed formats don't support anti-aliasing */
802 init_dib_info_from_bitmapinfo( &dib
, info
, bits
->ptr
);
805 visrect
.rects
= &src
->visrect
;
807 if (flags
& ETO_OPAQUE
)
809 rop_mask bkgnd_color
;
810 get_text_bkgnd_masks( hdc
, &dib
, &bkgnd_color
);
811 dib
.funcs
->solid_rects( &dib
, 1, &src
->visrect
, bkgnd_color
.and, bkgnd_color
.xor );
814 if (!(font
= add_cached_font( hdc
, GetCurrentObject( hdc
, OBJ_FONT
), aa_flags
))) return FALSE
;
816 render_string( hdc
, &dib
, font
, x
, y
, flags
, str
, count
, dx
, &visrect
, NULL
);
817 release_cached_font( font
);
821 /***********************************************************************
824 BOOL
dibdrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
,
825 const RECT
*rect
, LPCWSTR str
, UINT count
, const INT
*dx
)
827 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
828 struct clipped_rects clipped_rects
;
831 if (!pdev
->font
) return FALSE
;
833 init_clipped_rects( &clipped_rects
);
834 reset_bounds( &bounds
);
836 if (flags
& ETO_OPAQUE
)
838 rop_mask bkgnd_color
;
839 get_text_bkgnd_masks( dev
->hdc
, &pdev
->dib
, &bkgnd_color
);
840 add_bounds_rect( &bounds
, rect
);
841 get_clipped_rects( &pdev
->dib
, rect
, pdev
->clip
, &clipped_rects
);
842 pdev
->dib
.funcs
->solid_rects( &pdev
->dib
, clipped_rects
.count
, clipped_rects
.rects
,
843 bkgnd_color
.and, bkgnd_color
.xor );
846 if (count
== 0) goto done
;
848 if (flags
& ETO_CLIPPED
)
850 if (!(flags
& ETO_OPAQUE
)) /* otherwise we have done it already */
851 get_clipped_rects( &pdev
->dib
, rect
, pdev
->clip
, &clipped_rects
);
855 free_clipped_rects( &clipped_rects
);
856 get_clipped_rects( &pdev
->dib
, NULL
, pdev
->clip
, &clipped_rects
);
858 if (!clipped_rects
.count
) goto done
;
860 render_string( dev
->hdc
, &pdev
->dib
, pdev
->font
, x
, y
, flags
, str
, count
, dx
,
861 &clipped_rects
, &bounds
);
864 add_clipped_bounds( pdev
, &bounds
, pdev
->clip
);
865 free_clipped_rects( &clipped_rects
);
869 /***********************************************************************
872 HFONT
dibdrv_SelectFont( PHYSDEV dev
, HFONT font
, UINT
*aa_flags
)
874 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
877 if (pdev
->dib
.bit_count
<= 8) *aa_flags
= GGO_BITMAP
; /* no anti-aliasing on <= 8bpp */
879 dev
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
880 ret
= dev
->funcs
->pSelectFont( dev
, font
, aa_flags
);
883 struct cached_font
*prev
= pdev
->font
;
884 pdev
->font
= add_cached_font( dev
->hdc
, font
, *aa_flags
? *aa_flags
: GGO_BITMAP
);
885 release_cached_font( prev
);
890 /***********************************************************************
893 BOOL
dibdrv_Arc( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
894 INT start_x
, INT start_y
, INT end_x
, INT end_y
)
896 return draw_arc( dev
, left
, top
, right
, bottom
, start_x
, start_y
, end_x
, end_y
, 0 );
899 /***********************************************************************
902 BOOL
dibdrv_ArcTo( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
903 INT start_x
, INT start_y
, INT end_x
, INT end_y
)
905 return draw_arc( dev
, left
, top
, right
, bottom
, start_x
, start_y
, end_x
, end_y
, -1 );
908 /***********************************************************************
911 BOOL
dibdrv_Chord( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
912 INT start_x
, INT start_y
, INT end_x
, INT end_y
)
914 return draw_arc( dev
, left
, top
, right
, bottom
, start_x
, start_y
, end_x
, end_y
, 1 );
917 /***********************************************************************
920 BOOL
dibdrv_Ellipse( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
)
922 return dibdrv_RoundRect( dev
, left
, top
, right
, bottom
, right
- left
, bottom
- top
);
925 static inline BOOL
is_interior( dib_info
*dib
, HRGN clip
, int x
, int y
, DWORD pixel
, UINT type
)
927 /* the clip rgn stops the flooding */
928 if (clip
&& !PtInRegion( clip
, x
, y
)) return FALSE
;
930 if (type
== FLOODFILLBORDER
)
931 return dib
->funcs
->get_pixel( dib
, x
, y
) != pixel
;
933 return dib
->funcs
->get_pixel( dib
, x
, y
) == pixel
;
936 static void fill_row( dib_info
*dib
, HRGN clip
, RECT
*row
, DWORD pixel
, UINT type
, HRGN rgn
);
938 static inline void do_next_row( dib_info
*dib
, HRGN clip
, const RECT
*row
, int offset
, DWORD pixel
, UINT type
, HRGN rgn
)
942 next
.top
= row
->top
+ offset
;
943 next
.bottom
= next
.top
+ 1;
944 next
.left
= next
.right
= row
->left
;
945 while (next
.right
< row
->right
)
947 if (is_interior( dib
, clip
, next
.right
, next
.top
, pixel
, type
)) next
.right
++;
950 if (next
.left
!= next
.right
&& !PtInRegion( rgn
, next
.left
, next
.top
))
951 fill_row( dib
, clip
, &next
, pixel
, type
, rgn
);
952 next
.left
= ++next
.right
;
955 if (next
.left
!= next
.right
&& !PtInRegion( rgn
, next
.left
, next
.top
))
956 fill_row( dib
, clip
, &next
, pixel
, type
, rgn
);
959 static void fill_row( dib_info
*dib
, HRGN clip
, RECT
*row
, DWORD pixel
, UINT type
, HRGN rgn
)
961 while (row
->left
> 0 && is_interior( dib
, clip
, row
->left
- 1, row
->top
, pixel
, type
)) row
->left
--;
962 while (row
->right
< dib
->rect
.right
- dib
->rect
.left
&&
963 is_interior( dib
, clip
, row
->right
, row
->top
, pixel
, type
))
966 add_rect_to_region( rgn
, row
);
968 if (row
->top
> 0) do_next_row( dib
, clip
, row
, -1, pixel
, type
, rgn
);
969 if (row
->top
< dib
->rect
.bottom
- dib
->rect
.top
- 1)
970 do_next_row( dib
, clip
, row
, 1, pixel
, type
, rgn
);
973 /***********************************************************************
974 * dibdrv_ExtFloodFill
976 BOOL
dibdrv_ExtFloodFill( PHYSDEV dev
, INT x
, INT y
, COLORREF color
, UINT type
)
978 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
979 DWORD pixel
= get_pixel_color( dev
->hdc
, &pdev
->dib
, color
, FALSE
);
983 TRACE( "(%p, %d, %d, %08x, %d)\n", pdev
, x
, y
, color
, type
);
985 if (!is_interior( &pdev
->dib
, pdev
->clip
, x
, y
, pixel
, type
)) return FALSE
;
987 if (!(rgn
= CreateRectRgn( 0, 0, 0, 0 ))) return FALSE
;
993 fill_row( &pdev
->dib
, pdev
->clip
, &row
, pixel
, type
, rgn
);
995 add_clipped_bounds( pdev
, NULL
, rgn
);
996 brush_region( pdev
, rgn
);
1002 /***********************************************************************
1003 * dibdrv_GetNearestColor
1005 COLORREF
dibdrv_GetNearestColor( PHYSDEV dev
, COLORREF color
)
1007 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
1010 TRACE( "(%p, %08x)\n", dev
, color
);
1012 pixel
= get_pixel_color( dev
->hdc
, &pdev
->dib
, color
, FALSE
);
1013 return pdev
->dib
.funcs
->pixel_to_colorref( &pdev
->dib
, pixel
);
1016 /***********************************************************************
1019 COLORREF
dibdrv_GetPixel( PHYSDEV dev
, INT x
, INT y
)
1021 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
1025 TRACE( "(%p, %d, %d)\n", dev
, x
, y
);
1029 LPtoDP( dev
->hdc
, &pt
, 1 );
1031 if (pt
.x
< 0 || pt
.x
>= pdev
->dib
.rect
.right
- pdev
->dib
.rect
.left
||
1032 pt
.y
< 0 || pt
.y
>= pdev
->dib
.rect
.bottom
- pdev
->dib
.rect
.top
)
1035 pixel
= pdev
->dib
.funcs
->get_pixel( &pdev
->dib
, pt
.x
, pt
.y
);
1036 return pdev
->dib
.funcs
->pixel_to_colorref( &pdev
->dib
, pixel
);
1039 /***********************************************************************
1042 BOOL
dibdrv_LineTo( PHYSDEV dev
, INT x
, INT y
)
1044 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
1049 GetCurrentPositionEx(dev
->hdc
, pts
);
1053 LPtoDP(dev
->hdc
, pts
, 2);
1055 if (pdev
->pen_uses_region
&& !(region
= CreateRectRgn( 0, 0, 0, 0 ))) return FALSE
;
1057 reset_dash_origin(pdev
);
1059 ret
= pdev
->pen_lines(pdev
, 2, pts
, FALSE
, region
);
1060 add_pen_lines_bounds( pdev
, 2, pts
, region
);
1064 ret
= pen_region( pdev
, region
);
1065 DeleteObject( region
);
1070 /***********************************************************************
1073 * Returns the binary rop that is equivalent to the provided ternary rop
1074 * if the src bits are ignored.
1076 static inline INT
get_rop2_from_rop(INT rop
)
1078 return (((rop
>> 18) & 0x0c) | ((rop
>> 16) & 0x03)) + 1;
1081 /***********************************************************************
1084 BOOL
dibdrv_PatBlt( PHYSDEV dev
, struct bitblt_coords
*dst
, DWORD rop
)
1086 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
1087 dib_brush
*brush
= &pdev
->brush
;
1088 int rop2
= get_rop2_from_rop( rop
);
1089 struct clipped_rects clipped_rects
;
1090 DWORD
and = 0, xor = 0;
1093 TRACE("(%p, %d, %d, %d, %d, %06x)\n", dev
, dst
->x
, dst
->y
, dst
->width
, dst
->height
, rop
);
1095 add_clipped_bounds( pdev
, &dst
->visrect
, 0 );
1096 if (!get_clipped_rects( &pdev
->dib
, &dst
->visrect
, pdev
->clip
, &clipped_rects
)) return TRUE
;
1098 switch (rop2
) /* shortcuts for rops that don't involve the brush */
1100 case R2_NOT
: and = ~0u;
1102 case R2_WHITE
: xor = ~0u;
1105 pdev
->dib
.funcs
->solid_rects( &pdev
->dib
, clipped_rects
.count
, clipped_rects
.rects
, and, xor );
1110 ret
= brush
->rects( pdev
, brush
, &pdev
->dib
, clipped_rects
.count
, clipped_rects
.rects
, rop2
);
1113 free_clipped_rects( &clipped_rects
);
1117 /***********************************************************************
1120 BOOL
dibdrv_PaintRgn( PHYSDEV dev
, HRGN rgn
)
1122 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
1123 const WINEREGION
*region
;
1127 TRACE("%p, %p\n", dev
, rgn
);
1129 reset_bounds( &bounds
);
1131 region
= get_wine_region( rgn
);
1132 if(!region
) return FALSE
;
1134 for(i
= 0; i
< region
->numRects
; i
++)
1136 rect
= get_device_rect( dev
->hdc
, region
->rects
[i
].left
, region
->rects
[i
].top
,
1137 region
->rects
[i
].right
, region
->rects
[i
].bottom
, FALSE
);
1138 add_bounds_rect( &bounds
, &rect
);
1139 brush_rect( pdev
, &pdev
->brush
, &rect
, pdev
->clip
);
1142 release_wine_region( rgn
);
1143 add_clipped_bounds( pdev
, &bounds
, pdev
->clip
);
1147 /***********************************************************************
1148 * dibdrv_PolyPolygon
1150 BOOL
dibdrv_PolyPolygon( PHYSDEV dev
, const POINT
*pt
, const INT
*counts
, DWORD polygons
)
1152 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
1153 DWORD total
, i
, pos
;
1156 HRGN outline
= 0, interior
= 0;
1158 for (i
= total
= 0; i
< polygons
; i
++)
1160 if (counts
[i
] < 2) return FALSE
;
1164 points
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(*pt
) );
1165 if (!points
) return FALSE
;
1166 memcpy( points
, pt
, total
* sizeof(*pt
) );
1167 LPtoDP( dev
->hdc
, points
, total
);
1169 if (pdev
->brush
.style
!= BS_NULL
&&
1170 !(interior
= CreatePolyPolygonRgn( points
, counts
, polygons
, GetPolyFillMode( dev
->hdc
))))
1172 HeapFree( GetProcessHeap(), 0, points
);
1176 if (pdev
->pen_uses_region
) outline
= CreateRectRgn( 0, 0, 0, 0 );
1178 /* if not using a region, paint the interior first so the outline can overlap it */
1179 if (interior
&& !outline
)
1181 ret
= brush_region( pdev
, interior
);
1182 DeleteObject( interior
);
1186 for (i
= pos
= 0; i
< polygons
; i
++)
1188 reset_dash_origin( pdev
);
1189 pdev
->pen_lines( pdev
, counts
[i
], points
+ pos
, TRUE
, outline
);
1192 add_pen_lines_bounds( pdev
, total
, points
, outline
);
1196 CombineRgn( interior
, interior
, outline
, RGN_DIFF
);
1197 ret
= brush_region( pdev
, interior
);
1198 DeleteObject( interior
);
1202 if (ret
) ret
= pen_region( pdev
, outline
);
1203 DeleteObject( outline
);
1205 HeapFree( GetProcessHeap(), 0, points
);
1209 /***********************************************************************
1210 * dibdrv_PolyPolyline
1212 BOOL
dibdrv_PolyPolyline( PHYSDEV dev
, const POINT
* pt
, const DWORD
* counts
, DWORD polylines
)
1214 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
1215 DWORD total
, pos
, i
;
1220 for (i
= total
= 0; i
< polylines
; i
++)
1222 if (counts
[i
] < 2) return FALSE
;
1226 points
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(*pt
) );
1227 if (!points
) return FALSE
;
1228 memcpy( points
, pt
, total
* sizeof(*pt
) );
1229 LPtoDP( dev
->hdc
, points
, total
);
1231 if (pdev
->pen_uses_region
&& !(outline
= CreateRectRgn( 0, 0, 0, 0 )))
1233 HeapFree( GetProcessHeap(), 0, points
);
1237 for (i
= pos
= 0; i
< polylines
; i
++)
1239 reset_dash_origin( pdev
);
1240 pdev
->pen_lines( pdev
, counts
[i
], points
+ pos
, FALSE
, outline
);
1243 add_pen_lines_bounds( pdev
, total
, points
, outline
);
1247 ret
= pen_region( pdev
, outline
);
1248 DeleteObject( outline
);
1251 HeapFree( GetProcessHeap(), 0, points
);
1255 /***********************************************************************
1258 BOOL
dibdrv_Polygon( PHYSDEV dev
, const POINT
*pt
, INT count
)
1260 INT counts
[1] = { count
};
1262 return dibdrv_PolyPolygon( dev
, pt
, counts
, 1 );
1265 /***********************************************************************
1268 BOOL
dibdrv_Polyline( PHYSDEV dev
, const POINT
* pt
, INT count
)
1270 DWORD counts
[1] = { count
};
1272 if (count
< 0) return FALSE
;
1273 return dibdrv_PolyPolyline( dev
, pt
, counts
, 1 );
1276 /***********************************************************************
1279 BOOL
dibdrv_Rectangle( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
)
1281 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
1287 TRACE("(%p, %d, %d, %d, %d)\n", dev
, left
, top
, right
, bottom
);
1289 if (GetGraphicsMode( dev
->hdc
) == GM_ADVANCED
)
1291 pts
[0].x
= pts
[3].x
= left
;
1292 pts
[0].y
= pts
[1].y
= top
;
1293 pts
[1].x
= pts
[2].x
= right
;
1294 pts
[2].y
= pts
[3].y
= bottom
;
1295 return dibdrv_Polygon( dev
, pts
, 4 );
1298 if (!get_pen_device_rect( pdev
, &rect
, left
, top
, right
, bottom
)) return TRUE
;
1300 if (pdev
->pen_uses_region
&& !(outline
= CreateRectRgn( 0, 0, 0, 0 ))) return FALSE
;
1304 reset_dash_origin(pdev
);
1306 if (GetArcDirection( dev
->hdc
) == AD_CLOCKWISE
)
1308 /* 4 pts going clockwise starting from bottom-right */
1309 pts
[0].x
= pts
[3].x
= rect
.right
;
1310 pts
[0].y
= pts
[1].y
= rect
.bottom
;
1311 pts
[1].x
= pts
[2].x
= rect
.left
;
1312 pts
[2].y
= pts
[3].y
= rect
.top
;
1316 /* 4 pts going anti-clockwise starting from top-right */
1317 pts
[0].x
= pts
[3].x
= rect
.right
;
1318 pts
[0].y
= pts
[1].y
= rect
.top
;
1319 pts
[1].x
= pts
[2].x
= rect
.left
;
1320 pts
[2].y
= pts
[3].y
= rect
.bottom
;
1323 pdev
->pen_lines(pdev
, 4, pts
, TRUE
, outline
);
1324 add_pen_lines_bounds( pdev
, 4, pts
, outline
);
1328 if (pdev
->brush
.style
!= BS_NULL
)
1330 HRGN interior
= CreateRectRgnIndirect( &rect
);
1332 CombineRgn( interior
, interior
, outline
, RGN_DIFF
);
1333 brush_region( pdev
, interior
);
1334 DeleteObject( interior
);
1336 ret
= pen_region( pdev
, outline
);
1337 DeleteObject( outline
);
1341 rect
.left
+= (pdev
->pen_width
+ 1) / 2;
1342 rect
.top
+= (pdev
->pen_width
+ 1) / 2;
1343 rect
.right
-= pdev
->pen_width
/ 2;
1344 rect
.bottom
-= pdev
->pen_width
/ 2;
1345 ret
= brush_rect( pdev
, &pdev
->brush
, &rect
, pdev
->clip
);
1350 /***********************************************************************
1353 BOOL
dibdrv_RoundRect( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
1354 INT ellipse_width
, INT ellipse_height
)
1356 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
1358 POINT pt
[2], *points
;
1361 HRGN outline
= 0, interior
= 0;
1363 if (!get_pen_device_rect( pdev
, &rect
, left
, top
, right
, bottom
)) return TRUE
;
1365 pt
[0].x
= pt
[0].y
= 0;
1366 pt
[1].x
= ellipse_width
;
1367 pt
[1].y
= ellipse_height
;
1368 LPtoDP( dev
->hdc
, pt
, 2 );
1369 ellipse_width
= min( rect
.right
- rect
.left
, abs( pt
[1].x
- pt
[0].x
));
1370 ellipse_height
= min( rect
.bottom
- rect
.top
, abs( pt
[1].y
- pt
[0].y
));
1371 if (ellipse_width
<= 2|| ellipse_height
<= 2)
1372 return dibdrv_Rectangle( dev
, left
, top
, right
, bottom
);
1374 points
= HeapAlloc( GetProcessHeap(), 0, (ellipse_width
+ ellipse_height
) * 2 * sizeof(*points
) );
1375 if (!points
) return FALSE
;
1377 if (pdev
->pen_uses_region
&& !(outline
= CreateRectRgn( 0, 0, 0, 0 )))
1379 HeapFree( GetProcessHeap(), 0, points
);
1383 if (pdev
->brush
.style
!= BS_NULL
&&
1384 !(interior
= CreateRoundRectRgn( rect
.left
, rect
.top
, rect
.right
+ 1, rect
.bottom
+ 1,
1385 ellipse_width
, ellipse_height
)))
1387 HeapFree( GetProcessHeap(), 0, points
);
1388 if (outline
) DeleteObject( outline
);
1392 /* if not using a region, paint the interior first so the outline can overlap it */
1393 if (interior
&& !outline
)
1395 ret
= brush_region( pdev
, interior
);
1396 DeleteObject( interior
);
1400 count
= ellipse_first_quadrant( ellipse_width
, ellipse_height
, points
);
1402 if (GetArcDirection( dev
->hdc
) == AD_CLOCKWISE
)
1404 for (i
= 0; i
< count
; i
++)
1406 points
[i
].x
= rect
.right
- ellipse_width
+ points
[i
].x
;
1407 points
[i
].y
= rect
.bottom
- ellipse_height
+ points
[i
].y
;
1412 for (i
= 0; i
< count
; i
++)
1414 points
[i
].x
= rect
.right
- ellipse_width
+ points
[i
].x
;
1415 points
[i
].y
= rect
.top
+ ellipse_height
- 1 - points
[i
].y
;
1419 /* horizontal symmetry */
1421 end
= 2 * count
- 1;
1422 /* avoid duplicating the midpoint */
1423 if (ellipse_width
% 2 && ellipse_width
== rect
.right
- rect
.left
) end
--;
1424 for (i
= 0; i
< count
; i
++)
1426 points
[end
- i
].x
= rect
.left
+ rect
.right
- 1 - points
[i
].x
;
1427 points
[end
- i
].y
= points
[i
].y
;
1431 /* vertical symmetry */
1433 end
= 2 * count
- 1;
1434 /* avoid duplicating the midpoint */
1435 if (ellipse_height
% 2 && ellipse_height
== rect
.bottom
- rect
.top
) end
--;
1436 for (i
= 0; i
< count
; i
++)
1438 points
[end
- i
].x
= points
[i
].x
;
1439 points
[end
- i
].y
= rect
.top
+ rect
.bottom
- 1 - points
[i
].y
;
1443 reset_dash_origin( pdev
);
1444 pdev
->pen_lines( pdev
, count
, points
, TRUE
, outline
);
1445 add_pen_lines_bounds( pdev
, count
, points
, outline
);
1449 CombineRgn( interior
, interior
, outline
, RGN_DIFF
);
1450 ret
= brush_region( pdev
, interior
);
1451 DeleteObject( interior
);
1455 if (ret
) ret
= pen_region( pdev
, outline
);
1456 DeleteObject( outline
);
1458 HeapFree( GetProcessHeap(), 0, points
);
1462 /***********************************************************************
1465 BOOL
dibdrv_Pie( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
1466 INT start_x
, INT start_y
, INT end_x
, INT end_y
)
1468 return draw_arc( dev
, left
, top
, right
, bottom
, start_x
, start_y
, end_x
, end_y
, 2 );
1471 /***********************************************************************
1474 COLORREF
dibdrv_SetPixel( PHYSDEV dev
, INT x
, INT y
, COLORREF color
)
1476 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
1477 struct clipped_rects clipped_rects
;
1482 TRACE( "(%p, %d, %d, %08x)\n", dev
, x
, y
, color
);
1486 LPtoDP( dev
->hdc
, &pt
, 1 );
1489 rect
.right
= rect
.left
+ 1;
1490 rect
.bottom
= rect
.top
+ 1;
1491 add_clipped_bounds( pdev
, &rect
, pdev
->clip
);
1493 /* SetPixel doesn't do the 1bpp massaging like other fg colors */
1494 pixel
= get_pixel_color( dev
->hdc
, &pdev
->dib
, color
, FALSE
);
1495 color
= pdev
->dib
.funcs
->pixel_to_colorref( &pdev
->dib
, pixel
);
1497 if (!get_clipped_rects( &pdev
->dib
, &rect
, pdev
->clip
, &clipped_rects
)) return color
;
1498 pdev
->dib
.funcs
->solid_rects( &pdev
->dib
, clipped_rects
.count
, clipped_rects
.rects
, 0, pixel
);
1499 free_clipped_rects( &clipped_rects
);