msi/tests: Avoid a TRUE:FALSE conditional expression.
[wine/multimedia.git] / dlls / winex11.drv / bitblt.c
blob3db88892c7df7429f6890fd32035560c696001b2
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;
603 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
604 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
606 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
607 physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
608 width, height, 0, 0 );
609 exposures++;
611 else
613 INT x, y;
614 XImage *image;
616 /* Make sure we don't get a BadMatch error */
617 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
618 physDev->dc_rect.left + visRectDst->left,
619 physDev->dc_rect.top + visRectDst->top,
620 width, height, 0, 0);
621 exposures++;
622 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
623 AllPlanes, ZPixmap );
624 if (image)
626 for (y = 0; y < height; y++)
627 for (x = 0; x < width; x++)
628 XPutPixel( image, x, y,
629 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
630 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
631 XDestroyImage( image );
634 return exposures;
638 /***********************************************************************
639 * BITBLT_PutDstArea
641 * Put an area back into the destination DC, mapping the pixel
642 * colors to X pixels.
644 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, const RECT *visRectDst)
646 int exposures = 0;
647 INT width = visRectDst->right - visRectDst->left;
648 INT height = visRectDst->bottom - visRectDst->top;
650 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
652 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
653 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
655 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
656 physDev->dc_rect.left + visRectDst->left,
657 physDev->dc_rect.top + visRectDst->top );
658 exposures++;
660 else
662 register INT x, y;
663 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
664 AllPlanes, ZPixmap );
665 for (y = 0; y < height; y++)
666 for (x = 0; x < width; x++)
668 XPutPixel( image, x, y,
669 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
671 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
672 physDev->dc_rect.left + visRectDst->left,
673 physDev->dc_rect.top + visRectDst->top, width, height );
674 XDestroyImage( image );
676 return exposures;
679 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
681 if (physDevSrc->depth != physDevDst->depth) return FALSE;
682 if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
683 if (physDevSrc->color_shifts && physDevDst->color_shifts)
684 return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
685 return FALSE;
688 void execute_rop( X11DRV_PDEVICE *physdev, Pixmap src_pixmap, GC gc, const RECT *visrect, DWORD rop )
690 Pixmap pixmaps[3];
691 Pixmap result = src_pixmap;
692 BOOL null_brush;
693 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
694 BOOL use_pat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
695 BOOL use_dst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
696 int width = visrect->right - visrect->left;
697 int height = visrect->bottom - visrect->top;
699 pixmaps[SRC] = src_pixmap;
700 pixmaps[TMP] = 0;
701 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
703 if (use_dst) BITBLT_GetDstArea( physdev, pixmaps[DST], gc, visrect );
704 null_brush = use_pat && !X11DRV_SetupGCForPatBlt( physdev, gc, TRUE );
706 for ( ; *opcode; opcode++)
708 if (OP_DST(*opcode) == DST) result = pixmaps[DST];
709 XSetFunction( gdi_display, gc, OP_ROP(*opcode) );
710 switch(OP_SRCDST(*opcode))
712 case OP_ARGS(DST,TMP):
713 case OP_ARGS(SRC,TMP):
714 if (!pixmaps[TMP])
715 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
716 /* fall through */
717 case OP_ARGS(DST,SRC):
718 case OP_ARGS(SRC,DST):
719 case OP_ARGS(TMP,SRC):
720 case OP_ARGS(TMP,DST):
721 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)], pixmaps[OP_DST(*opcode)], gc,
722 0, 0, width, height, 0, 0 );
723 break;
724 case OP_ARGS(PAT,DST):
725 case OP_ARGS(PAT,SRC):
726 if (!null_brush)
727 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)], gc, 0, 0, width, height );
728 break;
731 XSetFunction( gdi_display, physdev->gc, GXcopy );
732 physdev->exposures += BITBLT_PutDstArea( physdev, result, visrect );
733 XFreePixmap( gdi_display, pixmaps[DST] );
734 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
735 add_device_bounds( physdev, visrect );
738 /***********************************************************************
739 * X11DRV_PatBlt
741 BOOL X11DRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
743 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
744 BOOL usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
745 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
747 if (usePat && !X11DRV_SetupGCForBrush( physDev )) return TRUE;
749 XSetFunction( gdi_display, physDev->gc, OP_ROP(*opcode) );
751 switch(rop) /* a few special cases */
753 case BLACKNESS: /* 0x00 */
754 case WHITENESS: /* 0xff */
755 if ((physDev->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
757 XSetFunction( gdi_display, physDev->gc, GXcopy );
758 if (rop == BLACKNESS)
759 XSetForeground( gdi_display, physDev->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
760 else
761 XSetForeground( gdi_display, physDev->gc,
762 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
763 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
765 break;
766 case DSTINVERT: /* 0x55 */
767 if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
769 /* Xor is much better when we do not have full colormap. */
770 /* Using white^black ensures that we invert at least black */
771 /* and white. */
772 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
773 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
774 XSetFunction( gdi_display, physDev->gc, GXxor );
775 XSetForeground( gdi_display, physDev->gc, xor_pix);
776 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
778 break;
780 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
781 physDev->dc_rect.left + dst->visrect.left,
782 physDev->dc_rect.top + dst->visrect.top,
783 dst->visrect.right - dst->visrect.left,
784 dst->visrect.bottom - dst->visrect.top );
785 add_device_bounds( physDev, &dst->visrect );
786 return TRUE;
790 /***********************************************************************
791 * X11DRV_StretchBlt
793 BOOL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
794 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
796 X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
797 X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev );
798 INT width, height;
799 const BYTE *opcode;
800 Pixmap src_pixmap;
801 GC gc;
803 if (src_dev->funcs != dst_dev->funcs ||
804 src->width != dst->width || src->height != dst->height || /* no stretching with core X11 */
805 (physDevDst->depth == 1 && physDevSrc->depth != 1) || /* color -> mono done by hand */
806 (X11DRV_PALETTE_XPixelToPalette && physDevSrc->depth != 1)) /* needs palette mapping */
808 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
809 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
812 width = dst->visrect.right - dst->visrect.left;
813 height = dst->visrect.bottom - dst->visrect.top;
814 opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
816 add_device_bounds( physDevDst, &dst->visrect );
818 /* a few optimizations for single-op ROPs */
819 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
821 if (same_format(physDevSrc, physDevDst))
823 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
824 XCopyArea( gdi_display, physDevSrc->drawable,
825 physDevDst->drawable, physDevDst->gc,
826 physDevSrc->dc_rect.left + src->visrect.left,
827 physDevSrc->dc_rect.top + src->visrect.top,
828 width, height,
829 physDevDst->dc_rect.left + dst->visrect.left,
830 physDevDst->dc_rect.top + dst->visrect.top );
831 physDevDst->exposures++;
832 return TRUE;
834 if (physDevSrc->depth == 1)
836 int text_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetTextColor(physDevDst->dev.hdc) );
837 int bkgnd_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetBkColor(physDevDst->dev.hdc) );
839 XSetBackground( gdi_display, physDevDst->gc, text_pixel );
840 XSetForeground( gdi_display, physDevDst->gc, bkgnd_pixel );
841 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
842 XCopyPlane( gdi_display, physDevSrc->drawable,
843 physDevDst->drawable, physDevDst->gc,
844 physDevSrc->dc_rect.left + src->visrect.left,
845 physDevSrc->dc_rect.top + src->visrect.top,
846 width, height,
847 physDevDst->dc_rect.left + dst->visrect.left,
848 physDevDst->dc_rect.top + dst->visrect.top, 1 );
849 physDevDst->exposures++;
850 return TRUE;
854 gc = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
855 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
856 XSetGraphicsExposures( gdi_display, gc, False );
858 /* retrieve the source */
860 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, physDevDst->depth );
861 if (physDevSrc->depth == 1)
863 /* MSDN says if StretchBlt must convert a bitmap from monochrome
864 to color or vice versa, the foreground and background color of
865 the device context are used. In fact, it also applies to the
866 case when it is converted from mono to mono. */
867 int text_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetTextColor(physDevDst->dev.hdc) );
868 int bkgnd_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetBkColor(physDevDst->dev.hdc) );
870 if (X11DRV_PALETTE_XPixelToPalette && physDevDst->depth != 1)
872 XSetBackground( gdi_display, gc, X11DRV_PALETTE_XPixelToPalette[text_pixel] );
873 XSetForeground( gdi_display, gc, X11DRV_PALETTE_XPixelToPalette[bkgnd_pixel]);
875 else
877 XSetBackground( gdi_display, gc, text_pixel );
878 XSetForeground( gdi_display, gc, bkgnd_pixel );
880 XCopyPlane( gdi_display, physDevSrc->drawable, src_pixmap, gc,
881 physDevSrc->dc_rect.left + src->visrect.left,
882 physDevSrc->dc_rect.top + src->visrect.top,
883 width, height, 0, 0, 1 );
885 else /* color -> color */
887 XCopyArea( gdi_display, physDevSrc->drawable, src_pixmap, gc,
888 physDevSrc->dc_rect.left + src->visrect.left,
889 physDevSrc->dc_rect.top + src->visrect.top,
890 width, height, 0, 0 );
893 execute_rop( physDevDst, src_pixmap, gc, &dst->visrect, rop );
895 XFreePixmap( gdi_display, src_pixmap );
896 XFreeGC( gdi_display, gc );
897 return TRUE;
901 static void free_heap_bits( struct gdi_image_bits *bits )
903 HeapFree( GetProcessHeap(), 0, bits->ptr );
906 static void free_ximage_bits( struct gdi_image_bits *bits )
908 XFree( bits->ptr );
911 /* only for use on sanitized BITMAPINFO structures */
912 static inline int get_dib_info_size( const BITMAPINFO *info, UINT coloruse )
914 if (info->bmiHeader.biCompression == BI_BITFIELDS)
915 return sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD);
916 if (coloruse == DIB_PAL_COLORS)
917 return sizeof(BITMAPINFOHEADER) + info->bmiHeader.biClrUsed * sizeof(WORD);
918 return FIELD_OFFSET( BITMAPINFO, bmiColors[info->bmiHeader.biClrUsed] );
921 /* store the palette or color mask data in the bitmap info structure */
922 static void set_color_info( const XVisualInfo *vis, BITMAPINFO *info )
924 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
926 info->bmiHeader.biCompression = BI_RGB;
927 info->bmiHeader.biClrUsed = 0;
929 switch (info->bmiHeader.biBitCount)
931 case 4:
932 case 8:
934 RGBQUAD *rgb = (RGBQUAD *)colors;
935 PALETTEENTRY palette[256];
936 UINT i, count;
938 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
939 count = X11DRV_GetSystemPaletteEntries( NULL, 0, info->bmiHeader.biClrUsed, palette );
940 for (i = 0; i < count; i++)
942 rgb[i].rgbRed = palette[i].peRed;
943 rgb[i].rgbGreen = palette[i].peGreen;
944 rgb[i].rgbBlue = palette[i].peBlue;
945 rgb[i].rgbReserved = 0;
947 memset( &rgb[count], 0, (info->bmiHeader.biClrUsed - count) * sizeof(*rgb) );
948 break;
950 case 16:
951 colors[0] = vis->red_mask;
952 colors[1] = vis->green_mask;
953 colors[2] = vis->blue_mask;
954 info->bmiHeader.biCompression = BI_BITFIELDS;
955 break;
956 case 32:
957 colors[0] = vis->red_mask;
958 colors[1] = vis->green_mask;
959 colors[2] = vis->blue_mask;
960 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
961 info->bmiHeader.biCompression = BI_BITFIELDS;
962 break;
966 /* check if the specified color info is suitable for PutImage */
967 static BOOL matching_color_info( const XVisualInfo *vis, const BITMAPINFO *info )
969 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
971 switch (info->bmiHeader.biBitCount)
973 case 1:
974 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
975 return !info->bmiHeader.biClrUsed; /* color map not allowed */
976 case 4:
977 case 8:
979 RGBQUAD *rgb = (RGBQUAD *)colors;
980 PALETTEENTRY palette[256];
981 UINT i, count;
983 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
984 count = X11DRV_GetSystemPaletteEntries( NULL, 0, 1 << info->bmiHeader.biBitCount, palette );
985 if (count != info->bmiHeader.biClrUsed) return FALSE;
986 for (i = 0; i < count; i++)
988 if (rgb[i].rgbRed != palette[i].peRed ||
989 rgb[i].rgbGreen != palette[i].peGreen ||
990 rgb[i].rgbBlue != palette[i].peBlue) return FALSE;
992 return TRUE;
994 case 16:
995 if (info->bmiHeader.biCompression == BI_BITFIELDS)
996 return (vis->red_mask == colors[0] &&
997 vis->green_mask == colors[1] &&
998 vis->blue_mask == colors[2]);
999 if (info->bmiHeader.biCompression == BI_RGB)
1000 return (vis->red_mask == 0x7c00 && vis->green_mask == 0x03e0 && vis->blue_mask == 0x001f);
1001 break;
1002 case 32:
1003 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1004 return (vis->red_mask == colors[0] &&
1005 vis->green_mask == colors[1] &&
1006 vis->blue_mask == colors[2]);
1007 /* fall through */
1008 case 24:
1009 if (info->bmiHeader.biCompression == BI_RGB)
1010 return (vis->red_mask == 0xff0000 && vis->green_mask == 0x00ff00 && vis->blue_mask == 0x0000ff);
1011 break;
1013 return FALSE;
1016 static inline BOOL is_r8g8b8( const XVisualInfo *vis )
1018 return vis->depth == 24 && vis->red_mask == 0xff0000 && vis->blue_mask == 0x0000ff;
1021 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1022 DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image,
1023 const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
1024 struct bitblt_coords *coords, const int *mapping, unsigned int zeropad_mask )
1026 #ifdef WORDS_BIGENDIAN
1027 static const int client_byte_order = MSBFirst;
1028 #else
1029 static const int client_byte_order = LSBFirst;
1030 #endif
1031 BOOL need_byteswap;
1032 int x, y, height = coords->visrect.bottom - coords->visrect.top;
1033 int width_bytes = image->bytes_per_line;
1034 int padding_pos;
1035 unsigned char *src, *dst;
1037 switch (info->bmiHeader.biBitCount)
1039 case 1:
1040 need_byteswap = (image->bitmap_bit_order != MSBFirst);
1041 break;
1042 case 4:
1043 need_byteswap = (image->byte_order != MSBFirst);
1044 break;
1045 case 16:
1046 case 32:
1047 need_byteswap = (image->byte_order != client_byte_order);
1048 break;
1049 case 24:
1050 need_byteswap = (image->byte_order == MSBFirst) ^ !is_r8g8b8;
1051 break;
1052 default:
1053 need_byteswap = FALSE;
1054 break;
1057 src = src_bits->ptr;
1058 if (info->bmiHeader.biHeight > 0)
1059 src += (info->bmiHeader.biHeight - coords->visrect.bottom) * width_bytes;
1060 else
1061 src += coords->visrect.top * width_bytes;
1063 if ((need_byteswap && !src_bits->is_copy) || /* need to swap bytes */
1064 (zeropad_mask != ~0u && !src_bits->is_copy) || /* need to clear padding bytes */
1065 (mapping && !src_bits->is_copy) || /* need to remap pixels */
1066 (width_bytes & 3) || /* need to fixup line alignment */
1067 (info->bmiHeader.biHeight > 0)) /* need to flip vertically */
1069 width_bytes = (width_bytes + 3) & ~3;
1070 info->bmiHeader.biSizeImage = height * width_bytes;
1071 if (!(dst_bits->ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
1072 return ERROR_OUTOFMEMORY;
1073 dst_bits->is_copy = TRUE;
1074 dst_bits->free = free_heap_bits;
1076 else
1078 /* swap bits in place */
1079 dst_bits->ptr = src;
1080 dst_bits->is_copy = src_bits->is_copy;
1081 dst_bits->free = NULL;
1082 if (!need_byteswap && zeropad_mask == ~0u && !mapping) return ERROR_SUCCESS; /* nothing to do */
1085 dst = dst_bits->ptr;
1086 padding_pos = width_bytes/sizeof(unsigned int) - 1;
1088 if (info->bmiHeader.biHeight > 0)
1090 dst += (height - 1) * width_bytes;
1091 width_bytes = -width_bytes;
1094 if (need_byteswap || mapping)
1096 switch (info->bmiHeader.biBitCount)
1098 case 1:
1099 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1101 for (x = 0; x < image->bytes_per_line; x++)
1102 dst[x] = bit_swap[src[x]];
1103 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1105 break;
1106 case 4:
1107 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1109 if (mapping)
1110 for (x = 0; x < image->bytes_per_line; x++)
1111 dst[x] = (mapping[src[x] & 0x0f] << 4) | mapping[src[x] >> 4];
1112 else
1113 for (x = 0; x < image->bytes_per_line; x++)
1114 dst[x] = (src[x] << 4) | (src[x] >> 4);
1115 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1117 break;
1118 case 8:
1119 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1121 for (x = 0; x < image->bytes_per_line; x++)
1122 dst[x] = mapping[src[x]];
1123 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1125 break;
1126 case 16:
1127 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1129 for (x = 0; x < info->bmiHeader.biWidth; x++)
1130 ((USHORT *)dst)[x] = RtlUshortByteSwap( ((const USHORT *)src)[x] );
1131 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1133 break;
1134 case 24:
1135 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1137 for (x = 0; x < info->bmiHeader.biWidth; x++)
1139 unsigned char tmp = src[3 * x];
1140 dst[3 * x] = src[3 * x + 2];
1141 dst[3 * x + 1] = src[3 * x + 1];
1142 dst[3 * x + 2] = tmp;
1144 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1146 break;
1147 case 32:
1148 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1149 for (x = 0; x < info->bmiHeader.biWidth; x++)
1150 ((ULONG *)dst)[x] = RtlUlongByteSwap( ((const ULONG *)src)[x] );
1151 break;
1154 else if (src != dst)
1156 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1158 memcpy( dst, src, image->bytes_per_line );
1159 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1162 else /* only need to clear the padding */
1164 for (y = 0; y < height; y++, dst += width_bytes)
1165 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1167 return ERROR_SUCCESS;
1170 /***********************************************************************
1171 * X11DRV_PutImage
1173 DWORD X11DRV_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
1174 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1175 struct bitblt_coords *dst, DWORD rop )
1177 X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1178 DWORD ret;
1179 XImage *image;
1180 XVisualInfo vis;
1181 struct gdi_image_bits dst_bits;
1182 const XPixmapFormatValues *format;
1183 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1184 const int *mapping = NULL;
1186 vis.depth = physdev->depth;
1187 if (physdev->color_shifts)
1189 vis.red_mask = physdev->color_shifts->logicalRed.max << physdev->color_shifts->logicalRed.shift;
1190 vis.green_mask = physdev->color_shifts->logicalGreen.max << physdev->color_shifts->logicalGreen.shift;
1191 vis.blue_mask = physdev->color_shifts->logicalBlue.max << physdev->color_shifts->logicalBlue.shift;
1193 format = pixmap_formats[vis.depth];
1195 if (info->bmiHeader.biPlanes != 1) goto update_format;
1196 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1197 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1198 if (!matching_color_info( &vis, info )) goto update_format;
1199 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1200 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
1202 image = XCreateImage( gdi_display, visual, vis.depth, ZPixmap, 0, NULL,
1203 info->bmiHeader.biWidth, src->visrect.bottom - src->visrect.top, 32, 0 );
1204 if (!image) return ERROR_OUTOFMEMORY;
1206 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1208 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1209 mapping = X11DRV_PALETTE_PaletteToXPixel;
1212 ret = copy_image_bits( info, is_r8g8b8(&vis), image, bits, &dst_bits, src, mapping, ~0u );
1214 if (!ret)
1216 BOOL restore_region = add_extra_clipping_region( physdev, clip );
1217 int width = dst->visrect.right - dst->visrect.left;
1218 int height = dst->visrect.bottom - dst->visrect.top;
1220 image->data = dst_bits.ptr;
1222 /* optimization for single-op ROPs */
1223 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1225 XSetFunction( gdi_display, physdev->gc, OP_ROP(*opcode) );
1226 XPutImage( gdi_display, physdev->drawable, physdev->gc, image, src->visrect.left, 0,
1227 physdev->dc_rect.left + dst->visrect.left,
1228 physdev->dc_rect.top + dst->visrect.top, width, height );
1230 else
1232 GC gc = XCreateGC( gdi_display, physdev->drawable, 0, NULL );
1233 Pixmap src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, vis.depth );
1235 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1236 XSetGraphicsExposures( gdi_display, gc, False );
1237 XPutImage( gdi_display, src_pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1239 execute_rop( physdev, src_pixmap, gc, &dst->visrect, rop );
1241 XFreePixmap( gdi_display, src_pixmap );
1242 XFreeGC( gdi_display, gc );
1245 if (restore_region) restore_clipping_region( physdev );
1246 add_device_bounds( physdev, &dst->visrect );
1247 image->data = NULL;
1250 XDestroyImage( image );
1251 if (dst_bits.free) dst_bits.free( &dst_bits );
1252 return ret;
1254 update_format:
1255 info->bmiHeader.biPlanes = 1;
1256 info->bmiHeader.biBitCount = format->bits_per_pixel;
1257 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1258 set_color_info( &vis, info );
1259 return ERROR_BAD_FORMAT;
1262 /***********************************************************************
1263 * X11DRV_GetImage
1265 DWORD X11DRV_GetImage( PHYSDEV dev, BITMAPINFO *info,
1266 struct gdi_image_bits *bits, struct bitblt_coords *src )
1268 X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1269 DWORD ret = ERROR_SUCCESS;
1270 XImage *image;
1271 XVisualInfo vis;
1272 UINT align, x, y, width, height;
1273 struct gdi_image_bits src_bits;
1274 const XPixmapFormatValues *format;
1275 const int *mapping = NULL;
1277 vis.depth = physdev->depth;
1278 if (physdev->color_shifts)
1280 vis.red_mask = physdev->color_shifts->logicalRed.max << physdev->color_shifts->logicalRed.shift;
1281 vis.green_mask = physdev->color_shifts->logicalGreen.max << physdev->color_shifts->logicalGreen.shift;
1282 vis.blue_mask = physdev->color_shifts->logicalBlue.max << physdev->color_shifts->logicalBlue.shift;
1284 format = pixmap_formats[vis.depth];
1286 /* align start and width to 32-bit boundary */
1287 switch (format->bits_per_pixel)
1289 case 1: align = 32; break;
1290 case 4: align = 8; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1291 case 8: align = 4; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1292 case 16: align = 2; break;
1293 case 24: align = 4; break;
1294 case 32: align = 1; break;
1295 default:
1296 FIXME( "depth %u bpp %u not supported yet\n", vis.depth, format->bits_per_pixel );
1297 return ERROR_BAD_FORMAT;
1300 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1301 info->bmiHeader.biPlanes = 1;
1302 info->bmiHeader.biBitCount = format->bits_per_pixel;
1303 info->bmiHeader.biXPelsPerMeter = 0;
1304 info->bmiHeader.biYPelsPerMeter = 0;
1305 info->bmiHeader.biClrImportant = 0;
1306 set_color_info( &vis, info );
1308 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
1310 x = src->visrect.left & ~(align - 1);
1311 y = src->visrect.top;
1312 width = src->visrect.right - x;
1313 height = src->visrect.bottom - src->visrect.top;
1314 if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1);
1315 /* make the source rectangle relative to the returned bits */
1316 src->x -= x;
1317 src->y -= y;
1318 OffsetRect( &src->visrect, -x, -y );
1320 X11DRV_expect_error( gdi_display, XGetImage_handler, NULL );
1321 image = XGetImage( gdi_display, physdev->drawable,
1322 physdev->dc_rect.left + x, physdev->dc_rect.top + y,
1323 width, height, AllPlanes, ZPixmap );
1324 if (X11DRV_check_error())
1326 /* use a temporary pixmap to avoid the BadMatch error */
1327 Pixmap pixmap = XCreatePixmap( gdi_display, root_window, width, height, vis.depth );
1328 GC gc = XCreateGC( gdi_display, pixmap, 0, NULL );
1330 XSetGraphicsExposures( gdi_display, gc, False );
1331 XCopyArea( gdi_display, physdev->drawable, pixmap, gc,
1332 physdev->dc_rect.left + x, physdev->dc_rect.top + y, width, height, 0, 0 );
1333 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1334 XFreePixmap( gdi_display, pixmap );
1335 XFreeGC( gdi_display, gc );
1338 if (!image) return ERROR_OUTOFMEMORY;
1340 info->bmiHeader.biWidth = width;
1341 info->bmiHeader.biHeight = -height;
1342 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1344 src_bits.ptr = image->data;
1345 src_bits.is_copy = TRUE;
1346 ret = copy_image_bits( info, is_r8g8b8(&vis), image, &src_bits, bits, src, mapping,
1347 zeropad_masks[(width * image->bits_per_pixel) & 31] );
1349 if (!ret && bits->ptr == image->data)
1351 bits->free = free_ximage_bits;
1352 image->data = NULL;
1354 XDestroyImage( image );
1355 return ret;
1359 /***********************************************************************
1360 * put_pixmap_image
1362 * Simplified equivalent of X11DRV_PutImage that writes directly to a pixmap.
1364 static DWORD put_pixmap_image( Pixmap pixmap, const XVisualInfo *vis,
1365 BITMAPINFO *info, const struct gdi_image_bits *bits )
1367 DWORD ret;
1368 XImage *image;
1369 GC gc;
1370 struct bitblt_coords coords;
1371 struct gdi_image_bits dst_bits;
1372 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1373 const int *mapping = NULL;
1375 if (!format) return ERROR_INVALID_PARAMETER;
1376 if (info->bmiHeader.biPlanes != 1) goto update_format;
1377 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1378 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1379 if (!matching_color_info( vis, info )) goto update_format;
1380 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1382 coords.x = 0;
1383 coords.y = 0;
1384 coords.width = info->bmiHeader.biWidth;
1385 coords.height = abs( info->bmiHeader.biHeight );
1386 SetRect( &coords.visrect, 0, 0, coords.width, coords.height );
1388 image = XCreateImage( gdi_display, visual, vis->depth, ZPixmap, 0, NULL,
1389 coords.width, coords.height, 32, 0 );
1390 if (!image) return ERROR_OUTOFMEMORY;
1392 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1393 mapping = X11DRV_PALETTE_PaletteToXPixel;
1395 if (!(ret = copy_image_bits( info, is_r8g8b8(vis), image, bits, &dst_bits, &coords, mapping, ~0u )))
1397 image->data = dst_bits.ptr;
1398 gc = XCreateGC( gdi_display, pixmap, 0, NULL );
1399 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, coords.width, coords.height );
1400 XFreeGC( gdi_display, gc );
1401 image->data = NULL;
1404 XDestroyImage( image );
1405 if (dst_bits.free) dst_bits.free( &dst_bits );
1406 return ret;
1408 update_format:
1409 info->bmiHeader.biPlanes = 1;
1410 info->bmiHeader.biBitCount = format->bits_per_pixel;
1411 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1412 set_color_info( vis, info );
1413 return ERROR_BAD_FORMAT;
1417 /***********************************************************************
1418 * create_pixmap_from_image
1420 Pixmap create_pixmap_from_image( HDC hdc, const XVisualInfo *vis, const BITMAPINFO *info,
1421 const struct gdi_image_bits *bits, UINT coloruse )
1423 static const RGBQUAD default_colortable[2] = { { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff } };
1424 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1425 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1426 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
1427 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
1428 struct gdi_image_bits dst_bits;
1429 Pixmap pixmap;
1430 DWORD err;
1431 HBITMAP dib;
1433 pixmap = XCreatePixmap( gdi_display, root_window,
1434 info->bmiHeader.biWidth, abs(info->bmiHeader.biHeight), vis->depth );
1435 if (!pixmap) return 0;
1437 memcpy( src_info, info, get_dib_info_size( info, coloruse ));
1438 memcpy( dst_info, info, get_dib_info_size( info, coloruse ));
1440 if (coloruse == DIB_PAL_COLORS ||
1441 (err = put_pixmap_image( pixmap, vis, dst_info, bits )) == ERROR_BAD_FORMAT)
1443 if (dst_info->bmiHeader.biBitCount == 1) /* set a default color table for 1-bpp */
1444 memcpy( dst_info->bmiColors, default_colortable, sizeof(default_colortable) );
1445 dib = CreateDIBSection( hdc, dst_info, coloruse, &dst_bits.ptr, 0, 0 );
1446 if (dib)
1448 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
1449 memcpy( src_info->bmiColors, default_colortable, sizeof(default_colortable) );
1450 SetDIBits( hdc, dib, 0, abs(info->bmiHeader.biHeight), bits->ptr, src_info, coloruse );
1451 dst_bits.free = NULL;
1452 dst_bits.is_copy = TRUE;
1453 err = put_pixmap_image( pixmap, vis, dst_info, &dst_bits );
1454 DeleteObject( dib );
1456 else err = ERROR_OUTOFMEMORY;
1459 if (!err) return pixmap;
1461 XFreePixmap( gdi_display, pixmap );
1462 return 0;
1467 /***********************************************************************
1468 * get_pixmap_image
1470 * Equivalent of X11DRV_GetImage that reads directly from a pixmap.
1472 DWORD get_pixmap_image( Pixmap pixmap, int width, int height, const XVisualInfo *vis,
1473 BITMAPINFO *info, struct gdi_image_bits *bits )
1475 DWORD ret = ERROR_SUCCESS;
1476 XImage *image;
1477 struct gdi_image_bits src_bits;
1478 struct bitblt_coords coords;
1479 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1480 const int *mapping = NULL;
1482 if (!format) return ERROR_INVALID_PARAMETER;
1484 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1485 info->bmiHeader.biWidth = width;
1486 info->bmiHeader.biHeight = -height;
1487 info->bmiHeader.biPlanes = 1;
1488 info->bmiHeader.biBitCount = format->bits_per_pixel;
1489 info->bmiHeader.biXPelsPerMeter = 0;
1490 info->bmiHeader.biYPelsPerMeter = 0;
1491 info->bmiHeader.biClrImportant = 0;
1492 set_color_info( vis, info );
1494 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
1496 coords.x = 0;
1497 coords.y = 0;
1498 coords.width = width;
1499 coords.height = height;
1500 SetRect( &coords.visrect, 0, 0, width, height );
1502 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1503 if (!image) return ERROR_OUTOFMEMORY;
1505 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1507 src_bits.ptr = image->data;
1508 src_bits.is_copy = TRUE;
1509 ret = copy_image_bits( info, is_r8g8b8(vis), image, &src_bits, bits, &coords, mapping,
1510 zeropad_masks[(width * image->bits_per_pixel) & 31] );
1512 if (!ret && bits->ptr == image->data)
1514 bits->free = free_ximage_bits;
1515 image->data = NULL;
1517 XDestroyImage( image );
1518 return ret;