advapi32: Return a fake handle from EventRegister.
[wine/multimedia.git] / dlls / winex11.drv / bitblt.c
blob056e4c4108d0abbbffd52f7897f30cabe511bff3
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 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
57 { OP(PAT,DST,GXclear) }, /* 0x00 0 */
58 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */
59 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */
60 { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */
61 { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */
62 { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */
63 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */
64 { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */
65 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */
66 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */
67 { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */
68 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */
69 { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */
70 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */
71 { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */
72 { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */
73 { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */
74 { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */
75 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */
76 { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */
77 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */
78 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */
79 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
80 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
81 OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */
82 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
83 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
84 OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/
85 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
86 OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */
87 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
88 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */
89 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
90 OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */
91 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
92 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */
93 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
94 OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */
95 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
96 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */
97 { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */
98 { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */
99 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */
100 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */
101 { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */
102 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */
103 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
104 OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */
105 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
106 OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */
107 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
108 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
109 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXequiv),
110 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */
111 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */
112 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
113 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
114 OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */
115 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */
116 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
117 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
118 OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/
119 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
120 OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */
121 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */
122 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
123 OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */
124 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */
125 { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */
126 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */
127 { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
128 OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */
129 { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */
130 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
131 OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */
132 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
133 OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */
134 { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */
135 { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */
136 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
137 OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */
138 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */
139 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
140 OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */
141 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */
142 { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */
143 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
144 OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */
145 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
146 OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */
147 { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */
148 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */
149 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */
150 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
151 OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */
152 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
153 OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */
154 { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */
155 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */
156 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
157 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */
158 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
159 OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */
160 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */
161 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
162 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
163 OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */
164 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
165 OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */
166 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */
167 { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */
168 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
169 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
170 OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/
171 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
172 OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */
173 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */
174 { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */
175 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */
176 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
177 OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */
178 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
179 OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */
180 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */
181 { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */
182 { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */
183 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */
184 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
185 OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */
186 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */
187 { OP(PAT,DST,GXxor) }, /* 0x5a D^P */
188 { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
189 OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */
190 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
191 OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */
192 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */
193 { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
194 OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */
195 { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */
196 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */
197 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
198 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
199 OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */
200 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
201 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */
202 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */
203 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
204 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */
205 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */
206 { OP(SRC,DST,GXxor) }, /* 0x66 S^D */
207 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
208 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */
209 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
210 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
211 OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/
212 { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */
213 { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */
214 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
215 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
216 OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */
217 { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */
218 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
219 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
220 OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */
221 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
222 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */
223 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */
224 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */
225 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
226 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
227 OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/
228 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
229 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */
230 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */
231 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
232 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */
233 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */
234 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
235 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */
236 { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */
237 { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */
238 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
239 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
240 OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */
241 { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
242 OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */
243 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */
244 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
245 OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */
246 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */
247 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
248 OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */
249 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */
250 { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */
251 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
252 OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */
253 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */
254 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
255 OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */
256 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */
257 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
258 OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */
259 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
260 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
261 OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */
262 { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */
263 { OP(SRC,DST,GXand) }, /* 0x88 S&D */
264 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
265 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */
266 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */
267 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
268 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */
269 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */
270 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
271 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */
272 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
273 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
274 OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/
275 { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */
276 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */
277 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
278 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */
279 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
280 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
281 OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */
282 { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */
283 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
284 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
285 OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */
286 { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */
287 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */
288 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
289 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
290 OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */
291 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
292 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */
293 { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */
294 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */
295 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
296 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */
297 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */
298 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
299 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */
300 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
301 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
302 OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */
303 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */
304 { OP(PAT,DST,GXand) }, /* 0xa0 D&P */
305 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
306 OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */
307 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */
308 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
309 OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */
310 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
311 OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */
312 { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */
313 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */
314 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
315 OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */
316 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */
317 { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */
318 { OP(PAT,DST,GXnoop) }, /* 0xaa D */
319 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */
320 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
321 OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */
322 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
323 OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */
324 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */
325 { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */
326 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */
327 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
328 OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */
329 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
330 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
331 OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/
332 { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */
333 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */
334 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
335 OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */
336 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
337 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
338 OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */
339 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */
340 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
341 OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */
342 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
343 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */
344 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */
345 { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */
346 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
347 OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */
348 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
349 OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */
350 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */
351 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */
352 { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */
353 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
354 OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */
355 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
356 OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */
357 { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */
358 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */
359 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
360 OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */
361 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */
362 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
363 OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */
364 { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */
365 { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */
366 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
367 OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */
368 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
369 OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */
370 { OP(SRC,DST,GXcopy) }, /* 0xcc S */
371 { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */
372 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */
373 { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */
374 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */
375 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
376 OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */
377 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */
378 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
379 OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */
380 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
381 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
382 OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/
383 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */
384 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
385 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
386 OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */
387 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */
388 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
389 OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */
390 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
391 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */
392 { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
393 OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */
394 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
395 OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */
396 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */
397 { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */
398 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */
399 { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */
400 { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */
401 { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */
402 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
403 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */
404 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
405 OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */
406 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
407 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */
408 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
409 OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */
410 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
411 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */
412 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
413 OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */
414 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
415 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
416 OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/
417 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
418 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
419 OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/
420 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */
421 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */
422 { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */
423 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */
424 { OP(SRC,DST,GXor) }, /* 0xee S|D */
425 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */
426 { OP(PAT,DST,GXcopy) }, /* 0xf0 P */
427 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */
428 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */
429 { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */
430 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */
431 { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */
432 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */
433 { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */
434 { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */
435 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */
436 { OP(PAT,DST,GXor) }, /* 0xfa D|P */
437 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */
438 { OP(PAT,SRC,GXor) }, /* 0xfc P|S */
439 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */
440 { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */
441 { OP(PAT,DST,GXset) } /* 0xff 1 */
444 static const unsigned char bit_swap[256] =
446 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
447 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
448 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
449 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
450 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
451 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
452 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
453 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
454 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
455 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
456 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
457 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
458 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
459 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
460 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
461 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
462 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
463 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
464 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
465 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
466 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
467 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
468 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
469 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
470 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
471 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
472 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
473 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
474 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
475 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
476 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
477 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
480 #ifdef WORDS_BIGENDIAN
481 static const unsigned int zeropad_masks[32] =
483 0xffffffff, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000, 0xfc000000, 0xfe000000,
484 0xff000000, 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000,
485 0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
486 0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe
488 #else
489 static const unsigned int zeropad_masks[32] =
491 0xffffffff, 0x00000080, 0x000000c0, 0x000000e0, 0x000000f0, 0x000000f8, 0x000000fc, 0x000000fe,
492 0x000000ff, 0x000080ff, 0x0000c0ff, 0x0000e0ff, 0x0000f0ff, 0x0000f8ff, 0x0000fcff, 0x0000feff,
493 0x0000ffff, 0x0080ffff, 0x00c0ffff, 0x00e0ffff, 0x00f0ffff, 0x00f8ffff, 0x00fcffff, 0x00feffff,
494 0x00ffffff, 0x80ffffff, 0xc0ffffff, 0xe0ffffff, 0xf0ffffff, 0xf8ffffff, 0xfcffffff, 0xfeffffff
496 #endif
498 #ifdef BITBLT_TEST /* Opcodes test */
500 static int do_bitop( int s, int d, int rop )
502 int res;
503 switch(rop)
505 case GXclear: res = 0; break;
506 case GXand: res = s & d; break;
507 case GXandReverse: res = s & ~d; break;
508 case GXcopy: res = s; break;
509 case GXandInverted: res = ~s & d; break;
510 case GXnoop: res = d; break;
511 case GXxor: res = s ^ d; break;
512 case GXor: res = s | d; break;
513 case GXnor: res = ~(s | d); break;
514 case GXequiv: res = ~s ^ d; break;
515 case GXinvert: res = ~d; break;
516 case GXorReverse: res = s | ~d; break;
517 case GXcopyInverted: res = ~s; break;
518 case GXorInverted: res = ~s | d; break;
519 case GXnand: res = ~(s & d); break;
520 case GXset: res = 1; break;
522 return res & 1;
525 int main()
527 int rop, i, res, src, dst, pat, tmp, dstUsed;
528 const unsigned char *opcode;
530 for (rop = 0; rop < 256; rop++)
532 res = dstUsed = 0;
533 for (i = 0; i < 8; i++)
535 pat = (i >> 2) & 1;
536 src = (i >> 1) & 1;
537 dst = i & 1;
538 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
540 switch(*opcode >> 4)
542 case OP_ARGS(DST,TMP):
543 tmp = do_bitop( dst, tmp, *opcode & 0xf );
544 break;
545 case OP_ARGS(DST,SRC):
546 src = do_bitop( dst, src, *opcode & 0xf );
547 break;
548 case OP_ARGS(SRC,TMP):
549 tmp = do_bitop( src, tmp, *opcode & 0xf );
550 break;
551 case OP_ARGS(SRC,DST):
552 dst = do_bitop( src, dst, *opcode & 0xf );
553 dstUsed = 1;
554 break;
555 case OP_ARGS(PAT,DST):
556 dst = do_bitop( pat, dst, *opcode & 0xf );
557 dstUsed = 1;
558 break;
559 case OP_ARGS(PAT,SRC):
560 src = do_bitop( pat, src, *opcode & 0xf );
561 break;
562 case OP_ARGS(TMP,DST):
563 dst = do_bitop( tmp, dst, *opcode & 0xf );
564 dstUsed = 1;
565 break;
566 case OP_ARGS(TMP,SRC):
567 src = do_bitop( tmp, src, *opcode & 0xf );
568 break;
569 default:
570 printf( "Invalid opcode %x\n", *opcode );
573 if (!dstUsed) dst = src;
574 if (dst) res |= 1 << i;
576 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
579 return 0;
582 #endif /* BITBLT_TEST */
585 /* handler for XGetImage BadMatch errors */
586 static int XGetImage_handler( Display *dpy, XErrorEvent *event, void *arg )
588 return (event->request_code == X_GetImage && event->error_code == BadMatch);
591 /***********************************************************************
592 * BITBLT_GetDstArea
594 * Retrieve an area from the destination DC, mapping all the
595 * pixels to Windows colors.
597 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, const RECT *visRectDst)
599 int exposures = 0;
600 INT width = visRectDst->right - visRectDst->left;
601 INT height = visRectDst->bottom - visRectDst->top;
602 BOOL memdc = (GetObjectType( physDev->dev.hdc ) == OBJ_MEMDC);
604 wine_tsx11_lock();
606 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
607 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
609 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
610 physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
611 width, height, 0, 0 );
612 exposures++;
614 else
616 register INT x, y;
617 XImage *image;
619 if (memdc)
620 image = XGetImage( gdi_display, physDev->drawable,
621 physDev->dc_rect.left + visRectDst->left,
622 physDev->dc_rect.top + visRectDst->top,
623 width, height, AllPlanes, ZPixmap );
624 else
626 /* Make sure we don't get a BadMatch error */
627 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
628 physDev->dc_rect.left + visRectDst->left,
629 physDev->dc_rect.top + visRectDst->top,
630 width, height, 0, 0);
631 exposures++;
632 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
633 AllPlanes, ZPixmap );
635 if (image)
637 for (y = 0; y < height; y++)
638 for (x = 0; x < width; x++)
639 XPutPixel( image, x, y,
640 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
641 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
642 XDestroyImage( image );
646 wine_tsx11_unlock();
647 return exposures;
651 /***********************************************************************
652 * BITBLT_PutDstArea
654 * Put an area back into the destination DC, mapping the pixel
655 * colors to X pixels.
657 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, const RECT *visRectDst)
659 int exposures = 0;
660 INT width = visRectDst->right - visRectDst->left;
661 INT height = visRectDst->bottom - visRectDst->top;
663 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
665 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
666 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
668 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
669 physDev->dc_rect.left + visRectDst->left,
670 physDev->dc_rect.top + visRectDst->top );
671 exposures++;
673 else
675 register INT x, y;
676 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
677 AllPlanes, ZPixmap );
678 for (y = 0; y < height; y++)
679 for (x = 0; x < width; x++)
681 XPutPixel( image, x, y,
682 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
684 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
685 physDev->dc_rect.left + visRectDst->left,
686 physDev->dc_rect.top + visRectDst->top, width, height );
687 XDestroyImage( image );
689 return exposures;
692 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
694 if (physDevSrc->depth != physDevDst->depth) return FALSE;
695 if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
696 if (physDevSrc->color_shifts && physDevDst->color_shifts)
697 return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
698 return FALSE;
701 void execute_rop( X11DRV_PDEVICE *physdev, Pixmap src_pixmap, GC gc, const RECT *visrect, DWORD rop )
703 Pixmap pixmaps[3];
704 Pixmap result = src_pixmap;
705 BOOL null_brush;
706 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
707 BOOL use_pat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
708 BOOL use_dst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
709 int width = visrect->right - visrect->left;
710 int height = visrect->bottom - visrect->top;
712 pixmaps[SRC] = src_pixmap;
713 pixmaps[TMP] = 0;
714 wine_tsx11_lock();
715 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
716 wine_tsx11_unlock();
718 if (use_dst) BITBLT_GetDstArea( physdev, pixmaps[DST], gc, visrect );
719 null_brush = use_pat && !X11DRV_SetupGCForPatBlt( physdev, gc, TRUE );
721 wine_tsx11_lock();
722 for ( ; *opcode; opcode++)
724 if (OP_DST(*opcode) == DST) result = pixmaps[DST];
725 XSetFunction( gdi_display, gc, OP_ROP(*opcode) );
726 switch(OP_SRCDST(*opcode))
728 case OP_ARGS(DST,TMP):
729 case OP_ARGS(SRC,TMP):
730 if (!pixmaps[TMP])
731 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
732 /* fall through */
733 case OP_ARGS(DST,SRC):
734 case OP_ARGS(SRC,DST):
735 case OP_ARGS(TMP,SRC):
736 case OP_ARGS(TMP,DST):
737 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)], pixmaps[OP_DST(*opcode)], gc,
738 0, 0, width, height, 0, 0 );
739 break;
740 case OP_ARGS(PAT,DST):
741 case OP_ARGS(PAT,SRC):
742 if (!null_brush)
743 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)], gc, 0, 0, width, height );
744 break;
747 XSetFunction( gdi_display, physdev->gc, GXcopy );
748 physdev->exposures += BITBLT_PutDstArea( physdev, result, visrect );
749 XFreePixmap( gdi_display, pixmaps[DST] );
750 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
751 wine_tsx11_unlock();
752 add_device_bounds( physdev, visrect );
755 /***********************************************************************
756 * X11DRV_PatBlt
758 BOOL X11DRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
760 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
761 BOOL usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
762 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
764 if (usePat && !X11DRV_SetupGCForBrush( physDev )) return TRUE;
766 wine_tsx11_lock();
767 XSetFunction( gdi_display, physDev->gc, OP_ROP(*opcode) );
769 switch(rop) /* a few special cases */
771 case BLACKNESS: /* 0x00 */
772 case WHITENESS: /* 0xff */
773 if ((physDev->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
775 XSetFunction( gdi_display, physDev->gc, GXcopy );
776 if (rop == BLACKNESS)
777 XSetForeground( gdi_display, physDev->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
778 else
779 XSetForeground( gdi_display, physDev->gc,
780 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
781 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
783 break;
784 case DSTINVERT: /* 0x55 */
785 if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
787 /* Xor is much better when we do not have full colormap. */
788 /* Using white^black ensures that we invert at least black */
789 /* and white. */
790 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
791 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
792 XSetFunction( gdi_display, physDev->gc, GXxor );
793 XSetForeground( gdi_display, physDev->gc, xor_pix);
794 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
796 break;
798 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
799 physDev->dc_rect.left + dst->visrect.left,
800 physDev->dc_rect.top + dst->visrect.top,
801 dst->visrect.right - dst->visrect.left,
802 dst->visrect.bottom - dst->visrect.top );
803 wine_tsx11_unlock();
804 add_device_bounds( physDev, &dst->visrect );
805 return TRUE;
809 /***********************************************************************
810 * X11DRV_StretchBlt
812 BOOL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
813 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
815 X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
816 X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev );
817 INT width, height;
818 const BYTE *opcode;
819 Pixmap src_pixmap;
820 GC gc;
822 if (src_dev->funcs != dst_dev->funcs ||
823 src->width != dst->width || src->height != dst->height || /* no stretching with core X11 */
824 (physDevDst->depth == 1 && physDevSrc->depth != 1) || /* color -> mono done by hand */
825 (X11DRV_PALETTE_XPixelToPalette && physDevSrc->depth != 1)) /* needs palette mapping */
827 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
828 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
831 width = dst->visrect.right - dst->visrect.left;
832 height = dst->visrect.bottom - dst->visrect.top;
833 opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
835 add_device_bounds( physDevDst, &dst->visrect );
837 /* a few optimizations for single-op ROPs */
838 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
840 if (same_format(physDevSrc, physDevDst))
842 wine_tsx11_lock();
843 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
844 XCopyArea( gdi_display, physDevSrc->drawable,
845 physDevDst->drawable, physDevDst->gc,
846 physDevSrc->dc_rect.left + src->visrect.left,
847 physDevSrc->dc_rect.top + src->visrect.top,
848 width, height,
849 physDevDst->dc_rect.left + dst->visrect.left,
850 physDevDst->dc_rect.top + dst->visrect.top );
851 physDevDst->exposures++;
852 wine_tsx11_unlock();
853 return TRUE;
855 if (physDevSrc->depth == 1)
857 int text_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetTextColor(physDevDst->dev.hdc) );
858 int bkgnd_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetBkColor(physDevDst->dev.hdc) );
860 wine_tsx11_lock();
861 XSetBackground( gdi_display, physDevDst->gc, text_pixel );
862 XSetForeground( gdi_display, physDevDst->gc, bkgnd_pixel );
863 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
864 XCopyPlane( gdi_display, physDevSrc->drawable,
865 physDevDst->drawable, physDevDst->gc,
866 physDevSrc->dc_rect.left + src->visrect.left,
867 physDevSrc->dc_rect.top + src->visrect.top,
868 width, height,
869 physDevDst->dc_rect.left + dst->visrect.left,
870 physDevDst->dc_rect.top + dst->visrect.top, 1 );
871 physDevDst->exposures++;
872 wine_tsx11_unlock();
873 return TRUE;
877 wine_tsx11_lock();
878 gc = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
879 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
880 XSetGraphicsExposures( gdi_display, gc, False );
882 /* retrieve the source */
884 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, physDevDst->depth );
885 if (physDevSrc->depth == 1)
887 /* MSDN says if StretchBlt must convert a bitmap from monochrome
888 to color or vice versa, the foreground and background color of
889 the device context are used. In fact, it also applies to the
890 case when it is converted from mono to mono. */
891 int text_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetTextColor(physDevDst->dev.hdc) );
892 int bkgnd_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetBkColor(physDevDst->dev.hdc) );
894 if (X11DRV_PALETTE_XPixelToPalette && physDevDst->depth != 1)
896 XSetBackground( gdi_display, gc, X11DRV_PALETTE_XPixelToPalette[text_pixel] );
897 XSetForeground( gdi_display, gc, X11DRV_PALETTE_XPixelToPalette[bkgnd_pixel]);
899 else
901 XSetBackground( gdi_display, gc, text_pixel );
902 XSetForeground( gdi_display, gc, bkgnd_pixel );
904 XCopyPlane( gdi_display, physDevSrc->drawable, src_pixmap, gc,
905 physDevSrc->dc_rect.left + src->visrect.left,
906 physDevSrc->dc_rect.top + src->visrect.top,
907 width, height, 0, 0, 1 );
909 else /* color -> color */
911 XCopyArea( gdi_display, physDevSrc->drawable, src_pixmap, gc,
912 physDevSrc->dc_rect.left + src->visrect.left,
913 physDevSrc->dc_rect.top + src->visrect.top,
914 width, height, 0, 0 );
916 wine_tsx11_unlock();
918 execute_rop( physDevDst, src_pixmap, gc, &dst->visrect, rop );
920 wine_tsx11_lock();
921 XFreePixmap( gdi_display, src_pixmap );
922 XFreeGC( gdi_display, gc );
923 wine_tsx11_unlock();
924 return TRUE;
928 static void free_heap_bits( struct gdi_image_bits *bits )
930 HeapFree( GetProcessHeap(), 0, bits->ptr );
933 static void free_ximage_bits( struct gdi_image_bits *bits )
935 wine_tsx11_lock();
936 XFree( bits->ptr );
937 wine_tsx11_unlock();
940 /* store the palette or color mask data in the bitmap info structure */
941 static void set_color_info( PHYSDEV dev, const ColorShifts *color_shifts, BITMAPINFO *info )
943 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
945 info->bmiHeader.biCompression = BI_RGB;
946 info->bmiHeader.biClrUsed = 0;
948 switch (info->bmiHeader.biBitCount)
950 case 4:
951 case 8:
953 RGBQUAD *rgb = (RGBQUAD *)colors;
954 PALETTEENTRY palette[256];
955 UINT i, count;
957 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
958 count = X11DRV_GetSystemPaletteEntries( dev, 0, info->bmiHeader.biClrUsed, palette );
959 for (i = 0; i < count; i++)
961 rgb[i].rgbRed = palette[i].peRed;
962 rgb[i].rgbGreen = palette[i].peGreen;
963 rgb[i].rgbBlue = palette[i].peBlue;
964 rgb[i].rgbReserved = 0;
966 memset( &rgb[count], 0, (info->bmiHeader.biClrUsed - count) * sizeof(*rgb) );
967 break;
969 case 16:
970 colors[0] = color_shifts->logicalRed.max << color_shifts->logicalRed.shift;
971 colors[1] = color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift;
972 colors[2] = color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift;
973 info->bmiHeader.biCompression = BI_BITFIELDS;
974 break;
975 case 32:
976 colors[0] = color_shifts->logicalRed.max << color_shifts->logicalRed.shift;
977 colors[1] = color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift;
978 colors[2] = color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift;
979 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
980 info->bmiHeader.biCompression = BI_BITFIELDS;
981 break;
985 /* check if the specified color info is suitable for PutImage */
986 static BOOL matching_color_info( PHYSDEV dev, const ColorShifts *color_shifts, const BITMAPINFO *info )
988 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
990 switch (info->bmiHeader.biBitCount)
992 case 1:
993 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
994 return !info->bmiHeader.biClrUsed; /* color map not allowed */
995 case 4:
996 case 8:
998 RGBQUAD *rgb = (RGBQUAD *)colors;
999 PALETTEENTRY palette[256];
1000 UINT i, count;
1002 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1003 count = X11DRV_GetSystemPaletteEntries( dev, 0, 1 << info->bmiHeader.biBitCount, palette );
1004 if (count != info->bmiHeader.biClrUsed) return FALSE;
1005 for (i = 0; i < count; i++)
1007 if (rgb[i].rgbRed != palette[i].peRed ||
1008 rgb[i].rgbGreen != palette[i].peGreen ||
1009 rgb[i].rgbBlue != palette[i].peBlue) return FALSE;
1011 return TRUE;
1013 case 16:
1014 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1015 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == colors[0] &&
1016 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == colors[1] &&
1017 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == colors[2]);
1018 if (info->bmiHeader.biCompression == BI_RGB)
1019 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == 0x7c00 &&
1020 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == 0x03e0 &&
1021 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == 0x001f);
1022 break;
1023 case 32:
1024 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1025 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == colors[0] &&
1026 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == colors[1] &&
1027 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == colors[2]);
1028 /* fall through */
1029 case 24:
1030 if (info->bmiHeader.biCompression == BI_RGB)
1031 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == 0xff0000 &&
1032 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == 0x00ff00 &&
1033 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == 0x0000ff);
1034 break;
1036 return FALSE;
1039 static inline BOOL is_r8g8b8( int depth, const ColorShifts *color_shifts )
1041 return depth == 24 && color_shifts->logicalBlue.shift == 0 && color_shifts->logicalRed.shift == 16;
1044 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1045 DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image,
1046 const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
1047 struct bitblt_coords *coords, const int *mapping, unsigned int zeropad_mask )
1049 #ifdef WORDS_BIGENDIAN
1050 static const int client_byte_order = MSBFirst;
1051 #else
1052 static const int client_byte_order = LSBFirst;
1053 #endif
1054 BOOL need_byteswap;
1055 int x, y, height = coords->visrect.bottom - coords->visrect.top;
1056 int width_bytes = image->bytes_per_line;
1057 int padding_pos;
1058 unsigned char *src, *dst;
1060 switch (info->bmiHeader.biBitCount)
1062 case 1:
1063 need_byteswap = (image->bitmap_bit_order != MSBFirst);
1064 break;
1065 case 4:
1066 need_byteswap = (image->byte_order != MSBFirst);
1067 break;
1068 case 16:
1069 case 32:
1070 need_byteswap = (image->byte_order != client_byte_order);
1071 break;
1072 case 24:
1073 need_byteswap = (image->byte_order == MSBFirst) ^ !is_r8g8b8;
1074 break;
1075 default:
1076 need_byteswap = FALSE;
1077 break;
1080 src = src_bits->ptr;
1081 if (info->bmiHeader.biHeight > 0)
1082 src += (info->bmiHeader.biHeight - coords->visrect.bottom) * width_bytes;
1083 else
1084 src += coords->visrect.top * width_bytes;
1086 if ((need_byteswap && !src_bits->is_copy) || /* need to swap bytes */
1087 (zeropad_mask != ~0u && !src_bits->is_copy) || /* need to clear padding bytes */
1088 (mapping && !src_bits->is_copy) || /* need to remap pixels */
1089 (width_bytes & 3) || /* need to fixup line alignment */
1090 (info->bmiHeader.biHeight > 0)) /* need to flip vertically */
1092 width_bytes = (width_bytes + 3) & ~3;
1093 info->bmiHeader.biSizeImage = height * width_bytes;
1094 if (!(dst_bits->ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
1095 return ERROR_OUTOFMEMORY;
1096 dst_bits->is_copy = TRUE;
1097 dst_bits->free = free_heap_bits;
1099 else
1101 /* swap bits in place */
1102 dst_bits->ptr = src;
1103 dst_bits->is_copy = src_bits->is_copy;
1104 dst_bits->free = NULL;
1105 if (!need_byteswap && zeropad_mask == ~0u && !mapping) return ERROR_SUCCESS; /* nothing to do */
1108 dst = dst_bits->ptr;
1109 padding_pos = width_bytes/sizeof(unsigned int) - 1;
1111 if (info->bmiHeader.biHeight > 0)
1113 dst += (height - 1) * width_bytes;
1114 width_bytes = -width_bytes;
1117 if (need_byteswap || mapping)
1119 switch (info->bmiHeader.biBitCount)
1121 case 1:
1122 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1124 for (x = 0; x < image->bytes_per_line; x++)
1125 dst[x] = bit_swap[src[x]];
1126 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1128 break;
1129 case 4:
1130 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1132 if (mapping)
1133 for (x = 0; x < image->bytes_per_line; x++)
1134 dst[x] = (mapping[src[x] & 0x0f] << 4) | mapping[src[x] >> 4];
1135 else
1136 for (x = 0; x < image->bytes_per_line; x++)
1137 dst[x] = (src[x] << 4) | (src[x] >> 4);
1138 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1140 break;
1141 case 8:
1142 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1144 for (x = 0; x < image->bytes_per_line; x++)
1145 dst[x] = mapping[src[x]];
1146 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1148 break;
1149 case 16:
1150 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1152 for (x = 0; x < info->bmiHeader.biWidth; x++)
1153 ((USHORT *)dst)[x] = RtlUshortByteSwap( ((const USHORT *)src)[x] );
1154 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1156 break;
1157 case 24:
1158 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1160 for (x = 0; x < info->bmiHeader.biWidth; x++)
1162 unsigned char tmp = src[3 * x];
1163 dst[3 * x] = src[3 * x + 2];
1164 dst[3 * x + 1] = src[3 * x + 1];
1165 dst[3 * x + 2] = tmp;
1167 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1169 break;
1170 case 32:
1171 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1172 for (x = 0; x < info->bmiHeader.biWidth; x++)
1173 ((ULONG *)dst)[x] = RtlUlongByteSwap( ((const ULONG *)src)[x] );
1174 break;
1177 else if (src != dst)
1179 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1181 memcpy( dst, src, image->bytes_per_line );
1182 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1185 else /* only need to clear the padding */
1187 for (y = 0; y < height; y++, dst += width_bytes)
1188 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1190 return ERROR_SUCCESS;
1193 /***********************************************************************
1194 * X11DRV_PutImage
1196 DWORD X11DRV_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
1197 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1198 struct bitblt_coords *dst, DWORD rop )
1200 X11DRV_PDEVICE *physdev;
1201 X_PHYSBITMAP *bitmap;
1202 DWORD ret;
1203 XImage *image;
1204 int depth;
1205 struct gdi_image_bits dst_bits;
1206 const XPixmapFormatValues *format;
1207 const ColorShifts *color_shifts;
1208 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1209 const int *mapping = NULL;
1211 if (hbitmap)
1213 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
1214 physdev = NULL;
1215 depth = bitmap->depth;
1216 color_shifts = &bitmap->color_shifts;
1218 else
1220 physdev = get_x11drv_dev( dev );
1221 bitmap = NULL;
1222 depth = physdev->depth;
1223 color_shifts = physdev->color_shifts;
1225 format = pixmap_formats[depth];
1227 if (info->bmiHeader.biPlanes != 1) goto update_format;
1228 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1229 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1230 if (!matching_color_info( dev, color_shifts, info )) goto update_format;
1231 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1232 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
1234 wine_tsx11_lock();
1235 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1236 info->bmiHeader.biWidth, src->visrect.bottom - src->visrect.top, 32, 0 );
1237 wine_tsx11_unlock();
1238 if (!image) return ERROR_OUTOFMEMORY;
1240 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1242 if (bitmap || (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST)))
1243 mapping = X11DRV_PALETTE_PaletteToXPixel;
1246 ret = copy_image_bits( info, is_r8g8b8(depth,color_shifts), image, bits, &dst_bits, src, mapping, ~0u );
1248 if (!ret)
1250 int width = dst->visrect.right - dst->visrect.left;
1251 int height = dst->visrect.bottom - dst->visrect.top;
1253 image->data = dst_bits.ptr;
1255 if (bitmap)
1257 RGNDATA *clip_data = NULL;
1258 GC gc;
1260 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1262 wine_tsx11_lock();
1263 gc = XCreateGC( gdi_display, bitmap->pixmap, 0, NULL );
1264 XSetGraphicsExposures( gdi_display, gc, False );
1265 if (clip_data) XSetClipRectangles( gdi_display, gc, 0, 0, (XRectangle *)clip_data->Buffer,
1266 clip_data->rdh.nCount, YXBanded );
1267 XPutImage( gdi_display, bitmap->pixmap, gc, image, src->visrect.left, 0,
1268 dst->visrect.left, dst->visrect.top, width, height );
1269 XFreeGC( gdi_display, gc );
1270 wine_tsx11_unlock();
1271 HeapFree( GetProcessHeap(), 0, clip_data );
1273 else
1275 BOOL restore_region = add_extra_clipping_region( physdev, clip );
1277 /* optimization for single-op ROPs */
1278 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1280 wine_tsx11_lock();
1281 XSetFunction( gdi_display, physdev->gc, OP_ROP(*opcode) );
1282 XPutImage( gdi_display, physdev->drawable, physdev->gc, image, src->visrect.left, 0,
1283 physdev->dc_rect.left + dst->visrect.left,
1284 physdev->dc_rect.top + dst->visrect.top, width, height );
1285 wine_tsx11_unlock();
1287 else
1289 Pixmap src_pixmap;
1290 GC gc;
1292 wine_tsx11_lock();
1293 gc = XCreateGC( gdi_display, physdev->drawable, 0, NULL );
1294 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1295 XSetGraphicsExposures( gdi_display, gc, False );
1296 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1297 XPutImage( gdi_display, src_pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1298 wine_tsx11_unlock();
1300 execute_rop( physdev, src_pixmap, gc, &dst->visrect, rop );
1302 wine_tsx11_lock();
1303 XFreePixmap( gdi_display, src_pixmap );
1304 XFreeGC( gdi_display, gc );
1305 wine_tsx11_unlock();
1308 if (restore_region) restore_clipping_region( physdev );
1309 add_device_bounds( physdev, &dst->visrect );
1311 image->data = NULL;
1314 wine_tsx11_lock();
1315 XDestroyImage( image );
1316 wine_tsx11_unlock();
1317 if (dst_bits.free) dst_bits.free( &dst_bits );
1318 return ret;
1320 update_format:
1321 info->bmiHeader.biPlanes = 1;
1322 info->bmiHeader.biBitCount = format->bits_per_pixel;
1323 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1324 set_color_info( dev, color_shifts, info );
1325 return ERROR_BAD_FORMAT;
1328 /***********************************************************************
1329 * X11DRV_GetImage
1331 DWORD X11DRV_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1332 struct gdi_image_bits *bits, struct bitblt_coords *src )
1334 X11DRV_PDEVICE *physdev;
1335 X_PHYSBITMAP *bitmap;
1336 DWORD ret = ERROR_SUCCESS;
1337 XImage *image;
1338 UINT align, x, y, width, height;
1339 int depth;
1340 struct gdi_image_bits src_bits;
1341 const XPixmapFormatValues *format;
1342 const ColorShifts *color_shifts;
1343 const int *mapping = NULL;
1345 if (hbitmap)
1347 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
1348 physdev = NULL;
1349 depth = bitmap->depth;
1350 color_shifts = &bitmap->color_shifts;
1352 else
1354 physdev = get_x11drv_dev( dev );
1355 bitmap = NULL;
1356 depth = physdev->depth;
1357 color_shifts = physdev->color_shifts;
1359 format = pixmap_formats[depth];
1361 /* align start and width to 32-bit boundary */
1362 switch (format->bits_per_pixel)
1364 case 1: align = 32; break;
1365 case 4: align = 8; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1366 case 8: align = 4; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1367 case 16: align = 2; break;
1368 case 24: align = 4; break;
1369 case 32: align = 1; break;
1370 default:
1371 FIXME( "depth %u bpp %u not supported yet\n", depth, format->bits_per_pixel );
1372 return ERROR_BAD_FORMAT;
1375 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1376 info->bmiHeader.biPlanes = 1;
1377 info->bmiHeader.biBitCount = format->bits_per_pixel;
1378 info->bmiHeader.biXPelsPerMeter = 0;
1379 info->bmiHeader.biYPelsPerMeter = 0;
1380 info->bmiHeader.biClrImportant = 0;
1381 set_color_info( dev, color_shifts, info );
1383 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
1385 x = src->visrect.left & ~(align - 1);
1386 y = src->visrect.top;
1387 width = src->visrect.right - x;
1388 height = src->visrect.bottom - src->visrect.top;
1389 if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1);
1390 /* make the source rectangle relative to the returned bits */
1391 src->x -= x;
1392 src->y -= y;
1393 OffsetRect( &src->visrect, -x, -y );
1395 if (bitmap)
1397 BITMAP bm;
1398 GetObjectW( hbitmap, sizeof(bm), &bm );
1399 width = min( width, bm.bmWidth - x );
1400 height = min( height, bm.bmHeight - y );
1401 wine_tsx11_lock();
1402 image = XGetImage( gdi_display, bitmap->pixmap, x, y, width, height, AllPlanes, ZPixmap );
1403 wine_tsx11_unlock();
1405 else if (GetObjectType( dev->hdc ) == OBJ_MEMDC)
1407 width = min( width, physdev->dc_rect.right - physdev->dc_rect.left - x );
1408 height = min( height, physdev->dc_rect.bottom - physdev->dc_rect.top - y );
1409 wine_tsx11_lock();
1410 image = XGetImage( gdi_display, physdev->drawable,
1411 physdev->dc_rect.left + x, physdev->dc_rect.top + y,
1412 width, height, AllPlanes, ZPixmap );
1413 wine_tsx11_unlock();
1415 else
1417 X11DRV_expect_error( gdi_display, XGetImage_handler, NULL );
1418 image = XGetImage( gdi_display, physdev->drawable,
1419 physdev->dc_rect.left + x, physdev->dc_rect.top + y,
1420 width, height, AllPlanes, ZPixmap );
1421 if (X11DRV_check_error())
1423 /* use a temporary pixmap to avoid the BadMatch error */
1424 Pixmap pixmap;
1426 wine_tsx11_lock();
1427 pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1428 XCopyArea( gdi_display, physdev->drawable, pixmap, get_bitmap_gc(depth),
1429 physdev->dc_rect.left + x, physdev->dc_rect.top + y, width, height, 0, 0 );
1430 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1431 XFreePixmap( gdi_display, pixmap );
1432 wine_tsx11_unlock();
1435 if (!image) return ERROR_OUTOFMEMORY;
1437 info->bmiHeader.biWidth = width;
1438 info->bmiHeader.biHeight = -height;
1439 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1441 src_bits.ptr = image->data;
1442 src_bits.is_copy = TRUE;
1443 ret = copy_image_bits( info, is_r8g8b8(depth,color_shifts), image, &src_bits, bits, src, mapping,
1444 zeropad_masks[(width * image->bits_per_pixel) & 31] );
1446 if (!ret && bits->ptr == image->data)
1448 bits->free = free_ximage_bits;
1449 image->data = NULL;
1451 wine_tsx11_lock();
1452 XDestroyImage( image );
1453 wine_tsx11_unlock();
1454 return ret;