winex11: Sync the dib-section bits before writing to the image.
[wine/multimedia.git] / dlls / winex11.drv / bitblt.c
blob6ee59090355967521f4fa7e0dc2470c0eef102f5
1 /*
2 * GDI bit-blit operations
4 * Copyright 1993, 1994, 2011 Alexandre Julliard
5 * Copyright 2006 Damjan Jovanovic
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winternl.h"
34 #include "x11drv.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
40 #define DST 0 /* Destination drawable */
41 #define SRC 1 /* Source drawable */
42 #define TMP 2 /* Temporary drawable */
43 #define PAT 3 /* Pattern (brush) in destination DC */
45 #define OP(src,dst,rop) (OP_ARGS(src,dst) << 4 | (rop))
46 #define OP_ARGS(src,dst) (((src) << 2) | (dst))
48 #define OP_SRC(opcode) ((opcode) >> 6)
49 #define OP_DST(opcode) (((opcode) >> 4) & 3)
50 #define OP_SRCDST(opcode) ((opcode) >> 4)
51 #define OP_ROP(opcode) ((opcode) & 0x0f)
53 #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */
55 #define SWAP_INT32(i1,i2) \
56 do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
58 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
60 { OP(PAT,DST,GXclear) }, /* 0x00 0 */
61 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */
62 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */
63 { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */
64 { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */
65 { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */
66 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */
67 { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */
68 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */
69 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */
70 { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */
71 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */
72 { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */
73 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */
74 { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */
75 { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */
76 { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */
77 { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */
78 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */
79 { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */
80 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */
81 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */
82 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
83 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
84 OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */
85 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
86 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
87 OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/
88 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
89 OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */
90 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
91 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */
92 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
93 OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */
94 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
95 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */
96 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
97 OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */
98 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
99 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */
100 { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */
101 { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */
102 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */
103 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */
104 { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */
105 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */
106 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
107 OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */
108 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
109 OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */
110 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
111 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
112 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXequiv),
113 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */
114 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */
115 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
116 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
117 OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */
118 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */
119 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
120 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
121 OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/
122 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
123 OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */
124 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */
125 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
126 OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */
127 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */
128 { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */
129 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */
130 { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
131 OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */
132 { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */
133 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
134 OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */
135 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
136 OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */
137 { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */
138 { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */
139 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
140 OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */
141 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */
142 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
143 OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */
144 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */
145 { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */
146 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
147 OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */
148 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
149 OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */
150 { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */
151 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */
152 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */
153 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
154 OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */
155 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
156 OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */
157 { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */
158 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */
159 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
160 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */
161 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
162 OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */
163 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */
164 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
165 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
166 OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */
167 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
168 OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */
169 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */
170 { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */
171 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
172 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
173 OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/
174 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
175 OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */
176 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */
177 { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */
178 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */
179 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
180 OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */
181 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
182 OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */
183 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */
184 { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */
185 { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */
186 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */
187 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
188 OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */
189 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */
190 { OP(PAT,DST,GXxor) }, /* 0x5a D^P */
191 { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
192 OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */
193 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
194 OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */
195 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */
196 { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
197 OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */
198 { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */
199 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */
200 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
201 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
202 OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */
203 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
204 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */
205 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */
206 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
207 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */
208 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */
209 { OP(SRC,DST,GXxor) }, /* 0x66 S^D */
210 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
211 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */
212 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
213 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
214 OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/
215 { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */
216 { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */
217 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
218 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
219 OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */
220 { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */
221 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
222 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
223 OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */
224 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
225 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */
226 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */
227 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */
228 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
229 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
230 OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/
231 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
232 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */
233 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */
234 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
235 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */
236 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */
237 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
238 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */
239 { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */
240 { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */
241 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
242 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
243 OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */
244 { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
245 OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */
246 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */
247 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
248 OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */
249 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */
250 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
251 OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */
252 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */
253 { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */
254 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
255 OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */
256 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */
257 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
258 OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */
259 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */
260 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
261 OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */
262 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
263 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
264 OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */
265 { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */
266 { OP(SRC,DST,GXand) }, /* 0x88 S&D */
267 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
268 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */
269 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */
270 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
271 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */
272 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */
273 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
274 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */
275 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
276 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
277 OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/
278 { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */
279 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */
280 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
281 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */
282 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
283 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
284 OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */
285 { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */
286 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
287 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
288 OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */
289 { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */
290 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */
291 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
292 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
293 OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */
294 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
295 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */
296 { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */
297 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */
298 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
299 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */
300 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */
301 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
302 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */
303 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
304 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
305 OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */
306 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */
307 { OP(PAT,DST,GXand) }, /* 0xa0 D&P */
308 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
309 OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */
310 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */
311 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
312 OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */
313 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
314 OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */
315 { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */
316 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */
317 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
318 OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */
319 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */
320 { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */
321 { OP(PAT,DST,GXnoop) }, /* 0xaa D */
322 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */
323 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
324 OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */
325 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
326 OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */
327 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */
328 { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */
329 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */
330 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
331 OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */
332 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
333 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
334 OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/
335 { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */
336 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */
337 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
338 OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */
339 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
340 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
341 OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */
342 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */
343 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
344 OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */
345 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
346 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */
347 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */
348 { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */
349 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
350 OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */
351 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
352 OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */
353 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */
354 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */
355 { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */
356 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
357 OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */
358 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
359 OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */
360 { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */
361 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */
362 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
363 OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */
364 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */
365 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
366 OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */
367 { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */
368 { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */
369 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
370 OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */
371 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
372 OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */
373 { OP(SRC,DST,GXcopy) }, /* 0xcc S */
374 { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */
375 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */
376 { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */
377 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */
378 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
379 OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */
380 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */
381 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
382 OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */
383 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
384 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
385 OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/
386 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */
387 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
388 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
389 OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */
390 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */
391 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
392 OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */
393 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
394 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */
395 { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
396 OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */
397 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
398 OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */
399 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */
400 { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */
401 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */
402 { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */
403 { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */
404 { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */
405 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
406 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */
407 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
408 OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */
409 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
410 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */
411 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
412 OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */
413 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
414 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */
415 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
416 OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */
417 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
418 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
419 OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/
420 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
421 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
422 OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/
423 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */
424 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */
425 { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */
426 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */
427 { OP(SRC,DST,GXor) }, /* 0xee S|D */
428 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */
429 { OP(PAT,DST,GXcopy) }, /* 0xf0 P */
430 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */
431 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */
432 { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */
433 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */
434 { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */
435 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */
436 { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */
437 { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */
438 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */
439 { OP(PAT,DST,GXor) }, /* 0xfa D|P */
440 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */
441 { OP(PAT,SRC,GXor) }, /* 0xfc P|S */
442 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */
443 { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */
444 { OP(PAT,DST,GXset) } /* 0xff 1 */
447 static const unsigned char bit_swap[256] =
449 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
450 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
451 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
452 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
453 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
454 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
455 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
456 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
457 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
458 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
459 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
460 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
461 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
462 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
463 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
464 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
465 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
466 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
467 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
468 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
469 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
470 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
471 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
472 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
473 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
474 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
475 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
476 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
477 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
478 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
479 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
480 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
483 #ifdef WORDS_BIGENDIAN
484 static const unsigned int zeropad_masks[32] =
486 0xffffffff, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000, 0xfc000000, 0xfe000000,
487 0xff000000, 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000,
488 0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
489 0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe
491 #else
492 static const unsigned int zeropad_masks[32] =
494 0xffffffff, 0x00000080, 0x000000c0, 0x000000e0, 0x000000f0, 0x000000f8, 0x000000fc, 0x000000fe,
495 0x000000ff, 0x000080ff, 0x0000c0ff, 0x0000e0ff, 0x0000f0ff, 0x0000f8ff, 0x0000fcff, 0x0000feff,
496 0x0000ffff, 0x0080ffff, 0x00c0ffff, 0x00e0ffff, 0x00f0ffff, 0x00f8ffff, 0x00fcffff, 0x00feffff,
497 0x00ffffff, 0x80ffffff, 0xc0ffffff, 0xe0ffffff, 0xf0ffffff, 0xf8ffffff, 0xfcffffff, 0xfeffffff
499 #endif
501 #ifdef BITBLT_TEST /* Opcodes test */
503 static int do_bitop( int s, int d, int rop )
505 int res;
506 switch(rop)
508 case GXclear: res = 0; break;
509 case GXand: res = s & d; break;
510 case GXandReverse: res = s & ~d; break;
511 case GXcopy: res = s; break;
512 case GXandInverted: res = ~s & d; break;
513 case GXnoop: res = d; break;
514 case GXxor: res = s ^ d; break;
515 case GXor: res = s | d; break;
516 case GXnor: res = ~(s | d); break;
517 case GXequiv: res = ~s ^ d; break;
518 case GXinvert: res = ~d; break;
519 case GXorReverse: res = s | ~d; break;
520 case GXcopyInverted: res = ~s; break;
521 case GXorInverted: res = ~s | d; break;
522 case GXnand: res = ~(s & d); break;
523 case GXset: res = 1; break;
525 return res & 1;
528 int main()
530 int rop, i, res, src, dst, pat, tmp, dstUsed;
531 const unsigned char *opcode;
533 for (rop = 0; rop < 256; rop++)
535 res = dstUsed = 0;
536 for (i = 0; i < 8; i++)
538 pat = (i >> 2) & 1;
539 src = (i >> 1) & 1;
540 dst = i & 1;
541 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
543 switch(*opcode >> 4)
545 case OP_ARGS(DST,TMP):
546 tmp = do_bitop( dst, tmp, *opcode & 0xf );
547 break;
548 case OP_ARGS(DST,SRC):
549 src = do_bitop( dst, src, *opcode & 0xf );
550 break;
551 case OP_ARGS(SRC,TMP):
552 tmp = do_bitop( src, tmp, *opcode & 0xf );
553 break;
554 case OP_ARGS(SRC,DST):
555 dst = do_bitop( src, dst, *opcode & 0xf );
556 dstUsed = 1;
557 break;
558 case OP_ARGS(PAT,DST):
559 dst = do_bitop( pat, dst, *opcode & 0xf );
560 dstUsed = 1;
561 break;
562 case OP_ARGS(PAT,SRC):
563 src = do_bitop( pat, src, *opcode & 0xf );
564 break;
565 case OP_ARGS(TMP,DST):
566 dst = do_bitop( tmp, dst, *opcode & 0xf );
567 dstUsed = 1;
568 break;
569 case OP_ARGS(TMP,SRC):
570 src = do_bitop( tmp, src, *opcode & 0xf );
571 break;
572 default:
573 printf( "Invalid opcode %x\n", *opcode );
576 if (!dstUsed) dst = src;
577 if (dst) res |= 1 << i;
579 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
582 return 0;
585 #endif /* BITBLT_TEST */
588 static void get_colors(X11DRV_PDEVICE *physDevDst, X11DRV_PDEVICE *physDevSrc,
589 int *fg, int *bg)
591 RGBQUAD rgb[2];
593 *fg = physDevDst->textPixel;
594 *bg = physDevDst->backgroundPixel;
595 if(physDevSrc->depth == 1) {
596 if(GetDIBColorTable(physDevSrc->dev.hdc, 0, 2, rgb) == 2) {
597 DWORD logcolor;
598 logcolor = RGB(rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue);
599 *fg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
600 logcolor = RGB(rgb[1].rgbRed, rgb[1].rgbGreen,rgb[1].rgbBlue);
601 *bg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
606 /* return a mask for meaningful bits when doing an XGetPixel on an image */
607 static unsigned long image_pixel_mask( X11DRV_PDEVICE *physDev )
609 unsigned long ret;
610 ColorShifts *shifts = physDev->color_shifts;
612 if (!shifts) shifts = &X11DRV_PALETTE_default_shifts;
613 ret = (shifts->physicalRed.max << shifts->physicalRed.shift) |
614 (shifts->physicalGreen.max << shifts->physicalGreen.shift) |
615 (shifts->physicalBlue.max << shifts->physicalBlue.shift);
616 if (!ret) ret = (1 << physDev->depth) - 1;
617 return ret;
621 /***********************************************************************
622 * BITBLT_StretchRow
624 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
626 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
627 INT startDst, INT widthDst,
628 INT xinc, INT xoff, WORD mode )
630 register INT xsrc = xinc * startDst + xoff;
631 rowDst += startDst;
632 switch(mode)
634 case STRETCH_ANDSCANS:
635 for(; widthDst > 0; widthDst--, xsrc += xinc)
636 *rowDst++ &= rowSrc[xsrc >> 16];
637 break;
638 case STRETCH_ORSCANS:
639 for(; widthDst > 0; widthDst--, xsrc += xinc)
640 *rowDst++ |= rowSrc[xsrc >> 16];
641 break;
642 case STRETCH_DELETESCANS:
643 for(; widthDst > 0; widthDst--, xsrc += xinc)
644 *rowDst++ = rowSrc[xsrc >> 16];
645 break;
650 /***********************************************************************
651 * BITBLT_ShrinkRow
653 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
655 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
656 INT startSrc, INT widthSrc,
657 INT xinc, INT xoff, WORD mode )
659 register INT xdst = xinc * startSrc + xoff;
660 rowSrc += startSrc;
661 switch(mode)
663 case STRETCH_ORSCANS:
664 for(; widthSrc > 0; widthSrc--, xdst += xinc)
665 rowDst[xdst >> 16] |= *rowSrc++;
666 break;
667 case STRETCH_ANDSCANS:
668 for(; widthSrc > 0; widthSrc--, xdst += xinc)
669 rowDst[xdst >> 16] &= *rowSrc++;
670 break;
671 case STRETCH_DELETESCANS:
672 for(; widthSrc > 0; widthSrc--, xdst += xinc)
673 rowDst[xdst >> 16] = *rowSrc++;
674 break;
679 /***********************************************************************
680 * BITBLT_GetRow
682 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
684 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
685 INT start, INT width, INT depthDst,
686 int fg, int bg, unsigned long pixel_mask, BOOL swap)
688 register INT i;
690 assert( (row >= 0) && (row < image->height) );
691 assert( (start >= 0) && (width <= image->width) );
693 pdata += swap ? start+width-1 : start;
694 if (image->depth == depthDst) /* color -> color */
696 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
697 if (swap) for (i = 0; i < width; i++)
698 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
699 else for (i = 0; i < width; i++)
700 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
701 else
702 if (swap) for (i = 0; i < width; i++)
703 *pdata-- = XGetPixel( image, i, row );
704 else for (i = 0; i < width; i++)
705 *pdata++ = XGetPixel( image, i, row );
707 else
709 if (image->depth == 1) /* monochrome -> color */
711 if (X11DRV_PALETTE_XPixelToPalette)
713 fg = X11DRV_PALETTE_XPixelToPalette[fg];
714 bg = X11DRV_PALETTE_XPixelToPalette[bg];
716 if (swap) for (i = 0; i < width; i++)
717 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
718 else for (i = 0; i < width; i++)
719 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
721 else /* color -> monochrome */
723 if (swap) for (i = 0; i < width; i++)
724 *pdata-- = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0;
725 else for (i = 0; i < width; i++)
726 *pdata++ = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0;
732 /***********************************************************************
733 * BITBLT_StretchImage
735 * Stretch an X image.
736 * FIXME: does not work for full 32-bit coordinates.
738 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
739 INT widthSrc, INT heightSrc,
740 INT widthDst, INT heightDst,
741 RECT *visRectSrc, RECT *visRectDst,
742 int foreground, int background,
743 unsigned long pixel_mask, WORD mode )
745 int *rowSrc, *rowDst, *pixel;
746 char *pdata;
747 INT xinc, xoff, yinc, ysrc, ydst;
748 register INT x, y;
749 BOOL hstretch, vstretch, hswap, vswap;
751 hswap = widthSrc * widthDst < 0;
752 vswap = heightSrc * heightDst < 0;
753 widthSrc = abs(widthSrc);
754 heightSrc = abs(heightSrc);
755 widthDst = abs(widthDst);
756 heightDst = abs(heightDst);
758 if (!(rowSrc = HeapAlloc( GetProcessHeap(), 0,
759 (widthSrc+widthDst)*sizeof(int) ))) return;
760 rowDst = rowSrc + widthSrc;
762 /* When stretching, all modes are the same, and DELETESCANS is faster */
763 if ((widthSrc < widthDst) && (heightSrc < heightDst))
764 mode = STRETCH_DELETESCANS;
766 if (mode == STRETCH_HALFTONE) /* FIXME */
767 mode = STRETCH_DELETESCANS;
769 if (mode != STRETCH_DELETESCANS)
770 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
771 widthDst*sizeof(int) );
773 hstretch = (widthSrc < widthDst);
774 vstretch = (heightSrc < heightDst);
776 if (hstretch)
778 xinc = (widthSrc << 16) / widthDst;
779 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
781 else
783 xinc = ((int)widthDst << 16) / widthSrc;
784 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
787 wine_tsx11_lock();
788 if (vstretch)
790 yinc = (heightSrc << 16) / heightDst;
791 ydst = visRectDst->top;
792 if (vswap)
794 ysrc = yinc * (heightDst - ydst - 1);
795 yinc = -yinc;
797 else
798 ysrc = yinc * ydst;
800 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
802 if (((ysrc >> 16) < visRectSrc->top) ||
803 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
805 /* Retrieve a source row */
806 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
807 visRectSrc->left, visRectSrc->right - visRectSrc->left,
808 dstImage->depth, foreground, background, pixel_mask, hswap );
810 /* Stretch or shrink it */
811 if (hstretch)
812 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
813 visRectDst->right - visRectDst->left,
814 xinc, xoff, mode );
815 else BITBLT_ShrinkRow( rowSrc, rowDst, visRectSrc->left,
816 visRectSrc->right - visRectSrc->left,
817 xinc, xoff, mode );
819 /* Store the destination row */
820 pixel = rowDst + visRectDst->right - 1;
821 y = ydst - visRectDst->top;
822 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
823 XPutPixel( dstImage, x, y, *pixel-- );
824 if (mode != STRETCH_DELETESCANS)
825 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
826 widthDst*sizeof(int) );
828 /* Make copies of the destination row */
830 pdata = dstImage->data + dstImage->bytes_per_line * y;
831 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
832 (ydst < visRectDst->bottom-1))
834 memcpy( pdata + dstImage->bytes_per_line, pdata,
835 dstImage->bytes_per_line );
836 pdata += dstImage->bytes_per_line;
837 ysrc += yinc;
838 ydst++;
842 else /* Shrinking */
844 yinc = (heightDst << 16) / heightSrc;
845 ysrc = visRectSrc->top;
846 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
847 if (vswap)
849 ydst += yinc * (heightSrc - ysrc - 1);
850 yinc = -yinc;
852 else
853 ydst += yinc * ysrc;
855 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
857 if (((ydst >> 16) < visRectDst->top) ||
858 ((ydst >> 16) >= visRectDst->bottom)) continue;
860 /* Retrieve a source row */
861 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
862 visRectSrc->left, visRectSrc->right - visRectSrc->left,
863 dstImage->depth, foreground, background, pixel_mask, hswap );
865 /* Stretch or shrink it */
866 if (hstretch)
867 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
868 visRectDst->right - visRectDst->left,
869 xinc, xoff, mode );
870 else BITBLT_ShrinkRow( rowSrc, rowDst, visRectSrc->left,
871 visRectSrc->right - visRectSrc->left,
872 xinc, xoff, mode );
874 /* Merge several source rows into the destination */
875 if (mode == STRETCH_DELETESCANS)
877 /* Simply skip the overlapping rows */
878 while (((ydst + yinc) >> 16 == ydst >> 16) &&
879 (ysrc < visRectSrc->bottom-1))
881 ydst += yinc;
882 ysrc++;
885 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
886 (ysrc < visRectSrc->bottom-1))
887 continue; /* Restart loop for next overlapping row */
889 /* Store the destination row */
890 pixel = rowDst + visRectDst->right - 1;
891 y = (ydst >> 16) - visRectDst->top;
892 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
893 XPutPixel( dstImage, x, y, *pixel-- );
894 if (mode != STRETCH_DELETESCANS)
895 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
896 widthDst*sizeof(int) );
899 wine_tsx11_unlock();
900 HeapFree( GetProcessHeap(), 0, rowSrc );
904 /***********************************************************************
905 * BITBLT_GetSrcAreaStretch
907 * Retrieve an area from the source DC, stretching and mapping all the
908 * pixels to Windows colors.
910 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
911 Pixmap pixmap, GC gc,
912 const struct bitblt_coords *src, const struct bitblt_coords *dst )
914 XImage *imageSrc, *imageDst;
915 RECT rectSrc = src->visrect;
916 RECT rectDst = dst->visrect;
917 int fg, bg;
919 rectSrc.left -= src->x;
920 rectSrc.right -= src->x;
921 rectSrc.top -= src->y;
922 rectSrc.bottom -= src->y;
923 rectDst.left -= dst->x;
924 rectDst.right -= dst->x;
925 rectDst.top -= dst->y;
926 rectDst.bottom -= dst->y;
927 if (src->width < 0)
929 rectSrc.left -= src->width;
930 rectSrc.right -= src->width;
932 if (dst->width < 0)
934 rectDst.left -= dst->width;
935 rectDst.right -= dst->width;
937 if (src->height < 0)
939 rectSrc.top -= src->height;
940 rectSrc.bottom -= src->height;
942 if (dst->height < 0)
944 rectDst.top -= dst->height;
945 rectDst.bottom -= dst->height;
948 get_colors(physDevDst, physDevSrc, &fg, &bg);
949 wine_tsx11_lock();
950 /* FIXME: avoid BadMatch errors */
951 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
952 physDevSrc->dc_rect.left + src->visrect.left,
953 physDevSrc->dc_rect.top + src->visrect.top,
954 src->visrect.right - src->visrect.left,
955 src->visrect.bottom - src->visrect.top,
956 AllPlanes, ZPixmap );
957 wine_tsx11_unlock();
959 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
960 rectDst.bottom - rectDst.top, physDevDst->depth );
961 BITBLT_StretchImage( imageSrc, imageDst, src->width, src->height,
962 dst->width, dst->height, &rectSrc, &rectDst,
963 fg, physDevDst->depth != 1 ? bg : physDevSrc->backgroundPixel,
964 image_pixel_mask( physDevSrc ), GetStretchBltMode(physDevDst->dev.hdc) );
965 wine_tsx11_lock();
966 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
967 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
968 XDestroyImage( imageSrc );
969 X11DRV_DIB_DestroyXImage( imageDst );
970 wine_tsx11_unlock();
971 return 0; /* no exposure events generated */
975 /***********************************************************************
976 * BITBLT_GetSrcArea
978 * Retrieve an area from the source DC, mapping all the
979 * pixels to Windows colors.
981 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
982 Pixmap pixmap, GC gc, RECT *visRectSrc )
984 XImage *imageSrc, *imageDst;
985 register INT x, y;
986 int exposures = 0;
987 INT width = visRectSrc->right - visRectSrc->left;
988 INT height = visRectSrc->bottom - visRectSrc->top;
989 int fg, bg;
990 BOOL memdc = (GetObjectType(physDevSrc->dev.hdc) == OBJ_MEMDC);
992 if (physDevSrc->depth == physDevDst->depth)
994 wine_tsx11_lock();
995 if (!X11DRV_PALETTE_XPixelToPalette ||
996 (physDevDst->depth == 1)) /* monochrome -> monochrome */
998 if (physDevDst->depth == 1)
1000 /* MSDN says if StretchBlt must convert a bitmap from monochrome
1001 to color or vice versa, the foreground and background color of
1002 the device context are used. In fact, it also applies to the
1003 case when it is converted from mono to mono. */
1004 XSetBackground( gdi_display, gc, physDevDst->textPixel );
1005 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
1006 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
1007 physDevSrc->dc_rect.left + visRectSrc->left,
1008 physDevSrc->dc_rect.top + visRectSrc->top,
1009 width, height, 0, 0, 1);
1011 else
1012 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
1013 physDevSrc->dc_rect.left + visRectSrc->left,
1014 physDevSrc->dc_rect.top + visRectSrc->top,
1015 width, height, 0, 0);
1016 exposures++;
1018 else /* color -> color */
1020 if (memdc)
1021 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1022 physDevSrc->dc_rect.left + visRectSrc->left,
1023 physDevSrc->dc_rect.top + visRectSrc->top,
1024 width, height, AllPlanes, ZPixmap );
1025 else
1027 /* Make sure we don't get a BadMatch error */
1028 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
1029 physDevSrc->dc_rect.left + visRectSrc->left,
1030 physDevSrc->dc_rect.top + visRectSrc->top,
1031 width, height, 0, 0);
1032 exposures++;
1033 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1034 AllPlanes, ZPixmap );
1036 for (y = 0; y < height; y++)
1037 for (x = 0; x < width; x++)
1038 XPutPixel(imageSrc, x, y,
1039 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
1040 XPutImage( gdi_display, pixmap, gc, imageSrc,
1041 0, 0, 0, 0, width, height );
1042 XDestroyImage( imageSrc );
1044 wine_tsx11_unlock();
1046 else
1048 if (physDevSrc->depth == 1) /* monochrome -> color */
1050 get_colors(physDevDst, physDevSrc, &fg, &bg);
1052 wine_tsx11_lock();
1053 if (X11DRV_PALETTE_XPixelToPalette)
1055 XSetBackground( gdi_display, gc,
1056 X11DRV_PALETTE_XPixelToPalette[fg] );
1057 XSetForeground( gdi_display, gc,
1058 X11DRV_PALETTE_XPixelToPalette[bg]);
1060 else
1062 XSetBackground( gdi_display, gc, fg );
1063 XSetForeground( gdi_display, gc, bg );
1065 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
1066 physDevSrc->dc_rect.left + visRectSrc->left,
1067 physDevSrc->dc_rect.top + visRectSrc->top,
1068 width, height, 0, 0, 1 );
1069 exposures++;
1070 wine_tsx11_unlock();
1072 else /* color -> monochrome */
1074 unsigned long pixel_mask;
1075 wine_tsx11_lock();
1076 /* FIXME: avoid BadMatch error */
1077 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1078 physDevSrc->dc_rect.left + visRectSrc->left,
1079 physDevSrc->dc_rect.top + visRectSrc->top,
1080 width, height, AllPlanes, ZPixmap );
1081 if (!imageSrc)
1083 wine_tsx11_unlock();
1084 return exposures;
1086 imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1087 if (!imageDst)
1089 XDestroyImage(imageSrc);
1090 wine_tsx11_unlock();
1091 return exposures;
1093 pixel_mask = image_pixel_mask( physDevSrc );
1094 for (y = 0; y < height; y++)
1095 for (x = 0; x < width; x++)
1096 XPutPixel(imageDst, x, y,
1097 !((XGetPixel(imageSrc,x,y) ^ physDevSrc->backgroundPixel) & pixel_mask));
1098 XPutImage( gdi_display, pixmap, gc, imageDst,
1099 0, 0, 0, 0, width, height );
1100 XDestroyImage( imageSrc );
1101 X11DRV_DIB_DestroyXImage( imageDst );
1102 wine_tsx11_unlock();
1105 return exposures;
1109 /***********************************************************************
1110 * BITBLT_GetDstArea
1112 * Retrieve an area from the destination DC, mapping all the
1113 * pixels to Windows colors.
1115 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, const RECT *visRectDst)
1117 int exposures = 0;
1118 INT width = visRectDst->right - visRectDst->left;
1119 INT height = visRectDst->bottom - visRectDst->top;
1120 BOOL memdc = (GetObjectType( physDev->dev.hdc ) == OBJ_MEMDC);
1122 wine_tsx11_lock();
1124 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1125 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1127 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1128 physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
1129 width, height, 0, 0 );
1130 exposures++;
1132 else
1134 register INT x, y;
1135 XImage *image;
1137 if (memdc)
1138 image = XGetImage( gdi_display, physDev->drawable,
1139 physDev->dc_rect.left + visRectDst->left,
1140 physDev->dc_rect.top + visRectDst->top,
1141 width, height, AllPlanes, ZPixmap );
1142 else
1144 /* Make sure we don't get a BadMatch error */
1145 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1146 physDev->dc_rect.left + visRectDst->left,
1147 physDev->dc_rect.top + visRectDst->top,
1148 width, height, 0, 0);
1149 exposures++;
1150 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1151 AllPlanes, ZPixmap );
1153 if (image)
1155 for (y = 0; y < height; y++)
1156 for (x = 0; x < width; x++)
1157 XPutPixel( image, x, y,
1158 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1159 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1160 XDestroyImage( image );
1164 wine_tsx11_unlock();
1165 return exposures;
1169 /***********************************************************************
1170 * BITBLT_PutDstArea
1172 * Put an area back into the destination DC, mapping the pixel
1173 * colors to X pixels.
1175 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, const RECT *visRectDst)
1177 int exposures = 0;
1178 INT width = visRectDst->right - visRectDst->left;
1179 INT height = visRectDst->bottom - visRectDst->top;
1181 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1183 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1184 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1186 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1187 physDev->dc_rect.left + visRectDst->left,
1188 physDev->dc_rect.top + visRectDst->top );
1189 exposures++;
1191 else
1193 register INT x, y;
1194 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1195 AllPlanes, ZPixmap );
1196 for (y = 0; y < height; y++)
1197 for (x = 0; x < width; x++)
1199 XPutPixel( image, x, y,
1200 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1202 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1203 physDev->dc_rect.left + visRectDst->left,
1204 physDev->dc_rect.top + visRectDst->top, width, height );
1205 XDestroyImage( image );
1207 return exposures;
1211 /***********************************************************************
1212 * client_side_dib_copy
1214 static BOOL client_side_dib_copy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1215 X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1216 INT width, INT height )
1218 DIBSECTION srcDib, dstDib;
1219 BYTE *srcPtr, *dstPtr;
1220 INT srcRowOffset, dstRowOffset;
1221 INT bytesPerPixel;
1222 INT bytesToCopy;
1223 INT y;
1224 static RECT unusedRect;
1226 if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib))
1227 return FALSE;
1228 if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib))
1229 return FALSE;
1231 /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */
1232 if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight)
1233 return FALSE;
1234 if (xSrc + width > srcDib.dsBm.bmWidth)
1235 width = srcDib.dsBm.bmWidth - xSrc;
1236 if (ySrc + height > srcDib.dsBm.bmHeight)
1237 height = srcDib.dsBm.bmHeight - ySrc;
1239 if (GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION)
1241 /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */
1242 FIXME("potential optimization: client-side complex region clipping\n");
1243 return FALSE;
1245 if (dstDib.dsBm.bmBitsPixel <= 8)
1247 static BOOL fixme_once;
1248 if(!fixme_once++) FIXME("potential optimization: client-side color-index mode DIB copy\n");
1249 return FALSE;
1251 if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1252 dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1253 !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1254 && !(srcDib.dsBmih.biCompression == BI_RGB &&
1255 dstDib.dsBmih.biCompression == BI_RGB))
1257 FIXME("potential optimization: client-side compressed DIB copy\n");
1258 return FALSE;
1260 if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1262 FIXME("potential optimization: pixel format conversion\n");
1263 return FALSE;
1265 if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1267 FIXME("negative widths not yet implemented\n");
1268 return FALSE;
1271 switch (dstDib.dsBm.bmBitsPixel)
1273 case 15:
1274 case 16:
1275 bytesPerPixel = 2;
1276 break;
1277 case 24:
1278 bytesPerPixel = 3;
1279 break;
1280 case 32:
1281 bytesPerPixel = 4;
1282 break;
1283 default:
1284 FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1285 return FALSE;
1288 bytesToCopy = width * bytesPerPixel;
1290 if (physDevSrc->bitmap->topdown)
1292 srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1293 srcRowOffset = srcDib.dsBm.bmWidthBytes;
1295 else
1297 srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1298 + xSrc*bytesPerPixel];
1299 srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1301 if (physDevDst->bitmap->topdown)
1303 dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1304 dstRowOffset = dstDib.dsBm.bmWidthBytes;
1306 else
1308 dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1309 + xDst*bytesPerPixel];
1310 dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1313 /* Handle overlapping regions on the same DIB */
1314 if (physDevSrc == physDevDst && ySrc < yDst)
1316 srcPtr += srcRowOffset * (height - 1);
1317 srcRowOffset = -srcRowOffset;
1318 dstPtr += dstRowOffset * (height - 1);
1319 dstRowOffset = -dstRowOffset;
1322 for (y = yDst; y < yDst + height; ++y)
1324 memmove(dstPtr, srcPtr, bytesToCopy);
1325 srcPtr += srcRowOffset;
1326 dstPtr += dstRowOffset;
1329 return TRUE;
1332 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
1334 if (physDevSrc->depth != physDevDst->depth) return FALSE;
1335 if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
1336 if (physDevSrc->color_shifts && physDevDst->color_shifts)
1337 return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
1338 return FALSE;
1341 static void execute_rop( X11DRV_PDEVICE *physdev, Pixmap src_pixmap, GC gc,
1342 const RECT *visrect, DWORD rop )
1344 Pixmap pixmaps[3];
1345 Pixmap result = src_pixmap;
1346 BOOL null_brush;
1347 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1348 BOOL use_pat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1349 BOOL use_dst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1350 int width = visrect->right - visrect->left;
1351 int height = visrect->bottom - visrect->top;
1353 pixmaps[SRC] = src_pixmap;
1354 pixmaps[TMP] = 0;
1355 wine_tsx11_lock();
1356 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
1357 wine_tsx11_unlock();
1359 if (use_dst) BITBLT_GetDstArea( physdev, pixmaps[DST], gc, visrect );
1360 null_brush = use_pat && !X11DRV_SetupGCForPatBlt( physdev, gc, TRUE );
1362 wine_tsx11_lock();
1363 for ( ; *opcode; opcode++)
1365 if (OP_DST(*opcode) == DST) result = pixmaps[DST];
1366 XSetFunction( gdi_display, gc, OP_ROP(*opcode) );
1367 switch(OP_SRCDST(*opcode))
1369 case OP_ARGS(DST,TMP):
1370 case OP_ARGS(SRC,TMP):
1371 if (!pixmaps[TMP])
1372 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
1373 /* fall through */
1374 case OP_ARGS(DST,SRC):
1375 case OP_ARGS(SRC,DST):
1376 case OP_ARGS(TMP,SRC):
1377 case OP_ARGS(TMP,DST):
1378 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)], pixmaps[OP_DST(*opcode)], gc,
1379 0, 0, width, height, 0, 0 );
1380 break;
1381 case OP_ARGS(PAT,DST):
1382 case OP_ARGS(PAT,SRC):
1383 if (!null_brush)
1384 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)], gc, 0, 0, width, height );
1385 break;
1388 XSetFunction( gdi_display, physdev->gc, GXcopy );
1389 physdev->exposures += BITBLT_PutDstArea( physdev, result, visrect );
1390 XFreePixmap( gdi_display, pixmaps[DST] );
1391 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1392 wine_tsx11_unlock();
1395 /***********************************************************************
1396 * X11DRV_PatBlt
1398 BOOL X11DRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
1400 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1401 BOOL usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1402 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1404 if (usePat && !X11DRV_SetupGCForBrush( physDev )) return TRUE;
1406 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1408 wine_tsx11_lock();
1409 XSetFunction( gdi_display, physDev->gc, OP_ROP(*opcode) );
1411 switch(rop) /* a few special cases */
1413 case BLACKNESS: /* 0x00 */
1414 case WHITENESS: /* 0xff */
1415 if ((physDev->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
1417 XSetFunction( gdi_display, physDev->gc, GXcopy );
1418 if (rop == BLACKNESS)
1419 XSetForeground( gdi_display, physDev->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1420 else
1421 XSetForeground( gdi_display, physDev->gc,
1422 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1423 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
1425 break;
1426 case DSTINVERT: /* 0x55 */
1427 if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
1429 /* Xor is much better when we do not have full colormap. */
1430 /* Using white^black ensures that we invert at least black */
1431 /* and white. */
1432 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1433 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1434 XSetFunction( gdi_display, physDev->gc, GXxor );
1435 XSetForeground( gdi_display, physDev->gc, xor_pix);
1436 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
1438 break;
1440 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1441 physDev->dc_rect.left + dst->visrect.left,
1442 physDev->dc_rect.top + dst->visrect.top,
1443 dst->visrect.right - dst->visrect.left,
1444 dst->visrect.bottom - dst->visrect.top );
1445 wine_tsx11_unlock();
1447 X11DRV_UnlockDIBSection( physDev, TRUE );
1448 return TRUE;
1452 /***********************************************************************
1453 * X11DRV_StretchBlt
1455 BOOL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1456 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1458 X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
1459 X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev ); /* FIXME: check that it's really an x11 dev */
1460 BOOL fStretch;
1461 INT width, height;
1462 INT sDst, sSrc = DIB_Status_None;
1463 const BYTE *opcode;
1464 Pixmap src_pixmap;
1465 GC tmpGC;
1467 fStretch = (src->width != dst->width) || (src->height != dst->height);
1469 if (physDevDst != physDevSrc)
1470 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None );
1472 width = dst->visrect.right - dst->visrect.left;
1473 height = dst->visrect.bottom - dst->visrect.top;
1475 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None );
1476 if (physDevDst == physDevSrc) sSrc = sDst;
1478 /* try client-side DIB copy */
1479 if (!fStretch && rop == SRCCOPY &&
1480 sSrc == DIB_Status_AppMod && sDst == DIB_Status_AppMod &&
1481 same_format(physDevSrc, physDevDst))
1483 if (client_side_dib_copy( physDevSrc, src->visrect.left, src->visrect.top,
1484 physDevDst, dst->visrect.left, dst->visrect.top, width, height ))
1485 goto done;
1488 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod );
1490 opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1492 /* a few optimizations for single-op ROPs */
1493 if (!fStretch && !opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1495 if (same_format(physDevSrc, physDevDst))
1497 wine_tsx11_lock();
1498 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1499 wine_tsx11_unlock();
1501 if (physDevSrc != physDevDst)
1503 if (sSrc == DIB_Status_AppMod)
1505 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, src->visrect.left, src->visrect.top,
1506 dst->visrect.left, dst->visrect.top, width, height );
1507 goto done;
1509 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1511 wine_tsx11_lock();
1512 XCopyArea( gdi_display, physDevSrc->drawable,
1513 physDevDst->drawable, physDevDst->gc,
1514 physDevSrc->dc_rect.left + src->visrect.left,
1515 physDevSrc->dc_rect.top + src->visrect.top,
1516 width, height,
1517 physDevDst->dc_rect.left + dst->visrect.left,
1518 physDevDst->dc_rect.top + dst->visrect.top );
1519 physDevDst->exposures++;
1520 wine_tsx11_unlock();
1521 goto done;
1523 if (physDevSrc->depth == 1)
1525 int fg, bg;
1527 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1528 get_colors(physDevDst, physDevSrc, &fg, &bg);
1529 wine_tsx11_lock();
1530 XSetBackground( gdi_display, physDevDst->gc, fg );
1531 XSetForeground( gdi_display, physDevDst->gc, bg );
1532 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1533 XCopyPlane( gdi_display, physDevSrc->drawable,
1534 physDevDst->drawable, physDevDst->gc,
1535 physDevSrc->dc_rect.left + src->visrect.left,
1536 physDevSrc->dc_rect.top + src->visrect.top,
1537 width, height,
1538 physDevDst->dc_rect.left + dst->visrect.left,
1539 physDevDst->dc_rect.top + dst->visrect.top, 1 );
1540 physDevDst->exposures++;
1541 wine_tsx11_unlock();
1542 goto done;
1546 wine_tsx11_lock();
1547 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1548 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1549 XSetGraphicsExposures( gdi_display, tmpGC, False );
1550 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, physDevDst->depth );
1551 wine_tsx11_unlock();
1553 if (physDevDst != physDevSrc) X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1555 if(!X11DRV_XRender_GetSrcAreaStretch( physDevSrc, physDevDst, src_pixmap, tmpGC, src, dst ))
1557 if (fStretch)
1558 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, src_pixmap, tmpGC, src, dst );
1559 else
1560 BITBLT_GetSrcArea( physDevSrc, physDevDst, src_pixmap, tmpGC, &src->visrect );
1563 execute_rop( physDevDst, src_pixmap, tmpGC, &dst->visrect, rop );
1565 wine_tsx11_lock();
1566 XFreePixmap( gdi_display, src_pixmap );
1567 XFreeGC( gdi_display, tmpGC );
1568 wine_tsx11_unlock();
1570 done:
1571 if (physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1572 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1573 return TRUE;
1577 /***********************************************************************
1578 * X11DRV_AlphaBlend
1580 BOOL X11DRV_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
1581 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
1583 X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
1584 X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev ); /* FIXME: check that it's really an x11 dev */
1586 if (src->x < 0 || src->y < 0 || src->width < 0 || src->height < 0 ||
1587 src->width > physDevSrc->drawable_rect.right - physDevSrc->drawable_rect.left - src->x ||
1588 src->height > physDevSrc->drawable_rect.bottom - physDevSrc->drawable_rect.top - src->y)
1590 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src->x, src->y, src->width, src->height );
1591 SetLastError( ERROR_INVALID_PARAMETER );
1592 return FALSE;
1595 return XRender_AlphaBlend( physDevDst, dst, physDevSrc, src, blendfn );
1599 static void free_heap_bits( struct gdi_image_bits *bits )
1601 HeapFree( GetProcessHeap(), 0, bits->ptr );
1604 static void free_ximage_bits( struct gdi_image_bits *bits )
1606 wine_tsx11_lock();
1607 XFree( bits->ptr );
1608 wine_tsx11_unlock();
1611 /* store the palette or color mask data in the bitmap info structure */
1612 static void set_color_info( PHYSDEV dev, const ColorShifts *color_shifts, BITMAPINFO *info )
1614 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1616 info->bmiHeader.biCompression = BI_RGB;
1617 info->bmiHeader.biClrUsed = 0;
1619 switch (info->bmiHeader.biBitCount)
1621 case 4:
1622 case 8:
1624 RGBQUAD *rgb = (RGBQUAD *)colors;
1625 PALETTEENTRY palette[256];
1626 UINT i, count;
1628 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1629 count = X11DRV_GetSystemPaletteEntries( dev, 0, info->bmiHeader.biClrUsed, palette );
1630 for (i = 0; i < count; i++)
1632 rgb[i].rgbRed = palette[i].peRed;
1633 rgb[i].rgbGreen = palette[i].peGreen;
1634 rgb[i].rgbBlue = palette[i].peBlue;
1635 rgb[i].rgbReserved = 0;
1637 memset( &rgb[count], 0, (info->bmiHeader.biClrUsed - count) * sizeof(*rgb) );
1638 break;
1640 case 16:
1641 colors[0] = color_shifts->logicalRed.max << color_shifts->logicalRed.shift;
1642 colors[1] = color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift;
1643 colors[2] = color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift;
1644 if (colors[0] != 0x7c00 || colors[1] != 0x03e0 || colors[2] != 0x001f)
1645 info->bmiHeader.biCompression = BI_BITFIELDS;
1646 break;
1647 case 32:
1648 colors[0] = color_shifts->logicalRed.max << color_shifts->logicalRed.shift;
1649 colors[1] = color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift;
1650 colors[2] = color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift;
1651 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1652 info->bmiHeader.biCompression = BI_BITFIELDS;
1653 break;
1657 /* check if the specified color info is suitable for PutImage */
1658 static BOOL matching_color_info( PHYSDEV dev, const ColorShifts *color_shifts, const BITMAPINFO *info )
1660 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1662 switch (info->bmiHeader.biBitCount)
1664 case 1:
1665 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1666 return !info->bmiHeader.biClrUsed; /* color map not allowed */
1667 case 4:
1668 case 8:
1670 RGBQUAD *rgb = (RGBQUAD *)colors;
1671 PALETTEENTRY palette[256];
1672 UINT i, count;
1674 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1675 count = X11DRV_GetSystemPaletteEntries( dev, 0, 1 << info->bmiHeader.biBitCount, palette );
1676 if (count != info->bmiHeader.biClrUsed) return FALSE;
1677 for (i = 0; i < count; i++)
1679 if (rgb[i].rgbRed != palette[i].peRed ||
1680 rgb[i].rgbGreen != palette[i].peGreen ||
1681 rgb[i].rgbBlue != palette[i].peBlue) return FALSE;
1683 return TRUE;
1685 case 16:
1686 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1687 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == colors[0] &&
1688 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == colors[1] &&
1689 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == colors[2]);
1690 if (info->bmiHeader.biCompression == BI_RGB)
1691 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == 0x7c00 &&
1692 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == 0x03e0 &&
1693 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == 0x001f);
1694 break;
1695 case 32:
1696 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1697 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == colors[0] &&
1698 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == colors[1] &&
1699 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == colors[2]);
1700 /* fall through */
1701 case 24:
1702 if (info->bmiHeader.biCompression == BI_RGB)
1703 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == 0xff0000 &&
1704 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == 0x00ff00 &&
1705 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == 0x0000ff);
1706 break;
1708 return FALSE;
1711 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1712 static DWORD copy_image_bits( BITMAPINFO *info, const ColorShifts *color_shifts, XImage *image,
1713 const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
1714 const int *mapping, unsigned int zeropad_mask )
1716 #ifdef WORDS_BIGENDIAN
1717 static const int client_byte_order = MSBFirst;
1718 #else
1719 static const int client_byte_order = LSBFirst;
1720 #endif
1721 BOOL need_byteswap;
1722 int x, y, height = abs(info->bmiHeader.biHeight);
1723 int width_bytes = image->bytes_per_line;
1724 int padding_pos;
1725 unsigned char *src, *dst;
1727 switch (info->bmiHeader.biBitCount)
1729 case 1:
1730 need_byteswap = (image->bitmap_bit_order != MSBFirst);
1731 break;
1732 case 4:
1733 need_byteswap = (image->byte_order != MSBFirst);
1734 break;
1735 case 16:
1736 case 32:
1737 need_byteswap = (image->byte_order != client_byte_order);
1738 break;
1739 case 24:
1740 need_byteswap = ((image->byte_order == LSBFirst && color_shifts->logicalBlue.shift == 16) ||
1741 (image->byte_order == MSBFirst && color_shifts->logicalBlue.shift == 0));
1742 break;
1743 default:
1744 need_byteswap = FALSE;
1745 break;
1748 if ((need_byteswap && !src_bits->is_copy) || /* need to swap bytes */
1749 (zeropad_mask != ~0u && !src_bits->is_copy) || /* need to clear padding bytes */
1750 (mapping && !src_bits->is_copy) || /* need to remap pixels */
1751 (width_bytes & 3) || /* need to fixup line alignment */
1752 (info->bmiHeader.biHeight > 0)) /* need to flip vertically */
1754 width_bytes = (width_bytes + 3) & ~3;
1755 info->bmiHeader.biSizeImage = height * width_bytes;
1756 if (!(dst_bits->ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
1757 return ERROR_OUTOFMEMORY;
1758 dst_bits->offset = src_bits->offset;
1759 dst_bits->is_copy = TRUE;
1760 dst_bits->free = free_heap_bits;
1762 else
1764 /* swap bits in place */
1765 dst_bits->ptr = src_bits->ptr;
1766 dst_bits->offset = src_bits->offset;
1767 dst_bits->is_copy = src_bits->is_copy;
1768 dst_bits->free = NULL;
1769 if (!need_byteswap && zeropad_mask == ~0u && !mapping) return ERROR_SUCCESS; /* nothing to do */
1772 src = src_bits->ptr;
1773 dst = dst_bits->ptr;
1774 padding_pos = width_bytes/sizeof(unsigned int) - 1;
1776 if (info->bmiHeader.biHeight > 0)
1778 dst += (height - 1) * width_bytes;
1779 width_bytes = -width_bytes;
1782 if (need_byteswap || mapping)
1784 switch (info->bmiHeader.biBitCount)
1786 case 1:
1787 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1789 for (x = 0; x < image->bytes_per_line; x++)
1790 dst[x] = bit_swap[src[x]];
1791 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1793 break;
1794 case 4:
1795 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1797 if (mapping)
1798 for (x = 0; x < image->bytes_per_line; x++)
1799 dst[x] = (mapping[src[x] & 0x0f] << 4) | mapping[src[x] >> 4];
1800 else
1801 for (x = 0; x < image->bytes_per_line; x++)
1802 dst[x] = (src[x] << 4) | (src[x] >> 4);
1803 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1805 break;
1806 case 8:
1807 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1809 for (x = 0; x < image->bytes_per_line; x++)
1810 dst[x] = mapping[src[x]];
1811 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1813 break;
1814 case 16:
1815 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1817 for (x = 0; x < info->bmiHeader.biWidth; x++)
1818 ((USHORT *)dst)[x] = RtlUshortByteSwap( ((const USHORT *)src)[x] );
1819 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1821 break;
1822 case 24:
1823 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1825 for (x = 0; x < info->bmiHeader.biWidth; x++)
1827 unsigned char tmp = src[3 * x];
1828 dst[3 * x] = src[3 * x + 2];
1829 dst[3 * x + 1] = src[3 * x + 1];
1830 dst[3 * x + 2] = tmp;
1832 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1834 break;
1835 case 32:
1836 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1837 for (x = 0; x < info->bmiHeader.biWidth; x++)
1838 ((ULONG *)dst)[x] = RtlUlongByteSwap( ((const ULONG *)src)[x] );
1839 break;
1842 else if (src != dst)
1844 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1846 memcpy( dst, src, image->bytes_per_line );
1847 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1850 else /* only need to clear the padding */
1852 for (y = 0; y < height; y++, dst += width_bytes)
1853 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1855 return ERROR_SUCCESS;
1858 /***********************************************************************
1859 * X11DRV_PutImage
1861 DWORD X11DRV_PutImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info, const struct gdi_image_bits *bits,
1862 const RECT *rect, DWORD rop )
1864 X11DRV_PDEVICE *physdev;
1865 X_PHYSBITMAP *bitmap;
1866 DWORD ret;
1867 XImage *image;
1868 int depth;
1869 struct gdi_image_bits dst_bits;
1870 const XPixmapFormatValues *format;
1871 const ColorShifts *color_shifts;
1872 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1873 const int *mapping = NULL;
1875 if (hbitmap)
1877 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
1878 physdev = NULL;
1879 depth = bitmap->pixmap_depth;
1880 color_shifts = &bitmap->pixmap_color_shifts;
1882 else
1884 physdev = get_x11drv_dev( dev );
1885 bitmap = NULL;
1886 depth = physdev->depth;
1887 color_shifts = physdev->color_shifts;
1889 format = pixmap_formats[depth];
1891 if (info->bmiHeader.biPlanes != 1) goto update_format;
1892 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1893 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1894 if (!matching_color_info( dev, color_shifts, info )) goto update_format;
1895 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1897 wine_tsx11_lock();
1898 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1899 info->bmiHeader.biWidth, abs(info->bmiHeader.biHeight), 32, 0 );
1900 wine_tsx11_unlock();
1901 if (!image) return ERROR_OUTOFMEMORY;
1903 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1905 if (bitmap || (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST)))
1906 mapping = X11DRV_PALETTE_PaletteToXPixel;
1909 ret = copy_image_bits( info, color_shifts, image, bits, &dst_bits, mapping, ~0u );
1911 if (!ret)
1913 int width = rect->right - rect->left;
1914 int height = rect->bottom - rect->top;
1916 image->data = dst_bits.ptr;
1917 if (bitmap)
1919 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
1920 wine_tsx11_lock();
1921 XPutImage( gdi_display, bitmap->pixmap, get_bitmap_gc(depth), image, dst_bits.offset, 0,
1922 rect->left, rect->top, width, height );
1923 wine_tsx11_unlock();
1924 X11DRV_DIB_Unlock( bitmap, TRUE );
1926 else
1928 X11DRV_LockDIBSection( physdev, DIB_Status_GdiMod );
1930 /* optimization for single-op ROPs */
1931 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1933 wine_tsx11_lock();
1934 XSetFunction( gdi_display, physdev->gc, OP_ROP(*opcode) );
1935 XPutImage( gdi_display, physdev->drawable, physdev->gc, image, dst_bits.offset, 0,
1936 physdev->dc_rect.left + rect->left, physdev->dc_rect.top + rect->top,
1937 width, height );
1938 wine_tsx11_unlock();
1940 else
1942 Pixmap src_pixmap;
1943 GC gc;
1945 wine_tsx11_lock();
1946 gc = XCreateGC( gdi_display, physdev->drawable, 0, NULL );
1947 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1948 XSetGraphicsExposures( gdi_display, gc, False );
1949 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1950 XPutImage( gdi_display, src_pixmap, gc, image, dst_bits.offset, 0, 0, 0, width, height );
1951 wine_tsx11_unlock();
1953 execute_rop( physdev, src_pixmap, gc, rect, rop );
1955 wine_tsx11_lock();
1956 XFreePixmap( gdi_display, src_pixmap );
1957 XFreeGC( gdi_display, gc );
1958 wine_tsx11_unlock();
1961 X11DRV_UnlockDIBSection( physdev, !ret );
1963 image->data = NULL;
1966 wine_tsx11_lock();
1967 XDestroyImage( image );
1968 wine_tsx11_unlock();
1969 if (dst_bits.free) dst_bits.free( &dst_bits );
1970 return ret;
1972 update_format:
1973 info->bmiHeader.biPlanes = 1;
1974 info->bmiHeader.biBitCount = format->bits_per_pixel;
1975 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1976 set_color_info( dev, physdev->color_shifts, info );
1977 return ERROR_BAD_FORMAT;
1980 /***********************************************************************
1981 * X11DRV_GetImage
1983 DWORD X11DRV_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1984 struct gdi_image_bits *bits, const RECT *rect )
1986 X11DRV_PDEVICE *physdev;
1987 X_PHYSBITMAP *bitmap;
1988 DWORD ret = ERROR_SUCCESS;
1989 XImage *image;
1990 UINT align, x, y, width, height;
1991 int depth;
1992 struct gdi_image_bits src_bits;
1993 const XPixmapFormatValues *format;
1994 const ColorShifts *color_shifts;
1995 const int *mapping = NULL;
1997 if (hbitmap)
1999 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2000 physdev = NULL;
2001 depth = bitmap->pixmap_depth;
2002 color_shifts = &bitmap->pixmap_color_shifts;
2004 else
2006 physdev = get_x11drv_dev( dev );
2007 bitmap = NULL;
2008 depth = physdev->depth;
2009 color_shifts = physdev->color_shifts;
2011 format = pixmap_formats[depth];
2013 /* align start and width to 32-bit boundary */
2014 switch (format->bits_per_pixel)
2016 case 1: align = 32; break;
2017 case 4: align = 8; mapping = X11DRV_PALETTE_XPixelToPalette; break;
2018 case 8: align = 4; mapping = X11DRV_PALETTE_XPixelToPalette; break;
2019 case 16: align = 2; break;
2020 case 24: align = 4; break;
2021 case 32: align = 1; break;
2022 default:
2023 FIXME( "depth %u bpp %u not supported yet\n", depth, format->bits_per_pixel );
2024 return ERROR_BAD_FORMAT;
2026 src_bits.offset = rect->left & (align - 1);
2027 x = rect->left - src_bits.offset;
2028 y = rect->top;
2029 width = rect->right - x;
2030 height = rect->bottom - rect->top;
2031 if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1);
2033 if (bitmap)
2035 BITMAP bm;
2036 GetObjectW( hbitmap, sizeof(bm), &bm );
2037 width = min( width, bm.bmWidth - x );
2038 height = min( height, bm.bmHeight - y );
2039 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
2040 wine_tsx11_lock();
2041 image = XGetImage( gdi_display, bitmap->pixmap, x, y, width, height, AllPlanes, ZPixmap );
2042 wine_tsx11_unlock();
2043 X11DRV_DIB_Unlock( bitmap, TRUE );
2045 else if (GetObjectType( dev->hdc ) == OBJ_MEMDC)
2047 X11DRV_LockDIBSection( physdev, DIB_Status_GdiMod );
2048 width = min( width, physdev->dc_rect.right - physdev->dc_rect.left - x );
2049 height = min( height, physdev->dc_rect.bottom - physdev->dc_rect.top - y );
2050 wine_tsx11_lock();
2051 image = XGetImage( gdi_display, physdev->drawable,
2052 physdev->dc_rect.left + x, physdev->dc_rect.top + y,
2053 width, height, AllPlanes, ZPixmap );
2054 wine_tsx11_unlock();
2055 X11DRV_UnlockDIBSection( physdev, FALSE );
2057 else
2059 Pixmap pixmap;
2061 wine_tsx11_lock();
2062 /* use a temporary pixmap to avoid BadMatch errors */
2063 pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2064 XCopyArea( gdi_display, physdev->drawable, pixmap, get_bitmap_gc(depth),
2065 physdev->dc_rect.left + x, physdev->dc_rect.top + y, width, height, 0, 0 );
2066 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
2067 XFreePixmap( gdi_display, pixmap );
2068 wine_tsx11_unlock();
2070 if (!image) return ERROR_OUTOFMEMORY;
2072 info->bmiHeader.biSize = sizeof(info->bmiHeader);
2073 info->bmiHeader.biWidth = width;
2074 info->bmiHeader.biHeight = -height;
2075 info->bmiHeader.biPlanes = 1;
2076 info->bmiHeader.biBitCount = image->bits_per_pixel;
2077 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
2078 info->bmiHeader.biXPelsPerMeter = 0;
2079 info->bmiHeader.biYPelsPerMeter = 0;
2080 info->bmiHeader.biClrImportant = 0;
2081 set_color_info( dev, color_shifts, info );
2083 src_bits.ptr = image->data;
2084 src_bits.is_copy = TRUE;
2085 ret = copy_image_bits( info, color_shifts, image, &src_bits, bits, mapping,
2086 zeropad_masks[(width * image->bits_per_pixel) & 31] );
2088 if (!ret && bits->ptr == image->data)
2090 bits->free = free_ximage_bits;
2091 image->data = NULL;
2093 wine_tsx11_lock();
2094 XDestroyImage( image );
2095 wine_tsx11_unlock();
2096 return ret;