winex11: Remove redundant pixmap prefix in X_PHYSBITMAP field names.
[wine.git] / dlls / winex11.drv / bitblt.c
blob4c7246e39a9e79d3d57089995ab1a3391d3c0989
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 #define SWAP_INT32(i1,i2) \
56 do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
58 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
60 { OP(PAT,DST,GXclear) }, /* 0x00 0 */
61 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */
62 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */
63 { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */
64 { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */
65 { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */
66 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */
67 { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */
68 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */
69 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */
70 { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */
71 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */
72 { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */
73 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */
74 { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */
75 { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */
76 { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */
77 { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */
78 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */
79 { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */
80 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */
81 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */
82 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
83 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
84 OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */
85 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
86 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
87 OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/
88 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
89 OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */
90 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
91 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */
92 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
93 OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */
94 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
95 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */
96 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
97 OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */
98 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
99 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */
100 { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */
101 { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */
102 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */
103 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */
104 { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */
105 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */
106 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
107 OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */
108 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
109 OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */
110 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
111 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
112 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXequiv),
113 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */
114 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */
115 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
116 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
117 OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */
118 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */
119 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
120 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
121 OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/
122 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
123 OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */
124 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */
125 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
126 OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */
127 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */
128 { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */
129 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */
130 { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
131 OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */
132 { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */
133 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
134 OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */
135 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
136 OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */
137 { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */
138 { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */
139 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
140 OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */
141 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */
142 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
143 OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */
144 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */
145 { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */
146 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
147 OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */
148 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
149 OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */
150 { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */
151 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */
152 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */
153 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
154 OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */
155 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
156 OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */
157 { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */
158 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */
159 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
160 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */
161 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
162 OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */
163 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */
164 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
165 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
166 OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */
167 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
168 OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */
169 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */
170 { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */
171 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
172 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
173 OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/
174 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
175 OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */
176 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */
177 { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */
178 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */
179 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
180 OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */
181 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
182 OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */
183 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */
184 { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */
185 { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */
186 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */
187 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
188 OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */
189 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */
190 { OP(PAT,DST,GXxor) }, /* 0x5a D^P */
191 { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
192 OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */
193 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
194 OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */
195 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */
196 { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
197 OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */
198 { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */
199 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */
200 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
201 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
202 OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */
203 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
204 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */
205 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */
206 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
207 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */
208 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */
209 { OP(SRC,DST,GXxor) }, /* 0x66 S^D */
210 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
211 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */
212 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
213 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
214 OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/
215 { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */
216 { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */
217 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
218 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
219 OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */
220 { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */
221 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
222 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
223 OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */
224 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
225 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */
226 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */
227 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */
228 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
229 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
230 OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/
231 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
232 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */
233 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */
234 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
235 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */
236 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */
237 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
238 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */
239 { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */
240 { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */
241 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
242 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
243 OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */
244 { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
245 OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */
246 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */
247 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
248 OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */
249 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */
250 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
251 OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */
252 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */
253 { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */
254 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
255 OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */
256 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */
257 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
258 OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */
259 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */
260 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
261 OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */
262 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
263 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
264 OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */
265 { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */
266 { OP(SRC,DST,GXand) }, /* 0x88 S&D */
267 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
268 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */
269 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */
270 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
271 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */
272 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */
273 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
274 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */
275 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
276 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
277 OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/
278 { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */
279 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */
280 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
281 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */
282 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
283 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
284 OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */
285 { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */
286 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
287 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
288 OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */
289 { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */
290 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */
291 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
292 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
293 OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */
294 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
295 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */
296 { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */
297 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */
298 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
299 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */
300 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */
301 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
302 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */
303 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
304 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
305 OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */
306 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */
307 { OP(PAT,DST,GXand) }, /* 0xa0 D&P */
308 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
309 OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */
310 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */
311 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
312 OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */
313 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
314 OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */
315 { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */
316 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */
317 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
318 OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */
319 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */
320 { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */
321 { OP(PAT,DST,GXnoop) }, /* 0xaa D */
322 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */
323 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
324 OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */
325 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
326 OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */
327 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */
328 { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */
329 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */
330 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
331 OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */
332 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
333 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
334 OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/
335 { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */
336 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */
337 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
338 OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */
339 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
340 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
341 OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */
342 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */
343 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
344 OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */
345 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
346 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */
347 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */
348 { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */
349 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
350 OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */
351 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
352 OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */
353 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */
354 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */
355 { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */
356 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
357 OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */
358 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
359 OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */
360 { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */
361 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */
362 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
363 OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */
364 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */
365 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
366 OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */
367 { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */
368 { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */
369 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
370 OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */
371 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
372 OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */
373 { OP(SRC,DST,GXcopy) }, /* 0xcc S */
374 { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */
375 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */
376 { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */
377 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */
378 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
379 OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */
380 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */
381 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
382 OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */
383 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
384 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
385 OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/
386 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */
387 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
388 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
389 OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */
390 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */
391 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
392 OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */
393 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
394 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */
395 { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
396 OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */
397 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
398 OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */
399 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */
400 { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */
401 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */
402 { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */
403 { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */
404 { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */
405 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
406 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */
407 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
408 OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */
409 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
410 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */
411 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
412 OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */
413 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
414 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */
415 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
416 OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */
417 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
418 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
419 OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/
420 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
421 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
422 OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/
423 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */
424 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */
425 { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */
426 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */
427 { OP(SRC,DST,GXor) }, /* 0xee S|D */
428 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */
429 { OP(PAT,DST,GXcopy) }, /* 0xf0 P */
430 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */
431 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */
432 { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */
433 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */
434 { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */
435 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */
436 { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */
437 { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */
438 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */
439 { OP(PAT,DST,GXor) }, /* 0xfa D|P */
440 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */
441 { OP(PAT,SRC,GXor) }, /* 0xfc P|S */
442 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */
443 { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */
444 { OP(PAT,DST,GXset) } /* 0xff 1 */
447 static const unsigned char bit_swap[256] =
449 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
450 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
451 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
452 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
453 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
454 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
455 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
456 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
457 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
458 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
459 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
460 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
461 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
462 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
463 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
464 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
465 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
466 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
467 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
468 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
469 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
470 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
471 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
472 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
473 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
474 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
475 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
476 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
477 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
478 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
479 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
480 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
483 #ifdef WORDS_BIGENDIAN
484 static const unsigned int zeropad_masks[32] =
486 0xffffffff, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000, 0xfc000000, 0xfe000000,
487 0xff000000, 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000,
488 0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
489 0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe
491 #else
492 static const unsigned int zeropad_masks[32] =
494 0xffffffff, 0x00000080, 0x000000c0, 0x000000e0, 0x000000f0, 0x000000f8, 0x000000fc, 0x000000fe,
495 0x000000ff, 0x000080ff, 0x0000c0ff, 0x0000e0ff, 0x0000f0ff, 0x0000f8ff, 0x0000fcff, 0x0000feff,
496 0x0000ffff, 0x0080ffff, 0x00c0ffff, 0x00e0ffff, 0x00f0ffff, 0x00f8ffff, 0x00fcffff, 0x00feffff,
497 0x00ffffff, 0x80ffffff, 0xc0ffffff, 0xe0ffffff, 0xf0ffffff, 0xf8ffffff, 0xfcffffff, 0xfeffffff
499 #endif
501 #ifdef BITBLT_TEST /* Opcodes test */
503 static int do_bitop( int s, int d, int rop )
505 int res;
506 switch(rop)
508 case GXclear: res = 0; break;
509 case GXand: res = s & d; break;
510 case GXandReverse: res = s & ~d; break;
511 case GXcopy: res = s; break;
512 case GXandInverted: res = ~s & d; break;
513 case GXnoop: res = d; break;
514 case GXxor: res = s ^ d; break;
515 case GXor: res = s | d; break;
516 case GXnor: res = ~(s | d); break;
517 case GXequiv: res = ~s ^ d; break;
518 case GXinvert: res = ~d; break;
519 case GXorReverse: res = s | ~d; break;
520 case GXcopyInverted: res = ~s; break;
521 case GXorInverted: res = ~s | d; break;
522 case GXnand: res = ~(s & d); break;
523 case GXset: res = 1; break;
525 return res & 1;
528 int main()
530 int rop, i, res, src, dst, pat, tmp, dstUsed;
531 const unsigned char *opcode;
533 for (rop = 0; rop < 256; rop++)
535 res = dstUsed = 0;
536 for (i = 0; i < 8; i++)
538 pat = (i >> 2) & 1;
539 src = (i >> 1) & 1;
540 dst = i & 1;
541 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
543 switch(*opcode >> 4)
545 case OP_ARGS(DST,TMP):
546 tmp = do_bitop( dst, tmp, *opcode & 0xf );
547 break;
548 case OP_ARGS(DST,SRC):
549 src = do_bitop( dst, src, *opcode & 0xf );
550 break;
551 case OP_ARGS(SRC,TMP):
552 tmp = do_bitop( src, tmp, *opcode & 0xf );
553 break;
554 case OP_ARGS(SRC,DST):
555 dst = do_bitop( src, dst, *opcode & 0xf );
556 dstUsed = 1;
557 break;
558 case OP_ARGS(PAT,DST):
559 dst = do_bitop( pat, dst, *opcode & 0xf );
560 dstUsed = 1;
561 break;
562 case OP_ARGS(PAT,SRC):
563 src = do_bitop( pat, src, *opcode & 0xf );
564 break;
565 case OP_ARGS(TMP,DST):
566 dst = do_bitop( tmp, dst, *opcode & 0xf );
567 dstUsed = 1;
568 break;
569 case OP_ARGS(TMP,SRC):
570 src = do_bitop( tmp, src, *opcode & 0xf );
571 break;
572 default:
573 printf( "Invalid opcode %x\n", *opcode );
576 if (!dstUsed) dst = src;
577 if (dst) res |= 1 << i;
579 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
582 return 0;
585 #endif /* BITBLT_TEST */
588 static void get_colors(X11DRV_PDEVICE *physDevDst, X11DRV_PDEVICE *physDevSrc,
589 int *fg, int *bg)
591 RGBQUAD rgb[2];
593 *fg = physDevDst->textPixel;
594 *bg = physDevDst->backgroundPixel;
595 if(physDevSrc->depth == 1) {
596 if(GetDIBColorTable(physDevSrc->dev.hdc, 0, 2, rgb) == 2) {
597 DWORD logcolor;
598 logcolor = RGB(rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue);
599 *fg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
600 logcolor = RGB(rgb[1].rgbRed, rgb[1].rgbGreen,rgb[1].rgbBlue);
601 *bg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
606 /* return a mask for meaningful bits when doing an XGetPixel on an image */
607 static unsigned long image_pixel_mask( X11DRV_PDEVICE *physDev )
609 unsigned long ret;
610 ColorShifts *shifts = physDev->color_shifts;
612 if (!shifts) shifts = &X11DRV_PALETTE_default_shifts;
613 ret = (shifts->physicalRed.max << shifts->physicalRed.shift) |
614 (shifts->physicalGreen.max << shifts->physicalGreen.shift) |
615 (shifts->physicalBlue.max << shifts->physicalBlue.shift);
616 if (!ret) ret = (1 << physDev->depth) - 1;
617 return ret;
621 /***********************************************************************
622 * BITBLT_StretchRow
624 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
626 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
627 INT startDst, INT widthDst,
628 INT xinc, INT xoff, WORD mode )
630 register INT xsrc = xinc * startDst + xoff;
631 rowDst += startDst;
632 switch(mode)
634 case STRETCH_ANDSCANS:
635 for(; widthDst > 0; widthDst--, xsrc += xinc)
636 *rowDst++ &= rowSrc[xsrc >> 16];
637 break;
638 case STRETCH_ORSCANS:
639 for(; widthDst > 0; widthDst--, xsrc += xinc)
640 *rowDst++ |= rowSrc[xsrc >> 16];
641 break;
642 case STRETCH_DELETESCANS:
643 for(; widthDst > 0; widthDst--, xsrc += xinc)
644 *rowDst++ = rowSrc[xsrc >> 16];
645 break;
650 /***********************************************************************
651 * BITBLT_ShrinkRow
653 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
655 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
656 INT startSrc, INT widthSrc,
657 INT xinc, INT xoff, WORD mode )
659 register INT xdst = xinc * startSrc + xoff;
660 rowSrc += startSrc;
661 switch(mode)
663 case STRETCH_ORSCANS:
664 for(; widthSrc > 0; widthSrc--, xdst += xinc)
665 rowDst[xdst >> 16] |= *rowSrc++;
666 break;
667 case STRETCH_ANDSCANS:
668 for(; widthSrc > 0; widthSrc--, xdst += xinc)
669 rowDst[xdst >> 16] &= *rowSrc++;
670 break;
671 case STRETCH_DELETESCANS:
672 for(; widthSrc > 0; widthSrc--, xdst += xinc)
673 rowDst[xdst >> 16] = *rowSrc++;
674 break;
679 /***********************************************************************
680 * BITBLT_GetRow
682 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
684 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
685 INT start, INT width, INT depthDst,
686 int fg, int bg, unsigned long pixel_mask, BOOL swap)
688 register INT i;
690 assert( (row >= 0) && (row < image->height) );
691 assert( (start >= 0) && (width <= image->width) );
693 pdata += swap ? start+width-1 : start;
694 if (image->depth == depthDst) /* color -> color */
696 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
697 if (swap) for (i = 0; i < width; i++)
698 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
699 else for (i = 0; i < width; i++)
700 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
701 else
702 if (swap) for (i = 0; i < width; i++)
703 *pdata-- = XGetPixel( image, i, row );
704 else for (i = 0; i < width; i++)
705 *pdata++ = XGetPixel( image, i, row );
707 else
709 if (image->depth == 1) /* monochrome -> color */
711 if (X11DRV_PALETTE_XPixelToPalette)
713 fg = X11DRV_PALETTE_XPixelToPalette[fg];
714 bg = X11DRV_PALETTE_XPixelToPalette[bg];
716 if (swap) for (i = 0; i < width; i++)
717 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
718 else for (i = 0; i < width; i++)
719 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
721 else /* color -> monochrome */
723 if (swap) for (i = 0; i < width; i++)
724 *pdata-- = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0;
725 else for (i = 0; i < width; i++)
726 *pdata++ = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0;
732 /***********************************************************************
733 * BITBLT_StretchImage
735 * Stretch an X image.
736 * FIXME: does not work for full 32-bit coordinates.
738 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
739 INT widthSrc, INT heightSrc,
740 INT widthDst, INT heightDst,
741 RECT *visRectSrc, RECT *visRectDst,
742 int foreground, int background,
743 unsigned long pixel_mask, WORD mode )
745 int *rowSrc, *rowDst, *pixel;
746 char *pdata;
747 INT xinc, xoff, yinc, ysrc, ydst;
748 register INT x, y;
749 BOOL hstretch, vstretch, hswap, vswap;
751 hswap = widthSrc * widthDst < 0;
752 vswap = heightSrc * heightDst < 0;
753 widthSrc = abs(widthSrc);
754 heightSrc = abs(heightSrc);
755 widthDst = abs(widthDst);
756 heightDst = abs(heightDst);
758 if (!(rowSrc = HeapAlloc( GetProcessHeap(), 0,
759 (widthSrc+widthDst)*sizeof(int) ))) return;
760 rowDst = rowSrc + widthSrc;
762 /* When stretching, all modes are the same, and DELETESCANS is faster */
763 if ((widthSrc < widthDst) && (heightSrc < heightDst))
764 mode = STRETCH_DELETESCANS;
766 if (mode == STRETCH_HALFTONE) /* FIXME */
767 mode = STRETCH_DELETESCANS;
769 if (mode != STRETCH_DELETESCANS)
770 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
771 widthDst*sizeof(int) );
773 hstretch = (widthSrc < widthDst);
774 vstretch = (heightSrc < heightDst);
776 if (hstretch)
778 xinc = (widthSrc << 16) / widthDst;
779 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
781 else
783 xinc = ((int)widthDst << 16) / widthSrc;
784 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
787 wine_tsx11_lock();
788 if (vstretch)
790 yinc = (heightSrc << 16) / heightDst;
791 ydst = visRectDst->top;
792 if (vswap)
794 ysrc = yinc * (heightDst - ydst - 1);
795 yinc = -yinc;
797 else
798 ysrc = yinc * ydst;
800 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
802 if (((ysrc >> 16) < visRectSrc->top) ||
803 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
805 /* Retrieve a source row */
806 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
807 visRectSrc->left, visRectSrc->right - visRectSrc->left,
808 dstImage->depth, foreground, background, pixel_mask, hswap );
810 /* Stretch or shrink it */
811 if (hstretch)
812 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
813 visRectDst->right - visRectDst->left,
814 xinc, xoff, mode );
815 else BITBLT_ShrinkRow( rowSrc, rowDst, visRectSrc->left,
816 visRectSrc->right - visRectSrc->left,
817 xinc, xoff, mode );
819 /* Store the destination row */
820 pixel = rowDst + visRectDst->right - 1;
821 y = ydst - visRectDst->top;
822 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
823 XPutPixel( dstImage, x, y, *pixel-- );
824 if (mode != STRETCH_DELETESCANS)
825 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
826 widthDst*sizeof(int) );
828 /* Make copies of the destination row */
830 pdata = dstImage->data + dstImage->bytes_per_line * y;
831 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
832 (ydst < visRectDst->bottom-1))
834 memcpy( pdata + dstImage->bytes_per_line, pdata,
835 dstImage->bytes_per_line );
836 pdata += dstImage->bytes_per_line;
837 ysrc += yinc;
838 ydst++;
842 else /* Shrinking */
844 yinc = (heightDst << 16) / heightSrc;
845 ysrc = visRectSrc->top;
846 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
847 if (vswap)
849 ydst += yinc * (heightSrc - ysrc - 1);
850 yinc = -yinc;
852 else
853 ydst += yinc * ysrc;
855 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
857 if (((ydst >> 16) < visRectDst->top) ||
858 ((ydst >> 16) >= visRectDst->bottom)) continue;
860 /* Retrieve a source row */
861 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
862 visRectSrc->left, visRectSrc->right - visRectSrc->left,
863 dstImage->depth, foreground, background, pixel_mask, hswap );
865 /* Stretch or shrink it */
866 if (hstretch)
867 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
868 visRectDst->right - visRectDst->left,
869 xinc, xoff, mode );
870 else BITBLT_ShrinkRow( rowSrc, rowDst, visRectSrc->left,
871 visRectSrc->right - visRectSrc->left,
872 xinc, xoff, mode );
874 /* Merge several source rows into the destination */
875 if (mode == STRETCH_DELETESCANS)
877 /* Simply skip the overlapping rows */
878 while (((ydst + yinc) >> 16 == ydst >> 16) &&
879 (ysrc < visRectSrc->bottom-1))
881 ydst += yinc;
882 ysrc++;
885 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
886 (ysrc < visRectSrc->bottom-1))
887 continue; /* Restart loop for next overlapping row */
889 /* Store the destination row */
890 pixel = rowDst + visRectDst->right - 1;
891 y = (ydst >> 16) - visRectDst->top;
892 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
893 XPutPixel( dstImage, x, y, *pixel-- );
894 if (mode != STRETCH_DELETESCANS)
895 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
896 widthDst*sizeof(int) );
899 wine_tsx11_unlock();
900 HeapFree( GetProcessHeap(), 0, rowSrc );
904 /***********************************************************************
905 * BITBLT_GetSrcAreaStretch
907 * Retrieve an area from the source DC, stretching and mapping all the
908 * pixels to Windows colors.
910 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
911 Pixmap pixmap, GC gc,
912 const struct bitblt_coords *src, const struct bitblt_coords *dst )
914 XImage *imageSrc, *imageDst;
915 RECT rectSrc = src->visrect;
916 RECT rectDst = dst->visrect;
917 int fg, bg;
919 OffsetRect( &rectSrc, -src->x, -src->y );
920 OffsetRect( &rectDst, -dst->x, -dst->y );
922 if (src->width < 0) OffsetRect( &rectSrc, -src->width, 0 );
923 if (dst->width < 0) OffsetRect( &rectDst, -dst->width, 0 );
924 if (src->height < 0) OffsetRect( &rectSrc, 0, -src->height );
925 if (dst->height < 0) OffsetRect( &rectDst, 0, -dst->height );
927 get_colors(physDevDst, physDevSrc, &fg, &bg);
928 wine_tsx11_lock();
929 /* FIXME: avoid BadMatch errors */
930 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
931 physDevSrc->dc_rect.left + src->visrect.left,
932 physDevSrc->dc_rect.top + src->visrect.top,
933 src->visrect.right - src->visrect.left,
934 src->visrect.bottom - src->visrect.top,
935 AllPlanes, ZPixmap );
936 wine_tsx11_unlock();
938 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
939 rectDst.bottom - rectDst.top, physDevDst->depth );
940 BITBLT_StretchImage( imageSrc, imageDst, src->width, src->height,
941 dst->width, dst->height, &rectSrc, &rectDst,
942 fg, physDevDst->depth != 1 ? bg : physDevSrc->backgroundPixel,
943 image_pixel_mask( physDevSrc ), GetStretchBltMode(physDevDst->dev.hdc) );
944 wine_tsx11_lock();
945 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
946 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
947 XDestroyImage( imageSrc );
948 X11DRV_DIB_DestroyXImage( imageDst );
949 wine_tsx11_unlock();
950 return 0; /* no exposure events generated */
954 /***********************************************************************
955 * BITBLT_GetSrcArea
957 * Retrieve an area from the source DC, mapping all the
958 * pixels to Windows colors.
960 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
961 Pixmap pixmap, GC gc, RECT *visRectSrc )
963 XImage *imageSrc, *imageDst;
964 register INT x, y;
965 int exposures = 0;
966 INT width = visRectSrc->right - visRectSrc->left;
967 INT height = visRectSrc->bottom - visRectSrc->top;
968 int fg, bg;
969 BOOL memdc = (GetObjectType(physDevSrc->dev.hdc) == OBJ_MEMDC);
971 if (physDevSrc->depth == physDevDst->depth)
973 wine_tsx11_lock();
974 if (!X11DRV_PALETTE_XPixelToPalette ||
975 (physDevDst->depth == 1)) /* monochrome -> monochrome */
977 if (physDevDst->depth == 1)
979 /* MSDN says if StretchBlt must convert a bitmap from monochrome
980 to color or vice versa, the foreground and background color of
981 the device context are used. In fact, it also applies to the
982 case when it is converted from mono to mono. */
983 XSetBackground( gdi_display, gc, physDevDst->textPixel );
984 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
985 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
986 physDevSrc->dc_rect.left + visRectSrc->left,
987 physDevSrc->dc_rect.top + visRectSrc->top,
988 width, height, 0, 0, 1);
990 else
991 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
992 physDevSrc->dc_rect.left + visRectSrc->left,
993 physDevSrc->dc_rect.top + visRectSrc->top,
994 width, height, 0, 0);
995 exposures++;
997 else /* color -> color */
999 if (memdc)
1000 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1001 physDevSrc->dc_rect.left + visRectSrc->left,
1002 physDevSrc->dc_rect.top + visRectSrc->top,
1003 width, height, AllPlanes, ZPixmap );
1004 else
1006 /* Make sure we don't get a BadMatch error */
1007 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
1008 physDevSrc->dc_rect.left + visRectSrc->left,
1009 physDevSrc->dc_rect.top + visRectSrc->top,
1010 width, height, 0, 0);
1011 exposures++;
1012 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1013 AllPlanes, ZPixmap );
1015 for (y = 0; y < height; y++)
1016 for (x = 0; x < width; x++)
1017 XPutPixel(imageSrc, x, y,
1018 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
1019 XPutImage( gdi_display, pixmap, gc, imageSrc,
1020 0, 0, 0, 0, width, height );
1021 XDestroyImage( imageSrc );
1023 wine_tsx11_unlock();
1025 else
1027 if (physDevSrc->depth == 1) /* monochrome -> color */
1029 get_colors(physDevDst, physDevSrc, &fg, &bg);
1031 wine_tsx11_lock();
1032 if (X11DRV_PALETTE_XPixelToPalette)
1034 XSetBackground( gdi_display, gc,
1035 X11DRV_PALETTE_XPixelToPalette[fg] );
1036 XSetForeground( gdi_display, gc,
1037 X11DRV_PALETTE_XPixelToPalette[bg]);
1039 else
1041 XSetBackground( gdi_display, gc, fg );
1042 XSetForeground( gdi_display, gc, bg );
1044 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
1045 physDevSrc->dc_rect.left + visRectSrc->left,
1046 physDevSrc->dc_rect.top + visRectSrc->top,
1047 width, height, 0, 0, 1 );
1048 exposures++;
1049 wine_tsx11_unlock();
1051 else /* color -> monochrome */
1053 unsigned long pixel_mask;
1054 wine_tsx11_lock();
1055 /* FIXME: avoid BadMatch error */
1056 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1057 physDevSrc->dc_rect.left + visRectSrc->left,
1058 physDevSrc->dc_rect.top + visRectSrc->top,
1059 width, height, AllPlanes, ZPixmap );
1060 if (!imageSrc)
1062 wine_tsx11_unlock();
1063 return exposures;
1065 imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1066 if (!imageDst)
1068 XDestroyImage(imageSrc);
1069 wine_tsx11_unlock();
1070 return exposures;
1072 pixel_mask = image_pixel_mask( physDevSrc );
1073 for (y = 0; y < height; y++)
1074 for (x = 0; x < width; x++)
1075 XPutPixel(imageDst, x, y,
1076 !((XGetPixel(imageSrc,x,y) ^ physDevSrc->backgroundPixel) & pixel_mask));
1077 XPutImage( gdi_display, pixmap, gc, imageDst,
1078 0, 0, 0, 0, width, height );
1079 XDestroyImage( imageSrc );
1080 X11DRV_DIB_DestroyXImage( imageDst );
1081 wine_tsx11_unlock();
1084 return exposures;
1088 /***********************************************************************
1089 * BITBLT_GetDstArea
1091 * Retrieve an area from the destination DC, mapping all the
1092 * pixels to Windows colors.
1094 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, const RECT *visRectDst)
1096 int exposures = 0;
1097 INT width = visRectDst->right - visRectDst->left;
1098 INT height = visRectDst->bottom - visRectDst->top;
1099 BOOL memdc = (GetObjectType( physDev->dev.hdc ) == OBJ_MEMDC);
1101 wine_tsx11_lock();
1103 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1104 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1106 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1107 physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
1108 width, height, 0, 0 );
1109 exposures++;
1111 else
1113 register INT x, y;
1114 XImage *image;
1116 if (memdc)
1117 image = XGetImage( gdi_display, physDev->drawable,
1118 physDev->dc_rect.left + visRectDst->left,
1119 physDev->dc_rect.top + visRectDst->top,
1120 width, height, AllPlanes, ZPixmap );
1121 else
1123 /* Make sure we don't get a BadMatch error */
1124 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1125 physDev->dc_rect.left + visRectDst->left,
1126 physDev->dc_rect.top + visRectDst->top,
1127 width, height, 0, 0);
1128 exposures++;
1129 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1130 AllPlanes, ZPixmap );
1132 if (image)
1134 for (y = 0; y < height; y++)
1135 for (x = 0; x < width; x++)
1136 XPutPixel( image, x, y,
1137 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1138 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1139 XDestroyImage( image );
1143 wine_tsx11_unlock();
1144 return exposures;
1148 /***********************************************************************
1149 * BITBLT_PutDstArea
1151 * Put an area back into the destination DC, mapping the pixel
1152 * colors to X pixels.
1154 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, const RECT *visRectDst)
1156 int exposures = 0;
1157 INT width = visRectDst->right - visRectDst->left;
1158 INT height = visRectDst->bottom - visRectDst->top;
1160 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1162 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1163 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1165 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1166 physDev->dc_rect.left + visRectDst->left,
1167 physDev->dc_rect.top + visRectDst->top );
1168 exposures++;
1170 else
1172 register INT x, y;
1173 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1174 AllPlanes, ZPixmap );
1175 for (y = 0; y < height; y++)
1176 for (x = 0; x < width; x++)
1178 XPutPixel( image, x, y,
1179 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1181 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1182 physDev->dc_rect.left + visRectDst->left,
1183 physDev->dc_rect.top + visRectDst->top, width, height );
1184 XDestroyImage( image );
1186 return exposures;
1189 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
1191 if (physDevSrc->depth != physDevDst->depth) return FALSE;
1192 if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
1193 if (physDevSrc->color_shifts && physDevDst->color_shifts)
1194 return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
1195 return FALSE;
1198 void execute_rop( X11DRV_PDEVICE *physdev, Pixmap src_pixmap, GC gc, const RECT *visrect, DWORD rop )
1200 Pixmap pixmaps[3];
1201 Pixmap result = src_pixmap;
1202 BOOL null_brush;
1203 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1204 BOOL use_pat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1205 BOOL use_dst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1206 int width = visrect->right - visrect->left;
1207 int height = visrect->bottom - visrect->top;
1209 pixmaps[SRC] = src_pixmap;
1210 pixmaps[TMP] = 0;
1211 wine_tsx11_lock();
1212 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
1213 wine_tsx11_unlock();
1215 if (use_dst) BITBLT_GetDstArea( physdev, pixmaps[DST], gc, visrect );
1216 null_brush = use_pat && !X11DRV_SetupGCForPatBlt( physdev, gc, TRUE );
1218 wine_tsx11_lock();
1219 for ( ; *opcode; opcode++)
1221 if (OP_DST(*opcode) == DST) result = pixmaps[DST];
1222 XSetFunction( gdi_display, gc, OP_ROP(*opcode) );
1223 switch(OP_SRCDST(*opcode))
1225 case OP_ARGS(DST,TMP):
1226 case OP_ARGS(SRC,TMP):
1227 if (!pixmaps[TMP])
1228 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
1229 /* fall through */
1230 case OP_ARGS(DST,SRC):
1231 case OP_ARGS(SRC,DST):
1232 case OP_ARGS(TMP,SRC):
1233 case OP_ARGS(TMP,DST):
1234 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)], pixmaps[OP_DST(*opcode)], gc,
1235 0, 0, width, height, 0, 0 );
1236 break;
1237 case OP_ARGS(PAT,DST):
1238 case OP_ARGS(PAT,SRC):
1239 if (!null_brush)
1240 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)], gc, 0, 0, width, height );
1241 break;
1244 XSetFunction( gdi_display, physdev->gc, GXcopy );
1245 physdev->exposures += BITBLT_PutDstArea( physdev, result, visrect );
1246 XFreePixmap( gdi_display, pixmaps[DST] );
1247 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1248 wine_tsx11_unlock();
1251 /***********************************************************************
1252 * X11DRV_PatBlt
1254 BOOL X11DRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
1256 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1257 BOOL usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1258 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1260 if (usePat && !X11DRV_SetupGCForBrush( physDev )) return TRUE;
1262 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1264 wine_tsx11_lock();
1265 XSetFunction( gdi_display, physDev->gc, OP_ROP(*opcode) );
1267 switch(rop) /* a few special cases */
1269 case BLACKNESS: /* 0x00 */
1270 case WHITENESS: /* 0xff */
1271 if ((physDev->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
1273 XSetFunction( gdi_display, physDev->gc, GXcopy );
1274 if (rop == BLACKNESS)
1275 XSetForeground( gdi_display, physDev->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1276 else
1277 XSetForeground( gdi_display, physDev->gc,
1278 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1279 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
1281 break;
1282 case DSTINVERT: /* 0x55 */
1283 if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
1285 /* Xor is much better when we do not have full colormap. */
1286 /* Using white^black ensures that we invert at least black */
1287 /* and white. */
1288 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1289 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1290 XSetFunction( gdi_display, physDev->gc, GXxor );
1291 XSetForeground( gdi_display, physDev->gc, xor_pix);
1292 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
1294 break;
1296 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1297 physDev->dc_rect.left + dst->visrect.left,
1298 physDev->dc_rect.top + dst->visrect.top,
1299 dst->visrect.right - dst->visrect.left,
1300 dst->visrect.bottom - dst->visrect.top );
1301 wine_tsx11_unlock();
1303 X11DRV_UnlockDIBSection( physDev, TRUE );
1304 return TRUE;
1308 /***********************************************************************
1309 * X11DRV_StretchBlt
1311 BOOL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1312 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1314 X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
1315 X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev );
1316 BOOL fStretch;
1317 INT width, height;
1318 INT sDst, sSrc = DIB_Status_None;
1319 const BYTE *opcode;
1320 Pixmap src_pixmap;
1321 GC tmpGC;
1323 if (src_dev->funcs != dst_dev->funcs)
1325 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
1326 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
1329 fStretch = (src->width != dst->width) || (src->height != dst->height);
1331 if (physDevDst != physDevSrc)
1332 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None );
1334 width = dst->visrect.right - dst->visrect.left;
1335 height = dst->visrect.bottom - dst->visrect.top;
1337 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None );
1338 if (physDevDst == physDevSrc) sSrc = sDst;
1340 /* try client-side DIB copy */
1341 if (!fStretch && sSrc == DIB_Status_AppMod)
1343 if (physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1344 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1345 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
1346 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
1349 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod );
1351 opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1353 /* a few optimizations for single-op ROPs */
1354 if (!fStretch && !opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1356 if (same_format(physDevSrc, physDevDst))
1358 wine_tsx11_lock();
1359 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1360 wine_tsx11_unlock();
1362 if (physDevSrc != physDevDst) X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1363 wine_tsx11_lock();
1364 XCopyArea( gdi_display, physDevSrc->drawable,
1365 physDevDst->drawable, physDevDst->gc,
1366 physDevSrc->dc_rect.left + src->visrect.left,
1367 physDevSrc->dc_rect.top + src->visrect.top,
1368 width, height,
1369 physDevDst->dc_rect.left + dst->visrect.left,
1370 physDevDst->dc_rect.top + dst->visrect.top );
1371 physDevDst->exposures++;
1372 wine_tsx11_unlock();
1373 goto done;
1375 if (physDevSrc->depth == 1)
1377 int fg, bg;
1379 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1380 get_colors(physDevDst, physDevSrc, &fg, &bg);
1381 wine_tsx11_lock();
1382 XSetBackground( gdi_display, physDevDst->gc, fg );
1383 XSetForeground( gdi_display, physDevDst->gc, bg );
1384 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1385 XCopyPlane( gdi_display, physDevSrc->drawable,
1386 physDevDst->drawable, physDevDst->gc,
1387 physDevSrc->dc_rect.left + src->visrect.left,
1388 physDevSrc->dc_rect.top + src->visrect.top,
1389 width, height,
1390 physDevDst->dc_rect.left + dst->visrect.left,
1391 physDevDst->dc_rect.top + dst->visrect.top, 1 );
1392 physDevDst->exposures++;
1393 wine_tsx11_unlock();
1394 goto done;
1398 wine_tsx11_lock();
1399 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1400 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1401 XSetGraphicsExposures( gdi_display, tmpGC, False );
1402 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, physDevDst->depth );
1403 wine_tsx11_unlock();
1405 if (physDevDst != physDevSrc) X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1407 if (fStretch)
1408 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, src_pixmap, tmpGC, src, dst );
1409 else
1410 BITBLT_GetSrcArea( physDevSrc, physDevDst, src_pixmap, tmpGC, &src->visrect );
1412 execute_rop( physDevDst, src_pixmap, tmpGC, &dst->visrect, rop );
1414 wine_tsx11_lock();
1415 XFreePixmap( gdi_display, src_pixmap );
1416 XFreeGC( gdi_display, tmpGC );
1417 wine_tsx11_unlock();
1419 done:
1420 if (physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1421 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1422 return TRUE;
1426 static void free_heap_bits( struct gdi_image_bits *bits )
1428 HeapFree( GetProcessHeap(), 0, bits->ptr );
1431 static void free_ximage_bits( struct gdi_image_bits *bits )
1433 wine_tsx11_lock();
1434 XFree( bits->ptr );
1435 wine_tsx11_unlock();
1438 /* store the palette or color mask data in the bitmap info structure */
1439 static void set_color_info( PHYSDEV dev, const ColorShifts *color_shifts, BITMAPINFO *info )
1441 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1443 info->bmiHeader.biCompression = BI_RGB;
1444 info->bmiHeader.biClrUsed = 0;
1446 switch (info->bmiHeader.biBitCount)
1448 case 4:
1449 case 8:
1451 RGBQUAD *rgb = (RGBQUAD *)colors;
1452 PALETTEENTRY palette[256];
1453 UINT i, count;
1455 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1456 count = X11DRV_GetSystemPaletteEntries( dev, 0, info->bmiHeader.biClrUsed, palette );
1457 for (i = 0; i < count; i++)
1459 rgb[i].rgbRed = palette[i].peRed;
1460 rgb[i].rgbGreen = palette[i].peGreen;
1461 rgb[i].rgbBlue = palette[i].peBlue;
1462 rgb[i].rgbReserved = 0;
1464 memset( &rgb[count], 0, (info->bmiHeader.biClrUsed - count) * sizeof(*rgb) );
1465 break;
1467 case 16:
1468 colors[0] = color_shifts->logicalRed.max << color_shifts->logicalRed.shift;
1469 colors[1] = color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift;
1470 colors[2] = color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift;
1471 info->bmiHeader.biCompression = BI_BITFIELDS;
1472 break;
1473 case 32:
1474 colors[0] = color_shifts->logicalRed.max << color_shifts->logicalRed.shift;
1475 colors[1] = color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift;
1476 colors[2] = color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift;
1477 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1478 info->bmiHeader.biCompression = BI_BITFIELDS;
1479 break;
1483 /* check if the specified color info is suitable for PutImage */
1484 static BOOL matching_color_info( PHYSDEV dev, const ColorShifts *color_shifts, const BITMAPINFO *info )
1486 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1488 switch (info->bmiHeader.biBitCount)
1490 case 1:
1491 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1492 return !info->bmiHeader.biClrUsed; /* color map not allowed */
1493 case 4:
1494 case 8:
1496 RGBQUAD *rgb = (RGBQUAD *)colors;
1497 PALETTEENTRY palette[256];
1498 UINT i, count;
1500 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1501 count = X11DRV_GetSystemPaletteEntries( dev, 0, 1 << info->bmiHeader.biBitCount, palette );
1502 if (count != info->bmiHeader.biClrUsed) return FALSE;
1503 for (i = 0; i < count; i++)
1505 if (rgb[i].rgbRed != palette[i].peRed ||
1506 rgb[i].rgbGreen != palette[i].peGreen ||
1507 rgb[i].rgbBlue != palette[i].peBlue) return FALSE;
1509 return TRUE;
1511 case 16:
1512 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1513 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == colors[0] &&
1514 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == colors[1] &&
1515 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == colors[2]);
1516 if (info->bmiHeader.biCompression == BI_RGB)
1517 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == 0x7c00 &&
1518 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == 0x03e0 &&
1519 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == 0x001f);
1520 break;
1521 case 32:
1522 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1523 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == colors[0] &&
1524 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == colors[1] &&
1525 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == colors[2]);
1526 /* fall through */
1527 case 24:
1528 if (info->bmiHeader.biCompression == BI_RGB)
1529 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == 0xff0000 &&
1530 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == 0x00ff00 &&
1531 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == 0x0000ff);
1532 break;
1534 return FALSE;
1537 static inline BOOL is_r8g8b8( int depth, const ColorShifts *color_shifts )
1539 return depth == 24 && color_shifts->logicalBlue.shift == 0 && color_shifts->logicalRed.shift == 16;
1542 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1543 DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image,
1544 const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
1545 struct bitblt_coords *coords, const int *mapping, unsigned int zeropad_mask )
1547 #ifdef WORDS_BIGENDIAN
1548 static const int client_byte_order = MSBFirst;
1549 #else
1550 static const int client_byte_order = LSBFirst;
1551 #endif
1552 BOOL need_byteswap;
1553 int x, y, height = coords->visrect.bottom - coords->visrect.top;
1554 int width_bytes = image->bytes_per_line;
1555 int padding_pos;
1556 unsigned char *src, *dst;
1558 switch (info->bmiHeader.biBitCount)
1560 case 1:
1561 need_byteswap = (image->bitmap_bit_order != MSBFirst);
1562 break;
1563 case 4:
1564 need_byteswap = (image->byte_order != MSBFirst);
1565 break;
1566 case 16:
1567 case 32:
1568 need_byteswap = (image->byte_order != client_byte_order);
1569 break;
1570 case 24:
1571 need_byteswap = (image->byte_order == MSBFirst) ^ !is_r8g8b8;
1572 break;
1573 default:
1574 need_byteswap = FALSE;
1575 break;
1578 src = src_bits->ptr;
1579 if (info->bmiHeader.biHeight > 0)
1580 src += (info->bmiHeader.biHeight - coords->visrect.bottom) * width_bytes;
1581 else
1582 src += coords->visrect.top * width_bytes;
1584 if ((need_byteswap && !src_bits->is_copy) || /* need to swap bytes */
1585 (zeropad_mask != ~0u && !src_bits->is_copy) || /* need to clear padding bytes */
1586 (mapping && !src_bits->is_copy) || /* need to remap pixels */
1587 (width_bytes & 3) || /* need to fixup line alignment */
1588 (info->bmiHeader.biHeight > 0)) /* need to flip vertically */
1590 width_bytes = (width_bytes + 3) & ~3;
1591 info->bmiHeader.biSizeImage = height * width_bytes;
1592 if (!(dst_bits->ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
1593 return ERROR_OUTOFMEMORY;
1594 dst_bits->is_copy = TRUE;
1595 dst_bits->free = free_heap_bits;
1597 else
1599 /* swap bits in place */
1600 dst_bits->ptr = src;
1601 dst_bits->is_copy = src_bits->is_copy;
1602 dst_bits->free = NULL;
1603 if (!need_byteswap && zeropad_mask == ~0u && !mapping) return ERROR_SUCCESS; /* nothing to do */
1606 dst = dst_bits->ptr;
1607 padding_pos = width_bytes/sizeof(unsigned int) - 1;
1609 if (info->bmiHeader.biHeight > 0)
1611 dst += (height - 1) * width_bytes;
1612 width_bytes = -width_bytes;
1615 if (need_byteswap || mapping)
1617 switch (info->bmiHeader.biBitCount)
1619 case 1:
1620 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1622 for (x = 0; x < image->bytes_per_line; x++)
1623 dst[x] = bit_swap[src[x]];
1624 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1626 break;
1627 case 4:
1628 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1630 if (mapping)
1631 for (x = 0; x < image->bytes_per_line; x++)
1632 dst[x] = (mapping[src[x] & 0x0f] << 4) | mapping[src[x] >> 4];
1633 else
1634 for (x = 0; x < image->bytes_per_line; x++)
1635 dst[x] = (src[x] << 4) | (src[x] >> 4);
1636 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1638 break;
1639 case 8:
1640 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1642 for (x = 0; x < image->bytes_per_line; x++)
1643 dst[x] = mapping[src[x]];
1644 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1646 break;
1647 case 16:
1648 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1650 for (x = 0; x < info->bmiHeader.biWidth; x++)
1651 ((USHORT *)dst)[x] = RtlUshortByteSwap( ((const USHORT *)src)[x] );
1652 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1654 break;
1655 case 24:
1656 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1658 for (x = 0; x < info->bmiHeader.biWidth; x++)
1660 unsigned char tmp = src[3 * x];
1661 dst[3 * x] = src[3 * x + 2];
1662 dst[3 * x + 1] = src[3 * x + 1];
1663 dst[3 * x + 2] = tmp;
1665 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1667 break;
1668 case 32:
1669 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1670 for (x = 0; x < info->bmiHeader.biWidth; x++)
1671 ((ULONG *)dst)[x] = RtlUlongByteSwap( ((const ULONG *)src)[x] );
1672 break;
1675 else if (src != dst)
1677 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1679 memcpy( dst, src, image->bytes_per_line );
1680 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1683 else /* only need to clear the padding */
1685 for (y = 0; y < height; y++, dst += width_bytes)
1686 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1688 return ERROR_SUCCESS;
1691 /***********************************************************************
1692 * X11DRV_PutImage
1694 DWORD X11DRV_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
1695 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1696 struct bitblt_coords *dst, DWORD rop )
1698 X11DRV_PDEVICE *physdev;
1699 X_PHYSBITMAP *bitmap;
1700 DWORD ret;
1701 XImage *image;
1702 int depth;
1703 struct gdi_image_bits dst_bits;
1704 const XPixmapFormatValues *format;
1705 const ColorShifts *color_shifts;
1706 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1707 const int *mapping = NULL;
1709 if (hbitmap)
1711 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
1712 physdev = NULL;
1713 depth = bitmap->depth;
1714 color_shifts = &bitmap->color_shifts;
1716 else
1718 physdev = get_x11drv_dev( dev );
1719 bitmap = NULL;
1720 depth = physdev->depth;
1721 color_shifts = physdev->color_shifts;
1723 format = pixmap_formats[depth];
1725 if (info->bmiHeader.biPlanes != 1) goto update_format;
1726 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1727 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1728 if (!matching_color_info( dev, color_shifts, info )) goto update_format;
1729 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1730 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
1732 wine_tsx11_lock();
1733 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1734 info->bmiHeader.biWidth, src->visrect.bottom - src->visrect.top, 32, 0 );
1735 wine_tsx11_unlock();
1736 if (!image) return ERROR_OUTOFMEMORY;
1738 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1740 if (bitmap || (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST)))
1741 mapping = X11DRV_PALETTE_PaletteToXPixel;
1744 ret = copy_image_bits( info, is_r8g8b8(depth,color_shifts), image, bits, &dst_bits, src, mapping, ~0u );
1746 if (!ret)
1748 int width = dst->visrect.right - dst->visrect.left;
1749 int height = dst->visrect.bottom - dst->visrect.top;
1751 image->data = dst_bits.ptr;
1752 /* hack: make sure the bits are readable if we are reading from a DIB section */
1753 /* to be removed once we get rid of DIB access protections */
1754 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, height * image->bytes_per_line );
1756 if (bitmap)
1758 RGNDATA *clip_data = NULL;
1759 GC gc;
1761 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1762 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
1764 wine_tsx11_lock();
1765 gc = XCreateGC( gdi_display, bitmap->pixmap, 0, NULL );
1766 XSetGraphicsExposures( gdi_display, gc, False );
1767 if (clip_data) XSetClipRectangles( gdi_display, gc, 0, 0, (XRectangle *)clip_data->Buffer,
1768 clip_data->rdh.nCount, YXBanded );
1769 XPutImage( gdi_display, bitmap->pixmap, gc, image, src->visrect.left, 0,
1770 dst->visrect.left, dst->visrect.top, width, height );
1771 XFreeGC( gdi_display, gc );
1772 wine_tsx11_unlock();
1774 X11DRV_DIB_Unlock( bitmap, TRUE );
1775 HeapFree( GetProcessHeap(), 0, clip_data );
1777 else
1779 RGNDATA *saved_region = NULL;
1781 if (clip) saved_region = add_extra_clipping_region( physdev, clip );
1782 X11DRV_LockDIBSection( physdev, DIB_Status_GdiMod );
1784 /* optimization for single-op ROPs */
1785 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1787 wine_tsx11_lock();
1788 XSetFunction( gdi_display, physdev->gc, OP_ROP(*opcode) );
1789 XPutImage( gdi_display, physdev->drawable, physdev->gc, image, src->visrect.left, 0,
1790 physdev->dc_rect.left + dst->visrect.left,
1791 physdev->dc_rect.top + dst->visrect.top, width, height );
1792 wine_tsx11_unlock();
1794 else
1796 Pixmap src_pixmap;
1797 GC gc;
1799 wine_tsx11_lock();
1800 gc = XCreateGC( gdi_display, physdev->drawable, 0, NULL );
1801 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1802 XSetGraphicsExposures( gdi_display, gc, False );
1803 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1804 XPutImage( gdi_display, src_pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1805 wine_tsx11_unlock();
1807 execute_rop( physdev, src_pixmap, gc, &dst->visrect, rop );
1809 wine_tsx11_lock();
1810 XFreePixmap( gdi_display, src_pixmap );
1811 XFreeGC( gdi_display, gc );
1812 wine_tsx11_unlock();
1815 X11DRV_UnlockDIBSection( physdev, !ret );
1816 restore_clipping_region( physdev, saved_region );
1818 image->data = NULL;
1821 wine_tsx11_lock();
1822 XDestroyImage( image );
1823 wine_tsx11_unlock();
1824 if (dst_bits.free) dst_bits.free( &dst_bits );
1825 return ret;
1827 update_format:
1828 info->bmiHeader.biPlanes = 1;
1829 info->bmiHeader.biBitCount = format->bits_per_pixel;
1830 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1831 set_color_info( dev, color_shifts, info );
1832 return ERROR_BAD_FORMAT;
1835 /***********************************************************************
1836 * X11DRV_GetImage
1838 DWORD X11DRV_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1839 struct gdi_image_bits *bits, struct bitblt_coords *src )
1841 X11DRV_PDEVICE *physdev;
1842 X_PHYSBITMAP *bitmap;
1843 DWORD ret = ERROR_SUCCESS;
1844 XImage *image;
1845 UINT align, x, y, width, height;
1846 int depth;
1847 struct gdi_image_bits src_bits;
1848 const XPixmapFormatValues *format;
1849 const ColorShifts *color_shifts;
1850 const int *mapping = NULL;
1852 if (hbitmap)
1854 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
1855 physdev = NULL;
1856 depth = bitmap->depth;
1857 color_shifts = &bitmap->color_shifts;
1859 else
1861 physdev = get_x11drv_dev( dev );
1862 bitmap = NULL;
1863 depth = physdev->depth;
1864 color_shifts = physdev->color_shifts;
1866 format = pixmap_formats[depth];
1868 /* align start and width to 32-bit boundary */
1869 switch (format->bits_per_pixel)
1871 case 1: align = 32; break;
1872 case 4: align = 8; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1873 case 8: align = 4; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1874 case 16: align = 2; break;
1875 case 24: align = 4; break;
1876 case 32: align = 1; break;
1877 default:
1878 FIXME( "depth %u bpp %u not supported yet\n", depth, format->bits_per_pixel );
1879 return ERROR_BAD_FORMAT;
1882 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1883 info->bmiHeader.biPlanes = 1;
1884 info->bmiHeader.biBitCount = format->bits_per_pixel;
1885 info->bmiHeader.biXPelsPerMeter = 0;
1886 info->bmiHeader.biYPelsPerMeter = 0;
1887 info->bmiHeader.biClrImportant = 0;
1888 set_color_info( dev, color_shifts, info );
1890 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
1892 x = src->visrect.left & ~(align - 1);
1893 y = src->visrect.top;
1894 width = src->visrect.right - x;
1895 height = src->visrect.bottom - src->visrect.top;
1896 if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1);
1897 /* make the source rectangle relative to the returned bits */
1898 src->x -= x;
1899 src->y -= y;
1900 OffsetRect( &src->visrect, -x, -y );
1902 if (bitmap)
1904 BITMAP bm;
1905 GetObjectW( hbitmap, sizeof(bm), &bm );
1906 width = min( width, bm.bmWidth - x );
1907 height = min( height, bm.bmHeight - y );
1908 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
1909 wine_tsx11_lock();
1910 image = XGetImage( gdi_display, bitmap->pixmap, x, y, width, height, AllPlanes, ZPixmap );
1911 wine_tsx11_unlock();
1912 X11DRV_DIB_Unlock( bitmap, TRUE );
1914 else if (GetObjectType( dev->hdc ) == OBJ_MEMDC)
1916 X11DRV_LockDIBSection( physdev, DIB_Status_GdiMod );
1917 width = min( width, physdev->dc_rect.right - physdev->dc_rect.left - x );
1918 height = min( height, physdev->dc_rect.bottom - physdev->dc_rect.top - y );
1919 wine_tsx11_lock();
1920 image = XGetImage( gdi_display, physdev->drawable,
1921 physdev->dc_rect.left + x, physdev->dc_rect.top + y,
1922 width, height, AllPlanes, ZPixmap );
1923 wine_tsx11_unlock();
1924 X11DRV_UnlockDIBSection( physdev, FALSE );
1926 else
1928 Pixmap pixmap;
1930 wine_tsx11_lock();
1931 /* use a temporary pixmap to avoid BadMatch errors */
1932 pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1933 XCopyArea( gdi_display, physdev->drawable, pixmap, get_bitmap_gc(depth),
1934 physdev->dc_rect.left + x, physdev->dc_rect.top + y, width, height, 0, 0 );
1935 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1936 XFreePixmap( gdi_display, pixmap );
1937 wine_tsx11_unlock();
1939 if (!image) return ERROR_OUTOFMEMORY;
1941 info->bmiHeader.biWidth = width;
1942 info->bmiHeader.biHeight = -height;
1943 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1945 src_bits.ptr = image->data;
1946 src_bits.is_copy = TRUE;
1947 ret = copy_image_bits( info, is_r8g8b8(depth,color_shifts), image, &src_bits, bits, src, mapping,
1948 zeropad_masks[(width * image->bits_per_pixel) & 31] );
1950 if (!ret && bits->ptr == image->data)
1952 bits->free = free_ximage_bits;
1953 image->data = NULL;
1955 wine_tsx11_lock();
1956 XDestroyImage( image );
1957 wine_tsx11_unlock();
1958 return ret;