wbemprox: Win32_NetworkAdapter.InterfaceIndex is unsigned.
[wine/multimedia.git] / dlls / winex11.drv / bitblt.c
blobd7e1e07e705a7ece2c60fd22bfd682471a6d0438
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 wine_tsx11_lock();
605 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
606 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
608 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
609 physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
610 width, height, 0, 0 );
611 exposures++;
613 else
615 INT x, y;
616 XImage *image;
618 /* Make sure we don't get a BadMatch error */
619 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
620 physDev->dc_rect.left + visRectDst->left,
621 physDev->dc_rect.top + visRectDst->top,
622 width, height, 0, 0);
623 exposures++;
624 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
625 AllPlanes, ZPixmap );
626 if (image)
628 for (y = 0; y < height; y++)
629 for (x = 0; x < width; x++)
630 XPutPixel( image, x, y,
631 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
632 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
633 XDestroyImage( image );
637 wine_tsx11_unlock();
638 return exposures;
642 /***********************************************************************
643 * BITBLT_PutDstArea
645 * Put an area back into the destination DC, mapping the pixel
646 * colors to X pixels.
648 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, const RECT *visRectDst)
650 int exposures = 0;
651 INT width = visRectDst->right - visRectDst->left;
652 INT height = visRectDst->bottom - visRectDst->top;
654 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
656 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
657 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
659 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
660 physDev->dc_rect.left + visRectDst->left,
661 physDev->dc_rect.top + visRectDst->top );
662 exposures++;
664 else
666 register INT x, y;
667 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
668 AllPlanes, ZPixmap );
669 for (y = 0; y < height; y++)
670 for (x = 0; x < width; x++)
672 XPutPixel( image, x, y,
673 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
675 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
676 physDev->dc_rect.left + visRectDst->left,
677 physDev->dc_rect.top + visRectDst->top, width, height );
678 XDestroyImage( image );
680 return exposures;
683 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
685 if (physDevSrc->depth != physDevDst->depth) return FALSE;
686 if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
687 if (physDevSrc->color_shifts && physDevDst->color_shifts)
688 return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
689 return FALSE;
692 void execute_rop( X11DRV_PDEVICE *physdev, Pixmap src_pixmap, GC gc, const RECT *visrect, DWORD rop )
694 Pixmap pixmaps[3];
695 Pixmap result = src_pixmap;
696 BOOL null_brush;
697 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
698 BOOL use_pat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
699 BOOL use_dst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
700 int width = visrect->right - visrect->left;
701 int height = visrect->bottom - visrect->top;
703 pixmaps[SRC] = src_pixmap;
704 pixmaps[TMP] = 0;
705 wine_tsx11_lock();
706 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
707 wine_tsx11_unlock();
709 if (use_dst) BITBLT_GetDstArea( physdev, pixmaps[DST], gc, visrect );
710 null_brush = use_pat && !X11DRV_SetupGCForPatBlt( physdev, gc, TRUE );
712 wine_tsx11_lock();
713 for ( ; *opcode; opcode++)
715 if (OP_DST(*opcode) == DST) result = pixmaps[DST];
716 XSetFunction( gdi_display, gc, OP_ROP(*opcode) );
717 switch(OP_SRCDST(*opcode))
719 case OP_ARGS(DST,TMP):
720 case OP_ARGS(SRC,TMP):
721 if (!pixmaps[TMP])
722 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
723 /* fall through */
724 case OP_ARGS(DST,SRC):
725 case OP_ARGS(SRC,DST):
726 case OP_ARGS(TMP,SRC):
727 case OP_ARGS(TMP,DST):
728 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)], pixmaps[OP_DST(*opcode)], gc,
729 0, 0, width, height, 0, 0 );
730 break;
731 case OP_ARGS(PAT,DST):
732 case OP_ARGS(PAT,SRC):
733 if (!null_brush)
734 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)], gc, 0, 0, width, height );
735 break;
738 XSetFunction( gdi_display, physdev->gc, GXcopy );
739 physdev->exposures += BITBLT_PutDstArea( physdev, result, visrect );
740 XFreePixmap( gdi_display, pixmaps[DST] );
741 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
742 wine_tsx11_unlock();
743 add_device_bounds( physdev, visrect );
746 /***********************************************************************
747 * X11DRV_PatBlt
749 BOOL X11DRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
751 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
752 BOOL usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
753 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
755 if (usePat && !X11DRV_SetupGCForBrush( physDev )) return TRUE;
757 wine_tsx11_lock();
758 XSetFunction( gdi_display, physDev->gc, OP_ROP(*opcode) );
760 switch(rop) /* a few special cases */
762 case BLACKNESS: /* 0x00 */
763 case WHITENESS: /* 0xff */
764 if ((physDev->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
766 XSetFunction( gdi_display, physDev->gc, GXcopy );
767 if (rop == BLACKNESS)
768 XSetForeground( gdi_display, physDev->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
769 else
770 XSetForeground( gdi_display, physDev->gc,
771 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
772 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
774 break;
775 case DSTINVERT: /* 0x55 */
776 if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
778 /* Xor is much better when we do not have full colormap. */
779 /* Using white^black ensures that we invert at least black */
780 /* and white. */
781 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
782 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
783 XSetFunction( gdi_display, physDev->gc, GXxor );
784 XSetForeground( gdi_display, physDev->gc, xor_pix);
785 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
787 break;
789 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
790 physDev->dc_rect.left + dst->visrect.left,
791 physDev->dc_rect.top + dst->visrect.top,
792 dst->visrect.right - dst->visrect.left,
793 dst->visrect.bottom - dst->visrect.top );
794 wine_tsx11_unlock();
795 add_device_bounds( physDev, &dst->visrect );
796 return TRUE;
800 /***********************************************************************
801 * X11DRV_StretchBlt
803 BOOL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
804 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
806 X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
807 X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev );
808 INT width, height;
809 const BYTE *opcode;
810 Pixmap src_pixmap;
811 GC gc;
813 if (src_dev->funcs != dst_dev->funcs ||
814 src->width != dst->width || src->height != dst->height || /* no stretching with core X11 */
815 (physDevDst->depth == 1 && physDevSrc->depth != 1) || /* color -> mono done by hand */
816 (X11DRV_PALETTE_XPixelToPalette && physDevSrc->depth != 1)) /* needs palette mapping */
818 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
819 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
822 width = dst->visrect.right - dst->visrect.left;
823 height = dst->visrect.bottom - dst->visrect.top;
824 opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
826 add_device_bounds( physDevDst, &dst->visrect );
828 /* a few optimizations for single-op ROPs */
829 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
831 if (same_format(physDevSrc, physDevDst))
833 wine_tsx11_lock();
834 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
835 XCopyArea( gdi_display, physDevSrc->drawable,
836 physDevDst->drawable, physDevDst->gc,
837 physDevSrc->dc_rect.left + src->visrect.left,
838 physDevSrc->dc_rect.top + src->visrect.top,
839 width, height,
840 physDevDst->dc_rect.left + dst->visrect.left,
841 physDevDst->dc_rect.top + dst->visrect.top );
842 physDevDst->exposures++;
843 wine_tsx11_unlock();
844 return TRUE;
846 if (physDevSrc->depth == 1)
848 int text_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetTextColor(physDevDst->dev.hdc) );
849 int bkgnd_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetBkColor(physDevDst->dev.hdc) );
851 wine_tsx11_lock();
852 XSetBackground( gdi_display, physDevDst->gc, text_pixel );
853 XSetForeground( gdi_display, physDevDst->gc, bkgnd_pixel );
854 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
855 XCopyPlane( gdi_display, physDevSrc->drawable,
856 physDevDst->drawable, physDevDst->gc,
857 physDevSrc->dc_rect.left + src->visrect.left,
858 physDevSrc->dc_rect.top + src->visrect.top,
859 width, height,
860 physDevDst->dc_rect.left + dst->visrect.left,
861 physDevDst->dc_rect.top + dst->visrect.top, 1 );
862 physDevDst->exposures++;
863 wine_tsx11_unlock();
864 return TRUE;
868 wine_tsx11_lock();
869 gc = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
870 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
871 XSetGraphicsExposures( gdi_display, gc, False );
873 /* retrieve the source */
875 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, physDevDst->depth );
876 if (physDevSrc->depth == 1)
878 /* MSDN says if StretchBlt must convert a bitmap from monochrome
879 to color or vice versa, the foreground and background color of
880 the device context are used. In fact, it also applies to the
881 case when it is converted from mono to mono. */
882 int text_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetTextColor(physDevDst->dev.hdc) );
883 int bkgnd_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetBkColor(physDevDst->dev.hdc) );
885 if (X11DRV_PALETTE_XPixelToPalette && physDevDst->depth != 1)
887 XSetBackground( gdi_display, gc, X11DRV_PALETTE_XPixelToPalette[text_pixel] );
888 XSetForeground( gdi_display, gc, X11DRV_PALETTE_XPixelToPalette[bkgnd_pixel]);
890 else
892 XSetBackground( gdi_display, gc, text_pixel );
893 XSetForeground( gdi_display, gc, bkgnd_pixel );
895 XCopyPlane( gdi_display, physDevSrc->drawable, src_pixmap, gc,
896 physDevSrc->dc_rect.left + src->visrect.left,
897 physDevSrc->dc_rect.top + src->visrect.top,
898 width, height, 0, 0, 1 );
900 else /* color -> color */
902 XCopyArea( gdi_display, physDevSrc->drawable, src_pixmap, gc,
903 physDevSrc->dc_rect.left + src->visrect.left,
904 physDevSrc->dc_rect.top + src->visrect.top,
905 width, height, 0, 0 );
907 wine_tsx11_unlock();
909 execute_rop( physDevDst, src_pixmap, gc, &dst->visrect, rop );
911 wine_tsx11_lock();
912 XFreePixmap( gdi_display, src_pixmap );
913 XFreeGC( gdi_display, gc );
914 wine_tsx11_unlock();
915 return TRUE;
919 static void free_heap_bits( struct gdi_image_bits *bits )
921 HeapFree( GetProcessHeap(), 0, bits->ptr );
924 static void free_ximage_bits( struct gdi_image_bits *bits )
926 wine_tsx11_lock();
927 XFree( bits->ptr );
928 wine_tsx11_unlock();
931 /* only for use on sanitized BITMAPINFO structures */
932 static inline int get_dib_info_size( const BITMAPINFO *info, UINT coloruse )
934 if (info->bmiHeader.biCompression == BI_BITFIELDS)
935 return sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD);
936 if (coloruse == DIB_PAL_COLORS)
937 return sizeof(BITMAPINFOHEADER) + info->bmiHeader.biClrUsed * sizeof(WORD);
938 return FIELD_OFFSET( BITMAPINFO, bmiColors[info->bmiHeader.biClrUsed] );
941 /* store the palette or color mask data in the bitmap info structure */
942 static void set_color_info( const XVisualInfo *vis, BITMAPINFO *info )
944 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
946 info->bmiHeader.biCompression = BI_RGB;
947 info->bmiHeader.biClrUsed = 0;
949 switch (info->bmiHeader.biBitCount)
951 case 4:
952 case 8:
954 RGBQUAD *rgb = (RGBQUAD *)colors;
955 PALETTEENTRY palette[256];
956 UINT i, count;
958 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
959 count = X11DRV_GetSystemPaletteEntries( NULL, 0, info->bmiHeader.biClrUsed, palette );
960 for (i = 0; i < count; i++)
962 rgb[i].rgbRed = palette[i].peRed;
963 rgb[i].rgbGreen = palette[i].peGreen;
964 rgb[i].rgbBlue = palette[i].peBlue;
965 rgb[i].rgbReserved = 0;
967 memset( &rgb[count], 0, (info->bmiHeader.biClrUsed - count) * sizeof(*rgb) );
968 break;
970 case 16:
971 colors[0] = vis->red_mask;
972 colors[1] = vis->green_mask;
973 colors[2] = vis->blue_mask;
974 info->bmiHeader.biCompression = BI_BITFIELDS;
975 break;
976 case 32:
977 colors[0] = vis->red_mask;
978 colors[1] = vis->green_mask;
979 colors[2] = vis->blue_mask;
980 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
981 info->bmiHeader.biCompression = BI_BITFIELDS;
982 break;
986 /* check if the specified color info is suitable for PutImage */
987 static BOOL matching_color_info( const XVisualInfo *vis, const BITMAPINFO *info )
989 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
991 switch (info->bmiHeader.biBitCount)
993 case 1:
994 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
995 return !info->bmiHeader.biClrUsed; /* color map not allowed */
996 case 4:
997 case 8:
999 RGBQUAD *rgb = (RGBQUAD *)colors;
1000 PALETTEENTRY palette[256];
1001 UINT i, count;
1003 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1004 count = X11DRV_GetSystemPaletteEntries( NULL, 0, 1 << info->bmiHeader.biBitCount, palette );
1005 if (count != info->bmiHeader.biClrUsed) return FALSE;
1006 for (i = 0; i < count; i++)
1008 if (rgb[i].rgbRed != palette[i].peRed ||
1009 rgb[i].rgbGreen != palette[i].peGreen ||
1010 rgb[i].rgbBlue != palette[i].peBlue) return FALSE;
1012 return TRUE;
1014 case 16:
1015 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1016 return (vis->red_mask == colors[0] &&
1017 vis->green_mask == colors[1] &&
1018 vis->blue_mask == colors[2]);
1019 if (info->bmiHeader.biCompression == BI_RGB)
1020 return (vis->red_mask == 0x7c00 && vis->green_mask == 0x03e0 && vis->blue_mask == 0x001f);
1021 break;
1022 case 32:
1023 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1024 return (vis->red_mask == colors[0] &&
1025 vis->green_mask == colors[1] &&
1026 vis->blue_mask == colors[2]);
1027 /* fall through */
1028 case 24:
1029 if (info->bmiHeader.biCompression == BI_RGB)
1030 return (vis->red_mask == 0xff0000 && vis->green_mask == 0x00ff00 && vis->blue_mask == 0x0000ff);
1031 break;
1033 return FALSE;
1036 static inline BOOL is_r8g8b8( const XVisualInfo *vis )
1038 return vis->depth == 24 && vis->red_mask == 0xff0000 && vis->blue_mask == 0x0000ff;
1041 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1042 DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image,
1043 const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
1044 struct bitblt_coords *coords, const int *mapping, unsigned int zeropad_mask )
1046 #ifdef WORDS_BIGENDIAN
1047 static const int client_byte_order = MSBFirst;
1048 #else
1049 static const int client_byte_order = LSBFirst;
1050 #endif
1051 BOOL need_byteswap;
1052 int x, y, height = coords->visrect.bottom - coords->visrect.top;
1053 int width_bytes = image->bytes_per_line;
1054 int padding_pos;
1055 unsigned char *src, *dst;
1057 switch (info->bmiHeader.biBitCount)
1059 case 1:
1060 need_byteswap = (image->bitmap_bit_order != MSBFirst);
1061 break;
1062 case 4:
1063 need_byteswap = (image->byte_order != MSBFirst);
1064 break;
1065 case 16:
1066 case 32:
1067 need_byteswap = (image->byte_order != client_byte_order);
1068 break;
1069 case 24:
1070 need_byteswap = (image->byte_order == MSBFirst) ^ !is_r8g8b8;
1071 break;
1072 default:
1073 need_byteswap = FALSE;
1074 break;
1077 src = src_bits->ptr;
1078 if (info->bmiHeader.biHeight > 0)
1079 src += (info->bmiHeader.biHeight - coords->visrect.bottom) * width_bytes;
1080 else
1081 src += coords->visrect.top * width_bytes;
1083 if ((need_byteswap && !src_bits->is_copy) || /* need to swap bytes */
1084 (zeropad_mask != ~0u && !src_bits->is_copy) || /* need to clear padding bytes */
1085 (mapping && !src_bits->is_copy) || /* need to remap pixels */
1086 (width_bytes & 3) || /* need to fixup line alignment */
1087 (info->bmiHeader.biHeight > 0)) /* need to flip vertically */
1089 width_bytes = (width_bytes + 3) & ~3;
1090 info->bmiHeader.biSizeImage = height * width_bytes;
1091 if (!(dst_bits->ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
1092 return ERROR_OUTOFMEMORY;
1093 dst_bits->is_copy = TRUE;
1094 dst_bits->free = free_heap_bits;
1096 else
1098 /* swap bits in place */
1099 dst_bits->ptr = src;
1100 dst_bits->is_copy = src_bits->is_copy;
1101 dst_bits->free = NULL;
1102 if (!need_byteswap && zeropad_mask == ~0u && !mapping) return ERROR_SUCCESS; /* nothing to do */
1105 dst = dst_bits->ptr;
1106 padding_pos = width_bytes/sizeof(unsigned int) - 1;
1108 if (info->bmiHeader.biHeight > 0)
1110 dst += (height - 1) * width_bytes;
1111 width_bytes = -width_bytes;
1114 if (need_byteswap || mapping)
1116 switch (info->bmiHeader.biBitCount)
1118 case 1:
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] = bit_swap[src[x]];
1123 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1125 break;
1126 case 4:
1127 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1129 if (mapping)
1130 for (x = 0; x < image->bytes_per_line; x++)
1131 dst[x] = (mapping[src[x] & 0x0f] << 4) | mapping[src[x] >> 4];
1132 else
1133 for (x = 0; x < image->bytes_per_line; x++)
1134 dst[x] = (src[x] << 4) | (src[x] >> 4);
1135 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1137 break;
1138 case 8:
1139 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1141 for (x = 0; x < image->bytes_per_line; x++)
1142 dst[x] = mapping[src[x]];
1143 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1145 break;
1146 case 16:
1147 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1149 for (x = 0; x < info->bmiHeader.biWidth; x++)
1150 ((USHORT *)dst)[x] = RtlUshortByteSwap( ((const USHORT *)src)[x] );
1151 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1153 break;
1154 case 24:
1155 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1157 for (x = 0; x < info->bmiHeader.biWidth; x++)
1159 unsigned char tmp = src[3 * x];
1160 dst[3 * x] = src[3 * x + 2];
1161 dst[3 * x + 1] = src[3 * x + 1];
1162 dst[3 * x + 2] = tmp;
1164 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1166 break;
1167 case 32:
1168 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1169 for (x = 0; x < info->bmiHeader.biWidth; x++)
1170 ((ULONG *)dst)[x] = RtlUlongByteSwap( ((const ULONG *)src)[x] );
1171 break;
1174 else if (src != dst)
1176 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1178 memcpy( dst, src, image->bytes_per_line );
1179 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1182 else /* only need to clear the padding */
1184 for (y = 0; y < height; y++, dst += width_bytes)
1185 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1187 return ERROR_SUCCESS;
1190 /***********************************************************************
1191 * X11DRV_PutImage
1193 DWORD X11DRV_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
1194 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1195 struct bitblt_coords *dst, DWORD rop )
1197 X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1198 DWORD ret;
1199 XImage *image;
1200 XVisualInfo vis;
1201 struct gdi_image_bits dst_bits;
1202 const XPixmapFormatValues *format;
1203 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1204 const int *mapping = NULL;
1206 vis.depth = physdev->depth;
1207 if (physdev->color_shifts)
1209 vis.red_mask = physdev->color_shifts->logicalRed.max << physdev->color_shifts->logicalRed.shift;
1210 vis.green_mask = physdev->color_shifts->logicalGreen.max << physdev->color_shifts->logicalGreen.shift;
1211 vis.blue_mask = physdev->color_shifts->logicalBlue.max << physdev->color_shifts->logicalBlue.shift;
1213 format = pixmap_formats[vis.depth];
1215 if (info->bmiHeader.biPlanes != 1) goto update_format;
1216 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1217 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1218 if (!matching_color_info( &vis, info )) goto update_format;
1219 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1220 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
1222 wine_tsx11_lock();
1223 image = XCreateImage( gdi_display, visual, vis.depth, ZPixmap, 0, NULL,
1224 info->bmiHeader.biWidth, src->visrect.bottom - src->visrect.top, 32, 0 );
1225 wine_tsx11_unlock();
1226 if (!image) return ERROR_OUTOFMEMORY;
1228 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1230 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1231 mapping = X11DRV_PALETTE_PaletteToXPixel;
1234 ret = copy_image_bits( info, is_r8g8b8(&vis), image, bits, &dst_bits, src, mapping, ~0u );
1236 if (!ret)
1238 BOOL restore_region = add_extra_clipping_region( physdev, clip );
1239 int width = dst->visrect.right - dst->visrect.left;
1240 int height = dst->visrect.bottom - dst->visrect.top;
1242 image->data = dst_bits.ptr;
1244 /* optimization for single-op ROPs */
1245 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1247 wine_tsx11_lock();
1248 XSetFunction( gdi_display, physdev->gc, OP_ROP(*opcode) );
1249 XPutImage( gdi_display, physdev->drawable, physdev->gc, image, src->visrect.left, 0,
1250 physdev->dc_rect.left + dst->visrect.left,
1251 physdev->dc_rect.top + dst->visrect.top, width, height );
1252 wine_tsx11_unlock();
1254 else
1256 Pixmap src_pixmap;
1257 GC gc;
1259 wine_tsx11_lock();
1260 gc = XCreateGC( gdi_display, physdev->drawable, 0, NULL );
1261 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1262 XSetGraphicsExposures( gdi_display, gc, False );
1263 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, vis.depth );
1264 XPutImage( gdi_display, src_pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1265 wine_tsx11_unlock();
1267 execute_rop( physdev, src_pixmap, gc, &dst->visrect, rop );
1269 wine_tsx11_lock();
1270 XFreePixmap( gdi_display, src_pixmap );
1271 XFreeGC( gdi_display, gc );
1272 wine_tsx11_unlock();
1275 if (restore_region) restore_clipping_region( physdev );
1276 add_device_bounds( physdev, &dst->visrect );
1277 image->data = NULL;
1280 wine_tsx11_lock();
1281 XDestroyImage( image );
1282 wine_tsx11_unlock();
1283 if (dst_bits.free) dst_bits.free( &dst_bits );
1284 return ret;
1286 update_format:
1287 info->bmiHeader.biPlanes = 1;
1288 info->bmiHeader.biBitCount = format->bits_per_pixel;
1289 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1290 set_color_info( &vis, info );
1291 return ERROR_BAD_FORMAT;
1294 /***********************************************************************
1295 * X11DRV_GetImage
1297 DWORD X11DRV_GetImage( PHYSDEV dev, BITMAPINFO *info,
1298 struct gdi_image_bits *bits, struct bitblt_coords *src )
1300 X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1301 DWORD ret = ERROR_SUCCESS;
1302 XImage *image;
1303 XVisualInfo vis;
1304 UINT align, x, y, width, height;
1305 struct gdi_image_bits src_bits;
1306 const XPixmapFormatValues *format;
1307 const int *mapping = NULL;
1309 vis.depth = physdev->depth;
1310 if (physdev->color_shifts)
1312 vis.red_mask = physdev->color_shifts->logicalRed.max << physdev->color_shifts->logicalRed.shift;
1313 vis.green_mask = physdev->color_shifts->logicalGreen.max << physdev->color_shifts->logicalGreen.shift;
1314 vis.blue_mask = physdev->color_shifts->logicalBlue.max << physdev->color_shifts->logicalBlue.shift;
1316 format = pixmap_formats[vis.depth];
1318 /* align start and width to 32-bit boundary */
1319 switch (format->bits_per_pixel)
1321 case 1: align = 32; break;
1322 case 4: align = 8; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1323 case 8: align = 4; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1324 case 16: align = 2; break;
1325 case 24: align = 4; break;
1326 case 32: align = 1; break;
1327 default:
1328 FIXME( "depth %u bpp %u not supported yet\n", vis.depth, format->bits_per_pixel );
1329 return ERROR_BAD_FORMAT;
1332 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1333 info->bmiHeader.biPlanes = 1;
1334 info->bmiHeader.biBitCount = format->bits_per_pixel;
1335 info->bmiHeader.biXPelsPerMeter = 0;
1336 info->bmiHeader.biYPelsPerMeter = 0;
1337 info->bmiHeader.biClrImportant = 0;
1338 set_color_info( &vis, info );
1340 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
1342 x = src->visrect.left & ~(align - 1);
1343 y = src->visrect.top;
1344 width = src->visrect.right - x;
1345 height = src->visrect.bottom - src->visrect.top;
1346 if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1);
1347 /* make the source rectangle relative to the returned bits */
1348 src->x -= x;
1349 src->y -= y;
1350 OffsetRect( &src->visrect, -x, -y );
1352 X11DRV_expect_error( gdi_display, XGetImage_handler, NULL );
1353 image = XGetImage( gdi_display, physdev->drawable,
1354 physdev->dc_rect.left + x, physdev->dc_rect.top + y,
1355 width, height, AllPlanes, ZPixmap );
1356 if (X11DRV_check_error())
1358 /* use a temporary pixmap to avoid the BadMatch error */
1359 GC gc;
1360 Pixmap pixmap;
1362 wine_tsx11_lock();
1363 pixmap = XCreatePixmap( gdi_display, root_window, width, height, vis.depth );
1364 gc = XCreateGC( gdi_display, pixmap, 0, NULL );
1365 XSetGraphicsExposures( gdi_display, gc, False );
1366 XCopyArea( gdi_display, physdev->drawable, pixmap, gc,
1367 physdev->dc_rect.left + x, physdev->dc_rect.top + y, width, height, 0, 0 );
1368 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1369 XFreePixmap( gdi_display, pixmap );
1370 XFreeGC( gdi_display, gc );
1371 wine_tsx11_unlock();
1374 if (!image) return ERROR_OUTOFMEMORY;
1376 info->bmiHeader.biWidth = width;
1377 info->bmiHeader.biHeight = -height;
1378 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1380 src_bits.ptr = image->data;
1381 src_bits.is_copy = TRUE;
1382 ret = copy_image_bits( info, is_r8g8b8(&vis), image, &src_bits, bits, src, mapping,
1383 zeropad_masks[(width * image->bits_per_pixel) & 31] );
1385 if (!ret && bits->ptr == image->data)
1387 bits->free = free_ximage_bits;
1388 image->data = NULL;
1390 wine_tsx11_lock();
1391 XDestroyImage( image );
1392 wine_tsx11_unlock();
1393 return ret;
1397 /***********************************************************************
1398 * put_pixmap_image
1400 * Simplified equivalent of X11DRV_PutImage that writes directly to a pixmap.
1402 static DWORD put_pixmap_image( Pixmap pixmap, const XVisualInfo *vis,
1403 BITMAPINFO *info, const struct gdi_image_bits *bits )
1405 DWORD ret;
1406 XImage *image;
1407 GC gc;
1408 struct bitblt_coords coords;
1409 struct gdi_image_bits dst_bits;
1410 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1411 const int *mapping = NULL;
1413 if (!format) return ERROR_INVALID_PARAMETER;
1414 if (info->bmiHeader.biPlanes != 1) goto update_format;
1415 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1416 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1417 if (!matching_color_info( vis, info )) goto update_format;
1418 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1420 coords.x = 0;
1421 coords.y = 0;
1422 coords.width = info->bmiHeader.biWidth;
1423 coords.height = abs( info->bmiHeader.biHeight );
1424 SetRect( &coords.visrect, 0, 0, coords.width, coords.height );
1426 wine_tsx11_lock();
1427 image = XCreateImage( gdi_display, visual, vis->depth, ZPixmap, 0, NULL,
1428 coords.width, coords.height, 32, 0 );
1429 wine_tsx11_unlock();
1430 if (!image) return ERROR_OUTOFMEMORY;
1432 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1433 mapping = X11DRV_PALETTE_PaletteToXPixel;
1435 if (!(ret = copy_image_bits( info, is_r8g8b8(vis), image, bits, &dst_bits, &coords, mapping, ~0u )))
1437 image->data = dst_bits.ptr;
1438 wine_tsx11_lock();
1439 gc = XCreateGC( gdi_display, pixmap, 0, NULL );
1440 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, coords.width, coords.height );
1441 XFreeGC( gdi_display, gc );
1442 wine_tsx11_unlock();
1443 image->data = NULL;
1446 wine_tsx11_lock();
1447 XDestroyImage( image );
1448 wine_tsx11_unlock();
1449 if (dst_bits.free) dst_bits.free( &dst_bits );
1450 return ret;
1452 update_format:
1453 info->bmiHeader.biPlanes = 1;
1454 info->bmiHeader.biBitCount = format->bits_per_pixel;
1455 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1456 set_color_info( vis, info );
1457 return ERROR_BAD_FORMAT;
1461 /***********************************************************************
1462 * create_pixmap_from_image
1464 Pixmap create_pixmap_from_image( HDC hdc, const XVisualInfo *vis, const BITMAPINFO *info,
1465 const struct gdi_image_bits *bits, UINT coloruse )
1467 static const RGBQUAD default_colortable[2] = { { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff } };
1468 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1469 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1470 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
1471 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
1472 struct gdi_image_bits dst_bits;
1473 Pixmap pixmap;
1474 DWORD err;
1475 HBITMAP dib;
1477 wine_tsx11_lock();
1478 pixmap = XCreatePixmap( gdi_display, root_window,
1479 info->bmiHeader.biWidth, abs(info->bmiHeader.biHeight), vis->depth );
1480 wine_tsx11_unlock();
1481 if (!pixmap) return 0;
1483 memcpy( src_info, info, get_dib_info_size( info, coloruse ));
1484 memcpy( dst_info, info, get_dib_info_size( info, coloruse ));
1486 if (coloruse == DIB_PAL_COLORS ||
1487 (err = put_pixmap_image( pixmap, vis, dst_info, bits )) == ERROR_BAD_FORMAT)
1489 if (dst_info->bmiHeader.biBitCount == 1) /* set a default color table for 1-bpp */
1490 memcpy( dst_info->bmiColors, default_colortable, sizeof(default_colortable) );
1491 dib = CreateDIBSection( hdc, dst_info, coloruse, &dst_bits.ptr, 0, 0 );
1492 if (dib)
1494 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
1495 memcpy( src_info->bmiColors, default_colortable, sizeof(default_colortable) );
1496 SetDIBits( hdc, dib, 0, abs(info->bmiHeader.biHeight), bits->ptr, src_info, coloruse );
1497 dst_bits.free = NULL;
1498 dst_bits.is_copy = TRUE;
1499 err = put_pixmap_image( pixmap, vis, dst_info, &dst_bits );
1500 DeleteObject( dib );
1502 else err = ERROR_OUTOFMEMORY;
1505 if (!err) return pixmap;
1507 wine_tsx11_lock();
1508 XFreePixmap( gdi_display, pixmap );
1509 wine_tsx11_unlock();
1510 return 0;
1515 /***********************************************************************
1516 * get_pixmap_image
1518 * Equivalent of X11DRV_GetImage that reads directly from a pixmap.
1520 DWORD get_pixmap_image( Pixmap pixmap, int width, int height, const XVisualInfo *vis,
1521 BITMAPINFO *info, struct gdi_image_bits *bits )
1523 DWORD ret = ERROR_SUCCESS;
1524 XImage *image;
1525 struct gdi_image_bits src_bits;
1526 struct bitblt_coords coords;
1527 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1528 const int *mapping = NULL;
1530 if (!format) return ERROR_INVALID_PARAMETER;
1532 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1533 info->bmiHeader.biWidth = width;
1534 info->bmiHeader.biHeight = -height;
1535 info->bmiHeader.biPlanes = 1;
1536 info->bmiHeader.biBitCount = format->bits_per_pixel;
1537 info->bmiHeader.biXPelsPerMeter = 0;
1538 info->bmiHeader.biYPelsPerMeter = 0;
1539 info->bmiHeader.biClrImportant = 0;
1540 set_color_info( vis, info );
1542 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
1544 coords.x = 0;
1545 coords.y = 0;
1546 coords.width = width;
1547 coords.height = height;
1548 SetRect( &coords.visrect, 0, 0, width, height );
1550 wine_tsx11_lock();
1551 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1552 wine_tsx11_unlock();
1553 if (!image) return ERROR_OUTOFMEMORY;
1555 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1557 src_bits.ptr = image->data;
1558 src_bits.is_copy = TRUE;
1559 ret = copy_image_bits( info, is_r8g8b8(vis), image, &src_bits, bits, &coords, mapping,
1560 zeropad_masks[(width * image->bits_per_pixel) & 31] );
1562 if (!ret && bits->ptr == image->data)
1564 bits->free = free_ximage_bits;
1565 image->data = NULL;
1567 wine_tsx11_lock();
1568 XDestroyImage( image );
1569 wine_tsx11_unlock();
1570 return ret;