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 /***********************************************************************
682 * dibdrv_ExtFloodFill
684 BOOL dibdrv_ExtFloodFill( PHYSDEV dev, INT x, INT y, COLORREF color, UINT type )
686 FIXME( "not implemented yet\n" );
690 /***********************************************************************
691 * dibdrv_GetNearestColor
693 COLORREF dibdrv_GetNearestColor( PHYSDEV dev, COLORREF color )
695 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
698 TRACE( "(%p, %08x)\n", dev, color );
700 pixel = get_pixel_color( pdev, color, FALSE );
701 return pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
704 /***********************************************************************
707 COLORREF dibdrv_GetPixel( PHYSDEV dev, INT x, INT y )
709 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
713 TRACE( "(%p, %d, %d)\n", dev, x, y );
717 LPtoDP( dev->hdc, &pt, 1 );
719 if (pt.x < 0 || pt.x >= pdev->dib.width ||
720 pt.y < 0 || pt.y >= pdev->dib.height)
723 pixel = pdev->dib.funcs->get_pixel( &pdev->dib, &pt );
724 return pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
727 /***********************************************************************
730 BOOL dibdrv_LineTo( PHYSDEV dev, INT x, INT y )
732 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
737 GetCurrentPositionEx(dev->hdc, pts);
741 LPtoDP(dev->hdc, pts, 2);
743 if (pdev->pen_uses_region && !(region = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
745 reset_dash_origin(pdev);
747 ret = pdev->pen_lines(pdev, 2, pts, FALSE, region);
751 if (pdev->clip) CombineRgn( region, region, pdev->clip, RGN_AND );
752 ret = pen_region( pdev, region );
753 DeleteObject( region );
758 /***********************************************************************
761 * Returns the binary rop that is equivalent to the provided ternary rop
762 * if the src bits are ignored.
764 static inline INT get_rop2_from_rop(INT rop)
766 return (((rop >> 18) & 0x0c) | ((rop >> 16) & 0x03)) + 1;
769 /***********************************************************************
772 BOOL dibdrv_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
774 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
776 TRACE("(%p, %d, %d, %d, %d, %06x)\n", dev, dst->x, dst->y, dst->width, dst->height, rop);
778 return brush_rect( pdev, &pdev->brush, &dst->visrect, pdev->clip, get_rop2_from_rop(rop) );
781 /***********************************************************************
784 BOOL dibdrv_PaintRgn( PHYSDEV dev, HRGN rgn )
786 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
787 const WINEREGION *region;
791 TRACE("%p, %p\n", dev, rgn);
793 region = get_wine_region( rgn );
794 if(!region) return FALSE;
796 for(i = 0; i < region->numRects; i++)
798 rect = get_device_rect( dev->hdc, region->rects[i].left, region->rects[i].top,
799 region->rects[i].right, region->rects[i].bottom, FALSE );
800 brush_rect( pdev, &pdev->brush, &rect, pdev->clip, GetROP2( dev->hdc ) );
803 release_wine_region( rgn );
807 /***********************************************************************
810 BOOL dibdrv_PolyPolygon( PHYSDEV dev, const POINT *pt, const INT *counts, DWORD polygons )
812 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
816 HRGN outline = 0, interior = 0;
818 for (i = total = 0; i < polygons; i++)
820 if (counts[i] < 2) return FALSE;
824 points = HeapAlloc( GetProcessHeap(), 0, total * sizeof(*pt) );
825 if (!points) return FALSE;
826 memcpy( points, pt, total * sizeof(*pt) );
827 LPtoDP( dev->hdc, points, total );
829 if (pdev->brush.style != BS_NULL &&
830 !(interior = CreatePolyPolygonRgn( points, counts, polygons, GetPolyFillMode( dev->hdc ))))
832 HeapFree( GetProcessHeap(), 0, points );
836 if (pdev->pen_uses_region) outline = CreateRectRgn( 0, 0, 0, 0 );
838 /* if not using a region, paint the interior first so the outline can overlap it */
839 if (interior && !outline)
841 ret = brush_region( pdev, interior );
842 DeleteObject( interior );
846 for (i = pos = 0; i < polygons; i++)
848 reset_dash_origin( pdev );
849 pdev->pen_lines( pdev, counts[i], points + pos, TRUE, outline );
855 CombineRgn( interior, interior, outline, RGN_DIFF );
856 ret = brush_region( pdev, interior );
857 DeleteObject( interior );
861 if (ret) ret = pen_region( pdev, outline );
862 DeleteObject( outline );
864 HeapFree( GetProcessHeap(), 0, points );
868 /***********************************************************************
869 * dibdrv_PolyPolyline
871 BOOL dibdrv_PolyPolyline( PHYSDEV dev, const POINT* pt, const DWORD* counts, DWORD polylines )
873 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
874 DWORD max_points = 0, i;
879 for (i = 0; i < polylines; i++)
881 if (counts[i] < 2) return FALSE;
882 max_points = max( counts[i], max_points );
885 points = HeapAlloc( GetProcessHeap(), 0, max_points * sizeof(*pt) );
886 if (!points) return FALSE;
888 if (pdev->pen_uses_region && !(outline = CreateRectRgn( 0, 0, 0, 0 )))
890 HeapFree( GetProcessHeap(), 0, points );
894 for (i = 0; i < polylines; i++)
896 memcpy( points, pt, counts[i] * sizeof(*pt) );
898 LPtoDP( dev->hdc, points, counts[i] );
900 reset_dash_origin( pdev );
901 pdev->pen_lines( pdev, counts[i], points, FALSE, outline );
906 if (pdev->clip) CombineRgn( outline, outline, pdev->clip, RGN_AND );
907 ret = pen_region( pdev, outline );
908 DeleteObject( outline );
911 HeapFree( GetProcessHeap(), 0, points );
915 /***********************************************************************
918 BOOL dibdrv_Polygon( PHYSDEV dev, const POINT *pt, INT count )
920 INT counts[1] = { count };
922 return dibdrv_PolyPolygon( dev, pt, counts, 1 );
925 /***********************************************************************
928 BOOL dibdrv_Polyline( PHYSDEV dev, const POINT* pt, INT count )
930 DWORD counts[1] = { count };
932 if (count < 0) return FALSE;
933 return dibdrv_PolyPolyline( dev, pt, counts, 1 );
936 /***********************************************************************
939 BOOL dibdrv_Rectangle( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
941 dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
947 TRACE("(%p, %d, %d, %d, %d)\n", dev, left, top, right, bottom);
949 if (!get_pen_device_rect( pdev, &rect, left, top, right, bottom )) return TRUE;
951 if (pdev->pen_uses_region && !(outline = CreateRectRgn( 0, 0, 0, 0 ))) return FALSE;
955 reset_dash_origin(pdev);
957 if (GetArcDirection( dev->hdc ) == AD_CLOCKWISE)
959 /* 4 pts going clockwise starting from bottom-right */
960 pts[0].x = pts[3].x = rect.right;
961 pts[0].y = pts[1].y = rect.bottom;
962 pts[1].x = pts[2].x = rect.left;
963 pts[2].y = pts[3].y = rect.top;
967 /* 4 pts going anti-clockwise starting from top-right */
968 pts[0].x = pts[3].x = rect.right;
969 pts[0].y = pts[1].y = rect.top;
970 pts[1].x = pts[2].x = rect.left;
971 pts[2].y = pts[3].y = rect.bottom;
974 pdev->pen_lines(pdev, 4, pts, TRUE, outline);
978 if (pdev->brush.style != BS_NULL)
980 HRGN interior = CreateRectRgnIndirect( &rect );
982 CombineRgn( interior, interior, outline, RGN_DIFF );
983 brush_region( pdev, interior );
984 DeleteObject( interior );
986 ret = pen_region( pdev, outline );
987 DeleteObject( outline );
991 rect.left += (pdev->pen_width + 1) / 2;
992 rect.top += (pdev->pen_width + 1) / 2;
993 rect.right -= pdev->pen_width / 2;
994 rect.bottom -= pdev->pen_width / 2;
995 ret = brush_rect( pdev, &pdev->brush, &rect, pdev->clip, GetROP2(dev->hdc) );
1000 /***********************************************************************
1003 BOOL dibdrv_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
1004 INT ellipse_width, INT ellipse_height )
1006 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
1008 POINT pt[2], *points;
1011 HRGN outline = 0, interior = 0;
1013 if (!get_pen_device_rect( pdev, &rect, left, top, right, bottom )) return TRUE;
1015 pt[0].x = pt[0].y = 0;
1016 pt[1].x = ellipse_width;
1017 pt[1].y = ellipse_height;
1018 LPtoDP( dev->hdc, pt, 2 );
1019 ellipse_width = min( rect.right - rect.left, abs( pt[1].x - pt[0].x ));
1020 ellipse_height = min( rect.bottom - rect.top, abs( pt[1].y - pt[0].y ));
1021 if (ellipse_width <= 2|| ellipse_height <= 2)
1022 return dibdrv_Rectangle( dev, left, top, right, bottom );
1024 points = HeapAlloc( GetProcessHeap(), 0, (ellipse_width + ellipse_height) * 2 * sizeof(*points) );
1025 if (!points) return FALSE;
1027 if (pdev->pen_uses_region && !(outline = CreateRectRgn( 0, 0, 0, 0 )))
1029 HeapFree( GetProcessHeap(), 0, points );
1033 if (pdev->brush.style != BS_NULL &&
1034 !(interior = CreateRoundRectRgn( rect.left, rect.top, rect.right + 1, rect.bottom + 1,
1035 ellipse_width, ellipse_height )))
1037 HeapFree( GetProcessHeap(), 0, points );
1038 if (outline) DeleteObject( outline );
1042 /* if not using a region, paint the interior first so the outline can overlap it */
1043 if (interior && !outline)
1045 ret = brush_region( pdev, interior );
1046 DeleteObject( interior );
1050 count = ellipse_first_quadrant( ellipse_width, ellipse_height, points );
1052 if (GetArcDirection( dev->hdc ) == AD_CLOCKWISE)
1054 for (i = 0; i < count; i++)
1056 points[i].x = rect.right - ellipse_width + points[i].x;
1057 points[i].y = rect.bottom - ellipse_height + points[i].y;
1062 for (i = 0; i < count; i++)
1064 points[i].x = rect.right - ellipse_width + points[i].x;
1065 points[i].y = rect.top + ellipse_height - 1 - points[i].y;
1069 /* horizontal symmetry */
1071 end = 2 * count - 1;
1072 /* avoid duplicating the midpoint */
1073 if (ellipse_width % 2 && ellipse_width == rect.right - rect.left) end--;
1074 for (i = 0; i < count; i++)
1076 points[end - i].x = rect.left + rect.right - 1 - points[i].x;
1077 points[end - i].y = points[i].y;
1081 /* vertical symmetry */
1083 end = 2 * count - 1;
1084 /* avoid duplicating the midpoint */
1085 if (ellipse_height % 2 && ellipse_height == rect.bottom - rect.top) end--;
1086 for (i = 0; i < count; i++)
1088 points[end - i].x = points[i].x;
1089 points[end - i].y = rect.top + rect.bottom - 1 - points[i].y;
1093 reset_dash_origin( pdev );
1094 pdev->pen_lines( pdev, count, points, TRUE, outline );
1098 CombineRgn( interior, interior, outline, RGN_DIFF );
1099 ret = brush_region( pdev, interior );
1100 DeleteObject( interior );
1104 if (ret) ret = pen_region( pdev, outline );
1105 DeleteObject( outline );
1107 HeapFree( GetProcessHeap(), 0, points );
1111 /***********************************************************************
1114 BOOL dibdrv_Pie( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
1115 INT start_x, INT start_y, INT end_x, INT end_y )
1117 return draw_arc( dev, left, top, right, bottom, start_x, start_y, end_x, end_y, 2 );
1120 /***********************************************************************
1123 COLORREF dibdrv_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color )
1125 dibdrv_physdev *pdev = get_dibdrv_pdev( dev );
1126 struct clipped_rects clipped_rects;
1131 TRACE( "(%p, %d, %d, %08x)\n", dev, x, y, color );
1135 LPtoDP( dev->hdc, &pt, 1 );
1138 rect.right = rect.left + 1;
1139 rect.bottom = rect.top + 1;
1141 /* SetPixel doesn't do the 1bpp massaging like other fg colors */
1142 pixel = get_pixel_color( pdev, color, FALSE );
1143 color = pdev->dib.funcs->pixel_to_colorref( &pdev->dib, pixel );
1145 if (!get_clipped_rects( &pdev->dib, &rect, pdev->clip, &clipped_rects )) return color;
1146 pdev->dib.funcs->solid_rects( &pdev->dib, clipped_rects.count, clipped_rects.rects, 0, pixel );
1147 free_clipped_rects( &clipped_rects );