winex11: Allow the visible region to be zero when not clipping.
[wine/multimedia.git] / dlls / winex11.drv / bitblt.c
blobd75e90214e262aac5a20782c1cf078ee98ce3225
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 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
767 wine_tsx11_lock();
768 XSetFunction( gdi_display, physDev->gc, OP_ROP(*opcode) );
770 switch(rop) /* a few special cases */
772 case BLACKNESS: /* 0x00 */
773 case WHITENESS: /* 0xff */
774 if ((physDev->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
776 XSetFunction( gdi_display, physDev->gc, GXcopy );
777 if (rop == BLACKNESS)
778 XSetForeground( gdi_display, physDev->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
779 else
780 XSetForeground( gdi_display, physDev->gc,
781 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
782 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
784 break;
785 case DSTINVERT: /* 0x55 */
786 if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
788 /* Xor is much better when we do not have full colormap. */
789 /* Using white^black ensures that we invert at least black */
790 /* and white. */
791 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
792 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
793 XSetFunction( gdi_display, physDev->gc, GXxor );
794 XSetForeground( gdi_display, physDev->gc, xor_pix);
795 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
797 break;
799 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
800 physDev->dc_rect.left + dst->visrect.left,
801 physDev->dc_rect.top + dst->visrect.top,
802 dst->visrect.right - dst->visrect.left,
803 dst->visrect.bottom - dst->visrect.top );
804 wine_tsx11_unlock();
806 X11DRV_UnlockDIBSection( physDev, TRUE );
807 return TRUE;
811 /***********************************************************************
812 * X11DRV_StretchBlt
814 BOOL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
815 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
817 X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
818 X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev );
819 INT width, height;
820 const BYTE *opcode;
821 Pixmap src_pixmap;
822 GC gc;
824 if (src_dev->funcs != dst_dev->funcs ||
825 src->width != dst->width || src->height != dst->height || /* no stretching with core X11 */
826 (physDevDst->depth == 1 && physDevSrc->depth != 1) || /* color -> mono done by hand */
827 (X11DRV_PALETTE_XPixelToPalette && physDevSrc->depth != 1)) /* needs palette mapping */
829 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
830 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
833 width = dst->visrect.right - dst->visrect.left;
834 height = dst->visrect.bottom - dst->visrect.top;
836 X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod );
837 if (physDevDst != physDevSrc) X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod );
839 opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
841 /* a few optimizations for single-op ROPs */
842 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
844 if (same_format(physDevSrc, physDevDst))
846 wine_tsx11_lock();
847 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
848 XCopyArea( gdi_display, physDevSrc->drawable,
849 physDevDst->drawable, physDevDst->gc,
850 physDevSrc->dc_rect.left + src->visrect.left,
851 physDevSrc->dc_rect.top + src->visrect.top,
852 width, height,
853 physDevDst->dc_rect.left + dst->visrect.left,
854 physDevDst->dc_rect.top + dst->visrect.top );
855 physDevDst->exposures++;
856 wine_tsx11_unlock();
857 goto done;
859 if (physDevSrc->depth == 1)
861 wine_tsx11_lock();
862 XSetBackground( gdi_display, physDevDst->gc, physDevDst->textPixel );
863 XSetForeground( gdi_display, physDevDst->gc, physDevDst->backgroundPixel );
864 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
865 XCopyPlane( gdi_display, physDevSrc->drawable,
866 physDevDst->drawable, physDevDst->gc,
867 physDevSrc->dc_rect.left + src->visrect.left,
868 physDevSrc->dc_rect.top + src->visrect.top,
869 width, height,
870 physDevDst->dc_rect.left + dst->visrect.left,
871 physDevDst->dc_rect.top + dst->visrect.top, 1 );
872 physDevDst->exposures++;
873 wine_tsx11_unlock();
874 goto done;
878 wine_tsx11_lock();
879 gc = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
880 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
881 XSetGraphicsExposures( gdi_display, gc, False );
883 /* retrieve the source */
885 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, physDevDst->depth );
886 if (physDevSrc->depth == 1)
888 /* MSDN says if StretchBlt must convert a bitmap from monochrome
889 to color or vice versa, the foreground and background color of
890 the device context are used. In fact, it also applies to the
891 case when it is converted from mono to mono. */
892 if (X11DRV_PALETTE_XPixelToPalette && physDevDst->depth != 1)
894 XSetBackground( gdi_display, gc, X11DRV_PALETTE_XPixelToPalette[physDevDst->textPixel] );
895 XSetForeground( gdi_display, gc, X11DRV_PALETTE_XPixelToPalette[physDevDst->backgroundPixel]);
897 else
899 XSetBackground( gdi_display, gc, physDevDst->textPixel );
900 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
902 XCopyPlane( 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, 1 );
907 else /* color -> color */
909 XCopyArea( gdi_display, physDevSrc->drawable, src_pixmap, gc,
910 physDevSrc->dc_rect.left + src->visrect.left,
911 physDevSrc->dc_rect.top + src->visrect.top,
912 width, height, 0, 0 );
914 wine_tsx11_unlock();
916 execute_rop( physDevDst, src_pixmap, gc, &dst->visrect, rop );
918 wine_tsx11_lock();
919 XFreePixmap( gdi_display, src_pixmap );
920 XFreeGC( gdi_display, gc );
921 wine_tsx11_unlock();
923 done:
924 if (physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE );
925 X11DRV_UnlockDIBSection( physDevDst, TRUE );
926 return TRUE;
930 static void free_heap_bits( struct gdi_image_bits *bits )
932 HeapFree( GetProcessHeap(), 0, bits->ptr );
935 static void free_ximage_bits( struct gdi_image_bits *bits )
937 wine_tsx11_lock();
938 XFree( bits->ptr );
939 wine_tsx11_unlock();
942 /* store the palette or color mask data in the bitmap info structure */
943 static void set_color_info( PHYSDEV dev, const ColorShifts *color_shifts, BITMAPINFO *info )
945 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
947 info->bmiHeader.biCompression = BI_RGB;
948 info->bmiHeader.biClrUsed = 0;
950 switch (info->bmiHeader.biBitCount)
952 case 4:
953 case 8:
955 RGBQUAD *rgb = (RGBQUAD *)colors;
956 PALETTEENTRY palette[256];
957 UINT i, count;
959 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
960 count = X11DRV_GetSystemPaletteEntries( dev, 0, info->bmiHeader.biClrUsed, palette );
961 for (i = 0; i < count; i++)
963 rgb[i].rgbRed = palette[i].peRed;
964 rgb[i].rgbGreen = palette[i].peGreen;
965 rgb[i].rgbBlue = palette[i].peBlue;
966 rgb[i].rgbReserved = 0;
968 memset( &rgb[count], 0, (info->bmiHeader.biClrUsed - count) * sizeof(*rgb) );
969 break;
971 case 16:
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 info->bmiHeader.biCompression = BI_BITFIELDS;
976 break;
977 case 32:
978 colors[0] = color_shifts->logicalRed.max << color_shifts->logicalRed.shift;
979 colors[1] = color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift;
980 colors[2] = color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift;
981 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
982 info->bmiHeader.biCompression = BI_BITFIELDS;
983 break;
987 /* check if the specified color info is suitable for PutImage */
988 static BOOL matching_color_info( PHYSDEV dev, const ColorShifts *color_shifts, const BITMAPINFO *info )
990 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
992 switch (info->bmiHeader.biBitCount)
994 case 1:
995 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
996 return !info->bmiHeader.biClrUsed; /* color map not allowed */
997 case 4:
998 case 8:
1000 RGBQUAD *rgb = (RGBQUAD *)colors;
1001 PALETTEENTRY palette[256];
1002 UINT i, count;
1004 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1005 count = X11DRV_GetSystemPaletteEntries( dev, 0, 1 << info->bmiHeader.biBitCount, palette );
1006 if (count != info->bmiHeader.biClrUsed) return FALSE;
1007 for (i = 0; i < count; i++)
1009 if (rgb[i].rgbRed != palette[i].peRed ||
1010 rgb[i].rgbGreen != palette[i].peGreen ||
1011 rgb[i].rgbBlue != palette[i].peBlue) return FALSE;
1013 return TRUE;
1015 case 16:
1016 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1017 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == colors[0] &&
1018 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == colors[1] &&
1019 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == colors[2]);
1020 if (info->bmiHeader.biCompression == BI_RGB)
1021 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == 0x7c00 &&
1022 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == 0x03e0 &&
1023 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == 0x001f);
1024 break;
1025 case 32:
1026 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1027 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == colors[0] &&
1028 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == colors[1] &&
1029 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == colors[2]);
1030 /* fall through */
1031 case 24:
1032 if (info->bmiHeader.biCompression == BI_RGB)
1033 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == 0xff0000 &&
1034 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == 0x00ff00 &&
1035 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == 0x0000ff);
1036 break;
1038 return FALSE;
1041 static inline BOOL is_r8g8b8( int depth, const ColorShifts *color_shifts )
1043 return depth == 24 && color_shifts->logicalBlue.shift == 0 && color_shifts->logicalRed.shift == 16;
1046 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1047 DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image,
1048 const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
1049 struct bitblt_coords *coords, const int *mapping, unsigned int zeropad_mask )
1051 #ifdef WORDS_BIGENDIAN
1052 static const int client_byte_order = MSBFirst;
1053 #else
1054 static const int client_byte_order = LSBFirst;
1055 #endif
1056 BOOL need_byteswap;
1057 int x, y, height = coords->visrect.bottom - coords->visrect.top;
1058 int width_bytes = image->bytes_per_line;
1059 int padding_pos;
1060 unsigned char *src, *dst;
1062 switch (info->bmiHeader.biBitCount)
1064 case 1:
1065 need_byteswap = (image->bitmap_bit_order != MSBFirst);
1066 break;
1067 case 4:
1068 need_byteswap = (image->byte_order != MSBFirst);
1069 break;
1070 case 16:
1071 case 32:
1072 need_byteswap = (image->byte_order != client_byte_order);
1073 break;
1074 case 24:
1075 need_byteswap = (image->byte_order == MSBFirst) ^ !is_r8g8b8;
1076 break;
1077 default:
1078 need_byteswap = FALSE;
1079 break;
1082 src = src_bits->ptr;
1083 if (info->bmiHeader.biHeight > 0)
1084 src += (info->bmiHeader.biHeight - coords->visrect.bottom) * width_bytes;
1085 else
1086 src += coords->visrect.top * width_bytes;
1088 if ((need_byteswap && !src_bits->is_copy) || /* need to swap bytes */
1089 (zeropad_mask != ~0u && !src_bits->is_copy) || /* need to clear padding bytes */
1090 (mapping && !src_bits->is_copy) || /* need to remap pixels */
1091 (width_bytes & 3) || /* need to fixup line alignment */
1092 (info->bmiHeader.biHeight > 0)) /* need to flip vertically */
1094 width_bytes = (width_bytes + 3) & ~3;
1095 info->bmiHeader.biSizeImage = height * width_bytes;
1096 if (!(dst_bits->ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
1097 return ERROR_OUTOFMEMORY;
1098 dst_bits->is_copy = TRUE;
1099 dst_bits->free = free_heap_bits;
1101 else
1103 /* swap bits in place */
1104 dst_bits->ptr = src;
1105 dst_bits->is_copy = src_bits->is_copy;
1106 dst_bits->free = NULL;
1107 if (!need_byteswap && zeropad_mask == ~0u && !mapping) return ERROR_SUCCESS; /* nothing to do */
1110 dst = dst_bits->ptr;
1111 padding_pos = width_bytes/sizeof(unsigned int) - 1;
1113 if (info->bmiHeader.biHeight > 0)
1115 dst += (height - 1) * width_bytes;
1116 width_bytes = -width_bytes;
1119 if (need_byteswap || mapping)
1121 switch (info->bmiHeader.biBitCount)
1123 case 1:
1124 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1126 for (x = 0; x < image->bytes_per_line; x++)
1127 dst[x] = bit_swap[src[x]];
1128 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1130 break;
1131 case 4:
1132 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1134 if (mapping)
1135 for (x = 0; x < image->bytes_per_line; x++)
1136 dst[x] = (mapping[src[x] & 0x0f] << 4) | mapping[src[x] >> 4];
1137 else
1138 for (x = 0; x < image->bytes_per_line; x++)
1139 dst[x] = (src[x] << 4) | (src[x] >> 4);
1140 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1142 break;
1143 case 8:
1144 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1146 for (x = 0; x < image->bytes_per_line; x++)
1147 dst[x] = mapping[src[x]];
1148 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1150 break;
1151 case 16:
1152 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1154 for (x = 0; x < info->bmiHeader.biWidth; x++)
1155 ((USHORT *)dst)[x] = RtlUshortByteSwap( ((const USHORT *)src)[x] );
1156 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1158 break;
1159 case 24:
1160 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1162 for (x = 0; x < info->bmiHeader.biWidth; x++)
1164 unsigned char tmp = src[3 * x];
1165 dst[3 * x] = src[3 * x + 2];
1166 dst[3 * x + 1] = src[3 * x + 1];
1167 dst[3 * x + 2] = tmp;
1169 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1171 break;
1172 case 32:
1173 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1174 for (x = 0; x < info->bmiHeader.biWidth; x++)
1175 ((ULONG *)dst)[x] = RtlUlongByteSwap( ((const ULONG *)src)[x] );
1176 break;
1179 else if (src != dst)
1181 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1183 memcpy( dst, src, image->bytes_per_line );
1184 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1187 else /* only need to clear the padding */
1189 for (y = 0; y < height; y++, dst += width_bytes)
1190 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1192 return ERROR_SUCCESS;
1195 /***********************************************************************
1196 * X11DRV_PutImage
1198 DWORD X11DRV_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
1199 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1200 struct bitblt_coords *dst, DWORD rop )
1202 X11DRV_PDEVICE *physdev;
1203 X_PHYSBITMAP *bitmap;
1204 DWORD ret;
1205 XImage *image;
1206 int depth;
1207 struct gdi_image_bits dst_bits;
1208 const XPixmapFormatValues *format;
1209 const ColorShifts *color_shifts;
1210 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1211 const int *mapping = NULL;
1213 if (hbitmap)
1215 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
1216 physdev = NULL;
1217 depth = bitmap->depth;
1218 color_shifts = &bitmap->color_shifts;
1220 else
1222 physdev = get_x11drv_dev( dev );
1223 bitmap = NULL;
1224 depth = physdev->depth;
1225 color_shifts = physdev->color_shifts;
1227 format = pixmap_formats[depth];
1229 if (info->bmiHeader.biPlanes != 1) goto update_format;
1230 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1231 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1232 if (!matching_color_info( dev, color_shifts, info )) goto update_format;
1233 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1234 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
1236 wine_tsx11_lock();
1237 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1238 info->bmiHeader.biWidth, src->visrect.bottom - src->visrect.top, 32, 0 );
1239 wine_tsx11_unlock();
1240 if (!image) return ERROR_OUTOFMEMORY;
1242 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1244 if (bitmap || (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST)))
1245 mapping = X11DRV_PALETTE_PaletteToXPixel;
1248 ret = copy_image_bits( info, is_r8g8b8(depth,color_shifts), image, bits, &dst_bits, src, mapping, ~0u );
1250 if (!ret)
1252 int width = dst->visrect.right - dst->visrect.left;
1253 int height = dst->visrect.bottom - dst->visrect.top;
1255 image->data = dst_bits.ptr;
1256 /* hack: make sure the bits are readable if we are reading from a DIB section */
1257 /* to be removed once we get rid of DIB access protections */
1258 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, height * image->bytes_per_line );
1260 if (bitmap)
1262 RGNDATA *clip_data = NULL;
1263 GC gc;
1265 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1266 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
1268 wine_tsx11_lock();
1269 gc = XCreateGC( gdi_display, bitmap->pixmap, 0, NULL );
1270 XSetGraphicsExposures( gdi_display, gc, False );
1271 if (clip_data) XSetClipRectangles( gdi_display, gc, 0, 0, (XRectangle *)clip_data->Buffer,
1272 clip_data->rdh.nCount, YXBanded );
1273 XPutImage( gdi_display, bitmap->pixmap, gc, image, src->visrect.left, 0,
1274 dst->visrect.left, dst->visrect.top, width, height );
1275 XFreeGC( gdi_display, gc );
1276 wine_tsx11_unlock();
1278 X11DRV_DIB_Unlock( bitmap, TRUE );
1279 HeapFree( GetProcessHeap(), 0, clip_data );
1281 else
1283 BOOL restore_region = add_extra_clipping_region( physdev, clip );
1285 X11DRV_LockDIBSection( physdev, DIB_Status_GdiMod );
1287 /* optimization for single-op ROPs */
1288 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1290 wine_tsx11_lock();
1291 XSetFunction( gdi_display, physdev->gc, OP_ROP(*opcode) );
1292 XPutImage( gdi_display, physdev->drawable, physdev->gc, image, src->visrect.left, 0,
1293 physdev->dc_rect.left + dst->visrect.left,
1294 physdev->dc_rect.top + dst->visrect.top, width, height );
1295 wine_tsx11_unlock();
1297 else
1299 Pixmap src_pixmap;
1300 GC gc;
1302 wine_tsx11_lock();
1303 gc = XCreateGC( gdi_display, physdev->drawable, 0, NULL );
1304 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1305 XSetGraphicsExposures( gdi_display, gc, False );
1306 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1307 XPutImage( gdi_display, src_pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1308 wine_tsx11_unlock();
1310 execute_rop( physdev, src_pixmap, gc, &dst->visrect, rop );
1312 wine_tsx11_lock();
1313 XFreePixmap( gdi_display, src_pixmap );
1314 XFreeGC( gdi_display, gc );
1315 wine_tsx11_unlock();
1318 X11DRV_UnlockDIBSection( physdev, !ret );
1319 if (restore_region) restore_clipping_region( physdev );
1321 image->data = NULL;
1324 wine_tsx11_lock();
1325 XDestroyImage( image );
1326 wine_tsx11_unlock();
1327 if (dst_bits.free) dst_bits.free( &dst_bits );
1328 return ret;
1330 update_format:
1331 info->bmiHeader.biPlanes = 1;
1332 info->bmiHeader.biBitCount = format->bits_per_pixel;
1333 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1334 set_color_info( dev, color_shifts, info );
1335 return ERROR_BAD_FORMAT;
1338 /***********************************************************************
1339 * X11DRV_GetImage
1341 DWORD X11DRV_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1342 struct gdi_image_bits *bits, struct bitblt_coords *src )
1344 X11DRV_PDEVICE *physdev;
1345 X_PHYSBITMAP *bitmap;
1346 DWORD ret = ERROR_SUCCESS;
1347 XImage *image;
1348 UINT align, x, y, width, height;
1349 int depth;
1350 struct gdi_image_bits src_bits;
1351 const XPixmapFormatValues *format;
1352 const ColorShifts *color_shifts;
1353 const int *mapping = NULL;
1355 if (hbitmap)
1357 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
1358 physdev = NULL;
1359 depth = bitmap->depth;
1360 color_shifts = &bitmap->color_shifts;
1362 else
1364 physdev = get_x11drv_dev( dev );
1365 bitmap = NULL;
1366 depth = physdev->depth;
1367 color_shifts = physdev->color_shifts;
1369 format = pixmap_formats[depth];
1371 /* align start and width to 32-bit boundary */
1372 switch (format->bits_per_pixel)
1374 case 1: align = 32; break;
1375 case 4: align = 8; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1376 case 8: align = 4; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1377 case 16: align = 2; break;
1378 case 24: align = 4; break;
1379 case 32: align = 1; break;
1380 default:
1381 FIXME( "depth %u bpp %u not supported yet\n", depth, format->bits_per_pixel );
1382 return ERROR_BAD_FORMAT;
1385 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1386 info->bmiHeader.biPlanes = 1;
1387 info->bmiHeader.biBitCount = format->bits_per_pixel;
1388 info->bmiHeader.biXPelsPerMeter = 0;
1389 info->bmiHeader.biYPelsPerMeter = 0;
1390 info->bmiHeader.biClrImportant = 0;
1391 set_color_info( dev, color_shifts, info );
1393 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
1395 x = src->visrect.left & ~(align - 1);
1396 y = src->visrect.top;
1397 width = src->visrect.right - x;
1398 height = src->visrect.bottom - src->visrect.top;
1399 if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1);
1400 /* make the source rectangle relative to the returned bits */
1401 src->x -= x;
1402 src->y -= y;
1403 OffsetRect( &src->visrect, -x, -y );
1405 if (bitmap)
1407 BITMAP bm;
1408 GetObjectW( hbitmap, sizeof(bm), &bm );
1409 width = min( width, bm.bmWidth - x );
1410 height = min( height, bm.bmHeight - y );
1411 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
1412 wine_tsx11_lock();
1413 image = XGetImage( gdi_display, bitmap->pixmap, x, y, width, height, AllPlanes, ZPixmap );
1414 wine_tsx11_unlock();
1415 X11DRV_DIB_Unlock( bitmap, TRUE );
1417 else if (GetObjectType( dev->hdc ) == OBJ_MEMDC)
1419 X11DRV_LockDIBSection( physdev, DIB_Status_GdiMod );
1420 width = min( width, physdev->dc_rect.right - physdev->dc_rect.left - x );
1421 height = min( height, physdev->dc_rect.bottom - physdev->dc_rect.top - y );
1422 wine_tsx11_lock();
1423 image = XGetImage( gdi_display, physdev->drawable,
1424 physdev->dc_rect.left + x, physdev->dc_rect.top + y,
1425 width, height, AllPlanes, ZPixmap );
1426 wine_tsx11_unlock();
1427 X11DRV_UnlockDIBSection( physdev, FALSE );
1429 else
1431 X11DRV_expect_error( gdi_display, XGetImage_handler, NULL );
1432 image = XGetImage( gdi_display, physdev->drawable,
1433 physdev->dc_rect.left + x, physdev->dc_rect.top + y,
1434 width, height, AllPlanes, ZPixmap );
1435 if (X11DRV_check_error())
1437 /* use a temporary pixmap to avoid the BadMatch error */
1438 Pixmap pixmap;
1440 wine_tsx11_lock();
1441 pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1442 XCopyArea( gdi_display, physdev->drawable, pixmap, get_bitmap_gc(depth),
1443 physdev->dc_rect.left + x, physdev->dc_rect.top + y, width, height, 0, 0 );
1444 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1445 XFreePixmap( gdi_display, pixmap );
1446 wine_tsx11_unlock();
1449 if (!image) return ERROR_OUTOFMEMORY;
1451 info->bmiHeader.biWidth = width;
1452 info->bmiHeader.biHeight = -height;
1453 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1455 src_bits.ptr = image->data;
1456 src_bits.is_copy = TRUE;
1457 ret = copy_image_bits( info, is_r8g8b8(depth,color_shifts), image, &src_bits, bits, src, mapping,
1458 zeropad_masks[(width * image->bits_per_pixel) & 31] );
1460 if (!ret && bits->ptr == image->data)
1462 bits->free = free_ximage_bits;
1463 image->data = NULL;
1465 wine_tsx11_lock();
1466 XDestroyImage( image );
1467 wine_tsx11_unlock();
1468 return ret;