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 );
277 if (pdev->pen_uses_region) outline = CreateRectRgn( 0, 0, 0, 0 );
279 /* if not using a region, paint the interior first so the outline can overlap it */
280 if (interior && !outline)
282 ret = brush_region( pdev, interior );
283 DeleteObject( interior );
287 reset_dash_origin( pdev );
288 pdev->pen_lines( pdev, count, points, extra_lines > 0, outline );
292 CombineRgn( interior, interior, outline, RGN_DIFF );
293 ret = brush_region( pdev, interior );
294 DeleteObject( interior );
298 if (ret) ret = pen_region( pdev, outline );
299 DeleteObject( outline );
301 HeapFree( GetProcessHeap(), 0, points );
305 /* Intensities of the 17 glyph levels when drawn with text component of 0xff on a
306 black bkgnd. [A log-log plot of these data gives: y = 77.05 * x^0.4315]. */
307 static const BYTE ramp[17] =
310 0x8c, 0x9a, 0xa7, 0xb2,
311 0xbd, 0xc7, 0xd0, 0xd9,
312 0xe1, 0xe9, 0xf0, 0xf8,
316 /* For a give text-color component and a glyph level, calculate the
317 range of dst intensities, the min/max corresponding to 0/0xff bkgnd
318 components respectively.
320 The minimum is a linear interpolation between 0 and the value in
323 The maximum is a linear interpolation between the value from the
324 ramp table read in reverse and 0xff.
326 To find the resulting pixel intensity, we note that if the text and
327 bkgnd intensities are the same then the result must be that
328 intensity. Otherwise we linearly interpolate between either the
329 min or the max value and this intermediate value depending on which
330 side of the inequality we lie.
333 static inline void get_range( BYTE aa, DWORD text_comp, BYTE *min_comp, BYTE *max_comp )
335 *min_comp = (ramp[aa] * text_comp) / 0xff;
336 *max_comp = ramp[16 - aa] + ((0xff - ramp[16 - aa]) * text_comp) / 0xff;
339 static inline void get_aa_ranges( COLORREF col, struct intensity_range intensities[17] )
343 for (i = 0; i < 17; i++)
345 get_range( i, GetRValue(col), &intensities[i].r_min, &intensities[i].r_max );
346 get_range( i, GetGValue(col), &intensities[i].g_min, &intensities[i].g_max );
347 get_range( i, GetBValue(col), &intensities[i].b_min, &intensities[i].b_max );
351 /**********************************************************************
352 * get_text_bkgnd_masks
354 * See the comment above get_pen_bkgnd_masks
356 static inline void get_text_bkgnd_masks( dibdrv_physdev *pdev, rop_mask *mask )
358 COLORREF bg = GetBkColor( pdev->dev.hdc );
362 if (pdev->dib.bit_count != 1)
363 mask->xor = get_pixel_color( pdev, bg, FALSE );
366 COLORREF fg = GetTextColor( pdev->dev.hdc );
367 mask->xor = get_pixel_color( pdev, fg, TRUE );
368 if (fg != bg) mask->xor = ~mask->xor;
372 static void draw_glyph( dibdrv_physdev *pdev, const POINT *origin, const GLYPHMETRICS *metrics,
373 const struct gdi_image_bits *image, DWORD text_color,
374 const struct intensity_range *ranges, const struct clipped_rects *clipped_rects )
377 RECT rect, clipped_rect;
381 glyph_dib.bit_count = 8;
382 glyph_dib.width = metrics->gmBlackBoxX;
383 glyph_dib.height = metrics->gmBlackBoxY;
384 glyph_dib.stride = get_dib_stride( metrics->gmBlackBoxX, 8 );
385 glyph_dib.bits = *image;
387 rect.left = origin->x + metrics->gmptGlyphOrigin.x;
388 rect.top = origin->y - metrics->gmptGlyphOrigin.y;
389 rect.right = rect.left + metrics->gmBlackBoxX;
390 rect.bottom = rect.top + metrics->gmBlackBoxY;
392 for (i = 0; i < clipped_rects->count; i++)
394 if (intersect_rect( &clipped_rect, &rect, clipped_rects->rects + i ))
396 src_origin.x = clipped_rect.left - rect.left;
397 src_origin.y = clipped_rect.top - rect.top;
399 pdev->dib.funcs->draw_glyph( &pdev->dib, &clipped_rect, &glyph_dib, &src_origin,
400 text_color, ranges );
405 static const BYTE masks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
406 static const int padding[4] = {0, 3, 2, 1};
408 /***********************************************************************
411 * Retrieve a 17-level bitmap for the appropiate glyph.
413 * For non-antialiased bitmaps convert them to the 17-level format
414 * using only values 0 or 16.
416 static DWORD get_glyph_bitmap( HDC hdc, UINT index, UINT aa_flags, GLYPHMETRICS *metrics,
417 struct gdi_image_bits *image )
419 UINT ggo_flags = aa_flags | GGO_GLYPH_INDEX;
420 static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
421 UINT indices[3] = {0, 0, 0x20};
424 BYTE *buf, *dst, *src;
428 image->is_copy = FALSE;
429 image->free = free_heap_bits;
434 for (i = 0; i < sizeof(indices) / sizeof(indices[0]); i++)
437 ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, 0, NULL, &identity );
438 if (ret != GDI_ERROR) break;
441 if (ret == GDI_ERROR) return ERROR_NOT_FOUND;
442 if (!ret) return ERROR_SUCCESS; /* empty glyph */
444 /* We'll convert non-antialiased 1-bpp bitmaps to 8-bpp, so these sizes relate to 8-bpp */
445 pad = padding[ metrics->gmBlackBoxX % 4 ];
446 stride = get_dib_stride( metrics->gmBlackBoxX, 8 );
447 size = metrics->gmBlackBoxY * stride;
449 buf = HeapAlloc( GetProcessHeap(), 0, size );
450 if (!buf) return ERROR_OUTOFMEMORY;
452 ret = GetGlyphOutlineW( hdc, index, ggo_flags, metrics, size, buf, &identity );
453 if (ret == GDI_ERROR)
455 HeapFree( GetProcessHeap(), 0, buf );
456 return ERROR_NOT_FOUND;
459 if (aa_flags == GGO_BITMAP)
461 for (y = metrics->gmBlackBoxY - 1; y >= 0; y--)
463 src = buf + y * get_dib_stride( metrics->gmBlackBoxX, 1 );
464 dst = buf + y * stride;
466 if (pad) memset( dst + metrics->gmBlackBoxX, 0, pad );
468 for (x = metrics->gmBlackBoxX - 1; x >= 0; x--)
469 dst[x] = (src[x / 8] & masks[x % 8]) ? 0x10 : 0;
474 for (y = 0, dst = buf; y < metrics->gmBlackBoxY; y++, dst += stride)
475 memset( dst + metrics->gmBlackBoxX, 0, pad );
479 return ERROR_SUCCESS;
482 BOOL render_aa_text_bitmapinfo( HDC hdc, BITMAPINFO *info, struct gdi_image_bits *bits,
483 struct bitblt_coords *src, INT x, INT y, UINT flags,
484 UINT aa_flags, LPCWSTR str, UINT count, const INT *dx )
491 DWORD fg_pixel, bg_pixel;
492 struct intensity_range glyph_intensities[17];
494 assert( info->bmiHeader.biBitCount > 8 ); /* mono and indexed formats don't support anti-aliasing */
496 init_dib_info_from_bitmapinfo( &dib, info, bits->ptr, 0 );
498 fg = make_rgb_colorref( hdc, &dib, GetTextColor( hdc ), &got_pixel, &fg_pixel);
499 if (!got_pixel) fg_pixel = dib.funcs->colorref_to_pixel( &dib, fg );
501 get_aa_ranges( fg, glyph_intensities );
503 if (flags & ETO_OPAQUE)
505 rop_mask bkgnd_color;
507 bg = make_rgb_colorref( hdc, &dib, GetBkColor( hdc ), &got_pixel, &bg_pixel);
508 if (!got_pixel) bg_pixel = dib.funcs->colorref_to_pixel( &dib, bg );
511 bkgnd_color.xor = bg_pixel;
512 dib.funcs->solid_rects( &dib, 1, &src->visrect, bkgnd_color.and, bkgnd_color.xor );
515 for (i = 0; i < count; i++)
517 GLYPHMETRICS metrics;
518 struct gdi_image_bits image;
520 err = get_glyph_bitmap( hdc, (UINT)str[i], aa_flags, &metrics, &image );
525 RECT rect, clipped_rect;
529 glyph_dib.bit_count = 8;
530 glyph_dib.width = metrics.gmBlackBoxX;
531 glyph_dib.height = metrics.gmBlackBoxY;
532 glyph_dib.stride = get_dib_stride( metrics.gmBlackBoxX, 8 );
533 glyph_dib.bits = image;
535 rect.left = x + metrics.gmptGlyphOrigin.x;
536 rect.top = y - metrics.gmptGlyphOrigin.y;
537 rect.right = rect.left + metrics.gmBlackBoxX;
538 rect.bottom = rect.top + metrics.gmBlackBoxY;
540 if (intersect_rect( &clipped_rect, &rect, &src->visrect ))
542 src_origin.x = clipped_rect.left - rect.left;
543 src_origin.y = clipped_rect.top - rect.top;
545 dib.funcs->draw_glyph( &dib, &clipped_rect, &glyph_dib, &src_origin,
546 fg_pixel, glyph_intensities );
549 if (image.free) image.free( &image );
563 x += metrics.gmCellIncX;
564 y += metrics.gmCellIncY;
570 /***********************************************************************
573 BOOL dibdrv_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
574 const RECT *rect, LPCWSTR str, UINT count, const INT *dx )
576 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
577 struct clipped_rects clipped_rects;
580 DWORD text_color, err;
581 struct intensity_range ranges[17];
583 init_clipped_rects( &clipped_rects );
585 if (flags & ETO_OPAQUE)
587 rop_mask bkgnd_color;
588 get_text_bkgnd_masks( pdev, &bkgnd_color );
589 get_clipped_rects( &pdev->dib, rect, pdev->clip, &clipped_rects );
590 pdev->dib.funcs->solid_rects( &pdev->dib, clipped_rects.count, clipped_rects.rects,
591 bkgnd_color.and, bkgnd_color.xor );
594 if (count == 0) goto done;
596 if (flags & ETO_CLIPPED)
598 if (!(flags & ETO_OPAQUE)) /* otherwise we have done it already */
599 get_clipped_rects( &pdev->dib, rect, pdev->clip, &clipped_rects );
603 free_clipped_rects( &clipped_rects );
604 get_clipped_rects( &pdev->dib, NULL, pdev->clip, &clipped_rects );
606 if (!clipped_rects.count) return TRUE;
608 text_color = get_pixel_color( pdev, GetTextColor( pdev->dev.hdc ), TRUE );
609 get_aa_ranges( pdev->dib.funcs->pixel_to_colorref( &pdev->dib, text_color ), ranges );
611 aa_flags = get_font_aa_flags( dev->hdc );
614 for (i = 0; i < count; i++)
616 GLYPHMETRICS metrics;
617 struct gdi_image_bits image;
619 err = get_glyph_bitmap( dev->hdc, (UINT)str[i], aa_flags, &metrics, &image );
622 if (image.ptr) draw_glyph( pdev, &origin, &metrics, &image, text_color, ranges, &clipped_rects );
623 if (image.free) image.free( &image );
629 origin.x += dx[ i * 2 ];
630 origin.y += dx[ i * 2 + 1];
637 origin.x += metrics.gmCellIncX;
638 origin.y += metrics.gmCellIncY;
643 free_clipped_rects( &clipped_rects );
647 /***********************************************************************
650 BOOL dibdrv_Arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
651 INT start_x, INT start_y, INT end_x, INT end_y )
653 return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, 0 );
656 /***********************************************************************
659 BOOL dibdrv_ArcTo( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
660 INT start_x, INT start_y, INT end_x, INT end_y )
662 return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, -1 );
665 /***********************************************************************
668 BOOL dibdrv_Chord( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
669 INT start_x, INT start_y, INT end_x, INT end_y )
671 return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, 1 );
674 /***********************************************************************
677 BOOL dibdrv_Ellipse( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
679 return dibdrv_RoundRect( dev, left, top, right, bottom, right - left, bottom - top );
682 /***********************************************************************
683 * dibdrv_ExtFloodFill
685 BOOL dibdrv_ExtFloodFill( PHYSDEV dev, INT x, INT y, COLORREF color, UINT type )
687 FIXME( "not implemented yet\n" );
691 /***********************************************************************
692 * dibdrv_GetNearestColor
694 COLORREF dibdrv_GetNearestColor( PHYSDEV dev, COLORREF color )
696 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
699 TRACE( "(%p, %08x)\n", dev, color );
701 pixel = get_pixel_color( pdev, color, FALSE );
702 return pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
705 /***********************************************************************
708 COLORREF dibdrv_GetPixel( PHYSDEV dev, INT x, INT y )
710 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
714 TRACE( "(%p, %d, %d)\n", dev, x, y );
718 LPtoDP( dev->hdc, &pt, 1 );
720 if (pt.x < 0 || pt.x >= pdev->dib.width ||
721 pt.y < 0 || pt.y >= pdev->dib.height)
724 pixel = pdev->dib.funcs->get_pixel( &pdev->dib, &pt );
725 return pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
728 /***********************************************************************
731 BOOL dibdrv_LineTo( PHYSDEV dev, INT x, INT y )
733 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
738 GetCurrentPositionEx(dev->hdc, pts);
742 LPtoDP(dev->hdc, pts, 2);
744 if (pdev->pen_uses_region && !(region = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
746 reset_dash_origin(pdev);
748 ret = pdev->pen_lines(pdev, 2, pts, FALSE, region);
752 if (pdev->clip) CombineRgn( region, region, pdev->clip, RGN_AND );
753 ret = pen_region( pdev, region );
754 DeleteObject( region );
759 /***********************************************************************
762 * Returns the binary rop that is equivalent to the provided ternary rop
763 * if the src bits are ignored.
765 static inline INT get_rop2_from_rop(INT rop)
767 return (((rop >> 18) & 0x0c) | ((rop >> 16) & 0x03)) + 1;
770 /***********************************************************************
773 BOOL dibdrv_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
775 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
777 TRACE("(%p, %d, %d, %d, %d, %06x)\n", dev, dst->x, dst->y, dst->width, dst->height, rop);
779 return brush_rect( pdev, &pdev->brush, &dst->visrect, pdev->clip, get_rop2_from_rop(rop) );
782 /***********************************************************************
785 BOOL dibdrv_PaintRgn( PHYSDEV dev, HRGN rgn )
787 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
788 const WINEREGION *region;
792 TRACE("%p, %p\n", dev, rgn);
794 region = get_wine_region( rgn );
795 if(!region) return FALSE;
797 for(i = 0; i < region->numRects; i++)
799 rect = get_device_rect( dev->hdc, region->rects[i].left, region->rects[i].top,
800 region->rects[i].right, region->rects[i].bottom, FALSE );
801 brush_rect( pdev, &pdev->brush, &rect, pdev->clip, GetROP2( dev->hdc ) );
804 release_wine_region( rgn );
808 /***********************************************************************
811 BOOL dibdrv_PolyPolygon( PHYSDEV dev, const POINT *pt, const INT *counts, DWORD polygons )
813 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
817 HRGN outline = 0, interior = 0;
819 for (i = total = 0; i < polygons; i++)
821 if (counts[i] < 2) return FALSE;
825 points = HeapAlloc( GetProcessHeap(), 0, total * sizeof(*pt) );
826 if (!points) return FALSE;
827 memcpy( points, pt, total * sizeof(*pt) );
828 LPtoDP( dev->hdc, points, total );
830 if (pdev->brush.style != BS_NULL &&
831 !(interior = CreatePolyPolygonRgn( points, counts, polygons, GetPolyFillMode( dev->hdc ))))
833 HeapFree( GetProcessHeap(), 0, points );
837 if (pdev->pen_uses_region) outline = CreateRectRgn( 0, 0, 0, 0 );
839 /* if not using a region, paint the interior first so the outline can overlap it */
840 if (interior && !outline)
842 ret = brush_region( pdev, interior );
843 DeleteObject( interior );
847 for (i = pos = 0; i < polygons; i++)
849 reset_dash_origin( pdev );
850 pdev->pen_lines( pdev, counts[i], points + pos, TRUE, outline );
856 CombineRgn( interior, interior, outline, RGN_DIFF );
857 ret = brush_region( pdev, interior );
858 DeleteObject( interior );
862 if (ret) ret = pen_region( pdev, outline );
863 DeleteObject( outline );
865 HeapFree( GetProcessHeap(), 0, points );
869 /***********************************************************************
870 * dibdrv_PolyPolyline
872 BOOL dibdrv_PolyPolyline( PHYSDEV dev, const POINT* pt, const DWORD* counts, DWORD polylines )
874 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
875 DWORD max_points = 0, i;
880 for (i = 0; i < polylines; i++)
882 if (counts[i] < 2) return FALSE;
883 max_points = max( counts[i], max_points );
886 points = HeapAlloc( GetProcessHeap(), 0, max_points * sizeof(*pt) );
887 if (!points) return FALSE;
889 if (pdev->pen_uses_region && !(outline = CreateRectRgn( 0, 0, 0, 0 )))
891 HeapFree( GetProcessHeap(), 0, points );
895 for (i = 0; i < polylines; i++)
897 memcpy( points, pt, counts[i] * sizeof(*pt) );
899 LPtoDP( dev->hdc, points, counts[i] );
901 reset_dash_origin( pdev );
902 pdev->pen_lines( pdev, counts[i], points, FALSE, outline );
907 if (pdev->clip) CombineRgn( outline, outline, pdev->clip, RGN_AND );
908 ret = pen_region( pdev, outline );
909 DeleteObject( outline );
912 HeapFree( GetProcessHeap(), 0, points );
916 /***********************************************************************
919 BOOL dibdrv_Polygon( PHYSDEV dev, const POINT *pt, INT count )
921 INT counts[1] = { count };
923 return dibdrv_PolyPolygon( dev, pt, counts, 1 );
926 /***********************************************************************
929 BOOL dibdrv_Polyline( PHYSDEV dev, const POINT* pt, INT count )
931 DWORD counts[1] = { count };
933 if (count < 0) return FALSE;
934 return dibdrv_PolyPolyline( dev, pt, counts, 1 );
937 /***********************************************************************
940 BOOL dibdrv_Rectangle( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
942 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
948 TRACE("(%p, %d, %d, %d, %d)\n", dev, left, top, right, bottom);
950 if (!get_pen_device_rect( pdev, &rect, left, top, right, bottom )) return TRUE;
952 if (pdev->pen_uses_region && !(outline = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
956 reset_dash_origin(pdev);
958 if (GetArcDirection( dev->hdc ) == AD_CLOCKWISE)
960 /* 4 pts going clockwise starting from bottom-right */
961 pts[0].x = pts[3].x = rect.right;
962 pts[0].y = pts[1].y = rect.bottom;
963 pts[1].x = pts[2].x = rect.left;
964 pts[2].y = pts[3].y = rect.top;
968 /* 4 pts going anti-clockwise starting from top-right */
969 pts[0].x = pts[3].x = rect.right;
970 pts[0].y = pts[1].y = rect.top;
971 pts[1].x = pts[2].x = rect.left;
972 pts[2].y = pts[3].y = rect.bottom;
975 pdev->pen_lines(pdev, 4, pts, TRUE, outline);
979 if (pdev->brush.style != BS_NULL)
981 HRGN interior = CreateRectRgnIndirect( &rect );
983 CombineRgn( interior, interior, outline, RGN_DIFF );
984 brush_region( pdev, interior );
985 DeleteObject( interior );
987 ret = pen_region( pdev, outline );
988 DeleteObject( outline );
992 rect.left += (pdev->pen_width + 1) / 2;
993 rect.top += (pdev->pen_width + 1) / 2;
994 rect.right -= pdev->pen_width / 2;
995 rect.bottom -= pdev->pen_width / 2;
996 ret = brush_rect( pdev, &pdev->brush, &rect, pdev->clip, GetROP2(dev->hdc) );
1001 /***********************************************************************
1004 BOOL dibdrv_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
1005 INT ellipse_width, INT ellipse_height )
1007 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
1009 POINT pt[2], *points;
1012 HRGN outline = 0, interior = 0;
1014 if (!get_pen_device_rect( pdev, &rect, left, top, right, bottom )) return TRUE;
1016 pt[0].x = pt[0].y = 0;
1017 pt[1].x = ellipse_width;
1018 pt[1].y = ellipse_height;
1019 LPtoDP( dev->hdc, pt, 2 );
1020 ellipse_width = min( rect.right - rect.left, abs( pt[1].x - pt[0].x ));
1021 ellipse_height = min( rect.bottom - rect.top, abs( pt[1].y - pt[0].y ));
1022 if (ellipse_width <= 2|| ellipse_height <= 2)
1023 return dibdrv_Rectangle( dev, left, top, right, bottom );
1025 points = HeapAlloc( GetProcessHeap(), 0, (ellipse_width + ellipse_height) * 2 * sizeof(*points) );
1026 if (!points) return FALSE;
1028 if (pdev->pen_uses_region && !(outline = CreateRectRgn( 0, 0, 0, 0 )))
1030 HeapFree( GetProcessHeap(), 0, points );
1034 if (pdev->brush.style != BS_NULL &&
1035 !(interior = CreateRoundRectRgn( rect.left, rect.top, rect.right + 1, rect.bottom + 1,
1036 ellipse_width, ellipse_height )))
1038 HeapFree( GetProcessHeap(), 0, points );
1042 if (pdev->pen_uses_region) outline = CreateRectRgn( 0, 0, 0, 0 );
1044 /* if not using a region, paint the interior first so the outline can overlap it */
1045 if (interior && !outline)
1047 ret = brush_region( pdev, interior );
1048 DeleteObject( interior );
1052 count = ellipse_first_quadrant( ellipse_width, ellipse_height, points );
1054 if (GetArcDirection( dev->hdc ) == AD_CLOCKWISE)
1056 for (i = 0; i < count; i++)
1058 points[i].x = rect.right - ellipse_width + points[i].x;
1059 points[i].y = rect.bottom - ellipse_height + points[i].y;
1064 for (i = 0; i < count; i++)
1066 points[i].x = rect.right - ellipse_width + points[i].x;
1067 points[i].y = rect.top + ellipse_height - 1 - points[i].y;
1071 /* horizontal symmetry */
1073 end = 2 * count - 1;
1074 /* avoid duplicating the midpoint */
1075 if (ellipse_width % 2 && ellipse_width == rect.right - rect.left) end--;
1076 for (i = 0; i < count; i++)
1078 points[end - i].x = rect.left + rect.right - 1 - points[i].x;
1079 points[end - i].y = points[i].y;
1083 /* vertical symmetry */
1085 end = 2 * count - 1;
1086 /* avoid duplicating the midpoint */
1087 if (ellipse_height % 2 && ellipse_height == rect.bottom - rect.top) end--;
1088 for (i = 0; i < count; i++)
1090 points[end - i].x = points[i].x;
1091 points[end - i].y = rect.top + rect.bottom - 1 - points[i].y;
1095 reset_dash_origin( pdev );
1096 pdev->pen_lines( pdev, count, points, TRUE, outline );
1100 CombineRgn( interior, interior, outline, RGN_DIFF );
1101 ret = brush_region( pdev, interior );
1102 DeleteObject( interior );
1106 if (ret) ret = pen_region( pdev, outline );
1107 DeleteObject( outline );
1109 HeapFree( GetProcessHeap(), 0, points );
1113 /***********************************************************************
1116 BOOL dibdrv_Pie( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
1117 INT start_x, INT start_y, INT end_x, INT end_y )
1119 return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, 2 );
1122 /***********************************************************************
1125 COLORREF dibdrv_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color )
1127 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
1128 struct clipped_rects clipped_rects;
1133 TRACE( "(%p, %d, %d, %08x)\n", dev, x, y, color );
1137 LPtoDP( dev->hdc, &pt, 1 );
1140 rect.right = rect.left + 1;
1141 rect.bottom = rect.top + 1;
1143 /* SetPixel doesn't do the 1bpp massaging like other fg colors */
1144 pixel = get_pixel_color( pdev, color, FALSE );
1145 color = pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
1147 if (!get_clipped_rects( &pdev->dib, &rect, pdev->clip, &clipped_rects )) return color;
1148 pdev->dib.funcs->solid_rects( &pdev->dib, clipped_rects.count, clipped_rects.rects, 0, pixel );
1149 free_clipped_rects( &clipped_rects );