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