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