2 * DIB driver GDI objects.
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
24 #include "gdi_private.h"
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(dib
);
33 * Decompose the 16 ROP2s into an expression of the form
37 * Where A and X depend only on P (and so can be precomputed).
42 * R2_NOTMERGEPEN ~(D | P) ~P ~P
43 * R2_MASKNOTPEN ~P & D ~P 0
44 * R2_NOTCOPYPEN ~P 0 ~P
45 * R2_MASKPENNOT P & ~D P P
48 * R2_NOTMASKPEN ~(P & D) P 1
49 * R2_MASKPEN P & D P 0
50 * R2_NOTXORPEN ~(P ^ D) 1 ~P
52 * R2_MERGENOTPEN ~P | D P ~P
54 * R2_MERGEPENNOT P | ~D ~P 1
55 * R2_MERGEPEN P | D ~P P
60 /* A = (P & A1) ^ A2 */
61 #define ZERO { 0u, 0u}
62 #define ONE { 0u, ~0u}
64 #define NOT_P {~0u, ~0u}
66 static const DWORD rop2_and_array
[16][2] =
68 ZERO
, NOT_P
, NOT_P
, ZERO
,
71 ZERO
, NOT_P
, NOT_P
, ZERO
74 /* X = (P & X1) ^ X2 */
75 static const DWORD rop2_xor_array
[16][2] =
77 ZERO
, NOT_P
, ZERO
, NOT_P
,
79 ZERO
, NOT_P
, ZERO
, NOT_P
,
88 void get_rop_codes(INT rop
, struct rop_codes
*codes
)
90 /* NB The ROP2 codes start at one and the arrays are zero-based */
91 codes
->a1
= rop2_and_array
[rop
-1][0];
92 codes
->a2
= rop2_and_array
[rop
-1][1];
93 codes
->x1
= rop2_xor_array
[rop
-1][0];
94 codes
->x2
= rop2_xor_array
[rop
-1][1];
97 static inline void calc_and_xor_masks(INT rop
, DWORD color
, DWORD
*and, DWORD
*xor)
99 struct rop_codes codes
;
100 get_rop_codes( rop
, &codes
);
102 *and = (color
& codes
.a1
) ^ codes
.a2
;
103 *xor = (color
& codes
.x1
) ^ codes
.x2
;
106 static inline void calc_rop_masks(INT rop
, DWORD color
, rop_mask
*masks
)
108 calc_and_xor_masks( rop
, color
, &masks
->and, &masks
->xor );
111 static inline BOOL
rop_needs_and_mask( INT rop
)
113 struct rop_codes codes
;
114 get_rop_codes( rop
, &codes
);
115 return codes
.a1
|| codes
.a2
;
118 static inline RGBQUAD
rgbquad_from_colorref(COLORREF c
)
122 ret
.rgbRed
= GetRValue(c
);
123 ret
.rgbGreen
= GetGValue(c
);
124 ret
.rgbBlue
= GetBValue(c
);
129 static inline BOOL
rgbquad_equal(const RGBQUAD
*a
, const RGBQUAD
*b
)
131 if(a
->rgbRed
== b
->rgbRed
&&
132 a
->rgbGreen
== b
->rgbGreen
&&
133 a
->rgbBlue
== b
->rgbBlue
)
138 static COLORREF
make_rgb_colorref( DC
*dc
, const dib_info
*dib
, COLORREF color
,
139 BOOL
*got_pixel
, DWORD
*pixel
)
144 if (color
& (1 << 24)) /* PALETTEINDEX */
146 PALETTEENTRY pal_ent
;
148 if (!GetPaletteEntries( dc
->hPalette
, LOWORD(color
), 1, &pal_ent
))
149 GetPaletteEntries( dc
->hPalette
, 0, 1, &pal_ent
);
150 return RGB( pal_ent
.peRed
, pal_ent
.peGreen
, pal_ent
.peBlue
);
153 if (color
>> 16 == 0x10ff) /* DIBINDEX */
155 const RGBQUAD
*color_table
= get_dib_color_table( dib
);
156 WORD index
= LOWORD( color
);
158 if (!color_table
|| index
>= (1 << dib
->bit_count
)) return 0;
160 return RGB( color_table
[index
].rgbRed
, color_table
[index
].rgbGreen
, color_table
[index
].rgbBlue
);
163 return color
& 0xffffff;
166 /******************************************************************
169 * 1 bit bitmaps map the fg/bg colors as follows:
170 * If the fg colorref exactly matches one of the color table entries then
171 * that entry is the fg color and the other is the bg.
172 * Otherwise the bg color is mapped to the closest entry in the table and
173 * the fg takes the other one.
175 DWORD
get_pixel_color( DC
*dc
, const dib_info
*dib
, COLORREF color
, BOOL mono_fixup
)
181 const RGBQUAD
*color_table
;
183 rgb_ref
= make_rgb_colorref( dc
, dib
, color
, &got_pixel
, &pixel
);
184 if (got_pixel
) return pixel
;
186 if (dib
->bit_count
!= 1 || !mono_fixup
)
187 return dib
->funcs
->colorref_to_pixel( dib
, rgb_ref
);
189 color_table
= get_dib_color_table( dib
);
190 fg_quad
= rgbquad_from_colorref( rgb_ref
);
191 if(rgbquad_equal(&fg_quad
, color_table
))
193 if(rgbquad_equal(&fg_quad
, color_table
+ 1))
196 pixel
= get_pixel_color( dc
, dib
, dc
->backgroundColor
, FALSE
);
197 if (color
== dc
->backgroundColor
) return pixel
;
201 /***************************************************************************
204 * Returns the color masks unless the dib is 1 bpp. In this case since
205 * there are several fg sources (pen, brush, text) we take as bg the inverse
206 * of the relevant fg color (which is always set up correctly).
208 static inline void get_color_masks( DC
*dc
, const dib_info
*dib
, UINT rop
, COLORREF colorref
,
209 INT bkgnd_mode
, rop_mask
*fg_mask
, rop_mask
*bg_mask
)
211 DWORD color
= get_pixel_color( dc
, dib
, colorref
, TRUE
);
213 calc_rop_masks( rop
, color
, fg_mask
);
215 if (bkgnd_mode
== TRANSPARENT
)
222 if (dib
->bit_count
!= 1) color
= get_pixel_color( dc
, dib
, dc
->backgroundColor
, FALSE
);
223 else if (colorref
!= dc
->backgroundColor
) color
= !color
;
225 calc_rop_masks( rop
, color
, bg_mask
);
228 static inline void order_end_points(int *s
, int *e
)
239 #define Y_INCREASING_MASK 0x0f
240 #define X_INCREASING_MASK 0xc3
241 #define X_MAJOR_MASK 0x99
242 #define POS_SLOPE_MASK 0x33
244 static inline BOOL
is_xmajor(DWORD octant
)
246 return octant
& X_MAJOR_MASK
;
249 static inline BOOL
is_pos_slope(DWORD octant
)
251 return octant
& POS_SLOPE_MASK
;
254 static inline BOOL
is_x_increasing(DWORD octant
)
256 return octant
& X_INCREASING_MASK
;
259 static inline BOOL
is_y_increasing(DWORD octant
)
261 return octant
& Y_INCREASING_MASK
;
264 /**********************************************************************
267 * Return the octant number starting clockwise from the +ve x-axis.
269 static inline int get_octant_number(int dx
, int dy
)
273 return ( dx
> dy
) ? 1 : 2;
275 return (-dx
> dy
) ? 4 : 3;
278 return (-dx
> -dy
) ? 5 : 6;
280 return ( dx
> -dy
) ? 8 : 7;
283 static inline DWORD
get_octant_mask(int dx
, int dy
)
285 return 1 << (get_octant_number(dx
, dy
) - 1);
288 static inline int get_bias( DWORD mask
)
290 /* Octants 3, 5, 6 and 8 take a bias */
291 return (mask
& 0xb4) ? 1 : 0;
299 static inline DWORD
calc_outcode(const POINT
*pt
, const RECT
*clip
)
302 if(pt
->x
< clip
->left
) out
|= OUT_LEFT
;
303 else if(pt
->x
>= clip
->right
) out
|= OUT_RIGHT
;
304 if(pt
->y
< clip
->top
) out
|= OUT_TOP
;
305 else if(pt
->y
>= clip
->bottom
) out
|= OUT_BOTTOM
;
310 /* crop coordinates to a reasonable range to avoid overflows in calculations */
311 static inline POINT
crop_coords( POINT pt
)
313 if (pt
.x
>= 0x10000000 || pt
.x
<= -0x10000000 || pt
.y
>= 0x10000000 || pt
.y
<= -0x10000000)
321 static void init_bres_params( const POINT
*start
, const POINT
*end
, bres_params
*clip_params
,
322 struct line_params
*line_params
, RECT
*rect
)
324 INT dx
= end
->x
- start
->x
, dy
= end
->y
- start
->y
;
325 INT abs_dx
= abs(dx
), abs_dy
= abs(dy
);
327 clip_params
->dx
= abs_dx
;
328 clip_params
->dy
= abs_dy
;
329 clip_params
->octant
= get_octant_mask(dx
, dy
);
330 clip_params
->bias
= get_bias( clip_params
->octant
);
332 line_params
->bias
= clip_params
->bias
;
333 line_params
->x_major
= is_xmajor( clip_params
->octant
);
334 line_params
->x_inc
= is_x_increasing( clip_params
->octant
) ? 1 : -1;
335 line_params
->y_inc
= is_y_increasing( clip_params
->octant
) ? 1 : -1;
337 if (line_params
->x_major
)
339 line_params
->err_add_1
= 2 * abs_dy
- 2 * abs_dx
;
340 line_params
->err_add_2
= 2 * abs_dy
;
344 line_params
->err_add_1
= 2 * abs_dx
- 2 * abs_dy
;
345 line_params
->err_add_2
= 2 * abs_dx
;
348 rect
->left
= min( start
->x
, end
->x
);
349 rect
->top
= min( start
->y
, end
->y
);
350 rect
->right
= max( start
->x
, end
->x
) + 1;
351 rect
->bottom
= max( start
->y
, end
->y
) + 1;
354 /******************************************************************************
357 * Clips the start and end points to a rectangle.
359 * Note, this treats the end point like the start point. If the
360 * caller doesn't want it displayed, it should exclude it. If the end
361 * point is clipped out, then the likelihood is that the new end point
362 * should be displayed.
364 * Returns 0 if totally excluded, 1 if partially clipped and 2 if unclipped.
366 * This derivation is based on the comments in X.org's xserver/mi/mizerclip.c,
367 * however the Bresenham error term is defined differently so the equations
370 * For x major lines we have 2dy >= err + bias > 2dy - 2dx
371 * 0 >= err + bias - 2dy > -2dx
373 * Note dx, dy, m and n are all +ve.
375 * Moving the start pt from x1 to x1 + m, we need to figure out y1 + n.
376 * err = 2dy - dx + 2mdy - 2ndx
377 * 0 >= 2dy - dx + 2mdy - 2ndx + bias - 2dy > -2dx
378 * 0 >= 2mdy - 2ndx + bias - dx > -2dx
379 * which of course will give exactly one solution for n,
380 * so looking at the >= inequality
381 * n >= (2mdy + bias - dx) / 2dx
382 * n = ceiling((2mdy + bias - dx) / 2dx)
383 * = (2mdy + bias + dx - 1) / 2dx (assuming division truncation)
385 * Moving start pt from y1 to y1 + n we need to figure out x1 + m - there may be several
386 * solutions we pick the one that minimizes m (ie that first unlipped pt). As above:
387 * 0 >= 2mdy - 2ndx + bias - dx > -2dx
388 * 2mdy > 2ndx - bias - dx
389 * m > (2ndx - bias - dx) / 2dy
390 * m = floor((2ndx - bias - dx) / 2dy) + 1
391 * m = (2ndx - bias - dx) / 2dy + 1
393 * Moving end pt from x2 to x2 - m, we need to figure out y2 - n
394 * err = 2dy - dx + 2(dx - m)dy - 2(dy - n)dx
395 * = 2dy - dx - 2mdy + 2ndx
396 * 0 >= 2dy - dx - 2mdy + 2ndx + bias - 2dy > -2dx
397 * 0 >= 2ndx - 2mdy + bias - dx > -2dx
398 * again exactly one solution.
399 * 2ndx <= 2mdy - bias + dx
400 * n = floor((2mdy - bias + dx) / 2dx)
401 * = (2mdy - bias + dx) / 2dx
403 * Moving end pt from y2 to y2 - n when need x2 - m this time maximizing x2 - m so
404 * mininizing m to include all of the points at y = y2 - n. As above:
405 * 0 >= 2ndx - 2mdy + bias - dx > -2dx
406 * 2mdy >= 2ndx + bias - dx
407 * m = ceiling((2ndx + bias - dx) / 2dy)
408 * = (2ndx + bias - dx - 1) / 2dy + 1
410 * For y major lines, symmetry (dx <-> dy and swap the cases over) gives:
412 * Moving start point from y1 to y1 + n find x1 + m
413 * m = (2ndx + bias + dy - 1) / 2dy
415 * Moving start point from x1 to x1 + m find y1 + n
416 * n = (2mdy - bias - dy) / 2ndx + 1
418 * Moving end point from y2 to y2 - n find x1 - m
419 * m = (2ndx - bias + dy) / 2dy
421 * Moving end point from x2 to x2 - m find y2 - n
422 * n = (2mdy + bias - dy - 1) / 2dx + 1
424 int clip_line(const POINT
*start
, const POINT
*end
, const RECT
*clip
,
425 const bres_params
*params
, POINT
*pt1
, POINT
*pt2
)
428 INT64 m
, n
; /* 64-bit to avoid overflows (FIXME: find a more efficient way) */
429 BOOL clipped
= FALSE
;
430 DWORD start_oc
, end_oc
;
431 const int bias
= params
->bias
;
432 const unsigned int dx
= params
->dx
;
433 const unsigned int dy
= params
->dy
;
434 const unsigned int two_dx
= params
->dx
* 2;
435 const unsigned int two_dy
= params
->dy
* 2;
436 const BOOL xmajor
= is_xmajor(params
->octant
);
437 const BOOL neg_slope
= !is_pos_slope(params
->octant
);
442 start_oc
= calc_outcode(start
, clip
);
443 end_oc
= calc_outcode(end
, clip
);
447 if(start_oc
== 0 && end_oc
== 0) return clipped
? 1 : 2; /* trivial accept */
448 if(start_oc
& end_oc
) return 0; /* trivial reject */
451 if(start_oc
& OUT_LEFT
)
453 m
= clip
->left
- start
->x
;
455 n
= (m
* two_dy
+ bias
+ dx
- 1) / two_dx
;
457 n
= (m
* two_dy
- bias
- dy
) / two_dx
+ 1;
460 if(neg_slope
) n
= -n
;
461 pt1
->y
= start
->y
+ n
;
462 start_oc
= calc_outcode(pt1
, clip
);
464 else if(start_oc
& OUT_RIGHT
)
466 m
= start
->x
- clip
->right
+ 1;
468 n
= (m
* two_dy
+ bias
+ dx
- 1) / two_dx
;
470 n
= (m
* two_dy
- bias
- dy
) / two_dx
+ 1;
472 pt1
->x
= clip
->right
- 1;
473 if(neg_slope
) n
= -n
;
474 pt1
->y
= start
->y
- n
;
475 start_oc
= calc_outcode(pt1
, clip
);
477 else if(start_oc
& OUT_TOP
)
479 n
= clip
->top
- start
->y
;
481 m
= (n
* two_dx
- bias
- dx
) / two_dy
+ 1;
483 m
= (n
* two_dx
+ bias
+ dy
- 1) / two_dy
;
486 if(neg_slope
) m
= -m
;
487 pt1
->x
= start
->x
+ m
;
488 start_oc
= calc_outcode(pt1
, clip
);
490 else if(start_oc
& OUT_BOTTOM
)
492 n
= start
->y
- clip
->bottom
+ 1;
494 m
= (n
* two_dx
- bias
- dx
) / two_dy
+ 1;
496 m
= (n
* two_dx
+ bias
+ dy
- 1) / two_dy
;
498 pt1
->y
= clip
->bottom
- 1;
499 if(neg_slope
) m
= -m
;
500 pt1
->x
= start
->x
- m
;
501 start_oc
= calc_outcode(pt1
, clip
);
503 else if(end_oc
& OUT_LEFT
)
505 m
= clip
->left
- end
->x
;
507 n
= (m
* two_dy
- bias
+ dx
) / two_dx
;
509 n
= (m
* two_dy
+ bias
- dy
- 1) / two_dx
+ 1;
512 if(neg_slope
) n
= -n
;
514 end_oc
= calc_outcode(pt2
, clip
);
516 else if(end_oc
& OUT_RIGHT
)
518 m
= end
->x
- clip
->right
+ 1;
520 n
= (m
* two_dy
- bias
+ dx
) / two_dx
;
522 n
= (m
* two_dy
+ bias
- dy
- 1) / two_dx
+ 1;
524 pt2
->x
= clip
->right
- 1;
525 if(neg_slope
) n
= -n
;
527 end_oc
= calc_outcode(pt2
, clip
);
529 else if(end_oc
& OUT_TOP
)
531 n
= clip
->top
- end
->y
;
533 m
= (n
* two_dx
+ bias
- dx
- 1) / two_dy
+ 1;
535 m
= (n
* two_dx
- bias
+ dy
) / two_dy
;
538 if(neg_slope
) m
= -m
;
540 end_oc
= calc_outcode(pt2
, clip
);
542 else if(end_oc
& OUT_BOTTOM
)
544 n
= end
->y
- clip
->bottom
+ 1;
546 m
= (n
* two_dx
+ bias
- dx
- 1) / two_dy
+ 1;
548 m
= (n
* two_dx
- bias
+ dy
) / two_dy
;
550 pt2
->y
= clip
->bottom
- 1;
551 if(neg_slope
) m
= -m
;
553 end_oc
= calc_outcode(pt2
, clip
);
558 static void bres_line_with_bias(const POINT
*start
, const struct line_params
*params
,
559 void (* callback
)(dibdrv_physdev
*,INT
,INT
), dibdrv_physdev
*pdev
)
562 int len
= params
->length
, err
= params
->err_start
;
568 callback(pdev
, pt
.x
, pt
.y
);
569 if (err
+ params
->bias
> 0)
571 pt
.y
+= params
->y_inc
;
572 err
+= params
->err_add_1
;
574 else err
+= params
->err_add_2
;
575 pt
.x
+= params
->x_inc
;
582 callback(pdev
, pt
.x
, pt
.y
);
583 if (err
+ params
->bias
> 0)
585 pt
.x
+= params
->x_inc
;
586 err
+= params
->err_add_1
;
588 else err
+= params
->err_add_2
;
589 pt
.y
+= params
->y_inc
;
594 static BOOL
solid_pen_line(dibdrv_physdev
*pdev
, POINT
*start
, POINT
*end
, DWORD
and, DWORD
xor)
596 struct clipped_rects clipped_rects
;
600 if(start
->y
== end
->y
)
602 rect
.left
= start
->x
;
605 rect
.bottom
= end
->y
+ 1;
606 order_end_points(&rect
.left
, &rect
.right
);
607 if (!get_clipped_rects( &pdev
->dib
, &rect
, pdev
->clip
, &clipped_rects
)) return TRUE
;
608 pdev
->dib
.funcs
->solid_rects(&pdev
->dib
, clipped_rects
.count
, clipped_rects
.rects
, and, xor);
610 else if(start
->x
== end
->x
)
612 rect
.left
= start
->x
;
614 rect
.right
= end
->x
+ 1;
615 rect
.bottom
= end
->y
;
616 order_end_points(&rect
.top
, &rect
.bottom
);
617 if (!get_clipped_rects( &pdev
->dib
, &rect
, pdev
->clip
, &clipped_rects
)) return TRUE
;
618 pdev
->dib
.funcs
->solid_rects(&pdev
->dib
, clipped_rects
.count
, clipped_rects
.rects
, and, xor);
622 bres_params clip_params
;
623 struct line_params line_params
;
624 POINT p1
= crop_coords( *start
), p2
= crop_coords( *end
);
626 init_bres_params( &p1
, &p2
, &clip_params
, &line_params
, &rect
);
627 if (!get_clipped_rects( &pdev
->dib
, &rect
, pdev
->clip
, &clipped_rects
)) return TRUE
;
628 for (i
= 0; i
< clipped_rects
.count
; i
++)
630 POINT clipped_start
, clipped_end
;
633 clip_status
= clip_line( &p1
, &p2
, clipped_rects
.rects
+ i
, &clip_params
, &clipped_start
, &clipped_end
);
636 int m
= abs(clipped_start
.x
- p1
.x
);
637 int n
= abs(clipped_start
.y
- p1
.y
);
639 if (line_params
.x_major
)
641 line_params
.err_start
= 2 * clip_params
.dy
- clip_params
.dx
642 + m
* 2 * clip_params
.dy
- n
* 2 * clip_params
.dx
;
643 line_params
.length
= abs( clipped_end
.x
- clipped_start
.x
) + 1;
647 line_params
.err_start
= 2 * clip_params
.dx
- clip_params
.dy
648 + n
* 2 * clip_params
.dx
- m
* 2 * clip_params
.dy
;
649 line_params
.length
= abs( clipped_end
.y
- clipped_start
.y
) + 1;
652 if (clipped_end
.x
== p2
.x
&& clipped_end
.y
== p2
.y
) line_params
.length
--;
654 pdev
->dib
.funcs
->solid_line( &pdev
->dib
, &clipped_start
, &line_params
, and, xor );
656 if(clip_status
== 2) break; /* completely unclipped, so we can finish */
660 free_clipped_rects( &clipped_rects
);
664 static void solid_line_region( const dib_info
*dib
, const POINT
*start
, const struct line_params
*params
,
667 int len
, err
= params
->err_start
;
670 rect
.left
= start
->x
;
672 rect
.right
= start
->x
+ 1;
673 rect
.bottom
= start
->y
+ 1;
677 if (params
->x_inc
> 0)
679 for (len
= params
->length
; len
; len
--, rect
.right
++)
681 if (err
+ params
->bias
> 0)
683 add_rect_to_region( region
, &rect
);
684 rect
.left
= rect
.right
;
685 rect
.top
+= params
->y_inc
;
686 rect
.bottom
+= params
->y_inc
;
687 err
+= params
->err_add_1
;
689 else err
+= params
->err_add_2
;
694 for (len
= params
->length
; len
; len
--, rect
.left
--)
696 if (err
+ params
->bias
> 0)
698 add_rect_to_region( region
, &rect
);
699 rect
.right
= rect
.left
;
700 rect
.top
+= params
->y_inc
;
701 rect
.bottom
+= params
->y_inc
;
702 err
+= params
->err_add_1
;
704 else err
+= params
->err_add_2
;
710 if (params
->y_inc
> 0)
712 for (len
= params
->length
; len
; len
--, rect
.bottom
++)
714 if (err
+ params
->bias
> 0)
716 add_rect_to_region( region
, &rect
);
717 rect
.top
= rect
.bottom
;
718 rect
.left
+= params
->x_inc
;
719 rect
.right
+= params
->x_inc
;
720 err
+= params
->err_add_1
;
722 else err
+= params
->err_add_2
;
727 for (len
= params
->length
; len
; len
--, rect
.top
--)
729 if (err
+ params
->bias
> 0)
731 add_rect_to_region( region
, &rect
);
732 rect
.bottom
= rect
.top
;
733 rect
.left
+= params
->x_inc
;
734 rect
.right
+= params
->x_inc
;
735 err
+= params
->err_add_1
;
737 else err
+= params
->err_add_2
;
742 add_rect_to_region( region
, &rect
);
745 static BOOL
solid_pen_line_region( dibdrv_physdev
*pdev
, POINT
*start
, POINT
*end
, HRGN region
)
749 rect
.left
= start
->x
;
751 rect
.right
= start
->x
+ 1;
752 rect
.bottom
= start
->y
+ 1;
754 if (start
->y
== end
->y
)
757 order_end_points(&rect
.left
, &rect
.right
);
758 if (clip_rect_to_dib( &pdev
->dib
, &rect
)) add_rect_to_region( region
, &rect
);
760 else if(start
->x
== end
->x
)
762 rect
.bottom
= end
->y
;
763 order_end_points(&rect
.top
, &rect
.bottom
);
764 if (clip_rect_to_dib( &pdev
->dib
, &rect
)) add_rect_to_region( region
, &rect
);
768 bres_params clip_params
;
769 struct line_params line_params
;
770 POINT p1
= crop_coords( *start
), p2
= crop_coords( *end
);
772 init_bres_params( &p1
, &p2
, &clip_params
, &line_params
, &rect
);
773 if (clip_rect_to_dib( &pdev
->dib
, &rect
))
775 POINT clipped_start
, clipped_end
;
777 if (clip_line( &p1
, &p2
, &rect
, &clip_params
, &clipped_start
, &clipped_end
))
779 int m
= abs(clipped_start
.x
- p1
.x
);
780 int n
= abs(clipped_start
.y
- p1
.y
);
782 if (line_params
.x_major
)
784 line_params
.err_start
= 2 * clip_params
.dy
- clip_params
.dx
785 + m
* 2 * clip_params
.dy
- n
* 2 * clip_params
.dx
;
786 line_params
.length
= abs( clipped_end
.x
- clipped_start
.x
) + 1;
790 line_params
.err_start
= 2 * clip_params
.dx
- clip_params
.dy
791 + n
* 2 * clip_params
.dx
- m
* 2 * clip_params
.dy
;
792 line_params
.length
= abs( clipped_end
.y
- clipped_start
.y
) + 1;
795 if (clipped_end
.x
== p2
.x
&& clipped_end
.y
== p2
.y
) line_params
.length
--;
796 solid_line_region( &pdev
->dib
, &clipped_start
, &line_params
, region
);
803 static BOOL
solid_pen_lines(dibdrv_physdev
*pdev
, int num
, POINT
*pts
, BOOL close
, HRGN region
)
805 DC
*dc
= get_physdev_dc( &pdev
->dev
);
812 for (i
= 0; i
< num
- 1; i
++)
813 if (!solid_pen_line_region( pdev
, pts
+ i
, pts
+ i
+ 1, region
))
815 if (close
) return solid_pen_line_region( pdev
, pts
+ num
- 1, pts
, region
);
819 DWORD color
, and, xor;
821 color
= get_pixel_color( dc
, &pdev
->dib
, pdev
->pen_brush
.colorref
, TRUE
);
822 calc_and_xor_masks( dc
->ROPmode
, color
, &and, &xor );
824 for (i
= 0; i
< num
- 1; i
++)
825 if (!solid_pen_line( pdev
, pts
+ i
, pts
+ i
+ 1, and, xor ))
827 if (close
) return solid_pen_line( pdev
, pts
+ num
- 1, pts
, and, xor );
832 void reset_dash_origin(dibdrv_physdev
*pdev
)
834 pdev
->dash_pos
.cur_dash
= 0;
835 pdev
->dash_pos
.left_in_dash
= pdev
->pen_pattern
.dashes
[0];
836 pdev
->dash_pos
.mark
= TRUE
;
839 static inline void skip_dash(dibdrv_physdev
*pdev
, unsigned int skip
)
841 skip
%= pdev
->pen_pattern
.total_len
;
844 if(pdev
->dash_pos
.left_in_dash
> skip
)
846 pdev
->dash_pos
.left_in_dash
-= skip
;
849 skip
-= pdev
->dash_pos
.left_in_dash
;
850 pdev
->dash_pos
.cur_dash
++;
851 if(pdev
->dash_pos
.cur_dash
== pdev
->pen_pattern
.count
) pdev
->dash_pos
.cur_dash
= 0;
852 pdev
->dash_pos
.left_in_dash
= pdev
->pen_pattern
.dashes
[pdev
->dash_pos
.cur_dash
];
853 pdev
->dash_pos
.mark
= !pdev
->dash_pos
.mark
;
858 static void dashed_pen_line_callback(dibdrv_physdev
*pdev
, INT x
, INT y
)
861 rop_mask mask
= pdev
->dash_masks
[pdev
->dash_pos
.mark
];
868 pdev
->dib
.funcs
->solid_rects(&pdev
->dib
, 1, &rect
, mask
.and, mask
.xor);
872 static BOOL
dashed_pen_line(dibdrv_physdev
*pdev
, POINT
*start
, POINT
*end
)
874 struct clipped_rects clipped_rects
;
877 const dash_pos start_pos
= pdev
->dash_pos
;
879 if(start
->y
== end
->y
) /* hline */
882 INT left
, right
, cur_x
;
885 rect
.bottom
= start
->y
+ 1;
887 if(start
->x
<= end
->x
)
900 rect
.left
= min( start
->x
, end
->x
);
901 rect
.right
= max( start
->x
, end
->x
) + 1;
902 get_clipped_rects( &pdev
->dib
, &rect
, pdev
->clip
, &clipped_rects
);
903 for (i
= 0; i
< clipped_rects
.count
; i
++)
905 if(clipped_rects
.rects
[i
].right
> left
&& clipped_rects
.rects
[i
].left
<= right
)
907 int clipped_left
= max(clipped_rects
.rects
[i
].left
, left
);
908 int clipped_right
= min(clipped_rects
.rects
[i
].right
- 1, right
);
910 pdev
->dash_pos
= start_pos
;
914 cur_x
= clipped_left
;
916 skip_dash(pdev
, clipped_left
- left
);
918 while(cur_x
<= clipped_right
)
920 rop_mask mask
= pdev
->dash_masks
[pdev
->dash_pos
.mark
];
921 dash_len
= pdev
->dash_pos
.left_in_dash
;
922 if(cur_x
+ dash_len
> clipped_right
+ 1)
923 dash_len
= clipped_right
- cur_x
+ 1;
925 rect
.right
= cur_x
+ dash_len
;
927 pdev
->dib
.funcs
->solid_rects(&pdev
->dib
, 1, &rect
, mask
.and, mask
.xor);
929 skip_dash(pdev
, dash_len
);
934 cur_x
= clipped_right
;
936 skip_dash(pdev
, right
- clipped_right
);
938 while(cur_x
>= clipped_left
)
940 rop_mask mask
= pdev
->dash_masks
[pdev
->dash_pos
.mark
];
941 dash_len
= pdev
->dash_pos
.left_in_dash
;
942 if(cur_x
- dash_len
< clipped_left
- 1)
943 dash_len
= cur_x
- clipped_left
+ 1;
944 rect
.left
= cur_x
- dash_len
+ 1;
945 rect
.right
= cur_x
+ 1;
947 pdev
->dib
.funcs
->solid_rects(&pdev
->dib
, 1, &rect
, mask
.and, mask
.xor);
949 skip_dash(pdev
, dash_len
);
954 pdev
->dash_pos
= start_pos
;
955 skip_dash(pdev
, right
- left
+ 1);
957 else if(start
->x
== end
->x
) /* vline */
960 INT top
, bottom
, cur_y
;
962 rect
.left
= start
->x
;
963 rect
.right
= start
->x
+ 1;
965 if(start
->y
<= end
->y
)
978 rect
.top
= min( start
->y
, end
->y
);
979 rect
.bottom
= max( start
->y
, end
->y
) + 1;
980 get_clipped_rects( &pdev
->dib
, &rect
, pdev
->clip
, &clipped_rects
);
981 for (i
= 0; i
< clipped_rects
.count
; i
++)
983 if(clipped_rects
.rects
[i
].right
> start
->x
&& clipped_rects
.rects
[i
].left
<= start
->x
)
985 int clipped_top
= max(clipped_rects
.rects
[i
].top
, top
);
986 int clipped_bottom
= min(clipped_rects
.rects
[i
].bottom
- 1, bottom
);
988 pdev
->dash_pos
= start_pos
;
994 skip_dash(pdev
, clipped_top
- top
);
996 while(cur_y
<= clipped_bottom
)
998 rop_mask mask
= pdev
->dash_masks
[pdev
->dash_pos
.mark
];
999 dash_len
= pdev
->dash_pos
.left_in_dash
;
1000 if(cur_y
+ dash_len
> clipped_bottom
+ 1)
1001 dash_len
= clipped_bottom
- cur_y
+ 1;
1003 rect
.bottom
= cur_y
+ dash_len
;
1005 pdev
->dib
.funcs
->solid_rects(&pdev
->dib
, 1, &rect
, mask
.and, mask
.xor);
1007 skip_dash(pdev
, dash_len
);
1012 cur_y
= clipped_bottom
;
1014 skip_dash(pdev
, bottom
- clipped_bottom
);
1016 while(cur_y
>= clipped_top
)
1018 rop_mask mask
= pdev
->dash_masks
[pdev
->dash_pos
.mark
];
1019 dash_len
= pdev
->dash_pos
.left_in_dash
;
1020 if(cur_y
- dash_len
< clipped_top
- 1)
1021 dash_len
= cur_y
- clipped_top
+ 1;
1022 rect
.top
= cur_y
- dash_len
+ 1;
1023 rect
.bottom
= cur_y
+ 1;
1025 pdev
->dib
.funcs
->solid_rects(&pdev
->dib
, 1, &rect
, mask
.and, mask
.xor);
1027 skip_dash(pdev
, dash_len
);
1032 pdev
->dash_pos
= start_pos
;
1033 skip_dash(pdev
, bottom
- top
+ 1);
1037 bres_params clip_params
;
1038 struct line_params line_params
;
1039 POINT p1
= crop_coords( *start
), p2
= crop_coords( *end
);
1041 init_bres_params( &p1
, &p2
, &clip_params
, &line_params
, &rect
);
1042 get_clipped_rects( &pdev
->dib
, &rect
, pdev
->clip
, &clipped_rects
);
1043 for (i
= 0; i
< clipped_rects
.count
; i
++)
1045 POINT clipped_start
, clipped_end
;
1047 clip_status
= clip_line(&p1
, &p2
, clipped_rects
.rects
+ i
, &clip_params
, &clipped_start
, &clipped_end
);
1051 int m
= abs(clipped_start
.x
- p1
.x
);
1052 int n
= abs(clipped_start
.y
- p1
.y
);
1054 pdev
->dash_pos
= start_pos
;
1056 if (line_params
.x_major
)
1058 line_params
.err_start
= 2 * clip_params
.dy
- clip_params
.dx
1059 + m
* 2 * clip_params
.dy
- n
* 2 * clip_params
.dx
;
1060 line_params
.length
= abs( clipped_end
.x
- clipped_start
.x
) + 1;
1065 line_params
.err_start
= 2 * clip_params
.dx
- clip_params
.dy
1066 + n
* 2 * clip_params
.dx
- m
* 2 * clip_params
.dy
;
1067 line_params
.length
= abs( clipped_end
.y
- clipped_start
.y
) + 1;
1070 if (clipped_end
.x
== end
->x
&& clipped_end
.y
== end
->y
) line_params
.length
--;
1072 bres_line_with_bias( &clipped_start
, &line_params
, dashed_pen_line_callback
, pdev
);
1074 if(clip_status
== 2) break; /* completely unclipped, so we can finish */
1077 pdev
->dash_pos
= start_pos
;
1078 if(line_params
.x_major
)
1079 skip_dash(pdev
, clip_params
.dx
);
1081 skip_dash(pdev
, clip_params
.dy
);
1084 free_clipped_rects( &clipped_rects
);
1088 static BOOL
dashed_pen_line_region(dibdrv_physdev
*pdev
, POINT
*start
, POINT
*end
, HRGN region
)
1093 rect
.left
= start
->x
;
1094 rect
.top
= start
->y
;
1095 rect
.right
= start
->x
+ 1;
1096 rect
.bottom
= start
->y
+ 1;
1098 if (start
->y
== end
->y
) /* hline */
1100 if (start
->x
<= end
->x
)
1102 for (i
= start
->x
; i
< end
->x
; i
+= dash_len
)
1104 dash_len
= min( pdev
->dash_pos
.left_in_dash
, end
->x
- i
);
1105 if (pdev
->dash_pos
.mark
)
1108 rect
.right
= i
+ dash_len
;
1109 add_rect_to_region( region
, &rect
);
1111 skip_dash(pdev
, dash_len
);
1116 for (i
= start
->x
; i
> end
->x
; i
-= dash_len
)
1118 dash_len
= min( pdev
->dash_pos
.left_in_dash
, i
- end
->x
);
1119 if (pdev
->dash_pos
.mark
)
1121 rect
.left
= i
- dash_len
+ 1;
1123 add_rect_to_region( region
, &rect
);
1125 skip_dash(pdev
, dash_len
);
1129 else if (start
->x
== end
->x
) /* vline */
1131 if (start
->y
<= end
->y
)
1133 for (i
= start
->y
; i
< end
->y
; i
+= dash_len
)
1135 dash_len
= min( pdev
->dash_pos
.left_in_dash
, end
->y
- i
);
1136 if (pdev
->dash_pos
.mark
)
1139 rect
.bottom
= i
+ dash_len
;
1140 add_rect_to_region( region
, &rect
);
1142 skip_dash(pdev
, dash_len
);
1147 for (i
= start
->y
; i
> end
->y
; i
-= dash_len
)
1149 dash_len
= min( pdev
->dash_pos
.left_in_dash
, i
- end
->y
);
1150 if (pdev
->dash_pos
.mark
)
1152 rect
.top
= i
- dash_len
+ 1;
1153 rect
.bottom
= i
+ 1;
1154 add_rect_to_region( region
, &rect
);
1156 skip_dash(pdev
, dash_len
);
1162 INT dx
= end
->x
- start
->x
, dy
= end
->y
- start
->y
;
1163 INT abs_dx
= abs(dx
), abs_dy
= abs(dy
);
1164 DWORD octant
= get_octant_mask(dx
, dy
);
1165 INT bias
= get_bias( octant
);
1166 int x_inc
= is_x_increasing( octant
) ? 1 : -1;
1167 int y_inc
= is_y_increasing( octant
) ? 1 : -1;
1169 if (is_xmajor( octant
))
1171 int err_add_1
= 2 * abs_dy
- 2 * abs_dx
;
1172 int err_add_2
= 2 * abs_dy
;
1173 int err
= 2 * abs_dy
- abs_dx
;
1177 if (pdev
->dash_pos
.mark
) add_rect_to_region( region
, &rect
);
1180 rect
.right
+= x_inc
;
1184 rect
.bottom
+= y_inc
;
1187 else err
+= err_add_2
;
1193 int err_add_1
= 2 * abs_dx
- 2 * abs_dy
;
1194 int err_add_2
= 2 * abs_dx
;
1195 int err
= 2 * abs_dx
- abs_dy
;
1199 if (pdev
->dash_pos
.mark
) add_rect_to_region( region
, &rect
);
1202 rect
.bottom
+= y_inc
;
1206 rect
.right
+= x_inc
;
1209 else err
+= err_add_2
;
1216 static BOOL
dashed_pen_lines(dibdrv_physdev
*pdev
, int num
, POINT
*pts
, BOOL close
, HRGN region
)
1218 DC
*dc
= get_physdev_dc( &pdev
->dev
);
1225 for (i
= 0; i
< num
- 1; i
++)
1226 if (!dashed_pen_line_region( pdev
, pts
+ i
, pts
+ i
+ 1, region
))
1228 if (close
) return dashed_pen_line_region( pdev
, pts
+ num
- 1, pts
, region
);
1232 get_color_masks( dc
, &pdev
->dib
, dc
->ROPmode
, pdev
->pen_brush
.colorref
,
1233 pdev
->pen_is_ext
? TRANSPARENT
: dc
->backgroundMode
,
1234 &pdev
->dash_masks
[1], &pdev
->dash_masks
[0] );
1236 for (i
= 0; i
< num
- 1; i
++)
1237 if (!dashed_pen_line( pdev
, pts
+ i
, pts
+ i
+ 1 ))
1239 if (close
) return dashed_pen_line( pdev
, pts
+ num
- 1, pts
);
1244 static BOOL
null_pen_lines(dibdrv_physdev
*pdev
, int num
, POINT
*pts
, BOOL close
, HRGN region
)
1255 static void add_cap( dibdrv_physdev
*pdev
, HRGN region
, HRGN round_cap
, const POINT
*pt
)
1257 switch (pdev
->pen_endcap
)
1259 default: FIXME( "Unknown end cap %x\n", pdev
->pen_endcap
);
1261 case PS_ENDCAP_ROUND
:
1262 OffsetRgn( round_cap
, pt
->x
, pt
->y
);
1263 CombineRgn( region
, region
, round_cap
, RGN_OR
);
1264 OffsetRgn( round_cap
, -pt
->x
, -pt
->y
);
1267 case PS_ENDCAP_SQUARE
: /* already been handled */
1268 case PS_ENDCAP_FLAT
:
1273 #define round( f ) (((f) > 0) ? (f) + 0.5 : (f) - 0.5)
1275 /*******************************************************************************
1276 * create_miter_region
1278 * We need to calculate the intersection of two lines. We know a point
1279 * on each line (a face start and the other face end point) and
1280 * the direction vector of each line eg. (dx_1, dy_1).
1282 * (x, y) = (x_1, y_1) + u * (dx_1, dy_1) = (x_2, y_2) + v * (dx_2, dy_2)
1283 * solving (eg using Cramer's rule) gives:
1284 * u = ((x_2 - x_1) dy_2 - (y_2 - y_1) dx_2) / det
1285 * with det = dx_1 dy_2 - dx_2 dy_1
1286 * substituting back in and simplifying gives
1287 * (x, y) = a (dx_1, dy_1) - b (dx_2, dy_2)
1288 * with a = (x_2 dy_2 - y_2 dx_2) / det
1289 * and b = (x_1 dy_1 - y_1 dx_1) / det
1291 static HRGN
create_miter_region( dibdrv_physdev
*pdev
, const POINT
*pt
,
1292 const struct face
*face_1
, const struct face
*face_2
)
1294 DC
*dc
= get_physdev_dc( &pdev
->dev
);
1295 int det
= face_1
->dx
* face_2
->dy
- face_1
->dy
* face_2
->dx
;
1296 POINT pt_1
, pt_2
, pts
[5];
1299 if (det
== 0) return 0;
1303 const struct face
*tmp
= face_1
;
1309 pt_1
= face_1
->start
;
1312 a
= (double)(pt_2
.x
* face_2
->dy
- pt_2
.y
* face_2
->dx
) / det
;
1313 b
= (double)(pt_1
.x
* face_1
->dy
- pt_1
.y
* face_1
->dx
) / det
;
1315 x
= a
* face_1
->dx
- b
* face_2
->dx
;
1316 y
= a
* face_1
->dy
- b
* face_2
->dy
;
1318 if (((x
- pt
->x
) * (x
- pt
->x
) + (y
- pt
->y
) * (y
- pt
->y
)) * 4 >
1319 dc
->miterLimit
* dc
->miterLimit
* pdev
->pen_width
* pdev
->pen_width
)
1322 pts
[0] = face_2
->start
;
1323 pts
[1] = face_1
->start
;
1324 pts
[2].x
= round( x
);
1325 pts
[2].y
= round( y
);
1326 pts
[3] = face_2
->end
;
1327 pts
[4] = face_1
->end
;
1329 return CreatePolygonRgn( pts
, 5, ALTERNATE
);
1332 static void add_join( dibdrv_physdev
*pdev
, HRGN region
, HRGN round_cap
, const POINT
*pt
,
1333 const struct face
*face_1
, const struct face
*face_2
)
1338 switch (pdev
->pen_join
)
1340 default: FIXME( "Unknown line join %x\n", pdev
->pen_join
);
1343 OffsetRgn( round_cap
, pt
->x
, pt
->y
);
1344 CombineRgn( region
, region
, round_cap
, RGN_OR
);
1345 OffsetRgn( round_cap
, -pt
->x
, -pt
->y
);
1349 join
= create_miter_region( pdev
, pt
, face_1
, face_2
);
1353 pts
[0] = face_1
->start
;
1354 pts
[1] = face_2
->end
;
1355 pts
[2] = face_1
->end
;
1356 pts
[3] = face_2
->start
;
1357 join
= CreatePolygonRgn( pts
, 4, ALTERNATE
);
1361 CombineRgn( region
, region
, join
, RGN_OR
);
1362 DeleteObject( join
);
1366 static BOOL
wide_line_segment( dibdrv_physdev
*pdev
, HRGN total
,
1367 const POINT
*pt_1
, const POINT
*pt_2
, int dx
, int dy
,
1368 BOOL need_cap_1
, BOOL need_cap_2
, struct face
*face_1
, struct face
*face_2
)
1371 BOOL sq_cap_1
= need_cap_1
&& (pdev
->pen_endcap
== PS_ENDCAP_SQUARE
);
1372 BOOL sq_cap_2
= need_cap_2
&& (pdev
->pen_endcap
== PS_ENDCAP_SQUARE
);
1374 if (dx
== 0 && dy
== 0) return FALSE
;
1378 rect
.left
= min( pt_1
->x
, pt_2
->x
);
1379 rect
.right
= max( pt_1
->x
, pt_2
->x
);
1380 rect
.top
= pt_1
->y
- pdev
->pen_width
/ 2;
1381 rect
.bottom
= rect
.top
+ pdev
->pen_width
;
1382 if ((sq_cap_1
&& dx
> 0) || (sq_cap_2
&& dx
< 0)) rect
.left
-= pdev
->pen_width
/ 2;
1383 if ((sq_cap_2
&& dx
> 0) || (sq_cap_1
&& dx
< 0)) rect
.right
+= pdev
->pen_width
/ 2;
1384 add_rect_to_region( total
, &rect
);
1387 face_1
->start
.x
= face_1
->end
.x
= rect
.left
;
1388 face_1
->start
.y
= face_2
->end
.y
= rect
.bottom
;
1389 face_1
->end
.y
= face_2
->start
.y
= rect
.top
;
1390 face_2
->start
.x
= face_2
->end
.x
= rect
.right
- 1;
1394 face_1
->start
.x
= face_1
->end
.x
= rect
.right
;
1395 face_1
->start
.y
= face_2
->end
.y
= rect
.top
;
1396 face_1
->end
.y
= face_2
->start
.y
= rect
.bottom
;
1397 face_2
->start
.x
= face_2
->end
.x
= rect
.left
+ 1;
1402 rect
.top
= min( pt_1
->y
, pt_2
->y
);
1403 rect
.bottom
= max( pt_1
->y
, pt_2
->y
);
1404 rect
.left
= pt_1
->x
- pdev
->pen_width
/ 2;
1405 rect
.right
= rect
.left
+ pdev
->pen_width
;
1406 if ((sq_cap_1
&& dy
> 0) || (sq_cap_2
&& dy
< 0)) rect
.top
-= pdev
->pen_width
/ 2;
1407 if ((sq_cap_2
&& dy
> 0) || (sq_cap_1
&& dy
< 0)) rect
.bottom
+= pdev
->pen_width
/ 2;
1408 add_rect_to_region( total
, &rect
);
1411 face_1
->start
.x
= face_2
->end
.x
= rect
.left
;
1412 face_1
->start
.y
= face_1
->end
.y
= rect
.top
;
1413 face_1
->end
.x
= face_2
->start
.x
= rect
.right
;
1414 face_2
->start
.y
= face_2
->end
.y
= rect
.bottom
- 1;
1418 face_1
->start
.x
= face_2
->end
.x
= rect
.right
;
1419 face_1
->start
.y
= face_1
->end
.y
= rect
.bottom
;
1420 face_1
->end
.x
= face_2
->start
.x
= rect
.left
;
1421 face_2
->start
.y
= face_2
->end
.y
= rect
.top
+ 1;
1426 double len
= hypot( dx
, dy
);
1427 double width_x
, width_y
;
1429 POINT wide_half
, narrow_half
;
1432 width_x
= pdev
->pen_width
* abs( dy
) / len
;
1433 width_y
= pdev
->pen_width
* abs( dx
) / len
;
1435 narrow_half
.x
= round( width_x
/ 2 );
1436 narrow_half
.y
= round( width_y
/ 2 );
1437 wide_half
.x
= round( (width_x
+ 1) / 2 );
1438 wide_half
.y
= round( (width_y
+ 1) / 2 );
1442 wide_half
.y
= -wide_half
.y
;
1443 narrow_half
.y
= -narrow_half
.y
;
1448 POINT tmp
= narrow_half
; narrow_half
= wide_half
; wide_half
= tmp
;
1449 wide_half
.x
= -wide_half
.x
;
1450 narrow_half
.x
= -narrow_half
.x
;
1453 seg_pts
[0].x
= pt_1
->x
- narrow_half
.x
;
1454 seg_pts
[0].y
= pt_1
->y
+ narrow_half
.y
;
1455 seg_pts
[1].x
= pt_1
->x
+ wide_half
.x
;
1456 seg_pts
[1].y
= pt_1
->y
- wide_half
.y
;
1457 seg_pts
[2].x
= pt_2
->x
+ wide_half
.x
;
1458 seg_pts
[2].y
= pt_2
->y
- wide_half
.y
;
1459 seg_pts
[3].x
= pt_2
->x
- narrow_half
.x
;
1460 seg_pts
[3].y
= pt_2
->y
+ narrow_half
.y
;
1464 seg_pts
[0].x
-= narrow_half
.y
;
1465 seg_pts
[1].x
-= narrow_half
.y
;
1466 seg_pts
[0].y
-= narrow_half
.x
;
1467 seg_pts
[1].y
-= narrow_half
.x
;
1472 seg_pts
[2].x
+= wide_half
.y
;
1473 seg_pts
[3].x
+= wide_half
.y
;
1474 seg_pts
[2].y
+= wide_half
.x
;
1475 seg_pts
[3].y
+= wide_half
.x
;
1478 segment
= CreatePolygonRgn( seg_pts
, 4, ALTERNATE
);
1479 CombineRgn( total
, total
, segment
, RGN_OR
);
1480 DeleteObject( segment
);
1482 face_1
->start
= seg_pts
[0];
1483 face_1
->end
= seg_pts
[1];
1484 face_2
->start
= seg_pts
[2];
1485 face_2
->end
= seg_pts
[3];
1488 face_1
->dx
= face_2
->dx
= dx
;
1489 face_1
->dy
= face_2
->dy
= dy
;
1494 static void wide_line_segments( dibdrv_physdev
*pdev
, int num
, const POINT
*pts
, BOOL close
,
1495 int start
, int count
, const POINT
*first_pt
, const POINT
*last_pt
,
1496 HRGN round_cap
, HRGN total
)
1499 struct face face_1
, face_2
, prev_face
, first_face
;
1500 const POINT
*pt_1
, *pt_2
;
1504 add_cap( pdev
, total
, round_cap
, first_pt
);
1505 add_cap( pdev
, total
, round_cap
, last_pt
);
1511 pt_2
= &pts
[(start
+ 1) % num
];
1512 wide_line_segment( pdev
, total
, first_pt
, last_pt
, pt_2
->x
- pt_1
->x
, pt_2
->y
- pt_1
->y
,
1513 TRUE
, TRUE
, &face_1
, &face_2
);
1518 pt_2
= &pts
[(start
+ 1) % num
];
1519 wide_line_segment( pdev
, total
, first_pt
, pt_2
, pt_2
->x
- pt_1
->x
, pt_2
->y
- pt_1
->y
,
1520 !close
, FALSE
, &first_face
, &prev_face
);
1523 for (i
= 1; i
< count
- 1; i
++)
1525 pt_1
= &pts
[(start
+ i
) % num
];
1526 pt_2
= &pts
[(start
+ i
+ 1) % num
];
1527 if (wide_line_segment( pdev
, total
, pt_1
, pt_2
, pt_2
->x
- pt_1
->x
, pt_2
->y
- pt_1
->y
,
1528 FALSE
, FALSE
, &face_1
, &face_2
))
1530 add_join( pdev
, total
, round_cap
, pt_1
, &prev_face
, &face_1
);
1535 pt_1
= &pts
[(start
+ count
- 1) % num
];
1536 pt_2
= &pts
[(start
+ count
) % num
];
1537 wide_line_segment( pdev
, total
, pt_1
, last_pt
, pt_2
->x
- pt_1
->x
, pt_2
->y
- pt_1
->y
,
1538 FALSE
, !close
, &face_1
, &face_2
);
1539 add_join( pdev
, total
, round_cap
, pt_1
, &prev_face
, &face_1
);
1540 if (close
) add_join( pdev
, total
, round_cap
, last_pt
, &face_2
, &first_face
);
1543 static BOOL
wide_pen_lines(dibdrv_physdev
*pdev
, int num
, POINT
*pts
, BOOL close
, HRGN total
)
1547 assert( total
!= 0 ); /* wide pens should always be drawn through a region */
1550 /* skip empty segments */
1551 while (num
> 2 && pts
[0].x
== pts
[1].x
&& pts
[0].y
== pts
[1].y
) { pts
++; num
--; }
1552 while (num
> 2 && pts
[num
- 1].x
== pts
[num
- 2].x
&& pts
[num
- 1].y
== pts
[num
- 2].y
) num
--;
1554 if (pdev
->pen_join
== PS_JOIN_ROUND
|| pdev
->pen_endcap
== PS_ENDCAP_ROUND
)
1555 round_cap
= CreateEllipticRgn( -(pdev
->pen_width
/ 2), -(pdev
->pen_width
/ 2),
1556 (pdev
->pen_width
+ 1) / 2 + 1, (pdev
->pen_width
+ 1) / 2 + 1 );
1559 wide_line_segments( pdev
, num
, pts
, TRUE
, 0, num
, &pts
[0], &pts
[0], round_cap
, total
);
1561 wide_line_segments( pdev
, num
, pts
, FALSE
, 0, num
- 1, &pts
[0], &pts
[num
- 1], round_cap
, total
);
1563 if (round_cap
) DeleteObject( round_cap
);
1567 static BOOL
dashed_wide_pen_lines(dibdrv_physdev
*pdev
, int num
, POINT
*pts
, BOOL close
, HRGN total
)
1569 int i
, start
, cur_len
, initial_num
= 0;
1570 POINT initial_point
, start_point
, end_point
;
1573 assert( total
!= 0 ); /* wide pens should always be drawn through a region */
1576 /* skip empty segments */
1577 while (num
> 2 && pts
[0].x
== pts
[1].x
&& pts
[0].y
== pts
[1].y
) { pts
++; num
--; }
1578 while (num
> 2 && pts
[num
- 1].x
== pts
[num
- 2].x
&& pts
[num
- 1].y
== pts
[num
- 2].y
) num
--;
1580 if (pdev
->pen_join
== PS_JOIN_ROUND
|| pdev
->pen_endcap
== PS_ENDCAP_ROUND
)
1581 round_cap
= CreateEllipticRgn( -(pdev
->pen_width
/ 2), -(pdev
->pen_width
/ 2),
1582 (pdev
->pen_width
+ 1) / 2 + 1, (pdev
->pen_width
+ 1) / 2 + 1);
1586 start_point
= pts
[0];
1588 for (i
= 0; i
< (close
? num
: num
- 1); i
++)
1590 const POINT
*pt_1
= pts
+ i
;
1591 const POINT
*pt_2
= pts
+ ((close
&& i
== num
- 1) ? 0 : i
+ 1);
1592 int dx
= pt_2
->x
- pt_1
->x
;
1593 int dy
= pt_2
->y
- pt_1
->y
;
1595 if (dx
== 0 && dy
== 0) continue;
1599 if (abs( dx
) - cur_len
< pdev
->dash_pos
.left_in_dash
)
1601 skip_dash( pdev
, abs( dx
) - cur_len
);
1605 cur_len
+= pdev
->dash_pos
.left_in_dash
;
1606 dx
= (dx
> 0) ? cur_len
: -cur_len
;
1610 if (abs( dy
) - cur_len
< pdev
->dash_pos
.left_in_dash
)
1612 skip_dash( pdev
, abs( dy
) - cur_len
);
1616 cur_len
+= pdev
->dash_pos
.left_in_dash
;
1617 dy
= (dy
> 0) ? cur_len
: -cur_len
;
1621 double len
= hypot( dx
, dy
);
1623 if (len
- cur_len
< pdev
->dash_pos
.left_in_dash
)
1625 skip_dash( pdev
, len
- cur_len
);
1629 cur_len
+= pdev
->dash_pos
.left_in_dash
;
1630 dx
= dx
* cur_len
/ len
;
1631 dy
= dy
* cur_len
/ len
;
1633 end_point
.x
= pt_1
->x
+ dx
;
1634 end_point
.y
= pt_1
->y
+ dy
;
1636 if (pdev
->dash_pos
.mark
)
1638 if (!initial_num
&& close
) /* this is the first dash, save it for later */
1640 initial_num
= i
- start
+ 1;
1641 initial_point
= end_point
;
1643 else wide_line_segments( pdev
, num
, pts
, FALSE
, start
, i
- start
+ 1,
1644 &start_point
, &end_point
, round_cap
, total
);
1646 if (!initial_num
) initial_num
= -1; /* no need to close it */
1648 skip_dash( pdev
, pdev
->dash_pos
.left_in_dash
);
1649 start_point
= end_point
;
1651 i
--; /* go on with the same segment */
1654 if (pdev
->dash_pos
.mark
) /* we have a final dash */
1658 if (initial_num
> 0)
1660 count
= num
- start
+ initial_num
;
1661 end_point
= initial_point
;
1665 count
= num
- start
;
1670 count
= num
- start
- 1;
1671 end_point
= pts
[num
- 1];
1673 wide_line_segments( pdev
, num
, pts
, FALSE
, start
, count
,
1674 &start_point
, &end_point
, round_cap
, total
);
1676 else if (initial_num
> 0) /* initial dash only */
1678 wide_line_segments( pdev
, num
, pts
, FALSE
, 0, initial_num
,
1679 &pts
[0], &initial_point
, round_cap
, total
);
1682 if (round_cap
) DeleteObject( round_cap
);
1686 static const dash_pattern dash_patterns_cosmetic
[4] =
1688 {2, {18, 6}, 24}, /* PS_DASH */
1689 {2, {3, 3}, 6}, /* PS_DOT */
1690 {4, {9, 6, 3, 6}, 24}, /* PS_DASHDOT */
1691 {6, {9, 3, 3, 3, 3, 3}, 24} /* PS_DASHDOTDOT */
1694 static const dash_pattern dash_patterns_geometric
[4] =
1696 {2, {3, 1}, 4}, /* PS_DASH */
1697 {2, {1, 1}, 2}, /* PS_DOT */
1698 {4, {3, 1, 1, 1}, 6}, /* PS_DASHDOT */
1699 {6, {3, 1, 1, 1, 1, 1}, 8} /* PS_DASHDOTDOT */
1702 static inline void set_dash_pattern( dash_pattern
*pattern
, DWORD count
, DWORD
*dashes
)
1706 pattern
->count
= count
;
1707 pattern
->total_len
= 0;
1708 memcpy( pattern
->dashes
, dashes
, count
* sizeof(DWORD
) );
1709 for (i
= 0; i
< count
; i
++) pattern
->total_len
+= dashes
[i
];
1710 if (pattern
->count
% 2) pattern
->total_len
*= 2;
1713 static inline void scale_dash_pattern( dash_pattern
*pattern
, DWORD scale
, DWORD endcap
)
1717 for (i
= 0; i
< pattern
->count
; i
++) pattern
->dashes
[i
] *= scale
;
1718 pattern
->total_len
*= scale
;
1720 if (endcap
!= PS_ENDCAP_FLAT
) /* shrink the dashes to leave room for the caps */
1722 for (i
= 0; i
< pattern
->count
; i
+= 2)
1724 pattern
->dashes
[i
] -= scale
;
1725 pattern
->dashes
[i
+ 1] += scale
;
1730 static inline int get_pen_device_width( DC
*dc
, int width
)
1734 if (!width
) return 1;
1735 pts
[0].x
= pts
[0].y
= pts
[1].y
= 0;
1737 lp_to_dp( dc
, pts
, 2 );
1738 width
= floor( hypot( pts
[1].x
- pts
[0].x
, pts
[1].y
- pts
[0].y
));
1739 return max( width
, 1 );
1742 /***********************************************************************
1743 * dibdrv_SetDCPenColor
1745 COLORREF
dibdrv_SetDCPenColor( PHYSDEV dev
, COLORREF color
)
1747 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
1748 DC
*dc
= get_physdev_dc( dev
);
1750 if (dc
->hPen
== GetStockObject( DC_PEN
))
1751 pdev
->pen_brush
.colorref
= color
;
1756 /**********************************************************************
1759 * Fill a number of rectangles with the solid brush
1761 static BOOL
solid_brush(dibdrv_physdev
*pdev
, dib_brush
*brush
, dib_info
*dib
,
1762 int num
, const RECT
*rects
, INT rop
)
1764 DC
*dc
= get_physdev_dc( &pdev
->dev
);
1765 rop_mask brush_color
;
1766 DWORD color
= get_pixel_color( dc
, &pdev
->dib
, brush
->colorref
, TRUE
);
1768 calc_rop_masks( rop
, color
, &brush_color
);
1769 dib
->funcs
->solid_rects( dib
, num
, rects
, brush_color
.and, brush_color
.xor );
1773 static BOOL
alloc_brush_mask_bits( dib_brush
*brush
)
1775 DWORD size
= brush
->dib
.height
* abs(brush
->dib
.stride
);
1777 assert(brush
->masks
.and == NULL
);
1778 assert(brush
->masks
.xor == NULL
);
1779 assert(brush
->dib
.stride
> 0);
1781 if (!(brush
->masks
.xor = HeapAlloc(GetProcessHeap(), 0, 2 * size
))) return FALSE
;
1782 brush
->masks
.and = (char *)brush
->masks
.xor + size
;
1786 static void free_brush_mask_bits( dib_brush
*brush
)
1788 if (brush
->masks
.xor != brush
->dib
.bits
.ptr
) HeapFree(GetProcessHeap(), 0, brush
->masks
.xor);
1789 brush
->masks
.and = brush
->masks
.xor = NULL
;
1792 void free_pattern_brush( dib_brush
*brush
)
1794 free_brush_mask_bits( brush
);
1795 free_dib_info( &brush
->dib
);
1798 static BOOL
create_pattern_brush_bits( dib_brush
*brush
)
1800 DWORD size
= brush
->dib
.height
* abs(brush
->dib
.stride
);
1801 DWORD
*brush_bits
= brush
->dib
.bits
.ptr
;
1802 DWORD
*and_bits
, *xor_bits
;
1804 if (brush
->rop
== R2_COPYPEN
)
1806 brush
->masks
.xor = brush_bits
; /* use the pattern bits directly */
1810 if (!alloc_brush_mask_bits( brush
)) return FALSE
;
1812 and_bits
= brush
->masks
.and;
1813 xor_bits
= brush
->masks
.xor;
1817 calc_and_xor_masks(brush
->rop
, *brush_bits
++, and_bits
++, xor_bits
++);
1821 if (!rop_needs_and_mask( brush
->rop
)) brush
->masks
.and = NULL
; /* ignore the and mask */
1826 static const BYTE hatches
[6][8] =
1828 { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HS_HORIZONTAL */
1829 { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HS_VERTICAL */
1830 { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HS_FDIAGONAL */
1831 { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HS_BDIAGONAL */
1832 { 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HS_CROSS */
1833 { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 } /* HS_DIAGCROSS */
1836 static BOOL
init_hatch_brush( dibdrv_physdev
*pdev
, dib_brush
*brush
)
1838 /* Just initialise brush dib with the color / sizing info. We don't
1839 need the bits as we'll calculate the rop masks straight from
1840 the hatch patterns. */
1842 copy_dib_color_info(&brush
->dib
, &pdev
->dib
);
1843 brush
->dib
.width
= 8;
1844 brush
->dib
.height
= 8;
1845 brush
->dib
.stride
= get_dib_stride( brush
->dib
.width
, brush
->dib
.bit_count
);
1846 brush
->dib
.rect
.left
= 0;
1847 brush
->dib
.rect
.top
= 0;
1848 brush
->dib
.rect
.right
= 8;
1849 brush
->dib
.rect
.bottom
= 8;
1850 return alloc_brush_mask_bits( brush
);
1853 static BOOL
create_hatch_brush_bits(dibdrv_physdev
*pdev
, dib_brush
*brush
, BOOL
*needs_reselect
)
1855 DC
*dc
= get_physdev_dc( &pdev
->dev
);
1856 rop_mask fg_mask
, bg_mask
;
1858 if (!init_hatch_brush( pdev
, brush
)) return FALSE
;
1860 get_color_masks( dc
, &pdev
->dib
, brush
->rop
, brush
->colorref
, dc
->backgroundMode
,
1861 &fg_mask
, &bg_mask
);
1863 if (brush
->colorref
& (1 << 24)) /* PALETTEINDEX */
1864 *needs_reselect
= TRUE
;
1865 if (dc
->backgroundMode
!= TRANSPARENT
&& (dc
->backgroundColor
& (1 << 24)))
1866 *needs_reselect
= TRUE
;
1868 brush
->dib
.funcs
->create_rop_masks( &brush
->dib
, hatches
[brush
->hatch
],
1869 &fg_mask
, &bg_mask
, &brush
->masks
);
1871 if (!fg_mask
.and && !bg_mask
.and) brush
->masks
.and = NULL
; /* ignore the and mask */
1876 static BOOL
create_dither_brush_bits(dibdrv_physdev
*pdev
, dib_brush
*brush
, BOOL
*needs_reselect
)
1878 DC
*dc
= get_physdev_dc( &pdev
->dev
);
1883 if (!init_hatch_brush( pdev
, brush
)) return FALSE
;
1885 if (brush
->colorref
& (1 << 24)) /* PALETTEINDEX */
1886 *needs_reselect
= TRUE
;
1888 rgb
= make_rgb_colorref( dc
, &pdev
->dib
, brush
->colorref
, &got_pixel
, &pixel
);
1890 brush
->dib
.funcs
->create_dither_masks( &brush
->dib
, brush
->rop
, rgb
, &brush
->masks
);
1892 if (!rop_needs_and_mask( brush
->rop
)) brush
->masks
.and = NULL
; /* ignore the and mask */
1897 static BOOL
matching_pattern_format( dib_info
*dib
, dib_info
*pattern
)
1899 if (dib
->bit_count
!= pattern
->bit_count
) return FALSE
;
1900 if (dib
->stride
!= pattern
->stride
) return FALSE
;
1902 switch (dib
->bit_count
)
1907 if (dib
->color_table_size
!= pattern
->color_table_size
) return FALSE
;
1908 return !memcmp( dib
->color_table
, pattern
->color_table
, dib
->color_table_size
* sizeof(RGBQUAD
) );
1911 return (dib
->red_mask
== pattern
->red_mask
&&
1912 dib
->green_mask
== pattern
->green_mask
&&
1913 dib
->blue_mask
== pattern
->blue_mask
);
1918 static BOOL
select_pattern_brush( dibdrv_physdev
*pdev
, dib_brush
*brush
, BOOL
*needs_reselect
)
1920 DC
*dc
= get_physdev_dc( &pdev
->dev
);
1921 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
1922 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
1923 RGBQUAD color_table
[2];
1925 BOOL dither
= (brush
->dib
.bit_count
== 1);
1927 if (brush
->pattern
.info
->bmiHeader
.biClrUsed
&& brush
->pattern
.usage
== DIB_PAL_COLORS
)
1929 copy_bitmapinfo( info
, brush
->pattern
.info
);
1930 fill_color_table_from_pal_colors( info
, pdev
->dev
.hdc
);
1931 init_dib_info_from_bitmapinfo( &pattern
, info
, brush
->pattern
.bits
.ptr
);
1932 *needs_reselect
= TRUE
;
1936 init_dib_info_from_bitmapinfo( &pattern
, brush
->pattern
.info
, brush
->pattern
.bits
.ptr
);
1939 if (pattern
.bit_count
== 1 && !pattern
.color_table
)
1940 dither
= FALSE
; /* monochrome DDB pattern brushes don't get dithered */
1942 if (pattern
.bit_count
== 1 && !pattern
.color_table
&&
1943 (pdev
->dib
.bit_count
!= 1 || pdev
->dib
.color_table
))
1945 /* monochrome DDB pattern uses DC colors */
1950 color
= make_rgb_colorref( dc
, &pdev
->dib
, dc
->textColor
, &got_pixel
, &pixel
);
1951 color_table
[0].rgbRed
= GetRValue( color
);
1952 color_table
[0].rgbGreen
= GetGValue( color
);
1953 color_table
[0].rgbBlue
= GetBValue( color
);
1954 color_table
[0].rgbReserved
= 0;
1956 color
= make_rgb_colorref( dc
, &pdev
->dib
, dc
->backgroundColor
, &got_pixel
, &pixel
);
1957 color_table
[1].rgbRed
= GetRValue( color
);
1958 color_table
[1].rgbGreen
= GetGValue( color
);
1959 color_table
[1].rgbBlue
= GetBValue( color
);
1960 color_table
[1].rgbReserved
= 0;
1962 pattern
.color_table
= color_table
;
1963 pattern
.color_table_size
= 2;
1964 *needs_reselect
= TRUE
;
1967 copy_dib_color_info(&brush
->dib
, &pdev
->dib
);
1969 brush
->dib
.height
= pattern
.height
;
1970 brush
->dib
.width
= pattern
.width
;
1971 brush
->dib
.stride
= get_dib_stride( brush
->dib
.width
, brush
->dib
.bit_count
);
1972 brush
->dib
.rect
= pattern
.rect
;
1974 if (!dither
&& matching_pattern_format( &brush
->dib
, &pattern
))
1976 brush
->dib
.bits
.ptr
= pattern
.bits
.ptr
;
1977 brush
->dib
.bits
.is_copy
= FALSE
;
1978 brush
->dib
.bits
.free
= NULL
;
1982 brush
->dib
.bits
.ptr
= HeapAlloc( GetProcessHeap(), 0, brush
->dib
.height
* brush
->dib
.stride
);
1983 brush
->dib
.bits
.is_copy
= TRUE
;
1984 brush
->dib
.bits
.free
= free_heap_bits
;
1985 brush
->dib
.funcs
->convert_to(&brush
->dib
, &pattern
, &pattern
.rect
, dither
);
1990 /**********************************************************************
1993 * Fill a number of rectangles with the pattern brush
1994 * FIXME: Should we insist l < r && t < b? Currently we assume this.
1996 static BOOL
pattern_brush(dibdrv_physdev
*pdev
, dib_brush
*brush
, dib_info
*dib
,
1997 int num
, const RECT
*rects
, INT rop
)
1999 DC
*dc
= get_physdev_dc( &pdev
->dev
);
2000 BOOL needs_reselect
= FALSE
;
2002 if (rop
!= brush
->rop
)
2004 free_brush_mask_bits( brush
);
2008 if(brush
->masks
.xor == NULL
)
2010 switch(brush
->style
)
2013 if (!brush
->dib
.bits
.ptr
&& !select_pattern_brush( pdev
, brush
, &needs_reselect
))
2015 if(!create_pattern_brush_bits( brush
))
2020 if(!create_dither_brush_bits(pdev
, brush
, &needs_reselect
))
2025 if(!create_hatch_brush_bits(pdev
, brush
, &needs_reselect
))
2030 ERR("Unexpected brush style %d\n", brush
->style
);
2035 dib
->funcs
->pattern_rects( dib
, num
, rects
, &dc
->brush_org
, &brush
->dib
, &brush
->masks
);
2037 if (needs_reselect
) free_pattern_brush( brush
);
2041 static BOOL
null_brush(dibdrv_physdev
*pdev
, dib_brush
*brush
, dib_info
*dib
,
2042 int num
, const RECT
*rects
, INT rop
)
2047 static BOOL
brush_needs_dithering( dibdrv_physdev
*pdev
, COLORREF color
)
2051 const RGBQUAD
*color_table
= get_default_color_table( pdev
->dib
.bit_count
);
2053 if (!color_table
) return FALSE
;
2054 if (pdev
->dib
.color_table
) return FALSE
;
2055 if (color
& (1 << 24)) return TRUE
; /* PALETTEINDEX */
2056 if (color
>> 16 == 0x10ff) return FALSE
; /* DIBINDEX */
2058 rgb
= rgbquad_from_colorref( color
);
2059 for (i
= 0; i
< (1 << pdev
->dib
.bit_count
); i
++)
2060 if (rgbquad_equal( &color_table
[i
], &rgb
)) return FALSE
;
2065 static void select_brush( dibdrv_physdev
*pdev
, dib_brush
*brush
,
2066 const LOGBRUSH
*logbrush
, const struct brush_pattern
*pattern
)
2068 free_pattern_brush( brush
);
2072 brush
->style
= BS_DIBPATTERN
;
2073 brush
->pattern
= *pattern
; /* brush is actually selected only when it's used */
2074 brush
->rects
= pattern_brush
;
2078 brush
->style
= logbrush
->lbStyle
;
2079 brush
->colorref
= logbrush
->lbColor
;
2080 brush
->hatch
= logbrush
->lbHatch
;
2082 switch (logbrush
->lbStyle
)
2084 case BS_NULL
: brush
->rects
= null_brush
; break;
2085 case BS_HATCHED
: brush
->rects
= pattern_brush
; break;
2087 brush
->rects
= brush_needs_dithering( pdev
, brush
->colorref
) ? pattern_brush
: solid_brush
;
2093 /***********************************************************************
2094 * dibdrv_SelectBrush
2096 HBRUSH
dibdrv_SelectBrush( PHYSDEV dev
, HBRUSH hbrush
, const struct brush_pattern
*pattern
)
2098 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
2099 DC
*dc
= get_physdev_dc( dev
);
2102 TRACE("(%p, %p)\n", dev
, hbrush
);
2104 GetObjectW( hbrush
, sizeof(logbrush
), &logbrush
);
2106 if (hbrush
== GetStockObject( DC_BRUSH
))
2107 logbrush
.lbColor
= dc
->dcBrushColor
;
2109 select_brush( pdev
, &pdev
->brush
, &logbrush
, pattern
);
2113 /***********************************************************************
2116 HPEN
dibdrv_SelectPen( PHYSDEV dev
, HPEN hpen
, const struct brush_pattern
*pattern
)
2118 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
2119 DC
*dc
= get_physdev_dc( dev
);
2122 EXTLOGPEN
*elp
= NULL
;
2124 TRACE("(%p, %p)\n", dev
, hpen
);
2126 if (!GetObjectW( hpen
, sizeof(logpen
), &logpen
))
2128 /* must be an extended pen */
2129 INT size
= GetObjectW( hpen
, 0, NULL
);
2131 if (!size
) return 0;
2133 elp
= HeapAlloc( GetProcessHeap(), 0, size
);
2135 GetObjectW( hpen
, size
, elp
);
2136 logpen
.lopnStyle
= elp
->elpPenStyle
;
2137 logpen
.lopnWidth
.x
= elp
->elpWidth
;
2138 /* cosmetic ext pens are always 1-pixel wide */
2139 if (!(logpen
.lopnStyle
& PS_GEOMETRIC
)) logpen
.lopnWidth
.x
= 0;
2141 logbrush
.lbStyle
= elp
->elpBrushStyle
;
2142 logbrush
.lbColor
= elp
->elpColor
;
2143 logbrush
.lbHatch
= elp
->elpHatch
;
2147 logbrush
.lbStyle
= BS_SOLID
;
2148 logbrush
.lbColor
= logpen
.lopnColor
;
2149 logbrush
.lbHatch
= 0;
2152 pdev
->pen_join
= logpen
.lopnStyle
& PS_JOIN_MASK
;
2153 pdev
->pen_endcap
= logpen
.lopnStyle
& PS_ENDCAP_MASK
;
2154 pdev
->pen_width
= get_pen_device_width( dc
, logpen
.lopnWidth
.x
);
2156 if (hpen
== GetStockObject( DC_PEN
))
2157 logbrush
.lbColor
= dc
->dcPenColor
;
2159 set_dash_pattern( &pdev
->pen_pattern
, 0, NULL
);
2160 select_brush( pdev
, &pdev
->pen_brush
, &logbrush
, pattern
);
2162 pdev
->pen_style
= logpen
.lopnStyle
& PS_STYLE_MASK
;
2164 switch (pdev
->pen_style
)
2170 if (logpen
.lopnStyle
& PS_GEOMETRIC
)
2172 pdev
->pen_pattern
= dash_patterns_geometric
[pdev
->pen_style
- 1];
2173 if (pdev
->pen_width
> 1)
2175 scale_dash_pattern( &pdev
->pen_pattern
, pdev
->pen_width
, pdev
->pen_endcap
);
2176 pdev
->pen_lines
= dashed_wide_pen_lines
;
2178 else pdev
->pen_lines
= dashed_pen_lines
;
2181 if (pdev
->pen_width
== 1) /* wide cosmetic pens are not dashed */
2183 pdev
->pen_lines
= dashed_pen_lines
;
2184 pdev
->pen_pattern
= dash_patterns_cosmetic
[pdev
->pen_style
- 1];
2189 case PS_INSIDEFRAME
:
2190 pdev
->pen_lines
= (pdev
->pen_width
== 1) ? solid_pen_lines
: wide_pen_lines
;
2194 pdev
->pen_width
= 0;
2195 pdev
->pen_lines
= null_pen_lines
;
2199 pdev
->pen_lines
= dashed_pen_lines
;
2200 pdev
->pen_pattern
= dash_patterns_geometric
[PS_DOT
- 1];
2204 pdev
->pen_lines
= (pdev
->pen_width
== 1) ? dashed_pen_lines
: dashed_wide_pen_lines
;
2205 set_dash_pattern( &pdev
->pen_pattern
, elp
->elpNumEntries
, elp
->elpStyleEntry
);
2206 if (!(logpen
.lopnStyle
& PS_GEOMETRIC
)) scale_dash_pattern( &pdev
->pen_pattern
, 3, PS_ENDCAP_FLAT
);
2210 pdev
->pen_uses_region
= (logpen
.lopnStyle
& PS_GEOMETRIC
|| pdev
->pen_width
> 1);
2211 pdev
->pen_is_ext
= (elp
!= NULL
);
2212 HeapFree( GetProcessHeap(), 0, elp
);
2216 /***********************************************************************
2217 * dibdrv_SetDCBrushColor
2219 COLORREF
dibdrv_SetDCBrushColor( PHYSDEV dev
, COLORREF color
)
2221 dibdrv_physdev
*pdev
= get_dibdrv_pdev(dev
);
2222 DC
*dc
= get_physdev_dc( dev
);
2224 if (dc
->hBrush
== GetStockObject( DC_BRUSH
))
2226 LOGBRUSH logbrush
= { BS_SOLID
, color
, 0 };
2227 select_brush( pdev
, &pdev
->brush
, &logbrush
, NULL
);