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/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(dib);
29 static RECT get_device_rect( HDC hdc, int left, int top, int right, int bottom, BOOL rtl_correction )
37 if (rtl_correction && GetLayout( hdc ) & LAYOUT_RTL)
39 /* shift the rectangle so that the right border is included after mirroring */
40 /* it would be more correct to do this after LPtoDP but that's not what Windows does */
44 LPtoDP( hdc, (POINT *)&rect, 2 );
45 if (rect.left > rect.right)
48 rect.left = rect.right;
51 if (rect.top > rect.bottom)
54 rect.top = rect.bottom;
60 static BOOL get_pen_device_rect( dibdrv_physdev *dev, RECT *rect, int left, int top, int right, int bottom )
62 *rect = get_device_rect( dev->dev.hdc, left, top, right, bottom, TRUE );
63 if (rect->left == rect->right || rect->top == rect->bottom) return FALSE;
65 if (dev->pen_style == PS_INSIDEFRAME)
67 rect->left += dev->pen_width / 2;
68 rect->top += dev->pen_width / 2;
69 rect->right -= (dev->pen_width - 1) / 2;
70 rect->bottom -= (dev->pen_width - 1) / 2;
75 /* compute the points for the first quadrant of an ellipse, counterclockwise from the x axis */
76 /* 'data' must contain enough space, (width+height)/2 is a reasonable upper bound */
77 static int ellipse_first_quadrant( int width, int height, POINT *data )
79 const int a = width - 1;
80 const int b = height - 1;
81 const int asq = 8 * a * a;
82 const int bsq = 8 * b * b;
83 int dx = 4 * b * b * (1 - a);
84 int dy = 4 * a * a * (1 + (b % 2));
85 int err = dx + dy + a * a * (b % 2);
92 /* based on an algorithm by Alois Zingl */
94 while (pt.x >= width / 2)
112 static int find_intersection( const POINT *points, int x, int y, int count )
118 if (x >= 0) /* first quadrant */
120 for (i = 0; i < count; i++) if (points[i].x * y <= points[i].y * x) break;
123 /* second quadrant */
124 for (i = 0; i < count; i++) if (points[i].x * y < points[i].y * -x) break;
125 return 2 * count - i;
127 if (x >= 0) /* fourth quadrant */
129 for (i = 0; i < count; i++) if (points[i].x * -y <= points[i].y * x) break;
130 return 4 * count - i;
133 for (i = 0; i < count; i++) if (points[i].x * -y < points[i].y * -x) break;
134 return 2 * count + i;
137 static int get_arc_points( PHYSDEV dev, const RECT *rect, POINT start, POINT end, POINT *points )
139 int i, pos, count, start_pos, end_pos;
140 int width = rect->right - rect->left;
141 int height = rect->bottom - rect->top;
143 count = ellipse_first_quadrant( width, height, points );
144 for (i = 0; i < count; i++)
146 points[i].x -= width / 2;
147 points[i].y -= height / 2;
149 if (GetArcDirection( dev->hdc ) != AD_CLOCKWISE)
154 start_pos = find_intersection( points, start.x, start.y, count );
155 end_pos = find_intersection( points, end.x, end.y, count );
156 if (end_pos <= start_pos) end_pos += 4 * count;
159 if (GetArcDirection( dev->hdc ) == AD_CLOCKWISE)
161 for (i = start_pos; i < end_pos; i++, pos++)
163 switch ((i / count) % 4)
166 points[pos].x = rect->left + width/2 + points[i % count].x;
167 points[pos].y = rect->top + height/2 + points[i % count].y;
170 points[pos].x = rect->left + width/2 - points[count - 1 - i % count].x;
171 points[pos].y = rect->top + height/2 + points[count - 1 - i % count].y;
174 points[pos].x = rect->left + width/2 - points[i % count].x;
175 points[pos].y = rect->top + height/2 - points[i % count].y;
178 points[pos].x = rect->left + width/2 + points[count - 1 - i % count].x;
179 points[pos].y = rect->top + height/2 - points[count - 1 - i % count].y;
186 for (i = start_pos; i < end_pos; i++, pos++)
188 switch ((i / count) % 4)
191 points[pos].x = rect->left + width/2 + points[i % count].x;
192 points[pos].y = rect->top + height/2 - points[i % count].y;
195 points[pos].x = rect->left + width/2 - points[count - 1 - i % count].x;
196 points[pos].y = rect->top + height/2 - points[count - 1 - i % count].y;
199 points[pos].x = rect->left + width/2 - points[i % count].x;
200 points[pos].y = rect->top + height/2 + points[i % count].y;
203 points[pos].x = rect->left + width/2 + points[count - 1 - i % count].x;
204 points[pos].y = rect->top + height/2 + points[count - 1 - i % count].y;
210 memmove( points, points + count, (pos - count) * sizeof(POINT) );
214 /* backend for arc functions; extra_lines is -1 for ArcTo, 0 for Arc, 1 for Chord, 2 for Pie */
215 static BOOL draw_arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
216 INT start_x, INT start_y, INT end_x, INT end_y, INT extra_lines )
218 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
220 POINT pt[2], *points;
221 int width, height, count;
223 HRGN outline = 0, interior = 0;
225 if (!get_pen_device_rect( pdev, &rect, left, top, right, bottom )) return TRUE;
227 width = rect.right - rect.left;
228 height = rect.bottom - rect.top;
234 LPtoDP( dev->hdc, pt, 2 );
235 /* make them relative to the ellipse center */
236 pt[0].x -= left + width / 2;
237 pt[0].y -= top + height / 2;
238 pt[1].x -= left + width / 2;
239 pt[1].y -= top + height / 2;
241 points = HeapAlloc( GetProcessHeap(), 0, (width + height) * 3 * sizeof(*points) );
242 if (!points) return FALSE;
244 if (extra_lines == -1)
246 GetCurrentPositionEx( dev->hdc, points );
247 LPtoDP( dev->hdc, points, 1 );
248 count = 1 + get_arc_points( dev, &rect, pt[0], pt[1], points + 1 );
250 else count = get_arc_points( dev, &rect, pt[0], pt[1], points );
252 if (extra_lines == 2)
254 points[count].x = rect.left + width / 2;
255 points[count].y = rect.top + height / 2;
260 HeapFree( GetProcessHeap(), 0, points );
264 if (pdev->pen_uses_region && !(outline = CreateRectRgn( 0, 0, 0, 0 )))
266 HeapFree( GetProcessHeap(), 0, points );
270 if (pdev->brush.style != BS_NULL && extra_lines > 0 &&
271 !(interior = CreatePolygonRgn( points, count, WINDING )))
273 HeapFree( GetProcessHeap(), 0, points );
274 if (outline) DeleteObject( outline );
278 /* if not using a region, paint the interior first so the outline can overlap it */
279 if (interior && !outline)
281 ret = brush_region( pdev, interior );
282 DeleteObject( interior );
286 reset_dash_origin( pdev );
287 pdev->pen_lines( pdev, count, points, extra_lines > 0, outline );
291 CombineRgn( interior, interior, outline, RGN_DIFF );
292 ret = brush_region( pdev, interior );
293 DeleteObject( interior );
297 if (ret) ret = pen_region( pdev, outline );
298 DeleteObject( outline );
300 HeapFree( GetProcessHeap(), 0, points );
304 /* Intensities of the 17 glyph levels when drawn with text component of 0xff on a
305 black bkgnd. [A log-log plot of these data gives: y = 77.05 * x^0.4315]. */
306 static const BYTE ramp[17] =
309 0x8c, 0x9a, 0xa7, 0xb2,
310 0xbd, 0xc7, 0xd0, 0xd9,
311 0xe1, 0xe9, 0xf0, 0xf8,
315 /* For a give text-color component and a glyph level, calculate the
316 range of dst intensities, the min/max corresponding to 0/0xff bkgnd
317 components respectively.
319 The minimum is a linear interpolation between 0 and the value in
322 The maximum is a linear interpolation between the value from the
323 ramp table read in reverse and 0xff.
325 To find the resulting pixel intensity, we note that if the text and
326 bkgnd intensities are the same then the result must be that
327 intensity. Otherwise we linearly interpolate between either the
328 min or the max value and this intermediate value depending on which
329 side of the inequality we lie.
332 static inline void get_range( BYTE aa, DWORD text_comp, BYTE *min_comp, BYTE *max_comp )
334 *min_comp = (ramp[aa] * text_comp) / 0xff;
335 *max_comp = ramp[16 - aa] + ((0xff - ramp[16 - aa]) * text_comp) / 0xff;
338 static inline void get_aa_ranges( COLORREF col, struct intensity_range intensities[17] )
342 for (i = 0; i < 17; i++)
344 get_range( i, GetRValue(col), &intensities[i].r_min, &intensities[i].r_max );
345 get_range( i, GetGValue(col), &intensities[i].g_min, &intensities[i].g_max );
346 get_range( i, GetBValue(col), &intensities[i].b_min, &intensities[i].b_max );
350 /**********************************************************************
351 * get_text_bkgnd_masks
353 * See the comment above get_pen_bkgnd_masks
355 static inline void get_text_bkgnd_masks( dibdrv_physdev *pdev, rop_mask *mask )
357 COLORREF bg = GetBkColor( pdev->dev.hdc );
361 if (pdev->dib.bit_count != 1)
362 mask->xor = get_pixel_color( pdev, bg, FALSE );
365 COLORREF fg = GetTextColor( pdev->dev.hdc );
366 mask->xor = get_pixel_color( pdev, fg, TRUE );
367 if (fg != bg) mask->xor = ~mask->xor;
371 static void draw_glyph( dibdrv_physdev *pdev, const POINT *origin, const GLYPHMETRICS *metrics,
372 const struct gdi_image_bits *image, DWORD text_color,
373 const struct intensity_range *ranges, const struct clipped_rects *clipped_rects )
376 RECT rect, clipped_rect;
380 glyph_dib.bit_count = 8;
381 glyph_dib.width = metrics->gmBlackBoxX;
382 glyph_dib.height = metrics->gmBlackBoxY;
383 glyph_dib.stride = get_dib_stride( metrics->gmBlackBoxX, 8 );
384 glyph_dib.bits = *image;
386 rect.left = origin->x + metrics->gmptGlyphOrigin.x;
387 rect.top = origin->y - metrics->gmptGlyphOrigin.y;
388 rect.right = rect.left + metrics->gmBlackBoxX;
389 rect.bottom = rect.top + metrics->gmBlackBoxY;
391 for (i = 0; i < clipped_rects->count; i++)
393 if (intersect_rect( &clipped_rect, &rect, clipped_rects->rects + i ))
395 src_origin.x = clipped_rect.left - rect.left;
396 src_origin.y = clipped_rect.top - rect.top;
398 pdev->dib.funcs->draw_glyph( &pdev->dib, &clipped_rect, &glyph_dib, &src_origin,
399 text_color, ranges );
404 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
405 static const int padding[4] = {0, 3, 2, 1};
407 /***********************************************************************
410 * Retrieve a 17-level bitmap for the appropiate glyph.
412 * For non-antialiased bitmaps convert them to the 17-level format
413 * using only values 0 or 16.
415 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT aa_flags, GLYPHMETRICS *metrics,
416 struct gdi_image_bits *image )
418 UINT ggo_flags = aa_flags | GGO_GLYPH_INDEX;
419 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
420 UINT indices[3] = {0, 0, 0x20};
423 BYTE *buf, *dst, *src;
427 image->is_copy = FALSE;
428 image->free = free_heap_bits;
433 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
436 ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, 0, NULL, &identity );
437 if (ret != GDI_ERROR) break;
440 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
441 if (!ret) return ERROR_SUCCESS; /* empty glyph */
443 /* We'll convert non-antialiased 1-bpp bitmaps to 8-bpp, so these sizes relate to 8-bpp */
444 pad = padding[ metrics->gmBlackBoxX % 4 ];
445 stride = get_dib_stride( metrics->gmBlackBoxX, 8 );
446 size = metrics->gmBlackBoxY * stride;
448 buf = HeapAlloc( GetProcessHeap(), 0, size );
449 if (!buf) return ERROR_OUTOFMEMORY;
451 ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, size, buf, &identity );
452 if (ret == GDI_ERROR)
454 HeapFree( GetProcessHeap(), 0, buf );
455 return ERROR_NOT_FOUND;
458 if (aa_flags == GGO_BITMAP)
460 for (y = metrics->gmBlackBoxY - 1; y >= 0; y--)
462 src = buf + y * get_dib_stride( metrics->gmBlackBoxX, 1 );
463 dst = buf + y * stride;
465 if (pad) memset( dst + metrics->gmBlackBoxX, 0, pad );
467 for (x = metrics->gmBlackBoxX - 1; x >= 0; x--)
468 dst[x] = (src[x / 8] & masks[x % 8]) ? 0x10 : 0;
473 for (y = 0, dst = buf; y < metrics->gmBlackBoxY; y++, dst += stride)
474 memset( dst + metrics->gmBlackBoxX, 0, pad );
478 return ERROR_SUCCESS;
481 BOOL render_aa_text_bitmapinfo( HDC hdc, BITMAPINFO *info, struct gdi_image_bits *bits,
482 struct bitblt_coords *src, INT x, INT y, UINT flags,
483 UINT aa_flags, LPCWSTR str, UINT count, const INT *dx )
490 DWORD fg_pixel, bg_pixel;
491 struct intensity_range glyph_intensities[17];
493 assert( info->bmiHeader.biBitCount > 8 ); /* mono and indexed formats don't support anti-aliasing */
495 init_dib_info_from_bitmapinfo( &dib, info, bits->ptr, 0 );
497 fg = make_rgb_colorref( hdc, &dib, GetTextColor( hdc ), &got_pixel, &fg_pixel);
498 if (!got_pixel) fg_pixel = dib.funcs->colorref_to_pixel( &dib, fg );
500 get_aa_ranges( fg, glyph_intensities );
502 if (flags & ETO_OPAQUE)
504 rop_mask bkgnd_color;
506 bg = make_rgb_colorref( hdc, &dib, GetBkColor( hdc ), &got_pixel, &bg_pixel);
507 if (!got_pixel) bg_pixel = dib.funcs->colorref_to_pixel( &dib, bg );
510 bkgnd_color.xor = bg_pixel;
511 dib.funcs->solid_rects( &dib, 1, &src->visrect, bkgnd_color.and, bkgnd_color.xor );
514 for (i = 0; i < count; i++)
516 GLYPHMETRICS metrics;
517 struct gdi_image_bits image;
519 err = get_glyph_bitmap( hdc, (UINT)str[i], aa_flags, &metrics, &image );
524 RECT rect, clipped_rect;
528 glyph_dib.bit_count = 8;
529 glyph_dib.width = metrics.gmBlackBoxX;
530 glyph_dib.height = metrics.gmBlackBoxY;
531 glyph_dib.stride = get_dib_stride( metrics.gmBlackBoxX, 8 );
532 glyph_dib.bits = image;
534 rect.left = x + metrics.gmptGlyphOrigin.x;
535 rect.top = y - metrics.gmptGlyphOrigin.y;
536 rect.right = rect.left + metrics.gmBlackBoxX;
537 rect.bottom = rect.top + metrics.gmBlackBoxY;
539 if (intersect_rect( &clipped_rect, &rect, &src->visrect ))
541 src_origin.x = clipped_rect.left - rect.left;
542 src_origin.y = clipped_rect.top - rect.top;
544 dib.funcs->draw_glyph( &dib, &clipped_rect, &glyph_dib, &src_origin,
545 fg_pixel, glyph_intensities );
548 if (image.free) image.free( &image );
562 x += metrics.gmCellIncX;
563 y += metrics.gmCellIncY;
569 /***********************************************************************
572 BOOL dibdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
573 const RECT *rect, LPCWSTR str, UINT count, const INT *dx )
575 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
576 struct clipped_rects clipped_rects;
579 DWORD text_color, err;
580 struct intensity_range ranges[17];
582 init_clipped_rects( &clipped_rects );
584 if (flags & ETO_OPAQUE)
586 rop_mask bkgnd_color;
587 get_text_bkgnd_masks( pdev, &bkgnd_color );
588 get_clipped_rects( &pdev->dib, rect, pdev->clip, &clipped_rects );
589 pdev->dib.funcs->solid_rects( &pdev->dib, clipped_rects.count, clipped_rects.rects,
590 bkgnd_color.and, bkgnd_color.xor );
593 if (count == 0) goto done;
595 if (flags & ETO_CLIPPED)
597 if (!(flags & ETO_OPAQUE)) /* otherwise we have done it already */
598 get_clipped_rects( &pdev->dib, rect, pdev->clip, &clipped_rects );
602 free_clipped_rects( &clipped_rects );
603 get_clipped_rects( &pdev->dib, NULL, pdev->clip, &clipped_rects );
605 if (!clipped_rects.count) return TRUE;
607 text_color = get_pixel_color( pdev, GetTextColor( pdev->dev.hdc ), TRUE );
608 get_aa_ranges( pdev->dib.funcs->pixel_to_colorref( &pdev->dib, text_color ), ranges );
610 aa_flags = get_font_aa_flags( dev->hdc );
613 for (i = 0; i < count; i++)
615 GLYPHMETRICS metrics;
616 struct gdi_image_bits image;
618 err = get_glyph_bitmap( dev->hdc, (UINT)str[i], aa_flags, &metrics, &image );
621 if (image.ptr) draw_glyph( pdev, &origin, &metrics, &image, text_color, ranges, &clipped_rects );
622 if (image.free) image.free( &image );
628 origin.x += dx[ i * 2 ];
629 origin.y += dx[ i * 2 + 1];
636 origin.x += metrics.gmCellIncX;
637 origin.y += metrics.gmCellIncY;
642 free_clipped_rects( &clipped_rects );
646 /***********************************************************************
649 BOOL dibdrv_Arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
650 INT start_x, INT start_y, INT end_x, INT end_y )
652 return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, 0 );
655 /***********************************************************************
658 BOOL dibdrv_ArcTo( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
659 INT start_x, INT start_y, INT end_x, INT end_y )
661 return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, -1 );
664 /***********************************************************************
667 BOOL dibdrv_Chord( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
668 INT start_x, INT start_y, INT end_x, INT end_y )
670 return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, 1 );
673 /***********************************************************************
676 BOOL dibdrv_Ellipse( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
678 return dibdrv_RoundRect( dev, left, top, right, bottom, right - left, bottom - top );
681 static inline BOOL is_interior( dib_info *dib, HRGN clip, int x, int y, DWORD pixel, UINT type)
683 /* the clip rgn stops the flooding */
684 if (clip && !PtInRegion( clip, x, y )) return FALSE;
686 if (type == FLOODFILLBORDER)
687 return dib->funcs->get_pixel( dib, x, y ) != pixel;
689 return dib->funcs->get_pixel( dib, x, y ) == pixel;
692 static void fill_row( dib_info *dib, HRGN clip, RECT *row, DWORD pixel, UINT type, HRGN rgn );
694 static inline void do_next_row( dib_info *dib, HRGN clip, const RECT *row, int offset, DWORD pixel, UINT type, HRGN rgn )
698 next.top = row->top + offset;
699 next.bottom = next.top + 1;
700 next.left = next.right = row->left;
701 while (next.right < row->right)
703 if (is_interior( dib, clip, next.right, next.top, pixel, type)) next.right++;
706 if (next.left != next.right && !PtInRegion( rgn, next.left, next.top ))
707 fill_row( dib, clip, &next, pixel, type, rgn );
708 next.left = ++next.right;
711 if (next.left != next.right && !PtInRegion( rgn, next.left, next.top ))
712 fill_row( dib, clip, &next, pixel, type, rgn );
715 static void fill_row( dib_info *dib, HRGN clip, RECT *row, DWORD pixel, UINT type, HRGN rgn )
717 while (row->left > 0 && is_interior( dib, clip, row->left - 1, row->top, pixel, type)) row->left--;
718 while (row->right < dib->width && is_interior( dib, clip, row->right, row->top, pixel, type)) row->right++;
719 add_rect_to_region( rgn, row );
721 if (row->top > 0) do_next_row( dib, clip, row, -1, pixel, type, rgn );
722 if (row->top < dib->height - 1) do_next_row( dib, clip, row, 1, pixel, type, rgn );
727 /***********************************************************************
728 * dibdrv_ExtFloodFill
730 BOOL dibdrv_ExtFloodFill( PHYSDEV dev, INT x, INT y, COLORREF color, UINT type )
732 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
733 DWORD pixel = get_pixel_color( pdev, color, FALSE );
737 TRACE( "(%p, %d, %d, %08x, %d)\n", pdev, x, y, color, type );
739 if (!is_interior( &pdev->dib, pdev->clip, x, y, pixel, type )) return FALSE;
741 rgn = CreateRectRgn( 0, 0, 0, 0 );
747 fill_row( &pdev->dib, pdev->clip, &row, pixel, type, rgn );
749 brush_region( pdev, rgn );
755 /***********************************************************************
756 * dibdrv_GetNearestColor
758 COLORREF dibdrv_GetNearestColor( PHYSDEV dev, COLORREF color )
760 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
763 TRACE( "(%p, %08x)\n", dev, color );
765 pixel = get_pixel_color( pdev, color, FALSE );
766 return pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
769 /***********************************************************************
772 COLORREF dibdrv_GetPixel( PHYSDEV dev, INT x, INT y )
774 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
778 TRACE( "(%p, %d, %d)\n", dev, x, y );
782 LPtoDP( dev->hdc, &pt, 1 );
784 if (pt.x < 0 || pt.x >= pdev->dib.width ||
785 pt.y < 0 || pt.y >= pdev->dib.height)
788 pixel = pdev->dib.funcs->get_pixel( &pdev->dib, pt.x, pt.y );
789 return pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
792 /***********************************************************************
795 BOOL dibdrv_LineTo( PHYSDEV dev, INT x, INT y )
797 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
802 GetCurrentPositionEx(dev->hdc, pts);
806 LPtoDP(dev->hdc, pts, 2);
808 if (pdev->pen_uses_region && !(region = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
810 reset_dash_origin(pdev);
812 ret = pdev->pen_lines(pdev, 2, pts, FALSE, region);
816 if (pdev->clip) CombineRgn( region, region, pdev->clip, RGN_AND );
817 ret = pen_region( pdev, region );
818 DeleteObject( region );
823 /***********************************************************************
826 * Returns the binary rop that is equivalent to the provided ternary rop
827 * if the src bits are ignored.
829 static inline INT get_rop2_from_rop(INT rop)
831 return (((rop >> 18) & 0x0c) | ((rop >> 16) & 0x03)) + 1;
834 /***********************************************************************
837 BOOL dibdrv_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
839 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
841 TRACE("(%p, %d, %d, %d, %d, %06x)\n", dev, dst->x, dst->y, dst->width, dst->height, rop);
843 return brush_rect( pdev, &pdev->brush, &dst->visrect, pdev->clip, get_rop2_from_rop(rop) );
846 /***********************************************************************
849 BOOL dibdrv_PaintRgn( PHYSDEV dev, HRGN rgn )
851 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
852 const WINEREGION *region;
856 TRACE("%p, %p\n", dev, rgn);
858 region = get_wine_region( rgn );
859 if(!region) return FALSE;
861 for(i = 0; i < region->numRects; i++)
863 rect = get_device_rect( dev->hdc, region->rects[i].left, region->rects[i].top,
864 region->rects[i].right, region->rects[i].bottom, FALSE );
865 brush_rect( pdev, &pdev->brush, &rect, pdev->clip, GetROP2( dev->hdc ) );
868 release_wine_region( rgn );
872 /***********************************************************************
875 BOOL dibdrv_PolyPolygon( PHYSDEV dev, const POINT *pt, const INT *counts, DWORD polygons )
877 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
881 HRGN outline = 0, interior = 0;
883 for (i = total = 0; i < polygons; i++)
885 if (counts[i] < 2) return FALSE;
889 points = HeapAlloc( GetProcessHeap(), 0, total * sizeof(*pt) );
890 if (!points) return FALSE;
891 memcpy( points, pt, total * sizeof(*pt) );
892 LPtoDP( dev->hdc, points, total );
894 if (pdev->brush.style != BS_NULL &&
895 !(interior = CreatePolyPolygonRgn( points, counts, polygons, GetPolyFillMode( dev->hdc ))))
897 HeapFree( GetProcessHeap(), 0, points );
901 if (pdev->pen_uses_region) outline = CreateRectRgn( 0, 0, 0, 0 );
903 /* if not using a region, paint the interior first so the outline can overlap it */
904 if (interior && !outline)
906 ret = brush_region( pdev, interior );
907 DeleteObject( interior );
911 for (i = pos = 0; i < polygons; i++)
913 reset_dash_origin( pdev );
914 pdev->pen_lines( pdev, counts[i], points + pos, TRUE, outline );
920 CombineRgn( interior, interior, outline, RGN_DIFF );
921 ret = brush_region( pdev, interior );
922 DeleteObject( interior );
926 if (ret) ret = pen_region( pdev, outline );
927 DeleteObject( outline );
929 HeapFree( GetProcessHeap(), 0, points );
933 /***********************************************************************
934 * dibdrv_PolyPolyline
936 BOOL dibdrv_PolyPolyline( PHYSDEV dev, const POINT* pt, const DWORD* counts, DWORD polylines )
938 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
939 DWORD max_points = 0, i;
944 for (i = 0; i < polylines; i++)
946 if (counts[i] < 2) return FALSE;
947 max_points = max( counts[i], max_points );
950 points = HeapAlloc( GetProcessHeap(), 0, max_points * sizeof(*pt) );
951 if (!points) return FALSE;
953 if (pdev->pen_uses_region && !(outline = CreateRectRgn( 0, 0, 0, 0 )))
955 HeapFree( GetProcessHeap(), 0, points );
959 for (i = 0; i < polylines; i++)
961 memcpy( points, pt, counts[i] * sizeof(*pt) );
963 LPtoDP( dev->hdc, points, counts[i] );
965 reset_dash_origin( pdev );
966 pdev->pen_lines( pdev, counts[i], points, FALSE, outline );
971 if (pdev->clip) CombineRgn( outline, outline, pdev->clip, RGN_AND );
972 ret = pen_region( pdev, outline );
973 DeleteObject( outline );
976 HeapFree( GetProcessHeap(), 0, points );
980 /***********************************************************************
983 BOOL dibdrv_Polygon( PHYSDEV dev, const POINT *pt, INT count )
985 INT counts[1] = { count };
987 return dibdrv_PolyPolygon( dev, pt, counts, 1 );
990 /***********************************************************************
993 BOOL dibdrv_Polyline( PHYSDEV dev, const POINT* pt, INT count )
995 DWORD counts[1] = { count };
997 if (count < 0) return FALSE;
998 return dibdrv_PolyPolyline( dev, pt, counts, 1 );
1001 /***********************************************************************
1004 BOOL dibdrv_Rectangle( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
1006 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
1012 TRACE("(%p, %d, %d, %d, %d)\n", dev, left, top, right, bottom);
1014 if (!get_pen_device_rect( pdev, &rect, left, top, right, bottom )) return TRUE;
1016 if (pdev->pen_uses_region && !(outline = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
1020 reset_dash_origin(pdev);
1022 if (GetArcDirection( dev->hdc ) == AD_CLOCKWISE)
1024 /* 4 pts going clockwise starting from bottom-right */
1025 pts[0].x = pts[3].x = rect.right;
1026 pts[0].y = pts[1].y = rect.bottom;
1027 pts[1].x = pts[2].x = rect.left;
1028 pts[2].y = pts[3].y = rect.top;
1032 /* 4 pts going anti-clockwise starting from top-right */
1033 pts[0].x = pts[3].x = rect.right;
1034 pts[0].y = pts[1].y = rect.top;
1035 pts[1].x = pts[2].x = rect.left;
1036 pts[2].y = pts[3].y = rect.bottom;
1039 pdev->pen_lines(pdev, 4, pts, TRUE, outline);
1043 if (pdev->brush.style != BS_NULL)
1045 HRGN interior = CreateRectRgnIndirect( &rect );
1047 CombineRgn( interior, interior, outline, RGN_DIFF );
1048 brush_region( pdev, interior );
1049 DeleteObject( interior );
1051 ret = pen_region( pdev, outline );
1052 DeleteObject( outline );
1056 rect.left += (pdev->pen_width + 1) / 2;
1057 rect.top += (pdev->pen_width + 1) / 2;
1058 rect.right -= pdev->pen_width / 2;
1059 rect.bottom -= pdev->pen_width / 2;
1060 ret = brush_rect( pdev, &pdev->brush, &rect, pdev->clip, GetROP2(dev->hdc) );
1065 /***********************************************************************
1068 BOOL dibdrv_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
1069 INT ellipse_width, INT ellipse_height )
1071 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
1073 POINT pt[2], *points;
1076 HRGN outline = 0, interior = 0;
1078 if (!get_pen_device_rect( pdev, &rect, left, top, right, bottom )) return TRUE;
1080 pt[0].x = pt[0].y = 0;
1081 pt[1].x = ellipse_width;
1082 pt[1].y = ellipse_height;
1083 LPtoDP( dev->hdc, pt, 2 );
1084 ellipse_width = min( rect.right - rect.left, abs( pt[1].x - pt[0].x ));
1085 ellipse_height = min( rect.bottom - rect.top, abs( pt[1].y - pt[0].y ));
1086 if (ellipse_width <= 2|| ellipse_height <= 2)
1087 return dibdrv_Rectangle( dev, left, top, right, bottom );
1089 points = HeapAlloc( GetProcessHeap(), 0, (ellipse_width + ellipse_height) * 2 * sizeof(*points) );
1090 if (!points) return FALSE;
1092 if (pdev->pen_uses_region && !(outline = CreateRectRgn( 0, 0, 0, 0 )))
1094 HeapFree( GetProcessHeap(), 0, points );
1098 if (pdev->brush.style != BS_NULL &&
1099 !(interior = CreateRoundRectRgn( rect.left, rect.top, rect.right + 1, rect.bottom + 1,
1100 ellipse_width, ellipse_height )))
1102 HeapFree( GetProcessHeap(), 0, points );
1103 if (outline) DeleteObject( outline );
1107 /* if not using a region, paint the interior first so the outline can overlap it */
1108 if (interior && !outline)
1110 ret = brush_region( pdev, interior );
1111 DeleteObject( interior );
1115 count = ellipse_first_quadrant( ellipse_width, ellipse_height, points );
1117 if (GetArcDirection( dev->hdc ) == AD_CLOCKWISE)
1119 for (i = 0; i < count; i++)
1121 points[i].x = rect.right - ellipse_width + points[i].x;
1122 points[i].y = rect.bottom - ellipse_height + points[i].y;
1127 for (i = 0; i < count; i++)
1129 points[i].x = rect.right - ellipse_width + points[i].x;
1130 points[i].y = rect.top + ellipse_height - 1 - points[i].y;
1134 /* horizontal symmetry */
1136 end = 2 * count - 1;
1137 /* avoid duplicating the midpoint */
1138 if (ellipse_width % 2 && ellipse_width == rect.right - rect.left) end--;
1139 for (i = 0; i < count; i++)
1141 points[end - i].x = rect.left + rect.right - 1 - points[i].x;
1142 points[end - i].y = points[i].y;
1146 /* vertical symmetry */
1148 end = 2 * count - 1;
1149 /* avoid duplicating the midpoint */
1150 if (ellipse_height % 2 && ellipse_height == rect.bottom - rect.top) end--;
1151 for (i = 0; i < count; i++)
1153 points[end - i].x = points[i].x;
1154 points[end - i].y = rect.top + rect.bottom - 1 - points[i].y;
1158 reset_dash_origin( pdev );
1159 pdev->pen_lines( pdev, count, points, TRUE, outline );
1163 CombineRgn( interior, interior, outline, RGN_DIFF );
1164 ret = brush_region( pdev, interior );
1165 DeleteObject( interior );
1169 if (ret) ret = pen_region( pdev, outline );
1170 DeleteObject( outline );
1172 HeapFree( GetProcessHeap(), 0, points );
1176 /***********************************************************************
1179 BOOL dibdrv_Pie( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
1180 INT start_x, INT start_y, INT end_x, INT end_y )
1182 return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, 2 );
1185 /***********************************************************************
1188 COLORREF dibdrv_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color )
1190 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
1191 struct clipped_rects clipped_rects;
1196 TRACE( "(%p, %d, %d, %08x)\n", dev, x, y, color );
1200 LPtoDP( dev->hdc, &pt, 1 );
1203 rect.right = rect.left + 1;
1204 rect.bottom = rect.top + 1;
1206 /* SetPixel doesn't do the 1bpp massaging like other fg colors */
1207 pixel = get_pixel_color( pdev, color, FALSE );
1208 color = pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
1210 if (!get_clipped_rects( &pdev->dib, &rect, pdev->clip, &clipped_rects )) return color;
1211 pdev->dib.funcs->solid_rects( &pdev->dib, clipped_rects.count, clipped_rects.rects, 0, pixel );
1212 free_clipped_rects( &clipped_rects );