winex11: Add an implementation for the PutImage entry point.
[wine/multimedia.git] / dlls / winex11.drv / bitblt.c
blob21a664c52f5bb25c526b485049e1d403e914b59e
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,TMP,GXnand),
83 OP(TMP,DST,GXand), OP(SRC,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,TMP,GXnand),
91 OP(TMP,DST,GXand), OP(SRC,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,TMP,GXxor),
95 OP(TMP,DST,GXand), OP(SRC,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,TMP,GXand),
111 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
112 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXequiv),
113 OP(TMP,DST,GXor), OP(SRC,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,TMP,GXand),
116 OP(TMP,DST,GXor), OP(SRC,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 BITBLT_TEST /* Opcodes test */
485 static int do_bitop( int s, int d, int rop )
487 int res;
488 switch(rop)
490 case GXclear: res = 0; break;
491 case GXand: res = s & d; break;
492 case GXandReverse: res = s & ~d; break;
493 case GXcopy: res = s; break;
494 case GXandInverted: res = ~s & d; break;
495 case GXnoop: res = d; break;
496 case GXxor: res = s ^ d; break;
497 case GXor: res = s | d; break;
498 case GXnor: res = ~(s | d); break;
499 case GXequiv: res = ~s ^ d; break;
500 case GXinvert: res = ~d; break;
501 case GXorReverse: res = s | ~d; break;
502 case GXcopyInverted: res = ~s; break;
503 case GXorInverted: res = ~s | d; break;
504 case GXnand: res = ~(s & d); break;
505 case GXset: res = 1; break;
507 return res & 1;
510 int main()
512 int rop, i, res, src, dst, pat, tmp, dstUsed;
513 const BYTE *opcode;
515 for (rop = 0; rop < 256; rop++)
517 res = dstUsed = 0;
518 for (i = 0; i < 8; i++)
520 pat = (i >> 2) & 1;
521 src = (i >> 1) & 1;
522 dst = i & 1;
523 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
525 switch(*opcode >> 4)
527 case OP_ARGS(DST,TMP):
528 tmp = do_bitop( dst, tmp, *opcode & 0xf );
529 break;
530 case OP_ARGS(DST,SRC):
531 src = do_bitop( dst, src, *opcode & 0xf );
532 break;
533 case OP_ARGS(SRC,TMP):
534 tmp = do_bitop( src, tmp, *opcode & 0xf );
535 break;
536 case OP_ARGS(SRC,DST):
537 dst = do_bitop( src, dst, *opcode & 0xf );
538 dstUsed = 1;
539 break;
540 case OP_ARGS(PAT,TMP):
541 tmp = do_bitop( pat, tmp, *opcode & 0xf );
542 break;
543 case OP_ARGS(PAT,DST):
544 dst = do_bitop( pat, dst, *opcode & 0xf );
545 dstUsed = 1;
546 break;
547 case OP_ARGS(PAT,SRC):
548 src = do_bitop( pat, src, *opcode & 0xf );
549 break;
550 case OP_ARGS(TMP,DST):
551 dst = do_bitop( tmp, dst, *opcode & 0xf );
552 dstUsed = 1;
553 break;
554 case OP_ARGS(TMP,SRC):
555 src = do_bitop( tmp, src, *opcode & 0xf );
556 break;
557 default:
558 printf( "Invalid opcode %x\n", *opcode );
561 if (!dstUsed) dst = src;
562 if (dst) res |= 1 << i;
564 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
567 return 0;
570 #endif /* BITBLT_TEST */
573 static void get_colors(X11DRV_PDEVICE *physDevDst, X11DRV_PDEVICE *physDevSrc,
574 int *fg, int *bg)
576 RGBQUAD rgb[2];
578 *fg = physDevDst->textPixel;
579 *bg = physDevDst->backgroundPixel;
580 if(physDevSrc->depth == 1) {
581 if(GetDIBColorTable(physDevSrc->dev.hdc, 0, 2, rgb) == 2) {
582 DWORD logcolor;
583 logcolor = RGB(rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue);
584 *fg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
585 logcolor = RGB(rgb[1].rgbRed, rgb[1].rgbGreen,rgb[1].rgbBlue);
586 *bg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
591 /* return a mask for meaningful bits when doing an XGetPixel on an image */
592 static unsigned long image_pixel_mask( X11DRV_PDEVICE *physDev )
594 unsigned long ret;
595 ColorShifts *shifts = physDev->color_shifts;
597 if (!shifts) shifts = &X11DRV_PALETTE_default_shifts;
598 ret = (shifts->physicalRed.max << shifts->physicalRed.shift) |
599 (shifts->physicalGreen.max << shifts->physicalGreen.shift) |
600 (shifts->physicalBlue.max << shifts->physicalBlue.shift);
601 if (!ret) ret = (1 << physDev->depth) - 1;
602 return ret;
606 /***********************************************************************
607 * BITBLT_StretchRow
609 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
611 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
612 INT startDst, INT widthDst,
613 INT xinc, INT xoff, WORD mode )
615 register INT xsrc = xinc * startDst + xoff;
616 rowDst += startDst;
617 switch(mode)
619 case STRETCH_ANDSCANS:
620 for(; widthDst > 0; widthDst--, xsrc += xinc)
621 *rowDst++ &= rowSrc[xsrc >> 16];
622 break;
623 case STRETCH_ORSCANS:
624 for(; widthDst > 0; widthDst--, xsrc += xinc)
625 *rowDst++ |= rowSrc[xsrc >> 16];
626 break;
627 case STRETCH_DELETESCANS:
628 for(; widthDst > 0; widthDst--, xsrc += xinc)
629 *rowDst++ = rowSrc[xsrc >> 16];
630 break;
635 /***********************************************************************
636 * BITBLT_ShrinkRow
638 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
640 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
641 INT startSrc, INT widthSrc,
642 INT xinc, INT xoff, WORD mode )
644 register INT xdst = xinc * startSrc + xoff;
645 rowSrc += startSrc;
646 switch(mode)
648 case STRETCH_ORSCANS:
649 for(; widthSrc > 0; widthSrc--, xdst += xinc)
650 rowDst[xdst >> 16] |= *rowSrc++;
651 break;
652 case STRETCH_ANDSCANS:
653 for(; widthSrc > 0; widthSrc--, xdst += xinc)
654 rowDst[xdst >> 16] &= *rowSrc++;
655 break;
656 case STRETCH_DELETESCANS:
657 for(; widthSrc > 0; widthSrc--, xdst += xinc)
658 rowDst[xdst >> 16] = *rowSrc++;
659 break;
664 /***********************************************************************
665 * BITBLT_GetRow
667 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
669 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
670 INT start, INT width, INT depthDst,
671 int fg, int bg, unsigned long pixel_mask, BOOL swap)
673 register INT i;
675 assert( (row >= 0) && (row < image->height) );
676 assert( (start >= 0) && (width <= image->width) );
678 pdata += swap ? start+width-1 : start;
679 if (image->depth == depthDst) /* color -> color */
681 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
682 if (swap) for (i = 0; i < width; i++)
683 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
684 else for (i = 0; i < width; i++)
685 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
686 else
687 if (swap) for (i = 0; i < width; i++)
688 *pdata-- = XGetPixel( image, i, row );
689 else for (i = 0; i < width; i++)
690 *pdata++ = XGetPixel( image, i, row );
692 else
694 if (image->depth == 1) /* monochrome -> color */
696 if (X11DRV_PALETTE_XPixelToPalette)
698 fg = X11DRV_PALETTE_XPixelToPalette[fg];
699 bg = X11DRV_PALETTE_XPixelToPalette[bg];
701 if (swap) for (i = 0; i < width; i++)
702 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
703 else for (i = 0; i < width; i++)
704 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
706 else /* color -> monochrome */
708 if (swap) for (i = 0; i < width; i++)
709 *pdata-- = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0;
710 else for (i = 0; i < width; i++)
711 *pdata++ = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0;
717 /***********************************************************************
718 * BITBLT_StretchImage
720 * Stretch an X image.
721 * FIXME: does not work for full 32-bit coordinates.
723 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
724 INT widthSrc, INT heightSrc,
725 INT widthDst, INT heightDst,
726 RECT *visRectSrc, RECT *visRectDst,
727 int foreground, int background,
728 unsigned long pixel_mask, WORD mode )
730 int *rowSrc, *rowDst, *pixel;
731 char *pdata;
732 INT xinc, xoff, yinc, ysrc, ydst;
733 register INT x, y;
734 BOOL hstretch, vstretch, hswap, vswap;
736 hswap = widthSrc * widthDst < 0;
737 vswap = heightSrc * heightDst < 0;
738 widthSrc = abs(widthSrc);
739 heightSrc = abs(heightSrc);
740 widthDst = abs(widthDst);
741 heightDst = abs(heightDst);
743 if (!(rowSrc = HeapAlloc( GetProcessHeap(), 0,
744 (widthSrc+widthDst)*sizeof(int) ))) return;
745 rowDst = rowSrc + widthSrc;
747 /* When stretching, all modes are the same, and DELETESCANS is faster */
748 if ((widthSrc < widthDst) && (heightSrc < heightDst))
749 mode = STRETCH_DELETESCANS;
751 if (mode == STRETCH_HALFTONE) /* FIXME */
752 mode = STRETCH_DELETESCANS;
754 if (mode != STRETCH_DELETESCANS)
755 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
756 widthDst*sizeof(int) );
758 hstretch = (widthSrc < widthDst);
759 vstretch = (heightSrc < heightDst);
761 if (hstretch)
763 xinc = (widthSrc << 16) / widthDst;
764 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
766 else
768 xinc = ((int)widthDst << 16) / widthSrc;
769 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
772 wine_tsx11_lock();
773 if (vstretch)
775 yinc = (heightSrc << 16) / heightDst;
776 ydst = visRectDst->top;
777 if (vswap)
779 ysrc = yinc * (heightDst - ydst - 1);
780 yinc = -yinc;
782 else
783 ysrc = yinc * ydst;
785 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
787 if (((ysrc >> 16) < visRectSrc->top) ||
788 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
790 /* Retrieve a source row */
791 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
792 hswap ? widthSrc - visRectSrc->right
793 : visRectSrc->left,
794 visRectSrc->right - visRectSrc->left,
795 dstImage->depth, foreground, background, pixel_mask, hswap );
797 /* Stretch or shrink it */
798 if (hstretch)
799 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
800 visRectDst->right - visRectDst->left,
801 xinc, xoff, mode );
802 else BITBLT_ShrinkRow( rowSrc, rowDst,
803 hswap ? widthSrc - visRectSrc->right
804 : visRectSrc->left,
805 visRectSrc->right - visRectSrc->left,
806 xinc, xoff, mode );
808 /* Store the destination row */
809 pixel = rowDst + visRectDst->right - 1;
810 y = ydst - visRectDst->top;
811 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
812 XPutPixel( dstImage, x, y, *pixel-- );
813 if (mode != STRETCH_DELETESCANS)
814 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
815 widthDst*sizeof(int) );
817 /* Make copies of the destination row */
819 pdata = dstImage->data + dstImage->bytes_per_line * y;
820 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
821 (ydst < visRectDst->bottom-1))
823 memcpy( pdata + dstImage->bytes_per_line, pdata,
824 dstImage->bytes_per_line );
825 pdata += dstImage->bytes_per_line;
826 ysrc += yinc;
827 ydst++;
831 else /* Shrinking */
833 yinc = (heightDst << 16) / heightSrc;
834 ysrc = visRectSrc->top;
835 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
836 if (vswap)
838 ydst += yinc * (heightSrc - ysrc - 1);
839 yinc = -yinc;
841 else
842 ydst += yinc * ysrc;
844 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
846 if (((ydst >> 16) < visRectDst->top) ||
847 ((ydst >> 16) >= visRectDst->bottom)) continue;
849 /* Retrieve a source row */
850 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
851 hswap ? widthSrc - visRectSrc->right
852 : visRectSrc->left,
853 visRectSrc->right - visRectSrc->left,
854 dstImage->depth, foreground, background, pixel_mask, hswap );
856 /* Stretch or shrink it */
857 if (hstretch)
858 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
859 visRectDst->right - visRectDst->left,
860 xinc, xoff, mode );
861 else BITBLT_ShrinkRow( rowSrc, rowDst,
862 hswap ? widthSrc - visRectSrc->right
863 : visRectSrc->left,
864 visRectSrc->right - visRectSrc->left,
865 xinc, xoff, mode );
867 /* Merge several source rows into the destination */
868 if (mode == STRETCH_DELETESCANS)
870 /* Simply skip the overlapping rows */
871 while (((ydst + yinc) >> 16 == ydst >> 16) &&
872 (ysrc < visRectSrc->bottom-1))
874 ydst += yinc;
875 ysrc++;
878 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
879 (ysrc < visRectSrc->bottom-1))
880 continue; /* Restart loop for next overlapping row */
882 /* Store the destination row */
883 pixel = rowDst + visRectDst->right - 1;
884 y = (ydst >> 16) - visRectDst->top;
885 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
886 XPutPixel( dstImage, x, y, *pixel-- );
887 if (mode != STRETCH_DELETESCANS)
888 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
889 widthDst*sizeof(int) );
892 wine_tsx11_unlock();
893 HeapFree( GetProcessHeap(), 0, rowSrc );
897 /***********************************************************************
898 * BITBLT_GetSrcAreaStretch
900 * Retrieve an area from the source DC, stretching and mapping all the
901 * pixels to Windows colors.
903 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
904 Pixmap pixmap, GC gc,
905 const struct bitblt_coords *src, const struct bitblt_coords *dst )
907 XImage *imageSrc, *imageDst;
908 RECT rectSrc = src->visrect;
909 RECT rectDst = dst->visrect;
910 int fg, bg;
912 rectSrc.left -= src->x;
913 rectSrc.right -= src->x;
914 rectSrc.top -= src->y;
915 rectSrc.bottom -= src->y;
916 rectDst.left -= dst->x;
917 rectDst.right -= dst->x;
918 rectDst.top -= dst->y;
919 rectDst.bottom -= dst->y;
920 if (src->width < 0)
922 rectSrc.left -= src->width;
923 rectSrc.right -= src->width;
925 if (dst->width < 0)
927 rectDst.left -= dst->width;
928 rectDst.right -= dst->width;
930 if (src->height < 0)
932 rectSrc.top -= src->height;
933 rectSrc.bottom -= src->height;
935 if (dst->height < 0)
937 rectDst.top -= dst->height;
938 rectDst.bottom -= dst->height;
941 get_colors(physDevDst, physDevSrc, &fg, &bg);
942 wine_tsx11_lock();
943 /* FIXME: avoid BadMatch errors */
944 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
945 physDevSrc->dc_rect.left + src->visrect.left,
946 physDevSrc->dc_rect.top + src->visrect.top,
947 src->visrect.right - src->visrect.left,
948 src->visrect.bottom - src->visrect.top,
949 AllPlanes, ZPixmap );
950 wine_tsx11_unlock();
952 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
953 rectDst.bottom - rectDst.top, physDevDst->depth );
954 BITBLT_StretchImage( imageSrc, imageDst, src->width, src->height,
955 dst->width, dst->height, &rectSrc, &rectDst,
956 fg, physDevDst->depth != 1 ? bg : physDevSrc->backgroundPixel,
957 image_pixel_mask( physDevSrc ), GetStretchBltMode(physDevDst->dev.hdc) );
958 wine_tsx11_lock();
959 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
960 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
961 XDestroyImage( imageSrc );
962 X11DRV_DIB_DestroyXImage( imageDst );
963 wine_tsx11_unlock();
964 return 0; /* no exposure events generated */
968 /***********************************************************************
969 * BITBLT_GetSrcArea
971 * Retrieve an area from the source DC, mapping all the
972 * pixels to Windows colors.
974 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
975 Pixmap pixmap, GC gc, RECT *visRectSrc )
977 XImage *imageSrc, *imageDst;
978 register INT x, y;
979 int exposures = 0;
980 INT width = visRectSrc->right - visRectSrc->left;
981 INT height = visRectSrc->bottom - visRectSrc->top;
982 int fg, bg;
983 BOOL memdc = (GetObjectType(physDevSrc->dev.hdc) == OBJ_MEMDC);
985 if (physDevSrc->depth == physDevDst->depth)
987 wine_tsx11_lock();
988 if (!X11DRV_PALETTE_XPixelToPalette ||
989 (physDevDst->depth == 1)) /* monochrome -> monochrome */
991 if (physDevDst->depth == 1)
993 /* MSDN says if StretchBlt must convert a bitmap from monochrome
994 to color or vice versa, the foreground and background color of
995 the device context are used. In fact, it also applies to the
996 case when it is converted from mono to mono. */
997 XSetBackground( gdi_display, gc, physDevDst->textPixel );
998 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
999 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
1000 physDevSrc->dc_rect.left + visRectSrc->left,
1001 physDevSrc->dc_rect.top + visRectSrc->top,
1002 width, height, 0, 0, 1);
1004 else
1005 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
1006 physDevSrc->dc_rect.left + visRectSrc->left,
1007 physDevSrc->dc_rect.top + visRectSrc->top,
1008 width, height, 0, 0);
1009 exposures++;
1011 else /* color -> color */
1013 if (memdc)
1014 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1015 physDevSrc->dc_rect.left + visRectSrc->left,
1016 physDevSrc->dc_rect.top + visRectSrc->top,
1017 width, height, AllPlanes, ZPixmap );
1018 else
1020 /* Make sure we don't get a BadMatch error */
1021 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
1022 physDevSrc->dc_rect.left + visRectSrc->left,
1023 physDevSrc->dc_rect.top + visRectSrc->top,
1024 width, height, 0, 0);
1025 exposures++;
1026 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1027 AllPlanes, ZPixmap );
1029 for (y = 0; y < height; y++)
1030 for (x = 0; x < width; x++)
1031 XPutPixel(imageSrc, x, y,
1032 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
1033 XPutImage( gdi_display, pixmap, gc, imageSrc,
1034 0, 0, 0, 0, width, height );
1035 XDestroyImage( imageSrc );
1037 wine_tsx11_unlock();
1039 else
1041 if (physDevSrc->depth == 1) /* monochrome -> color */
1043 get_colors(physDevDst, physDevSrc, &fg, &bg);
1045 wine_tsx11_lock();
1046 if (X11DRV_PALETTE_XPixelToPalette)
1048 XSetBackground( gdi_display, gc,
1049 X11DRV_PALETTE_XPixelToPalette[fg] );
1050 XSetForeground( gdi_display, gc,
1051 X11DRV_PALETTE_XPixelToPalette[bg]);
1053 else
1055 XSetBackground( gdi_display, gc, fg );
1056 XSetForeground( gdi_display, gc, bg );
1058 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
1059 physDevSrc->dc_rect.left + visRectSrc->left,
1060 physDevSrc->dc_rect.top + visRectSrc->top,
1061 width, height, 0, 0, 1 );
1062 exposures++;
1063 wine_tsx11_unlock();
1065 else /* color -> monochrome */
1067 unsigned long pixel_mask;
1068 wine_tsx11_lock();
1069 /* FIXME: avoid BadMatch error */
1070 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1071 physDevSrc->dc_rect.left + visRectSrc->left,
1072 physDevSrc->dc_rect.top + visRectSrc->top,
1073 width, height, AllPlanes, ZPixmap );
1074 if (!imageSrc)
1076 wine_tsx11_unlock();
1077 return exposures;
1079 imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1080 if (!imageDst)
1082 XDestroyImage(imageSrc);
1083 wine_tsx11_unlock();
1084 return exposures;
1086 pixel_mask = image_pixel_mask( physDevSrc );
1087 for (y = 0; y < height; y++)
1088 for (x = 0; x < width; x++)
1089 XPutPixel(imageDst, x, y,
1090 !((XGetPixel(imageSrc,x,y) ^ physDevSrc->backgroundPixel) & pixel_mask));
1091 XPutImage( gdi_display, pixmap, gc, imageDst,
1092 0, 0, 0, 0, width, height );
1093 XDestroyImage( imageSrc );
1094 X11DRV_DIB_DestroyXImage( imageDst );
1095 wine_tsx11_unlock();
1098 return exposures;
1102 /***********************************************************************
1103 * BITBLT_GetDstArea
1105 * Retrieve an area from the destination DC, mapping all the
1106 * pixels to Windows colors.
1108 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1110 int exposures = 0;
1111 INT width = visRectDst->right - visRectDst->left;
1112 INT height = visRectDst->bottom - visRectDst->top;
1113 BOOL memdc = (GetObjectType( physDev->dev.hdc ) == OBJ_MEMDC);
1115 wine_tsx11_lock();
1117 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1118 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1120 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1121 physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
1122 width, height, 0, 0 );
1123 exposures++;
1125 else
1127 register INT x, y;
1128 XImage *image;
1130 if (memdc)
1131 image = XGetImage( gdi_display, physDev->drawable,
1132 physDev->dc_rect.left + visRectDst->left,
1133 physDev->dc_rect.top + visRectDst->top,
1134 width, height, AllPlanes, ZPixmap );
1135 else
1137 /* Make sure we don't get a BadMatch error */
1138 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1139 physDev->dc_rect.left + visRectDst->left,
1140 physDev->dc_rect.top + visRectDst->top,
1141 width, height, 0, 0);
1142 exposures++;
1143 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1144 AllPlanes, ZPixmap );
1146 if (image)
1148 for (y = 0; y < height; y++)
1149 for (x = 0; x < width; x++)
1150 XPutPixel( image, x, y,
1151 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1152 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1153 XDestroyImage( image );
1157 wine_tsx11_unlock();
1158 return exposures;
1162 /***********************************************************************
1163 * BITBLT_PutDstArea
1165 * Put an area back into the destination DC, mapping the pixel
1166 * colors to X pixels.
1168 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1170 int exposures = 0;
1171 INT width = visRectDst->right - visRectDst->left;
1172 INT height = visRectDst->bottom - visRectDst->top;
1174 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1176 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1177 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1179 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1180 physDev->dc_rect.left + visRectDst->left,
1181 physDev->dc_rect.top + visRectDst->top );
1182 exposures++;
1184 else
1186 register INT x, y;
1187 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1188 AllPlanes, ZPixmap );
1189 for (y = 0; y < height; y++)
1190 for (x = 0; x < width; x++)
1192 XPutPixel( image, x, y,
1193 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1195 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1196 physDev->dc_rect.left + visRectDst->left,
1197 physDev->dc_rect.top + visRectDst->top, width, height );
1198 XDestroyImage( image );
1200 return exposures;
1204 /***********************************************************************
1205 * client_side_dib_copy
1207 static BOOL client_side_dib_copy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1208 X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1209 INT width, INT height )
1211 DIBSECTION srcDib, dstDib;
1212 BYTE *srcPtr, *dstPtr;
1213 INT srcRowOffset, dstRowOffset;
1214 INT bytesPerPixel;
1215 INT bytesToCopy;
1216 INT y;
1217 static RECT unusedRect;
1219 if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib))
1220 return FALSE;
1221 if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib))
1222 return FALSE;
1224 /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */
1225 if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight)
1226 return FALSE;
1227 if (xSrc + width > srcDib.dsBm.bmWidth)
1228 width = srcDib.dsBm.bmWidth - xSrc;
1229 if (ySrc + height > srcDib.dsBm.bmHeight)
1230 height = srcDib.dsBm.bmHeight - ySrc;
1232 if (GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION)
1234 /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */
1235 FIXME("potential optimization: client-side complex region clipping\n");
1236 return FALSE;
1238 if (dstDib.dsBm.bmBitsPixel <= 8)
1240 static BOOL fixme_once;
1241 if(!fixme_once++) FIXME("potential optimization: client-side color-index mode DIB copy\n");
1242 return FALSE;
1244 if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1245 dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1246 !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1247 && !(srcDib.dsBmih.biCompression == BI_RGB &&
1248 dstDib.dsBmih.biCompression == BI_RGB))
1250 FIXME("potential optimization: client-side compressed DIB copy\n");
1251 return FALSE;
1253 if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1255 FIXME("potential optimization: pixel format conversion\n");
1256 return FALSE;
1258 if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1260 FIXME("negative widths not yet implemented\n");
1261 return FALSE;
1264 switch (dstDib.dsBm.bmBitsPixel)
1266 case 15:
1267 case 16:
1268 bytesPerPixel = 2;
1269 break;
1270 case 24:
1271 bytesPerPixel = 3;
1272 break;
1273 case 32:
1274 bytesPerPixel = 4;
1275 break;
1276 default:
1277 FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1278 return FALSE;
1281 bytesToCopy = width * bytesPerPixel;
1283 if (physDevSrc->bitmap->topdown)
1285 srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1286 srcRowOffset = srcDib.dsBm.bmWidthBytes;
1288 else
1290 srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1291 + xSrc*bytesPerPixel];
1292 srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1294 if (physDevDst->bitmap->topdown)
1296 dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1297 dstRowOffset = dstDib.dsBm.bmWidthBytes;
1299 else
1301 dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1302 + xDst*bytesPerPixel];
1303 dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1306 /* Handle overlapping regions on the same DIB */
1307 if (physDevSrc == physDevDst && ySrc < yDst)
1309 srcPtr += srcRowOffset * (height - 1);
1310 srcRowOffset = -srcRowOffset;
1311 dstPtr += dstRowOffset * (height - 1);
1312 dstRowOffset = -dstRowOffset;
1315 for (y = yDst; y < yDst + height; ++y)
1317 memmove(dstPtr, srcPtr, bytesToCopy);
1318 srcPtr += srcRowOffset;
1319 dstPtr += dstRowOffset;
1322 return TRUE;
1325 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
1327 if (physDevSrc->depth != physDevDst->depth) return FALSE;
1328 if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
1329 if (physDevSrc->color_shifts && physDevDst->color_shifts)
1330 return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
1331 return FALSE;
1334 /***********************************************************************
1335 * X11DRV_PatBlt
1337 BOOL X11DRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
1339 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
1340 BOOL usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1341 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1343 if (IsRectEmpty( &dst->visrect )) return TRUE;
1344 if (usePat && !X11DRV_SetupGCForBrush( physDev )) return TRUE;
1346 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1348 wine_tsx11_lock();
1349 XSetFunction( gdi_display, physDev->gc, OP_ROP(*opcode) );
1351 switch(rop) /* a few special cases */
1353 case BLACKNESS: /* 0x00 */
1354 case WHITENESS: /* 0xff */
1355 if ((physDev->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
1357 XSetFunction( gdi_display, physDev->gc, GXcopy );
1358 if (rop == BLACKNESS)
1359 XSetForeground( gdi_display, physDev->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1360 else
1361 XSetForeground( gdi_display, physDev->gc,
1362 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1363 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
1365 break;
1366 case DSTINVERT: /* 0x55 */
1367 if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
1369 /* Xor is much better when we do not have full colormap. */
1370 /* Using white^black ensures that we invert at least black */
1371 /* and white. */
1372 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1373 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1374 XSetFunction( gdi_display, physDev->gc, GXxor );
1375 XSetForeground( gdi_display, physDev->gc, xor_pix);
1376 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
1378 break;
1380 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
1381 physDev->dc_rect.left + dst->visrect.left,
1382 physDev->dc_rect.top + dst->visrect.top,
1383 dst->visrect.right - dst->visrect.left,
1384 dst->visrect.bottom - dst->visrect.top );
1385 wine_tsx11_unlock();
1387 X11DRV_UnlockDIBSection( physDev, TRUE );
1388 return TRUE;
1392 /***********************************************************************
1393 * X11DRV_StretchBlt
1395 BOOL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
1396 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
1398 X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
1399 X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev ); /* FIXME: check that it's really an x11 dev */
1400 BOOL usePat, useDst, destUsed, fStretch, fNullBrush;
1401 INT width, height;
1402 INT sDst, sSrc = DIB_Status_None;
1403 const BYTE *opcode;
1404 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1405 GC tmpGC = 0;
1407 if (IsRectEmpty( &dst->visrect )) return TRUE;
1409 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1410 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1411 fStretch = (src->width != dst->width) || (src->height != dst->height);
1413 if (physDevDst != physDevSrc)
1414 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None );
1416 width = dst->visrect.right - dst->visrect.left;
1417 height = dst->visrect.bottom - dst->visrect.top;
1419 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None );
1420 if (physDevDst == physDevSrc) sSrc = sDst;
1422 /* try client-side DIB copy */
1423 if (!fStretch && rop == SRCCOPY &&
1424 sSrc == DIB_Status_AppMod && sDst == DIB_Status_AppMod &&
1425 same_format(physDevSrc, physDevDst))
1427 if (client_side_dib_copy( physDevSrc, src->visrect.left, src->visrect.top,
1428 physDevDst, dst->visrect.left, dst->visrect.top, width, height ))
1429 goto done;
1432 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod );
1434 opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1436 /* a few optimizations for single-op ROPs */
1437 if (!fStretch && !opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1439 if (same_format(physDevSrc, physDevDst))
1441 wine_tsx11_lock();
1442 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1443 wine_tsx11_unlock();
1445 if (physDevSrc != physDevDst)
1447 if (sSrc == DIB_Status_AppMod)
1449 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, src->visrect.left, src->visrect.top,
1450 dst->visrect.left, dst->visrect.top, width, height );
1451 goto done;
1453 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1455 wine_tsx11_lock();
1456 XCopyArea( gdi_display, physDevSrc->drawable,
1457 physDevDst->drawable, physDevDst->gc,
1458 physDevSrc->dc_rect.left + src->visrect.left,
1459 physDevSrc->dc_rect.top + src->visrect.top,
1460 width, height,
1461 physDevDst->dc_rect.left + dst->visrect.left,
1462 physDevDst->dc_rect.top + dst->visrect.top );
1463 physDevDst->exposures++;
1464 wine_tsx11_unlock();
1465 goto done;
1467 if (physDevSrc->depth == 1)
1469 int fg, bg;
1471 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1472 get_colors(physDevDst, physDevSrc, &fg, &bg);
1473 wine_tsx11_lock();
1474 XSetBackground( gdi_display, physDevDst->gc, fg );
1475 XSetForeground( gdi_display, physDevDst->gc, bg );
1476 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1477 XCopyPlane( gdi_display, physDevSrc->drawable,
1478 physDevDst->drawable, physDevDst->gc,
1479 physDevSrc->dc_rect.left + src->visrect.left,
1480 physDevSrc->dc_rect.top + src->visrect.top,
1481 width, height,
1482 physDevDst->dc_rect.left + dst->visrect.left,
1483 physDevDst->dc_rect.top + dst->visrect.top, 1 );
1484 physDevDst->exposures++;
1485 wine_tsx11_unlock();
1486 goto done;
1490 wine_tsx11_lock();
1491 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1492 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1493 XSetGraphicsExposures( gdi_display, tmpGC, False );
1494 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1495 physDevDst->depth );
1496 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1497 physDevDst->depth );
1498 wine_tsx11_unlock();
1500 if (physDevDst != physDevSrc) X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1502 if(!X11DRV_XRender_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, src, dst ))
1504 if (fStretch)
1505 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, src, dst );
1506 else
1507 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, &src->visrect );
1510 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &dst->visrect );
1511 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1512 else fNullBrush = FALSE;
1513 destUsed = FALSE;
1515 wine_tsx11_lock();
1516 for ( ; *opcode; opcode++)
1518 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1519 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1520 switch(OP_SRCDST(*opcode))
1522 case OP_ARGS(DST,TMP):
1523 case OP_ARGS(SRC,TMP):
1524 if (!pixmaps[TMP])
1525 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1526 width, height, physDevDst->depth );
1527 /* fall through */
1528 case OP_ARGS(DST,SRC):
1529 case OP_ARGS(SRC,DST):
1530 case OP_ARGS(TMP,SRC):
1531 case OP_ARGS(TMP,DST):
1532 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1533 pixmaps[OP_DST(*opcode)], tmpGC,
1534 0, 0, width, height, 0, 0 );
1535 break;
1537 case OP_ARGS(PAT,TMP):
1538 if (!pixmaps[TMP] && !fNullBrush)
1539 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1540 width, height, physDevDst->depth );
1541 /* fall through */
1542 case OP_ARGS(PAT,DST):
1543 case OP_ARGS(PAT,SRC):
1544 if (!fNullBrush)
1545 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1546 tmpGC, 0, 0, width, height );
1547 break;
1550 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1551 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC], &dst->visrect );
1552 XFreePixmap( gdi_display, pixmaps[DST] );
1553 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1554 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1555 XFreeGC( gdi_display, tmpGC );
1556 wine_tsx11_unlock();
1558 done:
1559 if (physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1560 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1561 return TRUE;
1565 /***********************************************************************
1566 * X11DRV_AlphaBlend
1568 BOOL X11DRV_AlphaBlend( PHYSDEV dst_dev, struct bitblt_coords *dst,
1569 PHYSDEV src_dev, struct bitblt_coords *src, BLENDFUNCTION blendfn )
1571 X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
1572 X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev ); /* FIXME: check that it's really an x11 dev */
1574 if (src->x < 0 || src->y < 0 || src->width < 0 || src->height < 0 ||
1575 src->width > physDevSrc->drawable_rect.right - physDevSrc->drawable_rect.left - src->x ||
1576 src->height > physDevSrc->drawable_rect.bottom - physDevSrc->drawable_rect.top - src->y)
1578 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src->x, src->y, src->width, src->height );
1579 SetLastError( ERROR_INVALID_PARAMETER );
1580 return FALSE;
1582 if (IsRectEmpty( &dst->visrect )) return TRUE;
1584 return XRender_AlphaBlend( physDevDst, dst, physDevSrc, src, blendfn );
1588 static void free_heap_bits( struct gdi_image_bits *bits )
1590 HeapFree( GetProcessHeap(), 0, bits->ptr );
1593 static void free_ximage_bits( struct gdi_image_bits *bits )
1595 wine_tsx11_lock();
1596 XFree( bits->ptr );
1597 wine_tsx11_unlock();
1600 /* store the palette or color mask data in the bitmap info structure */
1601 static void set_color_info( const ColorShifts *color_shifts, BITMAPINFO *info )
1603 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1605 switch (info->bmiHeader.biBitCount)
1607 case 1:
1608 case 4:
1609 case 8:
1610 info->bmiHeader.biCompression = BI_RGB;
1611 /* FIXME: set color palette */
1612 break;
1613 case 16:
1614 case 32:
1615 info->bmiHeader.biCompression = BI_BITFIELDS;
1616 colors[0] = color_shifts->logicalRed.max << color_shifts->logicalRed.shift;
1617 colors[1] = color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift;
1618 colors[2] = color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift;
1619 break;
1620 case 24:
1621 info->bmiHeader.biCompression = BI_RGB;
1622 break;
1626 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1627 static DWORD copy_image_bits( BITMAPINFO *info, const ColorShifts *color_shifts, XImage *image,
1628 const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits )
1630 BOOL need_byteswap;
1631 int x, y, height = -info->bmiHeader.biHeight;
1632 unsigned int width_bytes = image->bytes_per_line;
1633 unsigned char *src, *dst;
1635 switch (info->bmiHeader.biBitCount)
1637 case 1:
1638 need_byteswap = (image->bitmap_bit_order != MSBFirst);
1639 break;
1640 case 4:
1641 need_byteswap = (image->byte_order != MSBFirst);
1642 break;
1643 case 16:
1644 case 32:
1645 need_byteswap = (image->byte_order != LSBFirst);
1646 break;
1647 case 24:
1648 need_byteswap = ((image->byte_order == LSBFirst && color_shifts->logicalBlue.shift == 16) ||
1649 (image->byte_order == MSBFirst && color_shifts->logicalBlue.shift == 0));
1650 break;
1651 default:
1652 need_byteswap = FALSE;
1653 break;
1656 if ((need_byteswap && !src_bits->is_copy) || (width_bytes & 3))
1658 width_bytes = (width_bytes + 3) & ~3;
1659 info->bmiHeader.biSizeImage = height * width_bytes;
1660 if (!(dst_bits->ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
1661 return ERROR_OUTOFMEMORY;
1662 dst_bits->offset = src_bits->offset;
1663 dst_bits->is_copy = TRUE;
1664 dst_bits->free = free_heap_bits;
1666 else
1668 /* swap bits in place */
1669 dst_bits->ptr = src_bits->ptr;
1670 dst_bits->offset = src_bits->offset;
1671 dst_bits->is_copy = src_bits->is_copy;
1672 dst_bits->free = NULL;
1673 if (!need_byteswap) return ERROR_SUCCESS; /* nothing to do */
1676 src = src_bits->ptr;
1677 dst = dst_bits->ptr;
1679 if (need_byteswap)
1681 switch (info->bmiHeader.biBitCount)
1683 case 1:
1684 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1685 for (x = 0; x < image->bytes_per_line; x++)
1686 dst[x] = bit_swap[src[x]];
1687 break;
1688 case 4:
1689 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1690 for (x = 0; x < image->bytes_per_line; x++)
1691 dst[x] = (src[x] << 4) | (src[x] >> 4);
1692 break;
1693 case 16:
1694 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1695 for (x = 0; x < info->bmiHeader.biWidth; x++)
1696 ((USHORT *)dst)[x] = RtlUshortByteSwap( ((const USHORT *)src)[x] );
1697 break;
1698 case 24:
1699 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1700 for (x = 0; x < info->bmiHeader.biWidth; x++)
1702 unsigned char tmp = src[3 * x];
1703 dst[3 * x] = src[3 * x + 2];
1704 dst[3 * x + 1] = src[3 * x + 1];
1705 dst[3 * x + 2] = tmp;
1707 break;
1708 case 32:
1709 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1710 for (x = 0; x < info->bmiHeader.biWidth; x++)
1711 ((ULONG *)dst)[x] = RtlUlongByteSwap( ((const ULONG *)src)[x] );
1712 break;
1715 else
1717 for (y = 0; y < height; y++, src += image->bytes_per_line, dst += width_bytes)
1718 memcpy( dst, src, image->bytes_per_line );
1720 return ERROR_SUCCESS;
1723 /***********************************************************************
1724 * X11DRV_PutImage
1726 DWORD X11DRV_PutImage( PHYSDEV dev, HBITMAP hbitmap, BITMAPINFO *info, const struct gdi_image_bits *bits,
1727 const RECT *rect, DWORD rop )
1729 X11DRV_PDEVICE *physdev;
1730 X_PHYSBITMAP *bitmap;
1731 DWORD ret = ERROR_SUCCESS;
1732 XImage *image;
1733 int depth;
1734 struct gdi_image_bits dst_bits;
1735 const XPixmapFormatValues *format;
1736 const ColorShifts *color_shifts;
1738 if (hbitmap)
1740 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
1741 physdev = NULL;
1742 depth = bitmap->pixmap_depth;
1743 color_shifts = &bitmap->pixmap_color_shifts;
1745 else
1747 physdev = get_x11drv_dev( dev );
1748 bitmap = NULL;
1749 depth = physdev->depth;
1750 color_shifts = physdev->color_shifts;
1752 format = pixmap_formats[depth];
1754 if (info->bmiHeader.biPlanes != 1) goto update_format;
1755 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1756 if (info->bmiHeader.biHeight > 0) goto update_format; /* bottom-up not supported */
1758 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1760 DWORD *masks = (DWORD *)((char *)info + info->bmiHeader.biSize);
1761 if (color_shifts->logicalRed.max << color_shifts->logicalRed.shift != masks[0] ||
1762 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift != masks[1] ||
1763 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift != masks[2])
1764 goto update_format;
1766 else if (info->bmiHeader.biCompression == BI_RGB)
1768 switch (info->bmiHeader.biBitCount)
1770 case 16:
1771 if (color_shifts->logicalRed.max << color_shifts->logicalRed.shift != 0x7c00 ||
1772 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift != 0x03e0 ||
1773 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift != 0x001f)
1774 goto update_format;
1775 break;
1776 case 24:
1777 case 32:
1778 if (color_shifts->logicalRed.max << color_shifts->logicalRed.shift != 0xff0000 ||
1779 color_shifts->logicalGreen.max << color_shifts->logicalGreen.shift != 0x00ff00 ||
1780 color_shifts->logicalBlue.max << color_shifts->logicalBlue.shift != 0x0000ff)
1781 goto update_format;
1782 break;
1785 else goto update_format;
1787 if (!bits) return ret; /* just querying the format */
1789 wine_tsx11_lock();
1790 image = XCreateImage( gdi_display, visual, depth, ZPixmap, 0, NULL,
1791 info->bmiHeader.biWidth, -info->bmiHeader.biHeight, 32, 0 );
1792 wine_tsx11_unlock();
1793 if (!image) return ERROR_OUTOFMEMORY;
1795 ret = copy_image_bits( info, color_shifts, image, bits, &dst_bits );
1797 if (!ret)
1799 image->data = dst_bits.ptr;
1800 if (bitmap)
1802 wine_tsx11_lock();
1803 XPutImage( gdi_display, bitmap->pixmap, get_bitmap_gc(depth), image, dst_bits.offset, 0,
1804 rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top );
1805 wine_tsx11_unlock();
1807 else
1809 /* FIXME: copy rop handling from BitBlt here */
1810 X11DRV_LockDIBSection( physdev, DIB_Status_GdiMod );
1811 wine_tsx11_lock();
1812 XPutImage( gdi_display, physdev->drawable, physdev->gc, image, dst_bits.offset, 0,
1813 physdev->dc_rect.left + rect->left, physdev->dc_rect.top + rect->top,
1814 rect->right - rect->left, rect->bottom - rect->top );
1815 wine_tsx11_unlock();
1816 X11DRV_UnlockDIBSection( physdev, !ret );
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( physdev->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, const RECT *rect )
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;
1851 if (hbitmap)
1853 if (!(bitmap = X11DRV_get_phys_bitmap( hbitmap ))) return ERROR_INVALID_HANDLE;
1854 physdev = NULL;
1855 depth = bitmap->pixmap_depth;
1856 color_shifts = &bitmap->pixmap_color_shifts;
1858 else
1860 physdev = get_x11drv_dev( dev );
1861 bitmap = NULL;
1862 depth = physdev->depth;
1863 color_shifts = physdev->color_shifts;
1865 format = pixmap_formats[depth];
1867 /* align start and width to 32-bit boundary */
1868 switch (format->bits_per_pixel)
1870 case 1: align = 32; break;
1871 case 4: align = 8; break;
1872 case 8: align = 4; break;
1873 case 16: align = 2; break;
1874 case 24: align = 4; break;
1875 case 32: align = 1; break;
1876 default:
1877 FIXME( "depth %u bpp %u not supported yet\n", depth, format->bits_per_pixel );
1878 return ERROR_BAD_FORMAT;
1880 src_bits.offset = rect->left & (align - 1);
1881 x = rect->left - src_bits.offset;
1882 y = rect->top;
1883 width = rect->right - x;
1884 height = rect->bottom - rect->top;
1885 if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1);
1887 if (bitmap)
1889 BITMAP bm;
1890 GetObjectW( hbitmap, sizeof(bm), &bm );
1891 width = min( width, bm.bmWidth - x );
1892 height = min( height, bm.bmHeight - y );
1893 wine_tsx11_lock();
1894 image = XGetImage( gdi_display, bitmap->pixmap, x, y, width, height, AllPlanes, ZPixmap );
1895 wine_tsx11_unlock();
1897 else if (GetObjectType( dev->hdc ) == OBJ_MEMDC)
1899 X11DRV_LockDIBSection( physdev, DIB_Status_GdiMod );
1900 width = min( width, physdev->dc_rect.right - physdev->dc_rect.left - x );
1901 height = min( height, physdev->dc_rect.bottom - physdev->dc_rect.top - y );
1902 wine_tsx11_lock();
1903 image = XGetImage( gdi_display, physdev->drawable,
1904 physdev->dc_rect.left + x, physdev->dc_rect.top + y,
1905 width, height, AllPlanes, ZPixmap );
1906 wine_tsx11_unlock();
1907 X11DRV_UnlockDIBSection( physdev, FALSE );
1909 else
1911 Pixmap pixmap;
1913 wine_tsx11_lock();
1914 /* use a temporary pixmap to avoid BadMatch errors */
1915 pixmap = XCreatePixmap( gdi_display, root_window, width, height, depth );
1916 XCopyArea( gdi_display, physdev->drawable, pixmap, get_bitmap_gc(depth),
1917 physdev->dc_rect.left + x, physdev->dc_rect.top + y, width, height, 0, 0 );
1918 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1919 XFreePixmap( gdi_display, pixmap );
1920 wine_tsx11_unlock();
1922 if (!image) return ERROR_OUTOFMEMORY;
1924 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1925 info->bmiHeader.biWidth = width;
1926 info->bmiHeader.biHeight = -height;
1927 info->bmiHeader.biPlanes = 1;
1928 info->bmiHeader.biBitCount = image->bits_per_pixel;
1929 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1930 info->bmiHeader.biXPelsPerMeter = 0;
1931 info->bmiHeader.biYPelsPerMeter = 0;
1932 info->bmiHeader.biClrUsed = 0;
1933 info->bmiHeader.biClrImportant = 0;
1934 set_color_info( color_shifts, info );
1936 src_bits.ptr = image->data;
1937 src_bits.is_copy = TRUE;
1938 ret = copy_image_bits( info, color_shifts, image, &src_bits, bits );
1940 if (!ret && bits->ptr == image->data)
1942 bits->free = free_ximage_bits;
1943 image->data = NULL;
1945 wine_tsx11_lock();
1946 XDestroyImage( image );
1947 wine_tsx11_unlock();
1948 return ret;