winex11: Simplify rectangle operations.
[wine.git] / dlls / winex11.drv / bitblt.c
blob2e851c0b4460a1e2bc6293ae3b86084688a69870
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;
1190 /***********************************************************************
1191 * client_side_dib_copy
1193 static BOOL client_side_dib_copy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1194 X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1195 INT width, INT height )
1197 DIBSECTION srcDib, dstDib;
1198 BYTE *srcPtr, *dstPtr;
1199 INT srcRowOffset, dstRowOffset;
1200 INT bytesPerPixel;
1201 INT bytesToCopy;
1202 INT y;
1203 static RECT unusedRect;
1205 if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib))
1206 return FALSE;
1207 if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib))
1208 return FALSE;
1210 /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */
1211 if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight)
1212 return FALSE;
1213 if (xSrc + width > srcDib.dsBm.bmWidth)
1214 width = srcDib.dsBm.bmWidth - xSrc;
1215 if (ySrc + height > srcDib.dsBm.bmHeight)
1216 height = srcDib.dsBm.bmHeight - ySrc;
1218 if (GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION)
1220 /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */
1221 FIXME("potential optimization: client-side complex region clipping\n");
1222 return FALSE;
1224 if (dstDib.dsBm.bmBitsPixel <= 8)
1226 static BOOL fixme_once;
1227 if(!fixme_once++) FIXME("potential optimization: client-side color-index mode DIB copy\n");
1228 return FALSE;
1230 if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1231 dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1232 !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1233 && !(srcDib.dsBmih.biCompression == BI_RGB &&
1234 dstDib.dsBmih.biCompression == BI_RGB))
1236 FIXME("potential optimization: client-side compressed DIB copy\n");
1237 return FALSE;
1239 if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1241 FIXME("potential optimization: pixel format conversion\n");
1242 return FALSE;
1244 if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1246 FIXME("negative widths not yet implemented\n");
1247 return FALSE;
1250 switch (dstDib.dsBm.bmBitsPixel)
1252 case 15:
1253 case 16:
1254 bytesPerPixel = 2;
1255 break;
1256 case 24:
1257 bytesPerPixel = 3;
1258 break;
1259 case 32:
1260 bytesPerPixel = 4;
1261 break;
1262 default:
1263 FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1264 return FALSE;
1267 bytesToCopy = width * bytesPerPixel;
1269 if (physDevSrc->bitmap->topdown)
1271 srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1272 srcRowOffset = srcDib.dsBm.bmWidthBytes;
1274 else
1276 srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1277 + xSrc*bytesPerPixel];
1278 srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1280 if (physDevDst->bitmap->topdown)
1282 dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1283 dstRowOffset = dstDib.dsBm.bmWidthBytes;
1285 else
1287 dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1288 + xDst*bytesPerPixel];
1289 dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1292 /* Handle overlapping regions on the same DIB */
1293 if (physDevSrc == physDevDst && ySrc < yDst)
1295 srcPtr += srcRowOffset * (height - 1);
1296 srcRowOffset = -srcRowOffset;
1297 dstPtr += dstRowOffset * (height - 1);
1298 dstRowOffset = -dstRowOffset;
1301 for (y = yDst; y < yDst + height; ++y)
1303 memmove(dstPtr, srcPtr, bytesToCopy);
1304 srcPtr += srcRowOffset;
1305 dstPtr += dstRowOffset;
1308 return TRUE;
1311 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
1313 if (physDevSrc->depth != physDevDst->depth) return FALSE;
1314 if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
1315 if (physDevSrc->color_shifts && physDevDst->color_shifts)
1316 return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
1317 return FALSE;
1320 static void execute_rop( X11DRV_PDEVICE *physdev, Pixmap src_pixmap, GC gc,
1321 const RECT *visrect, DWORD rop )
1323 Pixmap pixmaps[3];
1324 Pixmap result = src_pixmap;
1325 BOOL null_brush;
1326 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1327 BOOL use_pat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1328 BOOL use_dst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1329 int width = visrect->right - visrect->left;
1330 int height = visrect->bottom - visrect->top;
1332 pixmaps[SRC] = src_pixmap;
1333 pixmaps[TMP] = 0;
1334 wine_tsx11_lock();
1335 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
1336 wine_tsx11_unlock();
1338 if (use_dst) BITBLT_GetDstArea( physdev, pixmaps[DST], gc, visrect );
1339 null_brush = use_pat && !X11DRV_SetupGCForPatBlt( physdev, gc, TRUE );
1341 wine_tsx11_lock();
1342 for ( ; *opcode; opcode++)
1344 if (OP_DST(*opcode) == DST) result = pixmaps[DST];
1345 XSetFunction( gdi_display, gc, OP_ROP(*opcode) );
1346 switch(OP_SRCDST(*opcode))
1348 case OP_ARGS(DST,TMP):
1349 case OP_ARGS(SRC,TMP):
1350 if (!pixmaps[TMP])
1351 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
1352 /* fall through */
1353 case OP_ARGS(DST,SRC):
1354 case OP_ARGS(SRC,DST):
1355 case OP_ARGS(TMP,SRC):
1356 case OP_ARGS(TMP,DST):
1357 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)], pixmaps[OP_DST(*opcode)], gc,
1358 0, 0, width, height, 0, 0 );
1359 break;
1360 case OP_ARGS(PAT,DST):
1361 case OP_ARGS(PAT,SRC):
1362 if (!null_brush)
1363 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)], gc, 0, 0, width, height );
1364 break;
1367 XSetFunction( gdi_display, physdev->gc, GXcopy );
1368 physdev->exposures += BITBLT_PutDstArea( physdev, result, visrect );
1369 XFreePixmap( gdi_display, pixmaps[DST] );
1370 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1371 wine_tsx11_unlock();
1374 /***********************************************************************
1375 * X11DRV_PatBlt
1377 BOOL X11DRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
1379 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1380 BOOL usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1381 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1383 if (usePat && !X11DRV_SetupGCForBrush( physDev )) return TRUE;
1385 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1387 wine_tsx11_lock();
1388 XSetFunction( gdi_display, physDev->gc, OP_ROP(*opcode) );
1390 switch(rop) /* a few special cases */
1392 case BLACKNESS: /* 0x00 */
1393 case WHITENESS: /* 0xff */
1394 if ((physDev->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
1396 XSetFunction( gdi_display, physDev->gc, GXcopy );
1397 if (rop == BLACKNESS)
1398 XSetForeground( gdi_display, physDev->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1399 else
1400 XSetForeground( gdi_display, physDev->gc,
1401 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1402 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
1404 break;
1405 case DSTINVERT: /* 0x55 */
1406 if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
1408 /* Xor is much better when we do not have full colormap. */
1409 /* Using white^black ensures that we invert at least black */
1410 /* and white. */
1411 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1412 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1413 XSetFunction( gdi_display, physDev->gc, GXxor );
1414 XSetForeground( gdi_display, physDev->gc, xor_pix);
1415 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
1417 break;
1419 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1420 physDev->dc_rect.left + dst->visrect.left,
1421 physDev->dc_rect.top + dst->visrect.top,
1422 dst->visrect.right - dst->visrect.left,
1423 dst->visrect.bottom - dst->visrect.top );
1424 wine_tsx11_unlock();
1426 X11DRV_UnlockDIBSection( physDev, TRUE );
1427 return TRUE;
1431 /***********************************************************************
1432 * X11DRV_StretchBlt
1434 BOOL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1435 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1437 X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
1438 X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev ); /* FIXME: check that it's really an x11 dev */
1439 BOOL fStretch;
1440 INT width, height;
1441 INT sDst, sSrc = DIB_Status_None;
1442 const BYTE *opcode;
1443 Pixmap src_pixmap;
1444 GC tmpGC;
1446 fStretch = (src->width != dst->width) || (src->height != dst->height);
1448 if (physDevDst != physDevSrc)
1449 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None );
1451 width = dst->visrect.right - dst->visrect.left;
1452 height = dst->visrect.bottom - dst->visrect.top;
1454 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None );
1455 if (physDevDst == physDevSrc) sSrc = sDst;
1457 /* try client-side DIB copy */
1458 if (!fStretch && rop == SRCCOPY &&
1459 sSrc == DIB_Status_AppMod && sDst == DIB_Status_AppMod &&
1460 same_format(physDevSrc, physDevDst))
1462 if (client_side_dib_copy( physDevSrc, src->visrect.left, src->visrect.top,
1463 physDevDst, dst->visrect.left, dst->visrect.top, width, height ))
1464 goto done;
1467 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod );
1469 opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1471 /* a few optimizations for single-op ROPs */
1472 if (!fStretch && !opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1474 if (same_format(physDevSrc, physDevDst))
1476 wine_tsx11_lock();
1477 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1478 wine_tsx11_unlock();
1480 if (physDevSrc != physDevDst)
1482 if (sSrc == DIB_Status_AppMod)
1484 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, src->visrect.left, src->visrect.top,
1485 dst->visrect.left, dst->visrect.top, width, height );
1486 goto done;
1488 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1490 wine_tsx11_lock();
1491 XCopyArea( gdi_display, physDevSrc->drawable,
1492 physDevDst->drawable, physDevDst->gc,
1493 physDevSrc->dc_rect.left + src->visrect.left,
1494 physDevSrc->dc_rect.top + src->visrect.top,
1495 width, height,
1496 physDevDst->dc_rect.left + dst->visrect.left,
1497 physDevDst->dc_rect.top + dst->visrect.top );
1498 physDevDst->exposures++;
1499 wine_tsx11_unlock();
1500 goto done;
1502 if (physDevSrc->depth == 1)
1504 int fg, bg;
1506 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1507 get_colors(physDevDst, physDevSrc, &fg, &bg);
1508 wine_tsx11_lock();
1509 XSetBackground( gdi_display, physDevDst->gc, fg );
1510 XSetForeground( gdi_display, physDevDst->gc, bg );
1511 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1512 XCopyPlane( gdi_display, physDevSrc->drawable,
1513 physDevDst->drawable, physDevDst->gc,
1514 physDevSrc->dc_rect.left + src->visrect.left,
1515 physDevSrc->dc_rect.top + src->visrect.top,
1516 width, height,
1517 physDevDst->dc_rect.left + dst->visrect.left,
1518 physDevDst->dc_rect.top + dst->visrect.top, 1 );
1519 physDevDst->exposures++;
1520 wine_tsx11_unlock();
1521 goto done;
1525 wine_tsx11_lock();
1526 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1527 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1528 XSetGraphicsExposures( gdi_display, tmpGC, False );
1529 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, physDevDst->depth );
1530 wine_tsx11_unlock();
1532 if (physDevDst != physDevSrc) X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1534 if(!X11DRV_XRender_GetSrcAreaStretch( physDevSrc, physDevDst, src_pixmap, tmpGC, src, dst ))
1536 if (fStretch)
1537 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, src_pixmap, tmpGC, src, dst );
1538 else
1539 BITBLT_GetSrcArea( physDevSrc, physDevDst, src_pixmap, tmpGC, &src->visrect );
1542 execute_rop( physDevDst, src_pixmap, tmpGC, &dst->visrect, rop );
1544 wine_tsx11_lock();
1545 XFreePixmap( gdi_display, src_pixmap );
1546 XFreeGC( gdi_display, tmpGC );
1547 wine_tsx11_unlock();
1549 done:
1550 if (physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1551 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1552 return TRUE;
1556 /***********************************************************************
1557 * X11DRV_AlphaBlend
1559 BOOL X11DRV_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
1560 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
1562 X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
1563 X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev ); /* FIXME: check that it's really an x11 dev */
1565 if (src->x < 0 || src->y < 0 || src->width < 0 || src->height < 0 ||
1566 src->width > physDevSrc->drawable_rect.right - physDevSrc->drawable_rect.left - src->x ||
1567 src->height > physDevSrc->drawable_rect.bottom - physDevSrc->drawable_rect.top - src->y)
1569 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src->x, src->y, src->width, src->height );
1570 SetLastError( ERROR_INVALID_PARAMETER );
1571 return FALSE;
1574 return XRender_AlphaBlend( physDevDst, dst, physDevSrc, src, blendfn );
1578 static void free_heap_bits( struct gdi_image_bits *bits )
1580 HeapFree( GetProcessHeap(), 0, bits->ptr );
1583 static void free_ximage_bits( struct gdi_image_bits *bits )
1585 wine_tsx11_lock();
1586 XFree( bits->ptr );
1587 wine_tsx11_unlock();
1590 /* store the palette or color mask data in the bitmap info structure */
1591 static void set_color_info( PHYSDEV dev, const ColorShifts *color_shifts, BITMAPINFO *info )
1593 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1595 info->bmiHeader.biCompression = BI_RGB;
1596 info->bmiHeader.biClrUsed = 0;
1598 switch (info->bmiHeader.biBitCount)
1600 case 4:
1601 case 8:
1603 RGBQUAD *rgb = (RGBQUAD *)colors;
1604 PALETTEENTRY palette[256];
1605 UINT i, count;
1607 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
1608 count = X11DRV_GetSystemPaletteEntries( dev, 0, info->bmiHeader.biClrUsed, palette );
1609 for (i = 0; i < count; i++)
1611 rgb[i].rgbRed = palette[i].peRed;
1612 rgb[i].rgbGreen = palette[i].peGreen;
1613 rgb[i].rgbBlue = palette[i].peBlue;
1614 rgb[i].rgbReserved = 0;
1616 memset( &rgb[count], 0, (info->bmiHeader.biClrUsed - count) * sizeof(*rgb) );
1617 break;
1619 case 16:
1620 colors[0] = color_shifts->logicalRed.max << color_shifts->logicalRed.shift;
1621 colors[1] = color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift;
1622 colors[2] = color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift;
1623 info->bmiHeader.biCompression = BI_BITFIELDS;
1624 break;
1625 case 32:
1626 colors[0] = color_shifts->logicalRed.max << color_shifts->logicalRed.shift;
1627 colors[1] = color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift;
1628 colors[2] = color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift;
1629 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff)
1630 info->bmiHeader.biCompression = BI_BITFIELDS;
1631 break;
1635 /* check if the specified color info is suitable for PutImage */
1636 static BOOL matching_color_info( PHYSDEV dev, const ColorShifts *color_shifts, const BITMAPINFO *info )
1638 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1640 switch (info->bmiHeader.biBitCount)
1642 case 1:
1643 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1644 return !info->bmiHeader.biClrUsed; /* color map not allowed */
1645 case 4:
1646 case 8:
1648 RGBQUAD *rgb = (RGBQUAD *)colors;
1649 PALETTEENTRY palette[256];
1650 UINT i, count;
1652 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1653 count = X11DRV_GetSystemPaletteEntries( dev, 0, 1 << info->bmiHeader.biBitCount, palette );
1654 if (count != info->bmiHeader.biClrUsed) return FALSE;
1655 for (i = 0; i < count; i++)
1657 if (rgb[i].rgbRed != palette[i].peRed ||
1658 rgb[i].rgbGreen != palette[i].peGreen ||
1659 rgb[i].rgbBlue != palette[i].peBlue) return FALSE;
1661 return TRUE;
1663 case 16:
1664 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1665 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == colors[0] &&
1666 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == colors[1] &&
1667 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == colors[2]);
1668 if (info->bmiHeader.biCompression == BI_RGB)
1669 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == 0x7c00 &&
1670 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == 0x03e0 &&
1671 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == 0x001f);
1672 break;
1673 case 32:
1674 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1675 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == colors[0] &&
1676 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == colors[1] &&
1677 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == colors[2]);
1678 /* fall through */
1679 case 24:
1680 if (info->bmiHeader.biCompression == BI_RGB)
1681 return (color_shifts->logicalRed.max << color_shifts->logicalRed.shift == 0xff0000 &&
1682 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift == 0x00ff00 &&
1683 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift == 0x0000ff);
1684 break;
1686 return FALSE;
1689 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1690 static DWORD copy_image_bits( BITMAPINFO *info, const ColorShifts *color_shifts, XImage *image,
1691 const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
1692 struct bitblt_coords *coords, const int *mapping, unsigned int zeropad_mask )
1694 #ifdef WORDS_BIGENDIAN
1695 static const int client_byte_order = MSBFirst;
1696 #else
1697 static const int client_byte_order = LSBFirst;
1698 #endif
1699 BOOL need_byteswap;
1700 int x, y, height = coords->visrect.bottom - coords->visrect.top;
1701 int width_bytes = image->bytes_per_line;
1702 int padding_pos;
1703 unsigned char *src, *dst;
1705 switch (info->bmiHeader.biBitCount)
1707 case 1:
1708 need_byteswap = (image->bitmap_bit_order != MSBFirst);
1709 break;
1710 case 4:
1711 need_byteswap = (image->byte_order != MSBFirst);
1712 break;
1713 case 16:
1714 case 32:
1715 need_byteswap = (image->byte_order != client_byte_order);
1716 break;
1717 case 24:
1718 need_byteswap = ((image->byte_order == LSBFirst && color_shifts->logicalBlue.shift == 16) ||
1719 (image->byte_order == MSBFirst && color_shifts->logicalBlue.shift == 0));
1720 break;
1721 default:
1722 need_byteswap = FALSE;
1723 break;
1726 src = src_bits->ptr;
1727 if (info->bmiHeader.biHeight > 0)
1728 src += (info->bmiHeader.biHeight - coords->visrect.bottom) * width_bytes;
1729 else
1730 src += coords->visrect.top * width_bytes;
1732 if ((need_byteswap && !src_bits->is_copy) || /* need to swap bytes */
1733 (zeropad_mask != ~0u && !src_bits->is_copy) || /* need to clear padding bytes */
1734 (mapping && !src_bits->is_copy) || /* need to remap pixels */
1735 (width_bytes & 3) || /* need to fixup line alignment */
1736 (info->bmiHeader.biHeight > 0)) /* need to flip vertically */
1738 width_bytes = (width_bytes + 3) & ~3;
1739 info->bmiHeader.biSizeImage = height * width_bytes;
1740 if (!(dst_bits->ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
1741 return ERROR_OUTOFMEMORY;
1742 dst_bits->is_copy = TRUE;
1743 dst_bits->free = free_heap_bits;
1745 else
1747 /* swap bits in place */
1748 dst_bits->ptr = src;
1749 dst_bits->is_copy = src_bits->is_copy;
1750 dst_bits->free = NULL;
1751 if (!need_byteswap && zeropad_mask == ~0u && !mapping) return ERROR_SUCCESS; /* nothing to do */
1754 dst = dst_bits->ptr;
1755 padding_pos = width_bytes/sizeof(unsigned int) - 1;
1757 if (info->bmiHeader.biHeight > 0)
1759 dst += (height - 1) * width_bytes;
1760 width_bytes = -width_bytes;
1763 if (need_byteswap || mapping)
1765 switch (info->bmiHeader.biBitCount)
1767 case 1:
1768 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1770 for (x = 0; x < image->bytes_per_line; x++)
1771 dst[x] = bit_swap[src[x]];
1772 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1774 break;
1775 case 4:
1776 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1778 if (mapping)
1779 for (x = 0; x < image->bytes_per_line; x++)
1780 dst[x] = (mapping[src[x] & 0x0f] << 4) | mapping[src[x] >> 4];
1781 else
1782 for (x = 0; x < image->bytes_per_line; x++)
1783 dst[x] = (src[x] << 4) | (src[x] >> 4);
1784 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1786 break;
1787 case 8:
1788 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1790 for (x = 0; x < image->bytes_per_line; x++)
1791 dst[x] = mapping[src[x]];
1792 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1794 break;
1795 case 16:
1796 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1798 for (x = 0; x < info->bmiHeader.biWidth; x++)
1799 ((USHORT *)dst)[x] = RtlUshortByteSwap( ((const USHORT *)src)[x] );
1800 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1802 break;
1803 case 24:
1804 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1806 for (x = 0; x < info->bmiHeader.biWidth; x++)
1808 unsigned char tmp = src[3 * x];
1809 dst[3 * x] = src[3 * x + 2];
1810 dst[3 * x + 1] = src[3 * x + 1];
1811 dst[3 * x + 2] = tmp;
1813 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1815 break;
1816 case 32:
1817 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1818 for (x = 0; x < info->bmiHeader.biWidth; x++)
1819 ((ULONG *)dst)[x] = RtlUlongByteSwap( ((const ULONG *)src)[x] );
1820 break;
1823 else if (src != dst)
1825 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1827 memcpy( dst, src, image->bytes_per_line );
1828 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1831 else /* only need to clear the padding */
1833 for (y = 0; y < height; y++, dst += width_bytes)
1834 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1836 return ERROR_SUCCESS;
1839 /***********************************************************************
1840 * X11DRV_PutImage
1842 DWORD X11DRV_PutImage( PHYSDEV dev, HBITMAP hbitmap, HRGN clip, BITMAPINFO *info,
1843 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1844 struct bitblt_coords *dst, DWORD rop )
1846 X11DRV_PDEVICE *physdev;
1847 X_PHYSBITMAP *bitmap;
1848 DWORD ret;
1849 XImage *image;
1850 int depth;
1851 struct gdi_image_bits dst_bits;
1852 const XPixmapFormatValues *format;
1853 const ColorShifts *color_shifts;
1854 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1855 const int *mapping = NULL;
1857 if (hbitmap)
1859 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
1860 physdev = NULL;
1861 depth = bitmap->pixmap_depth;
1862 color_shifts = &bitmap->pixmap_color_shifts;
1864 else
1866 physdev = get_x11drv_dev( dev );
1867 bitmap = NULL;
1868 depth = physdev->depth;
1869 color_shifts = physdev->color_shifts;
1871 format = pixmap_formats[depth];
1873 if (info->bmiHeader.biPlanes != 1) goto update_format;
1874 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1875 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1876 if (!matching_color_info( dev, color_shifts, info )) goto update_format;
1877 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1878 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
1880 wine_tsx11_lock();
1881 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1882 info->bmiHeader.biWidth, src->visrect.bottom - src->visrect.top, 32, 0 );
1883 wine_tsx11_unlock();
1884 if (!image) return ERROR_OUTOFMEMORY;
1886 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1888 if (bitmap || (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST)))
1889 mapping = X11DRV_PALETTE_PaletteToXPixel;
1892 ret = copy_image_bits( info, color_shifts, image, bits, &dst_bits, src, mapping, ~0u );
1894 if (!ret)
1896 int width = dst->visrect.right - dst->visrect.left;
1897 int height = dst->visrect.bottom - dst->visrect.top;
1899 image->data = dst_bits.ptr;
1900 /* hack: make sure the bits are readable if we are reading from a DIB section */
1901 /* to be removed once we get rid of DIB access protections */
1902 if (!dst_bits.is_copy) IsBadReadPtr( dst_bits.ptr, height * image->bytes_per_line );
1904 if (bitmap)
1906 RGNDATA *clip_data = NULL;
1907 GC gc;
1909 if (clip) clip_data = X11DRV_GetRegionData( clip, 0 );
1910 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
1912 wine_tsx11_lock();
1913 gc = XCreateGC( gdi_display, bitmap->pixmap, 0, NULL );
1914 XSetGraphicsExposures( gdi_display, gc, False );
1915 if (clip_data) XSetClipRectangles( gdi_display, gc, 0, 0, (XRectangle *)clip_data->Buffer,
1916 clip_data->rdh.nCount, YXBanded );
1917 XPutImage( gdi_display, bitmap->pixmap, gc, image, src->visrect.left, 0,
1918 dst->visrect.left, dst->visrect.top, width, height );
1919 XFreeGC( gdi_display, gc );
1920 wine_tsx11_unlock();
1922 X11DRV_DIB_Unlock( bitmap, TRUE );
1923 HeapFree( GetProcessHeap(), 0, clip_data );
1925 else
1927 HRGN saved_region = 0;
1929 if (clip) saved_region = add_extra_clipping_region( physdev, clip );
1930 X11DRV_LockDIBSection( physdev, DIB_Status_GdiMod );
1932 /* optimization for single-op ROPs */
1933 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1935 wine_tsx11_lock();
1936 XSetFunction( gdi_display, physdev->gc, OP_ROP(*opcode) );
1937 XPutImage( gdi_display, physdev->drawable, physdev->gc, image, src->visrect.left, 0,
1938 physdev->dc_rect.left + dst->visrect.left,
1939 physdev->dc_rect.top + dst->visrect.top, width, height );
1940 wine_tsx11_unlock();
1942 else
1944 Pixmap src_pixmap;
1945 GC gc;
1947 wine_tsx11_lock();
1948 gc = XCreateGC( gdi_display, physdev->drawable, 0, NULL );
1949 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1950 XSetGraphicsExposures( gdi_display, gc, False );
1951 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1952 XPutImage( gdi_display, src_pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1953 wine_tsx11_unlock();
1955 execute_rop( physdev, src_pixmap, gc, &dst->visrect, rop );
1957 wine_tsx11_lock();
1958 XFreePixmap( gdi_display, src_pixmap );
1959 XFreeGC( gdi_display, gc );
1960 wine_tsx11_unlock();
1963 X11DRV_UnlockDIBSection( physdev, !ret );
1964 if (saved_region) restore_clipping_region( physdev, saved_region );
1966 image->data = NULL;
1969 wine_tsx11_lock();
1970 XDestroyImage( image );
1971 wine_tsx11_unlock();
1972 if (dst_bits.free) dst_bits.free( &dst_bits );
1973 return ret;
1975 update_format:
1976 info->bmiHeader.biPlanes = 1;
1977 info->bmiHeader.biBitCount = format->bits_per_pixel;
1978 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1979 set_color_info( dev, color_shifts, info );
1980 return ERROR_BAD_FORMAT;
1983 /***********************************************************************
1984 * X11DRV_GetImage
1986 DWORD X11DRV_GetImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info,
1987 struct gdi_image_bits *bits, struct bitblt_coords *src )
1989 X11DRV_PDEVICE *physdev;
1990 X_PHYSBITMAP *bitmap;
1991 DWORD ret = ERROR_SUCCESS;
1992 XImage *image;
1993 UINT align, x, y, width, height;
1994 int depth;
1995 struct gdi_image_bits src_bits;
1996 const XPixmapFormatValues *format;
1997 const ColorShifts *color_shifts;
1998 const int *mapping = NULL;
2000 if (hbitmap)
2002 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
2003 physdev = NULL;
2004 depth = bitmap->pixmap_depth;
2005 color_shifts = &bitmap->pixmap_color_shifts;
2007 else
2009 physdev = get_x11drv_dev( dev );
2010 bitmap = NULL;
2011 depth = physdev->depth;
2012 color_shifts = physdev->color_shifts;
2014 format = pixmap_formats[depth];
2016 /* align start and width to 32-bit boundary */
2017 switch (format->bits_per_pixel)
2019 case 1: align = 32; break;
2020 case 4: align = 8; mapping = X11DRV_PALETTE_XPixelToPalette; break;
2021 case 8: align = 4; mapping = X11DRV_PALETTE_XPixelToPalette; break;
2022 case 16: align = 2; break;
2023 case 24: align = 4; break;
2024 case 32: align = 1; break;
2025 default:
2026 FIXME( "depth %u bpp %u not supported yet\n", depth, format->bits_per_pixel );
2027 return ERROR_BAD_FORMAT;
2030 info->bmiHeader.biSize = sizeof(info->bmiHeader);
2031 info->bmiHeader.biPlanes = 1;
2032 info->bmiHeader.biBitCount = format->bits_per_pixel;
2033 info->bmiHeader.biXPelsPerMeter = 0;
2034 info->bmiHeader.biYPelsPerMeter = 0;
2035 info->bmiHeader.biClrImportant = 0;
2036 set_color_info( dev, color_shifts, info );
2038 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
2040 x = src->visrect.left & ~(align - 1);
2041 y = src->visrect.top;
2042 width = src->visrect.right - x;
2043 height = src->visrect.bottom - src->visrect.top;
2044 if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1);
2045 /* make the source rectangle relative to the returned bits */
2046 src->x -= x;
2047 src->y -= y;
2048 OffsetRect( &src->visrect, -x, -y );
2050 if (bitmap)
2052 BITMAP bm;
2053 GetObjectW( hbitmap, sizeof(bm), &bm );
2054 width = min( width, bm.bmWidth - x );
2055 height = min( height, bm.bmHeight - y );
2056 X11DRV_DIB_Lock( bitmap, DIB_Status_GdiMod );
2057 wine_tsx11_lock();
2058 image = XGetImage( gdi_display, bitmap->pixmap, x, y, width, height, AllPlanes, ZPixmap );
2059 wine_tsx11_unlock();
2060 X11DRV_DIB_Unlock( bitmap, TRUE );
2062 else if (GetObjectType( dev->hdc ) == OBJ_MEMDC)
2064 X11DRV_LockDIBSection( physdev, DIB_Status_GdiMod );
2065 width = min( width, physdev->dc_rect.right - physdev->dc_rect.left - x );
2066 height = min( height, physdev->dc_rect.bottom - physdev->dc_rect.top - y );
2067 wine_tsx11_lock();
2068 image = XGetImage( gdi_display, physdev->drawable,
2069 physdev->dc_rect.left + x, physdev->dc_rect.top + y,
2070 width, height, AllPlanes, ZPixmap );
2071 wine_tsx11_unlock();
2072 X11DRV_UnlockDIBSection( physdev, FALSE );
2074 else
2076 Pixmap pixmap;
2078 wine_tsx11_lock();
2079 /* use a temporary pixmap to avoid BadMatch errors */
2080 pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
2081 XCopyArea( gdi_display, physdev->drawable, pixmap, get_bitmap_gc(depth),
2082 physdev->dc_rect.left + x, physdev->dc_rect.top + y, width, height, 0, 0 );
2083 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
2084 XFreePixmap( gdi_display, pixmap );
2085 wine_tsx11_unlock();
2087 if (!image) return ERROR_OUTOFMEMORY;
2089 info->bmiHeader.biWidth = width;
2090 info->bmiHeader.biHeight = -height;
2091 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
2093 src_bits.ptr = image->data;
2094 src_bits.is_copy = TRUE;
2095 ret = copy_image_bits( info, color_shifts, image, &src_bits, bits, src, mapping,
2096 zeropad_masks[(width * image->bits_per_pixel) & 31] );
2098 if (!ret && bits->ptr == image->data)
2100 bits->free = free_ximage_bits;
2101 image->data = NULL;
2103 wine_tsx11_lock();
2104 XDestroyImage( image );
2105 wine_tsx11_unlock();
2106 return ret;