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
->left
+ 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
->left
+ width
/2 - points
[i
% count
].x
;
275 points
[pos
].y
= rect
->top
+ 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
->top
+ 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
->top
+ height
/2 - points
[i
% count
].y
;
295 points
[pos
].x
= rect
->left
+ width
/2 - points
[count
- 1 - i
% count
].x
;
296 points
[pos
].y
= rect
->top
+ height
/2 - points
[count
- 1 - i
% count
].y
;
299 points
[pos
].x
= rect
->left
+ 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
;
698 bit_count
= get_glyph_depth( font
->aa_flags
);
699 stride
= get_dib_stride( metrics
.gmBlackBoxX
, bit_count
);
700 size
= metrics
.gmBlackBoxY
* stride
;
701 glyph
= HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( struct cached_glyph
, bits
[size
] ));
702 if (!glyph
) return NULL
;
703 if (!ret
) goto done
; /* zero-size glyph */
705 if (bit_count
== 8) pad
= padding
[ metrics
.gmBlackBoxX
% 4 ];
707 ret
= GetGlyphOutlineW( hdc
, index
, ggo_flags
, &metrics
, size
, glyph
->bits
, &identity
);
708 if (ret
== GDI_ERROR
)
710 HeapFree( GetProcessHeap(), 0, glyph
);
713 assert( ret
<= size
);
714 if (font
->aa_flags
== GGO_BITMAP
)
716 for (y
= metrics
.gmBlackBoxY
- 1; y
>= 0; y
--)
718 src
= glyph
->bits
+ y
* get_dib_stride( metrics
.gmBlackBoxX
, 1 );
719 dst
= glyph
->bits
+ y
* stride
;
721 if (pad
) memset( dst
+ metrics
.gmBlackBoxX
, 0, pad
);
723 for (x
= metrics
.gmBlackBoxX
- 1; x
>= 0; x
--)
724 dst
[x
] = (src
[x
/ 8] & masks
[x
% 8]) ? 0x10 : 0;
729 for (y
= 0, dst
= glyph
->bits
; y
< metrics
.gmBlackBoxY
; y
++, dst
+= stride
)
730 memset( dst
+ metrics
.gmBlackBoxX
, 0, pad
);
734 glyph
->metrics
= metrics
;
735 return add_cached_glyph( font
, index
, flags
, glyph
);
738 static void render_string( HDC hdc
, dib_info
*dib
, struct cached_font
*font
, INT x
, INT y
,
739 UINT flags
, const WCHAR
*str
, UINT count
, const INT
*dx
,
740 const struct clipped_rects
*clipped_rects
, RECT
*bounds
)
743 struct cached_glyph
*glyph
;
746 struct intensity_range ranges
[17];
748 glyph_dib
.bit_count
= get_glyph_depth( font
->aa_flags
);
749 glyph_dib
.rect
.left
= 0;
750 glyph_dib
.rect
.top
= 0;
751 glyph_dib
.bits
.is_copy
= FALSE
;
752 glyph_dib
.bits
.free
= NULL
;
754 text_color
= get_pixel_color( hdc
, dib
, GetTextColor( hdc
), TRUE
);
756 if (glyph_dib
.bit_count
== 8)
757 get_aa_ranges( dib
->funcs
->pixel_to_colorref( dib
, text_color
), ranges
);
759 for (i
= 0; i
< count
; i
++)
761 if (!(glyph
= get_cached_glyph( font
, str
[i
], flags
)) &&
762 !(glyph
= cache_glyph_bitmap( hdc
, font
, str
[i
], flags
))) continue;
764 glyph_dib
.width
= glyph
->metrics
.gmBlackBoxX
;
765 glyph_dib
.height
= glyph
->metrics
.gmBlackBoxY
;
766 glyph_dib
.rect
.right
= glyph
->metrics
.gmBlackBoxX
;
767 glyph_dib
.rect
.bottom
= glyph
->metrics
.gmBlackBoxY
;
768 glyph_dib
.stride
= get_dib_stride( glyph
->metrics
.gmBlackBoxX
, glyph_dib
.bit_count
);
769 glyph_dib
.bits
.ptr
= glyph
->bits
;
771 draw_glyph( dib
, x
, y
, &glyph
->metrics
, &glyph_dib
, text_color
, ranges
, clipped_rects
, bounds
);
785 x
+= glyph
->metrics
.gmCellIncX
;
786 y
+= glyph
->metrics
.gmCellIncY
;
791 BOOL
render_aa_text_bitmapinfo( HDC hdc
, BITMAPINFO
*info
, struct gdi_image_bits
*bits
,
792 struct bitblt_coords
*src
, INT x
, INT y
, UINT flags
,
793 UINT aa_flags
, LPCWSTR str
, UINT count
, const INT
*dx
)
796 struct clipped_rects visrect
;
797 struct cached_font
*font
;
799 assert( info
->bmiHeader
.biBitCount
> 8 ); /* mono and indexed formats don't support anti-aliasing */
801 init_dib_info_from_bitmapinfo( &dib
, info
, bits
->ptr
);
804 visrect
.rects
= &src
->visrect
;
806 if (flags
& ETO_OPAQUE
)
808 rop_mask bkgnd_color
;
809 get_text_bkgnd_masks( hdc
, &dib
, &bkgnd_color
);
810 dib
.funcs
->solid_rects( &dib
, 1, &src
->visrect
, bkgnd_color
.and, bkgnd_color
.xor );
813 if (!(font
= add_cached_font( hdc
, GetCurrentObject( hdc
, OBJ_FONT
), aa_flags
))) return FALSE
;
815 render_string( hdc
, &dib
, font
, x
, y
, flags
, str
, count
, dx
, &visrect
, NULL
);
816 release_cached_font( font
);
820 /***********************************************************************
823 BOOL
dibdrv_ExtTextOut( PHYSDEV dev
, INT x
, INT y
, UINT flags
,
824 const RECT
*rect
, LPCWSTR str
, UINT count
, const INT
*dx
)
826 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
827 struct clipped_rects clipped_rects
;
830 if (!pdev
->font
) return FALSE
;
832 init_clipped_rects( &clipped_rects
);
833 reset_bounds( &bounds
);
835 if (flags
& ETO_OPAQUE
)
837 rop_mask bkgnd_color
;
838 get_text_bkgnd_masks( dev
->hdc
, &pdev
->dib
, &bkgnd_color
);
839 add_bounds_rect( &bounds
, rect
);
840 get_clipped_rects( &pdev
->dib
, rect
, pdev
->clip
, &clipped_rects
);
841 pdev
->dib
.funcs
->solid_rects( &pdev
->dib
, clipped_rects
.count
, clipped_rects
.rects
,
842 bkgnd_color
.and, bkgnd_color
.xor );
845 if (count
== 0) goto done
;
847 if (flags
& ETO_CLIPPED
)
849 if (!(flags
& ETO_OPAQUE
)) /* otherwise we have done it already */
850 get_clipped_rects( &pdev
->dib
, rect
, pdev
->clip
, &clipped_rects
);
854 free_clipped_rects( &clipped_rects
);
855 get_clipped_rects( &pdev
->dib
, NULL
, pdev
->clip
, &clipped_rects
);
857 if (!clipped_rects
.count
) goto done
;
859 render_string( dev
->hdc
, &pdev
->dib
, pdev
->font
, x
, y
, flags
, str
, count
, dx
,
860 &clipped_rects
, &bounds
);
863 add_clipped_bounds( pdev
, &bounds
, pdev
->clip
);
864 free_clipped_rects( &clipped_rects
);
868 /***********************************************************************
871 HFONT
dibdrv_SelectFont( PHYSDEV dev
, HFONT font
, UINT
*aa_flags
)
873 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
876 if (pdev
->dib
.bit_count
<= 8) *aa_flags
= GGO_BITMAP
; /* no anti-aliasing on <= 8bpp */
878 dev
= GET_NEXT_PHYSDEV( dev
, pSelectFont
);
879 ret
= dev
->funcs
->pSelectFont( dev
, font
, aa_flags
);
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
);
889 /***********************************************************************
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
)
895 return draw_arc( dev
, left
, top
, right
, bottom
, start_x
, start_y
, end_x
, end_y
, 0 );
898 /***********************************************************************
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
)
904 return draw_arc( dev
, left
, top
, right
, bottom
, start_x
, start_y
, end_x
, end_y
, -1 );
907 /***********************************************************************
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
)
913 return draw_arc( dev
, left
, top
, right
, bottom
, start_x
, start_y
, end_x
, end_y
, 1 );
916 /***********************************************************************
919 BOOL
dibdrv_Ellipse( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
)
921 return dibdrv_RoundRect( dev
, left
, top
, right
, bottom
, right
- left
, bottom
- top
);
924 static inline BOOL
is_interior( dib_info
*dib
, HRGN clip
, int x
, int y
, DWORD pixel
, UINT type
)
926 /* the clip rgn stops the flooding */
927 if (clip
&& !PtInRegion( clip
, x
, y
)) return FALSE
;
929 if (type
== FLOODFILLBORDER
)
930 return dib
->funcs
->get_pixel( dib
, x
, y
) != pixel
;
932 return dib
->funcs
->get_pixel( dib
, x
, y
) == pixel
;
935 static void fill_row( dib_info
*dib
, HRGN clip
, RECT
*row
, DWORD pixel
, UINT type
, HRGN rgn
);
937 static inline void do_next_row( dib_info
*dib
, HRGN clip
, const RECT
*row
, int offset
, DWORD pixel
, UINT type
, HRGN rgn
)
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
)
946 if (is_interior( dib
, clip
, next
.right
, next
.top
, pixel
, type
)) next
.right
++;
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
;
954 if (next
.left
!= next
.right
&& !PtInRegion( rgn
, next
.left
, next
.top
))
955 fill_row( dib
, clip
, &next
, pixel
, type
, rgn
);
958 static void fill_row( dib_info
*dib
, HRGN clip
, RECT
*row
, DWORD pixel
, UINT type
, HRGN rgn
)
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
))
965 add_rect_to_region( rgn
, row
);
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
);
972 /***********************************************************************
973 * dibdrv_ExtFloodFill
975 BOOL
dibdrv_ExtFloodFill( PHYSDEV dev
, INT x
, INT y
, COLORREF color
, UINT type
)
977 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
978 DWORD pixel
= get_pixel_color( dev
->hdc
, &pdev
->dib
, color
, FALSE
);
982 TRACE( "(%p, %d, %d, %08x, %d)\n", pdev
, x
, y
, color
, type
);
984 if (!is_interior( &pdev
->dib
, pdev
->clip
, x
, y
, pixel
, type
)) return FALSE
;
986 if (!(rgn
= CreateRectRgn( 0, 0, 0, 0 ))) return FALSE
;
992 fill_row( &pdev
->dib
, pdev
->clip
, &row
, pixel
, type
, rgn
);
994 add_clipped_bounds( pdev
, NULL
, rgn
);
995 brush_region( pdev
, rgn
);
1001 /***********************************************************************
1002 * dibdrv_GetNearestColor
1004 COLORREF
dibdrv_GetNearestColor( PHYSDEV dev
, COLORREF color
)
1006 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
1009 TRACE( "(%p, %08x)\n", dev
, color
);
1011 pixel
= get_pixel_color( dev
->hdc
, &pdev
->dib
, color
, FALSE
);
1012 return pdev
->dib
.funcs
->pixel_to_colorref( &pdev
->dib
, pixel
);
1015 /***********************************************************************
1018 COLORREF
dibdrv_GetPixel( PHYSDEV dev
, INT x
, INT y
)
1020 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
1024 TRACE( "(%p, %d, %d)\n", dev
, x
, y
);
1028 LPtoDP( dev
->hdc
, &pt
, 1 );
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
)
1034 pixel
= pdev
->dib
.funcs
->get_pixel( &pdev
->dib
, pt
.x
, pt
.y
);
1035 return pdev
->dib
.funcs
->pixel_to_colorref( &pdev
->dib
, pixel
);
1038 /***********************************************************************
1041 BOOL
dibdrv_LineTo( PHYSDEV dev
, INT x
, INT y
)
1043 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
1048 GetCurrentPositionEx(dev
->hdc
, pts
);
1052 LPtoDP(dev
->hdc
, pts
, 2);
1054 if (pdev
->pen_uses_region
&& !(region
= CreateRectRgn( 0, 0, 0, 0 ))) return FALSE
;
1056 reset_dash_origin(pdev
);
1058 ret
= pdev
->pen_lines(pdev
, 2, pts
, FALSE
, region
);
1059 add_pen_lines_bounds( pdev
, 2, pts
, region
);
1063 ret
= pen_region( pdev
, region
);
1064 DeleteObject( region
);
1069 /***********************************************************************
1072 * Returns the binary rop that is equivalent to the provided ternary rop
1073 * if the src bits are ignored.
1075 static inline INT
get_rop2_from_rop(INT rop
)
1077 return (((rop
>> 18) & 0x0c) | ((rop
>> 16) & 0x03)) + 1;
1080 /***********************************************************************
1083 BOOL
dibdrv_PatBlt( PHYSDEV dev
, struct bitblt_coords
*dst
, DWORD rop
)
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;
1092 TRACE("(%p, %d, %d, %d, %d, %06x)\n", dev
, dst
->x
, dst
->y
, dst
->width
, dst
->height
, rop
);
1094 add_clipped_bounds( pdev
, &dst
->visrect
, 0 );
1095 if (!get_clipped_rects( &pdev
->dib
, &dst
->visrect
, pdev
->clip
, &clipped_rects
)) return TRUE
;
1097 switch (rop2
) /* shortcuts for rops that don't involve the brush */
1099 case R2_NOT
: and = ~0u;
1101 case R2_WHITE
: xor = ~0u;
1104 pdev
->dib
.funcs
->solid_rects( &pdev
->dib
, clipped_rects
.count
, clipped_rects
.rects
, and, xor );
1109 ret
= brush
->rects( pdev
, brush
, &pdev
->dib
, clipped_rects
.count
, clipped_rects
.rects
, rop2
);
1112 free_clipped_rects( &clipped_rects
);
1116 /***********************************************************************
1119 BOOL
dibdrv_PaintRgn( PHYSDEV dev
, HRGN rgn
)
1121 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
1122 const WINEREGION
*region
;
1126 TRACE("%p, %p\n", dev
, rgn
);
1128 reset_bounds( &bounds
);
1130 region
= get_wine_region( rgn
);
1131 if(!region
) return FALSE
;
1133 for(i
= 0; i
< region
->numRects
; i
++)
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
);
1141 release_wine_region( rgn
);
1142 add_clipped_bounds( pdev
, &bounds
, pdev
->clip
);
1146 /***********************************************************************
1147 * dibdrv_PolyPolygon
1149 BOOL
dibdrv_PolyPolygon( PHYSDEV dev
, const POINT
*pt
, const INT
*counts
, DWORD polygons
)
1151 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
1152 DWORD total
, i
, pos
;
1155 HRGN outline
= 0, interior
= 0;
1157 for (i
= total
= 0; i
< polygons
; i
++)
1159 if (counts
[i
] < 2) return FALSE
;
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
);
1168 if (pdev
->brush
.style
!= BS_NULL
&&
1169 !(interior
= CreatePolyPolygonRgn( points
, counts
, polygons
, GetPolyFillMode( dev
->hdc
))))
1171 HeapFree( GetProcessHeap(), 0, points
);
1175 if (pdev
->pen_uses_region
) outline
= CreateRectRgn( 0, 0, 0, 0 );
1177 /* if not using a region, paint the interior first so the outline can overlap it */
1178 if (interior
&& !outline
)
1180 ret
= brush_region( pdev
, interior
);
1181 DeleteObject( interior
);
1185 for (i
= pos
= 0; i
< polygons
; i
++)
1187 reset_dash_origin( pdev
);
1188 pdev
->pen_lines( pdev
, counts
[i
], points
+ pos
, TRUE
, outline
);
1191 add_pen_lines_bounds( pdev
, total
, points
, outline
);
1195 CombineRgn( interior
, interior
, outline
, RGN_DIFF
);
1196 ret
= brush_region( pdev
, interior
);
1197 DeleteObject( interior
);
1201 if (ret
) ret
= pen_region( pdev
, outline
);
1202 DeleteObject( outline
);
1204 HeapFree( GetProcessHeap(), 0, points
);
1208 /***********************************************************************
1209 * dibdrv_PolyPolyline
1211 BOOL
dibdrv_PolyPolyline( PHYSDEV dev
, const POINT
* pt
, const DWORD
* counts
, DWORD polylines
)
1213 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
1214 DWORD total
, pos
, i
;
1219 for (i
= total
= 0; i
< polylines
; i
++)
1221 if (counts
[i
] < 2) return FALSE
;
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
);
1230 if (pdev
->pen_uses_region
&& !(outline
= CreateRectRgn( 0, 0, 0, 0 )))
1232 HeapFree( GetProcessHeap(), 0, points
);
1236 for (i
= pos
= 0; i
< polylines
; i
++)
1238 reset_dash_origin( pdev
);
1239 pdev
->pen_lines( pdev
, counts
[i
], points
+ pos
, FALSE
, outline
);
1242 add_pen_lines_bounds( pdev
, total
, points
, outline
);
1246 ret
= pen_region( pdev
, outline
);
1247 DeleteObject( outline
);
1250 HeapFree( GetProcessHeap(), 0, points
);
1254 /***********************************************************************
1257 BOOL
dibdrv_Polygon( PHYSDEV dev
, const POINT
*pt
, INT count
)
1259 INT counts
[1] = { count
};
1261 return dibdrv_PolyPolygon( dev
, pt
, counts
, 1 );
1264 /***********************************************************************
1267 BOOL
dibdrv_Polyline( PHYSDEV dev
, const POINT
* pt
, INT count
)
1269 DWORD counts
[1] = { count
};
1271 if (count
< 0) return FALSE
;
1272 return dibdrv_PolyPolyline( dev
, pt
, counts
, 1 );
1275 /***********************************************************************
1278 BOOL
dibdrv_Rectangle( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
)
1280 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
1286 TRACE("(%p, %d, %d, %d, %d)\n", dev
, left
, top
, right
, bottom
);
1288 if (!get_pen_device_rect( pdev
, &rect
, left
, top
, right
, bottom
)) return TRUE
;
1290 if (pdev
->pen_uses_region
&& !(outline
= CreateRectRgn( 0, 0, 0, 0 ))) return FALSE
;
1294 reset_dash_origin(pdev
);
1296 if (GetArcDirection( dev
->hdc
) == AD_CLOCKWISE
)
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
;
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
;
1313 pdev
->pen_lines(pdev
, 4, pts
, TRUE
, outline
);
1314 add_pen_lines_bounds( pdev
, 4, pts
, outline
);
1318 if (pdev
->brush
.style
!= BS_NULL
)
1320 HRGN interior
= CreateRectRgnIndirect( &rect
);
1322 CombineRgn( interior
, interior
, outline
, RGN_DIFF
);
1323 brush_region( pdev
, interior
);
1324 DeleteObject( interior
);
1326 ret
= pen_region( pdev
, outline
);
1327 DeleteObject( outline
);
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
);
1340 /***********************************************************************
1343 BOOL
dibdrv_RoundRect( PHYSDEV dev
, INT left
, INT top
, INT right
, INT bottom
,
1344 INT ellipse_width
, INT ellipse_height
)
1346 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
1348 POINT pt
[2], *points
;
1351 HRGN outline
= 0, interior
= 0;
1353 if (!get_pen_device_rect( pdev
, &rect
, left
, top
, right
, bottom
)) return TRUE
;
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
);
1364 points
= HeapAlloc( GetProcessHeap(), 0, (ellipse_width
+ ellipse_height
) * 2 * sizeof(*points
) );
1365 if (!points
) return FALSE
;
1367 if (pdev
->pen_uses_region
&& !(outline
= CreateRectRgn( 0, 0, 0, 0 )))
1369 HeapFree( GetProcessHeap(), 0, points
);
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
)))
1377 HeapFree( GetProcessHeap(), 0, points
);
1378 if (outline
) DeleteObject( outline
);
1382 /* if not using a region, paint the interior first so the outline can overlap it */
1383 if (interior
&& !outline
)
1385 ret
= brush_region( pdev
, interior
);
1386 DeleteObject( interior
);
1390 count
= ellipse_first_quadrant( ellipse_width
, ellipse_height
, points
);
1392 if (GetArcDirection( dev
->hdc
) == AD_CLOCKWISE
)
1394 for (i
= 0; i
< count
; i
++)
1396 points
[i
].x
= rect
.right
- ellipse_width
+ points
[i
].x
;
1397 points
[i
].y
= rect
.bottom
- ellipse_height
+ points
[i
].y
;
1402 for (i
= 0; i
< count
; i
++)
1404 points
[i
].x
= rect
.right
- ellipse_width
+ points
[i
].x
;
1405 points
[i
].y
= rect
.top
+ ellipse_height
- 1 - points
[i
].y
;
1409 /* horizontal symmetry */
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
++)
1416 points
[end
- i
].x
= rect
.left
+ rect
.right
- 1 - points
[i
].x
;
1417 points
[end
- i
].y
= points
[i
].y
;
1421 /* vertical symmetry */
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
++)
1428 points
[end
- i
].x
= points
[i
].x
;
1429 points
[end
- i
].y
= rect
.top
+ rect
.bottom
- 1 - points
[i
].y
;
1433 reset_dash_origin( pdev
);
1434 pdev
->pen_lines( pdev
, count
, points
, TRUE
, outline
);
1435 add_pen_lines_bounds( pdev
, count
, points
, outline
);
1439 CombineRgn( interior
, interior
, outline
, RGN_DIFF
);
1440 ret
= brush_region( pdev
, interior
);
1441 DeleteObject( interior
);
1445 if (ret
) ret
= pen_region( pdev
, outline
);
1446 DeleteObject( outline
);
1448 HeapFree( GetProcessHeap(), 0, points
);
1452 /***********************************************************************
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
)
1458 return draw_arc( dev
, left
, top
, right
, bottom
, start_x
, start_y
, end_x
, end_y
, 2 );
1461 /***********************************************************************
1464 COLORREF
dibdrv_SetPixel( PHYSDEV dev
, INT x
, INT y
, COLORREF color
)
1466 dibdrv_physdev
*pdev
= get_dibdrv_pdev( dev
);
1467 struct clipped_rects clipped_rects
;
1472 TRACE( "(%p, %d, %d, %08x)\n", dev
, x
, y
, color
);
1476 LPtoDP( dev
->hdc
, &pt
, 1 );
1479 rect
.right
= rect
.left
+ 1;
1480 rect
.bottom
= rect
.top
+ 1;
1481 add_clipped_bounds( pdev
, &rect
, pdev
->clip
);
1483 /* SetPixel doesn't do the 1bpp massaging like other fg colors */
1484 pixel
= get_pixel_color( dev
->hdc
, &pdev
->dib
, color
, FALSE
);
1485 color
= pdev
->dib
.funcs
->pixel_to_colorref( &pdev
->dib
, pixel
);
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
);