dinput: Stub IDirectInputJoyConfig8 interface.
[wine] / dlls / gdi32 / dibdrv / objects.c
1 /*
2  * DIB driver GDI objects.
3  *
4  * Copyright 2011 Huw Davies
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #include <assert.h>
22 #include <stdlib.h>
23
24 #include "gdi_private.h"
25 #include "dibdrv.h"
26
27 #include "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(dib);
30
31 /*
32  *
33  * Decompose the 16 ROP2s into an expression of the form
34  *
35  * D = (D & A) ^ X
36  *
37  * Where A and X depend only on P (and so can be precomputed).
38  *
39  *                                       A    X
40  *
41  * R2_BLACK         0                    0    0
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
46  * R2_NOT           ~D                   1    1
47  * R2_XORPEN        P ^ D                1    P
48  * R2_NOTMASKPEN    ~(P & D)             P    1
49  * R2_MASKPEN       P & D                P    0
50  * R2_NOTXORPEN     ~(P ^ D)             1   ~P
51  * R2_NOP           D                    1    0
52  * R2_MERGENOTPEN   ~P | D               P   ~P
53  * R2_COPYPEN       P                    0    P
54  * R2_MERGEPENNOT   P | ~D              ~P    1
55  * R2_MERGEPEN      P | D               ~P    P
56  * R2_WHITE         1                    0    1
57  *
58  */
59
60 /* A = (P & A1) ^ A2 */
61 #define ZERO  { 0u,  0u}
62 #define ONE   { 0u, ~0u}
63 #define P     {~0u,  0u}
64 #define NOT_P {~0u, ~0u}
65
66 static const DWORD rop2_and_array[16][2] =
67 {
68     ZERO, NOT_P, NOT_P, ZERO,
69     P,    ONE,   ONE,   P,
70     P,    ONE,   ONE,   P,
71     ZERO, NOT_P, NOT_P, ZERO
72 };
73
74 /* X = (P & X1) ^ X2 */
75 static const DWORD rop2_xor_array[16][2] =
76 {
77     ZERO, NOT_P, ZERO, NOT_P,
78     P,    ONE,   P,    ONE,
79     ZERO, NOT_P, ZERO, NOT_P,
80     P,    ONE,   P,    ONE
81 };
82
83 #undef NOT_P
84 #undef P
85 #undef ONE
86 #undef ZERO
87
88 void get_rop_codes(INT rop, struct rop_codes *codes)
89 {
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];
95 }
96
97 void calc_and_xor_masks(INT rop, DWORD color, DWORD *and, DWORD *xor)
98 {
99     struct rop_codes codes;
100     get_rop_codes( rop, &codes );
101
102     *and = (color & codes.a1) ^ codes.a2;
103     *xor = (color & codes.x1) ^ codes.x2;
104 }
105
106 static inline RGBQUAD rgbquad_from_colorref(COLORREF c)
107 {
108     RGBQUAD ret;
109
110     ret.rgbRed      = GetRValue(c);
111     ret.rgbGreen    = GetGValue(c);
112     ret.rgbBlue     = GetBValue(c);
113     ret.rgbReserved = 0;
114     return ret;
115 }
116
117 static inline BOOL rgbquad_equal(const RGBQUAD *a, const RGBQUAD *b)
118 {
119     if(a->rgbRed   == b->rgbRed   &&
120        a->rgbGreen == b->rgbGreen &&
121        a->rgbBlue  == b->rgbBlue)
122         return TRUE;
123     return FALSE;
124 }
125
126 COLORREF make_rgb_colorref( HDC hdc, dib_info *dib, COLORREF color, BOOL *got_pixel, DWORD *pixel )
127 {
128     BYTE type = color >> 24;
129     WORD index = LOWORD( color );
130     HPALETTE pal = GetCurrentObject( hdc, OBJ_PAL );
131     PALETTEENTRY pal_ent;
132
133     *pixel = 0;
134     *got_pixel = FALSE;
135
136     switch( type )
137     {
138     case 0: break;
139
140     case 0x10: /* DIBINDEX */
141         *got_pixel = TRUE;
142         *pixel = 0;
143         color = RGB(0, 0, 0);
144
145         if (dib->bit_count <= 8 && index < (1 << dib->bit_count))
146         {
147             *pixel = index;
148             if (index < dib->color_table_size)
149                 color = RGB( dib->color_table[index].rgbRed,
150                              dib->color_table[index].rgbGreen,
151                              dib->color_table[index].rgbBlue );
152         }
153         break;
154
155     case 2: /* PALETTERGB */
156         color &= 0xffffff;
157         break;
158
159     case 1: /* PALETTEINDEX */
160         if (!GetPaletteEntries( pal, index, 1, &pal_ent ))
161             GetPaletteEntries( pal, 0, 1, &pal_ent );
162         color = RGB( pal_ent.peRed, pal_ent.peGreen, pal_ent.peBlue );
163         break;
164
165     default:
166         FIXME("Unhandled color type %08x\n", color);
167         color &= 0xffffff;
168     }
169
170     return color;
171 }
172
173 /******************************************************************
174  *                   get_pixel_color
175  *
176  * 1 bit bitmaps map the fg/bg colors as follows:
177  * If the fg colorref exactly matches one of the color table entries then
178  * that entry is the fg color and the other is the bg.
179  * Otherwise the bg color is mapped to the closest entry in the table and
180  * the fg takes the other one.
181  */
182 DWORD get_pixel_color( dibdrv_physdev *pdev, COLORREF color, BOOL mono_fixup )
183 {
184     RGBQUAD fg_quad;
185     BOOL got_pixel;
186     DWORD pixel;
187     COLORREF rgb_ref;
188
189     rgb_ref = make_rgb_colorref( pdev->dev.hdc, &pdev->dib, color, &got_pixel, &pixel );
190     if (got_pixel) return pixel;
191
192     if (pdev->dib.bit_count != 1 || !mono_fixup)
193         return pdev->dib.funcs->colorref_to_pixel( &pdev->dib, rgb_ref );
194
195     fg_quad = rgbquad_from_colorref( rgb_ref );
196     if(rgbquad_equal(&fg_quad, pdev->dib.color_table))
197         return 0;
198     if(rgbquad_equal(&fg_quad, pdev->dib.color_table + 1))
199         return 1;
200
201     if(color == GetBkColor(pdev->dev.hdc)) return pdev->bkgnd_color;
202     else return pdev->bkgnd_color ? 0 : 1;
203 }
204
205 /***************************************************************************
206  *                get_pen_bkgnd_masks
207  *
208  * Returns the pre-calculated bkgnd color masks unless the dib is 1 bpp.
209  * In this case since there are several fg sources (pen, brush, text)
210  * this makes pdev->bkgnd_color unusable.  So here we take the inverse
211  * of the relevant fg color (which is always set up correctly).
212  */
213 static inline void get_pen_bkgnd_masks(const dibdrv_physdev *pdev, DWORD *and, DWORD *xor)
214 {
215     if(pdev->dib.bit_count != 1 || GetBkMode(pdev->dev.hdc) == TRANSPARENT)
216     {
217         *and = pdev->bkgnd_and;
218         *xor = pdev->bkgnd_xor;
219     }
220     else
221     {
222         DWORD color = ~pdev->pen_color;
223         if(pdev->pen_colorref == GetBkColor(pdev->dev.hdc)) color = pdev->pen_color;
224         calc_and_xor_masks( GetROP2(pdev->dev.hdc), color, and, xor );
225     }
226 }
227
228 static inline void get_brush_bkgnd_masks(const dibdrv_physdev *pdev, DWORD *and, DWORD *xor)
229 {
230     if(GetBkMode(pdev->dev.hdc) == TRANSPARENT)
231     {
232         *and = pdev->bkgnd_and;
233         *xor = pdev->bkgnd_xor;
234     }
235     else
236     {
237         DWORD color = pdev->bkgnd_color;
238
239         if(pdev->dib.bit_count == 1)
240         {
241             if(pdev->brush_colorref == GetBkColor(pdev->dev.hdc))
242                 color = pdev->brush_color;
243             else
244                 color = ~pdev->brush_color;
245         }
246         calc_and_xor_masks( pdev->brush_rop, color, and, xor );
247     }
248 }
249
250 static inline void order_end_points(int *s, int *e)
251 {
252     if(*s > *e)
253     {
254         int tmp;
255         tmp = *s + 1;
256         *s = *e + 1;
257         *e = tmp;
258     }
259 }
260
261 #define Y_INCREASING_MASK 0x0f
262 #define X_INCREASING_MASK 0xc3
263 #define X_MAJOR_MASK      0x99
264 #define POS_SLOPE_MASK    0x33
265
266 static inline BOOL is_xmajor(DWORD octant)
267 {
268     return octant & X_MAJOR_MASK;
269 }
270
271 static inline BOOL is_pos_slope(DWORD octant)
272 {
273     return octant & POS_SLOPE_MASK;
274 }
275
276 static inline BOOL is_x_increasing(DWORD octant)
277 {
278     return octant & X_INCREASING_MASK;
279 }
280
281 static inline BOOL is_y_increasing(DWORD octant)
282 {
283     return octant & Y_INCREASING_MASK;
284 }
285
286 /**********************************************************************
287  *                  get_octant_number
288  *
289  * Return the octant number starting clockwise from the +ve x-axis.
290  */
291 static inline int get_octant_number(int dx, int dy)
292 {
293     if(dy > 0)
294         if(dx > 0)
295             return ( dx >  dy) ? 1 : 2;
296         else
297             return (-dx >  dy) ? 4 : 3;
298     else
299         if(dx < 0)
300             return (-dx > -dy) ? 5 : 6;
301         else
302             return ( dx > -dy) ? 8 : 7;
303 }
304
305 static inline DWORD get_octant_mask(int dx, int dy)
306 {
307     return 1 << (get_octant_number(dx, dy) - 1);
308 }
309
310 static inline int get_bias( DWORD mask )
311 {
312     /* Octants 3, 5, 6 and 8 take a bias */
313     return (mask & 0xb4) ? 1 : 0;
314 }
315
316 #define OUT_LEFT    1
317 #define OUT_RIGHT   2
318 #define OUT_TOP     4
319 #define OUT_BOTTOM  8
320
321 static inline DWORD calc_outcode(const POINT *pt, const RECT *clip)
322 {
323     DWORD out = 0;
324     if(pt->x < clip->left)         out |= OUT_LEFT;
325     else if(pt->x >= clip->right)  out |= OUT_RIGHT;
326     if(pt->y < clip->top)          out |= OUT_TOP;
327     else if(pt->y >= clip->bottom) out |= OUT_BOTTOM;
328
329     return out;
330 }
331
332 /******************************************************************************
333  *                clip_line
334  *
335  * Clips the start and end points to a rectangle.
336  *
337  * Note, this treats the end point like the start point.  If the
338  * caller doesn't want it displayed, it should exclude it.  If the end
339  * point is clipped out, then the likelihood is that the new end point
340  * should be displayed.
341  *
342  * Returns 0 if totally excluded, 1 if partially clipped and 2 if unclipped.
343  *
344  * This derivation is based on the comments in X.org's xserver/mi/mizerclip.c,
345  * however the Bresenham error term is defined differently so the equations
346  * will also differ.
347  *
348  * For x major lines we have 2dy >= err + bias > 2dy - 2dx
349  *                           0   >= err + bias - 2dy > -2dx
350  *
351  * Note dx, dy, m and n are all +ve.
352  *
353  * Moving the start pt from x1 to x1 + m, we need to figure out y1 + n.
354  *                     err = 2dy - dx + 2mdy - 2ndx
355  *                      0 >= 2dy - dx + 2mdy - 2ndx + bias - 2dy > -2dx
356  *                      0 >= 2mdy - 2ndx + bias - dx > -2dx
357  *                      which of course will give exactly one solution for n,
358  *                      so looking at the >= inequality
359  *                      n >= (2mdy + bias - dx) / 2dx
360  *                      n = ceiling((2mdy + bias - dx) / 2dx)
361  *                        = (2mdy + bias + dx - 1) / 2dx (assuming division truncation)
362  *
363  * Moving start pt from y1 to y1 + n we need to figure out x1 + m - there may be several
364  * solutions we pick the one that minimizes m (ie that first unlipped pt). As above:
365  *                     0 >= 2mdy - 2ndx + bias - dx > -2dx
366  *                  2mdy > 2ndx - bias - dx
367  *                     m > (2ndx - bias - dx) / 2dy
368  *                     m = floor((2ndx - bias - dx) / 2dy) + 1
369  *                     m = (2ndx - bias - dx) / 2dy + 1
370  *
371  * Moving end pt from x2 to x2 - m, we need to figure out y2 - n
372  *                  err = 2dy - dx + 2(dx - m)dy - 2(dy - n)dx
373  *                      = 2dy - dx - 2mdy + 2ndx
374  *                   0 >= 2dy - dx - 2mdy + 2ndx + bias - 2dy > -2dx
375  *                   0 >= 2ndx - 2mdy + bias - dx > -2dx
376  *                   again exactly one solution.
377  *                   2ndx <= 2mdy - bias + dx
378  *                   n = floor((2mdy - bias + dx) / 2dx)
379  *                     = (2mdy - bias + dx) / 2dx
380  *
381  * Moving end pt from y2 to y2 - n when need x2 - m this time maximizing x2 - m so
382  * mininizing m to include all of the points at y = y2 - n.  As above:
383  *                  0 >= 2ndx - 2mdy + bias - dx > -2dx
384  *               2mdy >= 2ndx + bias - dx
385  *                   m = ceiling((2ndx + bias - dx) / 2dy)
386  *                     = (2ndx + bias - dx - 1) / 2dy + 1
387  *
388  * For y major lines, symmetry (dx <-> dy and swap the cases over) gives:
389  *
390  * Moving start point from y1 to y1 + n find x1 + m
391  *                     m = (2ndx + bias + dy - 1) / 2dy
392  *
393  * Moving start point from x1 to x1 + m find y1 + n
394  *                     n = (2mdy - bias - dy) / 2ndx + 1
395  *
396  * Moving end point from y2 to y2 - n find x1 - m
397  *                     m = (2ndx - bias + dy) / 2dy
398  *
399  * Moving end point from x2 to x2 - m find y2 - n
400  *                     n = (2mdy + bias - dy - 1) / 2dx + 1
401  */
402 int clip_line(const POINT *start, const POINT *end, const RECT *clip,
403               const bres_params *params, POINT *pt1, POINT *pt2)
404 {
405     int m, n;
406     BOOL clipped = FALSE;
407     DWORD start_oc, end_oc;
408     const int bias = params->bias;
409     const unsigned int dx = params->dx;
410     const unsigned int dy = params->dy;
411     const unsigned int two_dx = params->dx * 2;
412     const unsigned int two_dy = params->dy * 2;
413     const BOOL xmajor = is_xmajor(params->octant);
414     const BOOL neg_slope = !is_pos_slope(params->octant);
415
416     *pt1 = *start;
417     *pt2 = *end;
418
419     start_oc = calc_outcode(start, clip);
420     end_oc = calc_outcode(end, clip);
421
422     while(1)
423     {
424         if(start_oc == 0 && end_oc == 0) return clipped ? 1 : 2; /* trivial accept */
425         if(start_oc & end_oc)            return 0; /* trivial reject */
426
427         clipped = TRUE;
428         if(start_oc & OUT_LEFT)
429         {
430             m = clip->left - start->x;
431             if(xmajor)
432                 n = (m * two_dy + bias + dx - 1) / two_dx;
433             else
434                 n = (m * two_dy - bias - dy) / two_dx + 1;
435
436             pt1->x = clip->left;
437             if(neg_slope) n = -n;
438             pt1->y = start->y + n;
439             start_oc = calc_outcode(pt1, clip);
440         }
441         else if(start_oc & OUT_RIGHT)
442         {
443             m = start->x - clip->right + 1;
444             if(xmajor)
445                 n = (m * two_dy + bias + dx - 1) / two_dx;
446             else
447                 n = (m * two_dy - bias - dy) / two_dx + 1;
448
449             pt1->x = clip->right - 1;
450             if(neg_slope) n = -n;
451             pt1->y = start->y - n;
452             start_oc = calc_outcode(pt1, clip);
453         }
454         else if(start_oc & OUT_TOP)
455         {
456             n = clip->top - start->y;
457             if(xmajor)
458                 m = (n * two_dx - bias - dx) / two_dy + 1;
459             else
460                 m = (n * two_dx + bias + dy - 1) / two_dy;
461
462             pt1->y = clip->top;
463             if(neg_slope) m = -m;
464             pt1->x = start->x + m;
465             start_oc = calc_outcode(pt1, clip);
466         }
467         else if(start_oc & OUT_BOTTOM)
468         {
469             n = start->y - clip->bottom + 1;
470             if(xmajor)
471                 m = (n * two_dx - bias - dx) / two_dy + 1;
472             else
473                 m = (n * two_dx + bias + dy - 1) / two_dy;
474
475             pt1->y = clip->bottom - 1;
476             if(neg_slope) m = -m;
477             pt1->x = start->x - m;
478             start_oc = calc_outcode(pt1, clip);
479         }
480         else if(end_oc & OUT_LEFT)
481         {
482             m = clip->left - end->x;
483             if(xmajor)
484                 n = (m * two_dy - bias + dx) / two_dx;
485             else
486                 n = (m * two_dy + bias - dy - 1) / two_dx + 1;
487
488             pt2->x = clip->left;
489             if(neg_slope) n = -n;
490             pt2->y = end->y + n;
491             end_oc = calc_outcode(pt2, clip);
492         }
493         else if(end_oc & OUT_RIGHT)
494         {
495             m = end->x - clip->right + 1;
496             if(xmajor)
497                 n = (m * two_dy - bias + dx) / two_dx;
498             else
499                 n = (m * two_dy + bias - dy - 1) / two_dx + 1;
500
501             pt2->x = clip->right - 1;
502             if(neg_slope) n = -n;
503             pt2->y = end->y - n;
504             end_oc = calc_outcode(pt2, clip);
505         }
506         else if(end_oc & OUT_TOP)
507         {
508             n = clip->top - end->y;
509             if(xmajor)
510                 m = (n * two_dx + bias - dx - 1) / two_dy + 1;
511             else
512                 m = (n * two_dx - bias + dy) / two_dy;
513
514             pt2->y = clip->top;
515             if(neg_slope) m = -m;
516             pt2->x = end->x + m;
517             end_oc = calc_outcode(pt2, clip);
518         }
519         else if(end_oc & OUT_BOTTOM)
520         {
521             n = end->y - clip->bottom + 1;
522             if(xmajor)
523                 m = (n * two_dx + bias - dx - 1) / two_dy + 1;
524             else
525                 m = (n * two_dx - bias + dy) / two_dy;
526
527             pt2->y = clip->bottom - 1;
528             if(neg_slope) m = -m;
529             pt2->x = end->x - m;
530             end_oc = calc_outcode(pt2, clip);
531         }
532     }
533 }
534
535 static void bres_line_with_bias(const POINT *start, const struct line_params *params,
536                                 void (* callback)(dibdrv_physdev*,INT,INT), dibdrv_physdev *pdev)
537 {
538     POINT pt = *start;
539     int len = params->length, err = params->err_start;
540
541     if (params->x_major)
542     {
543         while(len--)
544         {
545             callback(pdev, pt.x, pt.y);
546             if (err + params->bias > 0)
547             {
548                 pt.y += params->y_inc;
549                 err += params->err_add_1;
550             }
551             else err += params->err_add_2;
552             pt.x += params->x_inc;
553         }
554     }
555     else
556     {
557         while(len--)
558         {
559             callback(pdev, pt.x, pt.y);
560             if (err + params->bias > 0)
561             {
562                 pt.x += params->x_inc;
563                 err += params->err_add_1;
564             }
565             else err += params->err_add_2;
566             pt.y += params->y_inc;
567         }
568     }
569 }
570
571 static BOOL solid_pen_line(dibdrv_physdev *pdev, POINT *start, POINT *end)
572 {
573     const WINEREGION *clip = get_wine_region(pdev->clip);
574
575     if(start->y == end->y)
576     {
577         RECT rect;
578         int i;
579
580         rect.left   = start->x;
581         rect.top    = start->y;
582         rect.right  = end->x;
583         rect.bottom = end->y + 1;
584         order_end_points(&rect.left, &rect.right);
585         for(i = 0; i < clip->numRects; i++)
586         {
587             if(clip->rects[i].top >= rect.bottom) break;
588             if(clip->rects[i].bottom <= rect.top) continue;
589             /* Optimize the unclipped case */
590             if(clip->rects[i].left <= rect.left && clip->rects[i].right >= rect.right)
591             {
592                 pdev->dib.funcs->solid_rects(&pdev->dib, 1, &rect, pdev->pen_and, pdev->pen_xor);
593                 break;
594             }
595             if(clip->rects[i].right > rect.left && clip->rects[i].left < rect.right)
596             {
597                 RECT tmp = rect;
598                 tmp.left = max(rect.left, clip->rects[i].left);
599                 tmp.right = min(rect.right, clip->rects[i].right);
600                 pdev->dib.funcs->solid_rects(&pdev->dib, 1, &tmp, pdev->pen_and, pdev->pen_xor);
601             }
602         }
603     }
604     else if(start->x == end->x)
605     {
606         RECT rect;
607         int i;
608
609         rect.left   = start->x;
610         rect.top    = start->y;
611         rect.right  = end->x + 1;
612         rect.bottom = end->y;
613         order_end_points(&rect.top, &rect.bottom);
614         for(i = 0; i < clip->numRects; i++)
615         {
616             /* Optimize unclipped case */
617             if(clip->rects[i].top <= rect.top && clip->rects[i].bottom >= rect.bottom &&
618                clip->rects[i].left <= rect.left && clip->rects[i].right >= rect.right)
619             {
620                 pdev->dib.funcs->solid_rects(&pdev->dib, 1, &rect, pdev->pen_and, pdev->pen_xor);
621                 break;
622             }
623             if(clip->rects[i].top >= rect.bottom) break;
624             if(clip->rects[i].bottom <= rect.top) continue;
625             if(clip->rects[i].right > rect.left && clip->rects[i].left < rect.right)
626             {
627                 RECT tmp = rect;
628                 tmp.top = max(rect.top, clip->rects[i].top);
629                 tmp.bottom = min(rect.bottom, clip->rects[i].bottom);
630                 pdev->dib.funcs->solid_rects(&pdev->dib, 1, &tmp, pdev->pen_and, pdev->pen_xor);
631             }
632         }
633     }
634     else
635     {
636         bres_params clip_params;
637         struct line_params line_params;
638         INT dx = end->x - start->x, dy = end->y - start->y;
639         INT abs_dx = abs(dx), abs_dy = abs(dy);
640         INT i;
641
642         clip_params.dx = abs_dx;
643         clip_params.dy = abs_dy;
644         clip_params.octant = get_octant_mask(dx, dy);
645         clip_params.bias   = get_bias( clip_params.octant );
646
647         line_params.bias    = clip_params.bias;
648         line_params.x_major = is_xmajor( clip_params.octant );
649         line_params.x_inc   = is_x_increasing( clip_params.octant ) ? 1 : -1;
650         line_params.y_inc   = is_y_increasing( clip_params.octant ) ? 1 : -1;
651
652         if (line_params.x_major)
653         {
654             line_params.err_add_1 = 2 * abs_dy - 2 * abs_dx;
655             line_params.err_add_2 = 2 * abs_dy;
656         }
657         else
658         {
659             line_params.err_add_1 = 2 * abs_dx - 2 * abs_dy;
660             line_params.err_add_2 = 2 * abs_dx;
661         }
662
663         for(i = 0; i < clip->numRects; i++)
664         {
665             POINT clipped_start, clipped_end;
666             int clip_status;
667             clip_status = clip_line(start, end, clip->rects + i, &clip_params, &clipped_start, &clipped_end);
668
669             if(clip_status)
670             {
671                 int m = abs(clipped_start.x - start->x);
672                 int n = abs(clipped_start.y - start->y);
673
674                 if (line_params.x_major)
675                 {
676                     line_params.err_start = 2 * abs_dy - abs_dx + m * 2 * abs_dy - n * 2 * abs_dx;
677                     line_params.length = abs( clipped_end.x - clipped_start.x ) + 1;
678                 }
679                 else
680                 {
681                     line_params.err_start = 2 * abs_dx - abs_dy + n * 2 * abs_dx - m * 2 * abs_dy;
682                     line_params.length = abs( clipped_end.y - clipped_start.y ) + 1;
683                 }
684
685                 if (clipped_end.x == end->x && clipped_end.y == end->y) line_params.length--;
686
687                 pdev->dib.funcs->solid_line( &pdev->dib, &clipped_start, &line_params,
688                                              pdev->pen_and, pdev->pen_xor );
689
690                 if(clip_status == 2) break; /* completely unclipped, so we can finish */
691             }
692         }
693
694     }
695     release_wine_region(pdev->clip);
696     return TRUE;
697 }
698
699 static BOOL solid_pen_lines(dibdrv_physdev *pdev, int num, POINT *pts, BOOL close)
700 {
701     int i;
702
703     assert( num >= 2 );
704     for (i = 0; i < num - 1; i++)
705         if (!solid_pen_line( pdev, pts + i, pts + i + 1 ))
706             return FALSE;
707
708     if (close) return solid_pen_line( pdev, pts + num - 1, pts );
709
710     return TRUE;
711 }
712
713 void reset_dash_origin(dibdrv_physdev *pdev)
714 {
715     pdev->dash_pos.cur_dash = 0;
716     pdev->dash_pos.left_in_dash = pdev->pen_pattern.dashes[0];
717     pdev->dash_pos.mark = TRUE;
718 }
719
720 static inline void skip_dash(dibdrv_physdev *pdev, unsigned int skip)
721 {
722     skip %= pdev->pen_pattern.total_len;
723     while(skip)
724     {
725         if(pdev->dash_pos.left_in_dash > skip)
726         {
727             pdev->dash_pos.left_in_dash -= skip;
728             return;
729         }
730         skip -= pdev->dash_pos.left_in_dash;
731         pdev->dash_pos.cur_dash++;
732         if(pdev->dash_pos.cur_dash == pdev->pen_pattern.count) pdev->dash_pos.cur_dash = 0;
733         pdev->dash_pos.left_in_dash = pdev->pen_pattern.dashes[pdev->dash_pos.cur_dash];
734         pdev->dash_pos.mark = !pdev->dash_pos.mark;
735     }
736 }
737
738 static inline void get_dash_colors(const dibdrv_physdev *pdev, DWORD *and, DWORD *xor)
739 {
740     if(pdev->dash_pos.mark)
741     {
742         *and = pdev->pen_and;
743         *xor = pdev->pen_xor;
744     }
745     else /* space */
746     {
747         get_pen_bkgnd_masks( pdev, and, xor );
748     }
749 }
750
751 static void dashed_pen_line_callback(dibdrv_physdev *pdev, INT x, INT y)
752 {
753     RECT rect;
754     DWORD and, xor;
755
756     get_dash_colors(pdev, &and, &xor);
757     skip_dash(pdev, 1);
758     rect.left   = x;
759     rect.right  = x + 1;
760     rect.top    = y;
761     rect.bottom = y + 1;
762     pdev->dib.funcs->solid_rects(&pdev->dib, 1, &rect, and, xor);
763     return;
764 }
765
766 static BOOL dashed_pen_line(dibdrv_physdev *pdev, POINT *start, POINT *end)
767 {
768     const WINEREGION *clip = get_wine_region(pdev->clip);
769     DWORD and, xor;
770     int i, dash_len;
771     RECT rect;
772     const dash_pos start_pos = pdev->dash_pos;
773
774     if(start->y == end->y) /* hline */
775     {
776         BOOL l_to_r;
777         INT left, right, cur_x;
778
779         rect.top = start->y;
780         rect.bottom = start->y + 1;
781
782         if(start->x <= end->x)
783         {
784             left = start->x;
785             right = end->x - 1;
786             l_to_r = TRUE;
787         }
788         else
789         {
790             left = end->x + 1;
791             right = start->x;
792             l_to_r = FALSE;
793         }
794
795         for(i = 0; i < clip->numRects; i++)
796         {
797             if(clip->rects[i].top > start->y) break;
798             if(clip->rects[i].bottom <= start->y) continue;
799
800             if(clip->rects[i].right > left && clip->rects[i].left <= right)
801             {
802                 int clipped_left  = max(clip->rects[i].left, left);
803                 int clipped_right = min(clip->rects[i].right - 1, right);
804
805                 pdev->dash_pos = start_pos;
806
807                 if(l_to_r)
808                 {
809                     cur_x = clipped_left;
810                     if(cur_x != left)
811                         skip_dash(pdev, clipped_left - left);
812
813                     while(cur_x <= clipped_right)
814                     {
815                         get_dash_colors(pdev, &and, &xor);
816                         dash_len = pdev->dash_pos.left_in_dash;
817                         if(cur_x + dash_len > clipped_right + 1)
818                             dash_len = clipped_right - cur_x + 1;
819                         rect.left = cur_x;
820                         rect.right = cur_x + dash_len;
821
822                         pdev->dib.funcs->solid_rects(&pdev->dib, 1, &rect, and, xor);
823                         cur_x += dash_len;
824                         skip_dash(pdev, dash_len);
825                     }
826                 }
827                 else
828                 {
829                     cur_x = clipped_right;
830                     if(cur_x != right)
831                         skip_dash(pdev, right - clipped_right);
832
833                     while(cur_x >= clipped_left)
834                     {
835                         get_dash_colors(pdev, &and, &xor);
836                         dash_len = pdev->dash_pos.left_in_dash;
837                         if(cur_x - dash_len < clipped_left - 1)
838                             dash_len = cur_x - clipped_left + 1;
839                         rect.left = cur_x - dash_len + 1;
840                         rect.right = cur_x + 1;
841
842                         pdev->dib.funcs->solid_rects(&pdev->dib, 1, &rect, and, xor);
843                         cur_x -= dash_len;
844                         skip_dash(pdev, dash_len);
845                     }
846                 }
847             }
848         }
849         pdev->dash_pos = start_pos;
850         skip_dash(pdev, right - left + 1);
851     }
852     else if(start->x == end->x) /* vline */
853     {
854         BOOL t_to_b;
855         INT top, bottom, cur_y;
856
857         rect.left = start->x;
858         rect.right = start->x + 1;
859
860         if(start->y <= end->y)
861         {
862             top = start->y;
863             bottom = end->y - 1;
864             t_to_b = TRUE;
865         }
866         else
867         {
868             top = end->y + 1;
869             bottom = start->y;
870             t_to_b = FALSE;
871         }
872
873         for(i = 0; i < clip->numRects; i++)
874         {
875             if(clip->rects[i].top > bottom) break;
876             if(clip->rects[i].bottom <= top) continue;
877             if(clip->rects[i].right > start->x && clip->rects[i].left <= start->x)
878             {
879                 int clipped_top    = max(clip->rects[i].top, top);
880                 int clipped_bottom = min(clip->rects[i].bottom - 1, bottom);
881
882                 pdev->dash_pos = start_pos;
883
884                 if(t_to_b)
885                 {
886                     cur_y = clipped_top;
887                     if(cur_y != top)
888                         skip_dash(pdev, clipped_top - top);
889
890                     while(cur_y <= clipped_bottom)
891                     {
892                         get_dash_colors(pdev, &and, &xor);
893                         dash_len = pdev->dash_pos.left_in_dash;
894                         if(cur_y + dash_len > clipped_bottom + 1)
895                             dash_len = clipped_bottom - cur_y + 1;
896                         rect.top = cur_y;
897                         rect.bottom = cur_y + dash_len;
898
899                         pdev->dib.funcs->solid_rects(&pdev->dib, 1, &rect, and, xor);
900                         cur_y += dash_len;
901                         skip_dash(pdev, dash_len);
902                     }
903                 }
904                 else
905                 {
906                     cur_y = clipped_bottom;
907                     if(cur_y != bottom)
908                         skip_dash(pdev, bottom - clipped_bottom);
909
910                     while(cur_y >= clipped_top)
911                     {
912                         get_dash_colors(pdev, &and, &xor);
913                         dash_len = pdev->dash_pos.left_in_dash;
914                         if(cur_y - dash_len < clipped_top - 1)
915                             dash_len = cur_y - clipped_top + 1;
916                         rect.top = cur_y - dash_len + 1;
917                         rect.bottom = cur_y + 1;
918
919                         pdev->dib.funcs->solid_rects(&pdev->dib, 1, &rect, and, xor);
920                         cur_y -= dash_len;
921                         skip_dash(pdev, dash_len);
922                     }
923                 }
924             }
925         }
926         pdev->dash_pos = start_pos;
927         skip_dash(pdev, bottom - top + 1);
928     }
929     else
930     {
931         bres_params clip_params;
932         struct line_params line_params;
933         INT dx = end->x - start->x, dy = end->y - start->y;
934         INT abs_dx = abs(dx), abs_dy = abs(dy);
935         INT i;
936
937         clip_params.dx = abs_dx;
938         clip_params.dy = abs_dy;
939         clip_params.octant = get_octant_mask(dx, dy);
940         clip_params.bias   = get_bias( clip_params.octant );
941
942         line_params.bias    = clip_params.bias;
943         line_params.x_major = is_xmajor( clip_params.octant );
944         line_params.x_inc   = is_x_increasing( clip_params.octant ) ? 1 : -1;
945         line_params.y_inc   = is_y_increasing( clip_params.octant ) ? 1 : -1;
946
947         if (line_params.x_major)
948         {
949             line_params.err_add_1 = 2 * abs_dy - 2 * abs_dx;
950             line_params.err_add_2 = 2 * abs_dy;
951         }
952         else
953         {
954             line_params.err_add_1 = 2 * abs_dx - 2 * abs_dy;
955             line_params.err_add_2 = 2 * abs_dx;
956         }
957
958         for(i = 0; i < clip->numRects; i++)
959         {
960             POINT clipped_start, clipped_end;
961             int clip_status;
962             clip_status = clip_line(start, end, clip->rects + i, &clip_params, &clipped_start, &clipped_end);
963
964             if(clip_status)
965             {
966                 int m = abs(clipped_start.x - start->x);
967                 int n = abs(clipped_start.y - start->y);
968
969                 pdev->dash_pos = start_pos;
970
971                 if (line_params.x_major)
972                 {
973                     line_params.err_start = 2 * abs_dy - abs_dx + m * 2 * abs_dy - n * 2 * abs_dx;
974                     line_params.length = abs( clipped_end.x - clipped_start.x ) + 1;
975                     skip_dash(pdev, m);
976                 }
977                 else
978                 {
979                     line_params.err_start = 2 * abs_dx - abs_dy + n * 2 * abs_dx - m * 2 * abs_dy;
980                     line_params.length = abs( clipped_end.y - clipped_start.y ) + 1;
981                     skip_dash(pdev, n);
982                 }
983                 if (clipped_end.x == end->x && clipped_end.y == end->y) line_params.length--;
984
985                 bres_line_with_bias( &clipped_start, &line_params, dashed_pen_line_callback, pdev );
986
987                 if(clip_status == 2) break; /* completely unclipped, so we can finish */
988             }
989         }
990         pdev->dash_pos = start_pos;
991         if(line_params.x_major)
992             skip_dash(pdev, abs_dx);
993         else
994             skip_dash(pdev, abs_dy);
995     }
996
997     release_wine_region(pdev->clip);
998     return TRUE;
999 }
1000
1001 static BOOL dashed_pen_lines(dibdrv_physdev *pdev, int num, POINT *pts, BOOL close)
1002 {
1003     int i;
1004
1005     assert( num >= 2 );
1006     for (i = 0; i < num - 1; i++)
1007         if (!dashed_pen_line( pdev, pts + i, pts + i + 1 ))
1008             return FALSE;
1009
1010     if (close) return dashed_pen_line( pdev, pts + num - 1, pts );
1011
1012     return TRUE;
1013 }
1014
1015 static BOOL null_pen_lines(dibdrv_physdev *pdev, int num, POINT *pts, BOOL close)
1016 {
1017     return TRUE;
1018 }
1019
1020 static const dash_pattern dash_patterns[5] =
1021 {
1022     {0, {0}, 0},                  /* PS_SOLID - a pseudo-pattern used to initialise unpatterned pens. */
1023     {2, {18, 6}, 24},             /* PS_DASH */
1024     {2, {3,  3}, 6},              /* PS_DOT */
1025     {4, {9, 6, 3, 6}, 24},        /* PS_DASHDOT */
1026     {6, {9, 3, 3, 3, 3, 3}, 24}   /* PS_DASHDOTDOT */
1027 };
1028
1029 /***********************************************************************
1030  *           dibdrv_SelectPen
1031  */
1032 HPEN dibdrv_SelectPen( PHYSDEV dev, HPEN hpen )
1033 {
1034     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectPen );
1035     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
1036     LOGPEN logpen;
1037     DWORD style;
1038
1039     TRACE("(%p, %p)\n", dev, hpen);
1040
1041     if (!GetObjectW( hpen, sizeof(logpen), &logpen ))
1042     {
1043         /* must be an extended pen */
1044         EXTLOGPEN *elp;
1045         INT size = GetObjectW( hpen, 0, NULL );
1046
1047         if (!size) return 0;
1048
1049         elp = HeapAlloc( GetProcessHeap(), 0, size );
1050
1051         GetObjectW( hpen, size, elp );
1052         /* FIXME: add support for user style pens */
1053         logpen.lopnStyle = elp->elpPenStyle;
1054         logpen.lopnWidth.x = elp->elpWidth;
1055         logpen.lopnWidth.y = 0;
1056         logpen.lopnColor = elp->elpColor;
1057
1058         HeapFree( GetProcessHeap(), 0, elp );
1059     }
1060
1061     if (hpen == GetStockObject( DC_PEN ))
1062         logpen.lopnColor = GetDCPenColor( dev->hdc );
1063
1064     pdev->pen_colorref = logpen.lopnColor;
1065     pdev->pen_color = get_pixel_color( pdev, pdev->pen_colorref, TRUE );
1066     calc_and_xor_masks(GetROP2(dev->hdc), pdev->pen_color, &pdev->pen_and, &pdev->pen_xor);
1067
1068     pdev->pen_pattern = dash_patterns[PS_SOLID];
1069
1070     pdev->defer |= DEFER_PEN;
1071
1072     style = logpen.lopnStyle & PS_STYLE_MASK;
1073
1074     switch(style)
1075     {
1076     case PS_SOLID:
1077         if(logpen.lopnStyle & PS_GEOMETRIC) break;
1078         if(logpen.lopnWidth.x > 1) break;
1079         pdev->pen_lines = solid_pen_lines;
1080         pdev->defer &= ~DEFER_PEN;
1081         break;
1082
1083     case PS_DASH:
1084     case PS_DOT:
1085     case PS_DASHDOT:
1086     case PS_DASHDOTDOT:
1087         if(logpen.lopnStyle & PS_GEOMETRIC) break;
1088         if(logpen.lopnWidth.x > 1) break;
1089         pdev->pen_lines = dashed_pen_lines;
1090         pdev->pen_pattern = dash_patterns[style];
1091         pdev->defer &= ~DEFER_PEN;
1092         break;
1093
1094     case PS_NULL:
1095         pdev->pen_lines = null_pen_lines;
1096         pdev->defer &= ~DEFER_PEN;
1097         break;
1098
1099     default:
1100         break;
1101     }
1102
1103     return next->funcs->pSelectPen( next, hpen );
1104 }
1105
1106 /***********************************************************************
1107  *           dibdrv_SetDCPenColor
1108  */
1109 COLORREF dibdrv_SetDCPenColor( PHYSDEV dev, COLORREF color )
1110 {
1111     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSetDCPenColor );
1112     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
1113
1114     if (GetCurrentObject(dev->hdc, OBJ_PEN) == GetStockObject( DC_PEN ))
1115     {
1116         pdev->pen_colorref = color;
1117         pdev->pen_color = get_pixel_color( pdev, pdev->pen_colorref, TRUE );
1118         calc_and_xor_masks(GetROP2(dev->hdc), pdev->pen_color, &pdev->pen_and, &pdev->pen_xor);
1119     }
1120
1121     return next->funcs->pSetDCPenColor( next, color );
1122 }
1123
1124 void solid_rects( dib_info *dib, int num, const RECT *rects, const rop_mask *color, HRGN region )
1125 {
1126     int i, j;
1127     const WINEREGION *clip;
1128
1129     if (!region)
1130     {
1131         dib->funcs->solid_rects( dib, num, rects, color->and, color->xor );
1132         return;
1133     }
1134
1135     clip = get_wine_region( region );
1136
1137     for(i = 0; i < num; i++)
1138     {
1139         for(j = 0; j < clip->numRects; j++)
1140         {
1141             RECT clipped_rect;
1142
1143             if (intersect_rect( &clipped_rect, rects + i, clip->rects + j ))
1144                 dib->funcs->solid_rects( dib, 1, &clipped_rect, color->and, color->xor );
1145         }
1146     }
1147     release_wine_region( region );
1148 }
1149
1150 /**********************************************************************
1151  *             solid_brush
1152  *
1153  * Fill a number of rectangles with the solid brush
1154  */
1155 static BOOL solid_brush(dibdrv_physdev *pdev, dib_info *dib, int num, const RECT *rects, HRGN region)
1156 {
1157     rop_mask brush_color;
1158
1159     brush_color.and = pdev->brush_and;
1160     brush_color.xor = pdev->brush_xor;
1161
1162     solid_rects( dib, num, rects, &brush_color, region );
1163     return TRUE;
1164 }
1165
1166 static void free_pattern_brush_bits( dibdrv_physdev *pdev )
1167 {
1168     HeapFree(GetProcessHeap(), 0, pdev->brush_and_bits);
1169     HeapFree(GetProcessHeap(), 0, pdev->brush_xor_bits);
1170     pdev->brush_and_bits = NULL;
1171     pdev->brush_xor_bits = NULL;
1172 }
1173
1174 void free_pattern_brush( dibdrv_physdev *pdev )
1175 {
1176     free_pattern_brush_bits( pdev );
1177     free_dib_info( &pdev->brush_dib );
1178 }
1179
1180 static BOOL create_pattern_brush_bits(dibdrv_physdev *pdev)
1181 {
1182     DWORD size = pdev->brush_dib.height * abs(pdev->brush_dib.stride);
1183     DWORD *brush_bits = pdev->brush_dib.bits.ptr;
1184     DWORD *and_bits, *xor_bits;
1185
1186     assert(pdev->brush_and_bits == NULL);
1187     assert(pdev->brush_xor_bits == NULL);
1188
1189     assert(pdev->brush_dib.stride > 0);
1190
1191     and_bits = pdev->brush_and_bits = HeapAlloc(GetProcessHeap(), 0, size);
1192     xor_bits = pdev->brush_xor_bits = HeapAlloc(GetProcessHeap(), 0, size);
1193
1194     if(!and_bits || !xor_bits)
1195     {
1196         ERR("Failed to create pattern brush bits\n");
1197         free_pattern_brush_bits( pdev );
1198         return FALSE;
1199     }
1200
1201     while(size)
1202     {
1203         calc_and_xor_masks(pdev->brush_rop, *brush_bits++, and_bits++, xor_bits++);
1204         size -= 4;
1205     }
1206
1207     return TRUE;
1208 }
1209
1210 static const DWORD hatches[6][8] =
1211 {
1212     { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HS_HORIZONTAL */
1213     { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HS_VERTICAL   */
1214     { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HS_FDIAGONAL  */
1215     { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HS_BDIAGONAL  */
1216     { 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HS_CROSS      */
1217     { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }  /* HS_DIAGCROSS  */
1218 };
1219
1220 static BOOL create_hatch_brush_bits(dibdrv_physdev *pdev)
1221 {
1222     dib_info hatch;
1223     rop_mask fg_mask, bg_mask;
1224     rop_mask_bits mask_bits;
1225     DWORD size;
1226     BOOL ret;
1227
1228     assert(pdev->brush_and_bits == NULL);
1229     assert(pdev->brush_xor_bits == NULL);
1230
1231     /* Just initialise brush_dib with the color / sizing info.  We don't
1232        need the bits as we'll calculate the rop masks straight from
1233        the hatch patterns. */
1234
1235     copy_dib_color_info(&pdev->brush_dib, &pdev->dib);
1236     pdev->brush_dib.width  = 8;
1237     pdev->brush_dib.height = 8;
1238     pdev->brush_dib.stride = get_dib_stride( pdev->brush_dib.width, pdev->brush_dib.bit_count );
1239
1240     size = pdev->brush_dib.height * pdev->brush_dib.stride;
1241
1242     mask_bits.and = pdev->brush_and_bits = HeapAlloc(GetProcessHeap(), 0, size);
1243     mask_bits.xor = pdev->brush_xor_bits = HeapAlloc(GetProcessHeap(), 0, size);
1244
1245     if(!mask_bits.and || !mask_bits.xor)
1246     {
1247         ERR("Failed to create pattern brush bits\n");
1248         free_pattern_brush_bits( pdev );
1249         return FALSE;
1250     }
1251
1252     hatch.bit_count = 1;
1253     hatch.height = hatch.width = 8;
1254     hatch.stride = 4;
1255     hatch.bits.ptr = (void *) hatches[pdev->brush_hatch];
1256     hatch.bits.free = hatch.bits.param = NULL;
1257     hatch.bits.is_copy = FALSE;
1258
1259     fg_mask.and = pdev->brush_and;
1260     fg_mask.xor = pdev->brush_xor;
1261     get_brush_bkgnd_masks( pdev, &bg_mask.and, &bg_mask.xor );
1262
1263     ret = pdev->brush_dib.funcs->create_rop_masks( &pdev->brush_dib, &hatch, &fg_mask, &bg_mask, &mask_bits );
1264     if(!ret) free_pattern_brush_bits( pdev );
1265
1266     return ret;
1267 }
1268
1269 static BOOL matching_pattern_format( dib_info *dib, dib_info *pattern )
1270 {
1271     if (dib->bit_count != pattern->bit_count) return FALSE;
1272     if (dib->stride != pattern->stride) return FALSE;
1273
1274     switch (dib->bit_count)
1275     {
1276     case 1:
1277     case 4:
1278     case 8:
1279         if (dib->color_table_size != pattern->color_table_size) return FALSE;
1280         return !memcmp( dib->color_table, pattern->color_table, dib->color_table_size * sizeof(RGBQUAD) );
1281     case 16:
1282     case 32:
1283         return (dib->red_mask == pattern->red_mask &&
1284                 dib->green_mask == pattern->green_mask &&
1285                 dib->blue_mask == pattern->blue_mask);
1286     }
1287     return TRUE;
1288 }
1289
1290 static void select_pattern_brush( dibdrv_physdev *pdev, dib_info *pattern )
1291 {
1292     RECT rect;
1293
1294     free_pattern_brush( pdev );
1295     copy_dib_color_info(&pdev->brush_dib, &pdev->dib);
1296
1297     pdev->brush_dib.height = pattern->height;
1298     pdev->brush_dib.width  = pattern->width;
1299     pdev->brush_dib.stride = get_dib_stride( pdev->brush_dib.width, pdev->brush_dib.bit_count );
1300
1301     if (matching_pattern_format( &pdev->brush_dib, pattern ))
1302     {
1303         pdev->brush_dib.bits.ptr     = pattern->bits.ptr;
1304         pdev->brush_dib.bits.is_copy = FALSE;
1305         pdev->brush_dib.bits.free    = NULL;
1306         return;
1307     }
1308
1309     pdev->brush_dib.bits.ptr     = HeapAlloc( GetProcessHeap(), 0,
1310                                               pdev->brush_dib.height * pdev->brush_dib.stride );
1311     pdev->brush_dib.bits.is_copy = TRUE;
1312     pdev->brush_dib.bits.free    = free_heap_bits;
1313
1314     rect.left = rect.top = 0;
1315     rect.right = pattern->width;
1316     rect.bottom = pattern->height;
1317
1318     pdev->brush_dib.funcs->convert_to(&pdev->brush_dib, pattern, &rect);
1319 }
1320
1321 /**********************************************************************
1322  *             pattern_brush
1323  *
1324  * Fill a number of rectangles with the pattern brush
1325  * FIXME: Should we insist l < r && t < b?  Currently we assume this.
1326  */
1327 static BOOL pattern_brush(dibdrv_physdev *pdev, dib_info *dib, int num, const RECT *rects, HRGN region)
1328 {
1329     int i, j;
1330     const WINEREGION *clip;
1331     POINT origin;
1332
1333     if(pdev->brush_and_bits == NULL)
1334     {
1335         switch(pdev->brush_style)
1336         {
1337         case BS_DIBPATTERN:
1338             if (pdev->brush_pattern_usage == DIB_PAL_COLORS)
1339             {
1340                 dib_info pattern;
1341                 HPALETTE pal = GetCurrentObject( pdev->dev.hdc, OBJ_PAL );
1342                 if (!init_dib_info_from_brush( &pattern, pdev->brush_pattern_info,
1343                                                pdev->brush_pattern_bits, DIB_PAL_COLORS, pal ))
1344                     return FALSE;
1345                 select_pattern_brush( pdev, &pattern );
1346                 free_dib_info( &pattern );
1347             }
1348             if(!create_pattern_brush_bits(pdev))
1349                 return FALSE;
1350             break;
1351
1352         case BS_HATCHED:
1353             if(!create_hatch_brush_bits(pdev))
1354                 return FALSE;
1355             break;
1356
1357         default:
1358             ERR("Unexpected brush style %d\n", pdev->brush_style);
1359             return FALSE;
1360         }
1361     }
1362
1363     GetBrushOrgEx(pdev->dev.hdc, &origin);
1364
1365     clip = get_wine_region( region );
1366
1367     if (!clip)
1368     {
1369         dib->funcs->pattern_rects( dib, num, rects, &origin, &pdev->brush_dib, pdev->brush_and_bits, pdev->brush_xor_bits );
1370         return TRUE;
1371     }
1372
1373     for(i = 0; i < num; i++)
1374     {
1375         for(j = 0; j < clip->numRects; j++)
1376         {
1377             RECT rect = rects[i];
1378
1379             /* Optimize unclipped case */
1380             if(clip->rects[j].top <= rect.top && clip->rects[j].bottom >= rect.bottom &&
1381                clip->rects[j].left <= rect.left && clip->rects[j].right >= rect.right)
1382             {
1383                 dib->funcs->pattern_rects( dib, 1, &rect, &origin, &pdev->brush_dib, pdev->brush_and_bits, pdev->brush_xor_bits );
1384                 break;
1385             }
1386
1387             if(clip->rects[j].top >= rect.bottom) break;
1388             if(clip->rects[j].bottom <= rect.top) continue;
1389
1390             if(clip->rects[j].right > rect.left && clip->rects[j].left < rect.right)
1391             {
1392                 rect.left   = max(rect.left,   clip->rects[j].left);
1393                 rect.top    = max(rect.top,    clip->rects[j].top);
1394                 rect.right  = min(rect.right,  clip->rects[j].right);
1395                 rect.bottom = min(rect.bottom, clip->rects[j].bottom);
1396
1397                 dib->funcs->pattern_rects( dib, 1, &rect, &origin, &pdev->brush_dib, pdev->brush_and_bits, pdev->brush_xor_bits );
1398             }
1399         }
1400     }
1401     release_wine_region( region );
1402
1403     /* we need to recompute the bits each time for DIB_PAL_COLORS */
1404     if (pdev->brush_style == BS_DIBPATTERN && pdev->brush_pattern_usage == DIB_PAL_COLORS)
1405         free_pattern_brush_bits( pdev );
1406
1407     return TRUE;
1408 }
1409
1410 static BOOL null_brush(dibdrv_physdev *pdev, dib_info *dib, int num, const RECT *rects, HRGN region)
1411 {
1412     return TRUE;
1413 }
1414
1415 void update_brush_rop( dibdrv_physdev *pdev, INT rop )
1416 {
1417     pdev->brush_rop = rop;
1418     if(pdev->brush_style == BS_SOLID || pdev->brush_style == BS_HATCHED)
1419         calc_and_xor_masks(rop, pdev->brush_color, &pdev->brush_and, &pdev->brush_xor);
1420     free_pattern_brush_bits( pdev );
1421 }
1422
1423 /***********************************************************************
1424  *           dibdrv_SelectBrush
1425  */
1426 HBRUSH dibdrv_SelectBrush( PHYSDEV dev, HBRUSH hbrush, HBITMAP bitmap,
1427                            const BITMAPINFO *info, void *bits, UINT usage )
1428 {
1429     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSelectBrush );
1430     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
1431     LOGBRUSH logbrush;
1432
1433     TRACE("(%p, %p)\n", dev, hbrush);
1434
1435     if (bitmap || info)  /* pattern brush */
1436     {
1437         dib_info pattern;
1438         BOOL ret;
1439
1440         if (!info)
1441         {
1442             BITMAPOBJ *bmp = GDI_GetObjPtr( bitmap, OBJ_BITMAP );
1443
1444             if (!bmp) return 0;
1445             ret = init_dib_info_from_bitmapobj( &pattern, bmp, 0 );
1446             GDI_ReleaseObj( bitmap );
1447             if (!ret) return 0;
1448             select_pattern_brush( pdev, &pattern );
1449             free_dib_info( &pattern );
1450         }
1451         else if (usage != DIB_PAL_COLORS)
1452         {
1453             if (!init_dib_info_from_brush( &pattern, info, bits, DIB_RGB_COLORS, 0 )) return 0;
1454             select_pattern_brush( pdev, &pattern );
1455             free_dib_info( &pattern );
1456         }
1457         else
1458         {
1459             /* brush is actually selected only when it's used */
1460             free_pattern_brush( pdev );
1461         }
1462
1463         pdev->brush_rects = pattern_brush;
1464         pdev->brush_style = BS_DIBPATTERN;
1465         pdev->brush_pattern_info = info;
1466         pdev->brush_pattern_bits = bits;
1467         pdev->brush_pattern_usage = usage;
1468         pdev->defer &= ~DEFER_BRUSH;
1469
1470         return next->funcs->pSelectBrush( next, hbrush, bitmap, info, bits, usage );
1471     }
1472
1473     if (!GetObjectW( hbrush, sizeof(logbrush), &logbrush )) return 0;
1474
1475     if (hbrush == GetStockObject( DC_BRUSH ))
1476         logbrush.lbColor = GetDCBrushColor( dev->hdc );
1477
1478     pdev->brush_style = logbrush.lbStyle;
1479
1480     pdev->defer |= DEFER_BRUSH;
1481
1482     free_pattern_brush( pdev );
1483
1484     switch(logbrush.lbStyle)
1485     {
1486     case BS_SOLID:
1487         pdev->brush_colorref = logbrush.lbColor;
1488         pdev->brush_color = get_pixel_color( pdev, pdev->brush_colorref, TRUE );
1489         calc_and_xor_masks(GetROP2(dev->hdc), pdev->brush_color, &pdev->brush_and, &pdev->brush_xor);
1490         pdev->brush_rects = solid_brush;
1491         pdev->defer &= ~DEFER_BRUSH;
1492         break;
1493
1494     case BS_NULL:
1495         pdev->brush_rects = null_brush;
1496         pdev->defer &= ~DEFER_BRUSH;
1497         break;
1498
1499     case BS_HATCHED:
1500         if(logbrush.lbHatch > HS_DIAGCROSS) return 0;
1501         pdev->brush_hatch = logbrush.lbHatch;
1502         pdev->brush_colorref = logbrush.lbColor;
1503         pdev->brush_color = get_pixel_color( pdev, pdev->brush_colorref, TRUE );
1504         calc_and_xor_masks(GetROP2(dev->hdc), pdev->brush_color, &pdev->brush_and, &pdev->brush_xor);
1505         pdev->brush_rects = pattern_brush;
1506         pdev->defer &= ~DEFER_BRUSH;
1507         break;
1508
1509     default:
1510         return 0;
1511     }
1512
1513     return next->funcs->pSelectBrush( next, hbrush, bitmap, info, bits, usage );
1514 }
1515
1516 /***********************************************************************
1517  *           dibdrv_SetDCBrushColor
1518  */
1519 COLORREF dibdrv_SetDCBrushColor( PHYSDEV dev, COLORREF color )
1520 {
1521     PHYSDEV next = GET_NEXT_PHYSDEV( dev, pSetDCBrushColor );
1522     dibdrv_physdev *pdev = get_dibdrv_pdev(dev);
1523
1524     if (GetCurrentObject(dev->hdc, OBJ_BRUSH) == GetStockObject( DC_BRUSH ))
1525     {
1526         pdev->brush_colorref = color;
1527         pdev->brush_color = get_pixel_color( pdev, pdev->brush_colorref, TRUE );
1528         calc_and_xor_masks(GetROP2(dev->hdc), pdev->brush_color, &pdev->brush_and, &pdev->brush_xor);
1529     }
1530
1531     return next->funcs->pSetDCBrushColor( next, color );
1532 }
1533
1534 BOOL brush_rects(dibdrv_physdev *pdev, int num, const RECT *rects)
1535 {
1536     return pdev->brush_rects( pdev, &pdev->dib, num, rects, pdev->clip );
1537 }