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