gdi32: Add support for DIB pattern brush fills.
[wine] / dlls / gdi32 / dibdrv / primitives.c
1 /*
2  * DIB driver primitives.
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 "gdi_private.h"
22 #include "dibdrv.h"
23
24 static inline DWORD *get_pixel_ptr_32(const dib_info *dib, int x, int y)
25 {
26     return (DWORD *)((BYTE*)dib->bits + y * dib->stride + x * 4);
27 }
28
29 static inline void do_rop_32(DWORD *ptr, DWORD and, DWORD xor)
30 {
31     *ptr = (*ptr & and) ^ xor;
32 }
33
34 static void solid_rects_32(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor)
35 {
36     DWORD *ptr, *start;
37     int x, y, i;
38
39     for(i = 0; i < num; i++, rc++)
40     {
41         start = ptr = get_pixel_ptr_32(dib, rc->left, rc->top);
42         for(y = rc->top; y < rc->bottom; y++, start += dib->stride / 4)
43             for(x = rc->left, ptr = start; x < rc->right; x++)
44                 do_rop_32(ptr++, and, xor);
45     }
46 }
47
48 static void solid_rects_null(const dib_info *dib, int num, const RECT *rc, DWORD and, DWORD xor)
49 {
50     return;
51 }
52
53 static inline INT calc_offset(INT edge, INT size, INT origin)
54 {
55     INT offset;
56
57     if(edge - origin >= 0)
58         offset = (edge - origin) % size;
59     else
60     {
61         offset = (origin - edge) % size;
62         if(offset) offset = size - offset;
63     }
64     return offset;
65 }
66
67 static inline POINT calc_brush_offset(const RECT *rc, const dib_info *brush, const POINT *origin)
68 {
69     POINT offset;
70
71     offset.x = calc_offset(rc->left, brush->width,  origin->x);
72     offset.y = calc_offset(rc->top,  brush->height, origin->y);
73
74     return offset;
75 }
76
77 static void pattern_rects_32(const dib_info *dib, int num, const RECT *rc, const POINT *origin,
78                              const dib_info *brush, void *and_bits, void *xor_bits)
79 {
80     DWORD *ptr, *start, *start_and, *and_ptr, *start_xor, *xor_ptr;
81     int x, y, i;
82     POINT offset;
83
84     for(i = 0; i < num; i++, rc++)
85     {
86         offset = calc_brush_offset(rc, brush, origin);
87
88         start = get_pixel_ptr_32(dib, rc->left, rc->top);
89         start_and = (DWORD*)and_bits + offset.y * brush->stride / 4;
90         start_xor = (DWORD*)xor_bits + offset.y * brush->stride / 4;
91
92         for(y = rc->top; y < rc->bottom; y++, start += dib->stride / 4)
93         {
94             and_ptr = start_and + offset.x;
95             xor_ptr = start_xor + offset.x;
96
97             for(x = rc->left, ptr = start; x < rc->right; x++)
98             {
99                 do_rop_32(ptr++, *and_ptr++, *xor_ptr++);
100                 if(and_ptr == start_and + brush->width)
101                 {
102                     and_ptr = start_and;
103                     xor_ptr = start_xor;
104                 }
105             }
106
107             offset.y++;
108             if(offset.y == brush->height)
109             {
110                 start_and = and_bits;
111                 start_xor = xor_bits;
112                 offset.y = 0;
113             }
114             else
115             {
116                 start_and += brush->stride / 4;
117                 start_xor += brush->stride / 4;
118             }
119         }
120     }
121 }
122
123 static void pattern_rects_null(const dib_info *dib, int num, const RECT *rc, const POINT *origin,
124                                const dib_info *brush, void *and_bits, void *xor_bits)
125 {
126     return;
127 }
128
129 static DWORD colorref_to_pixel_888(const dib_info *dib, COLORREF color)
130 {
131     return ( ((color >> 16) & 0xff) | (color & 0xff00) | ((color << 16) & 0xff0000) );
132 }
133
134 static inline DWORD put_field(DWORD field, int shift, int len)
135 {
136     shift = shift - (8 - len);
137     if (len <= 8)
138         field &= (((1 << len) - 1) << (8 - len));
139     if (shift < 0)
140         field >>= -shift;
141     else
142         field <<= shift;
143     return field;
144 }
145
146 static DWORD colorref_to_pixel_masks(const dib_info *dib, COLORREF colour)
147 {
148     DWORD r,g,b;
149
150     r = GetRValue(colour);
151     g = GetGValue(colour);
152     b = GetBValue(colour);
153
154     return put_field(r, dib->red_shift,   dib->red_len) |
155            put_field(g, dib->green_shift, dib->green_len) |
156            put_field(b, dib->blue_shift,  dib->blue_len);
157 }
158
159 static DWORD colorref_to_pixel_null(const dib_info *dib, COLORREF color)
160 {
161     return 0;
162 }
163
164 const primitive_funcs funcs_8888 =
165 {
166     solid_rects_32,
167     pattern_rects_32,
168     colorref_to_pixel_888
169 };
170
171 const primitive_funcs funcs_32 =
172 {
173     solid_rects_32,
174     pattern_rects_32,
175     colorref_to_pixel_masks
176 };
177
178 const primitive_funcs funcs_null =
179 {
180     solid_rects_null,
181     pattern_rects_null,
182     colorref_to_pixel_null
183 };