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
30 #include <X11/Xresource.h>
31 #include <X11/Xutil.h>
32 #ifdef HAVE_X11_EXTENSIONS_SHAPE_H
33 #include <X11/extensions/shape.h>
35 #ifdef HAVE_X11_EXTENSIONS_XSHM_H
36 # include <X11/extensions/XShm.h>
37 # ifdef HAVE_SYS_SHM_H
40 # ifdef HAVE_SYS_IPC_H
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
56 #define DST 0 /* Destination drawable */
57 #define SRC 1 /* Source drawable */
58 #define TMP 2 /* Temporary drawable */
59 #define PAT 3 /* Pattern (brush) in destination DC */
61 #define OP(src,dst,rop) (OP_ARGS(src,dst) << 4 | (rop))
62 #define OP_ARGS(src,dst) (((src) << 2) | (dst))
64 #define OP_SRC(opcode) ((opcode) >> 6)
65 #define OP_DST(opcode) (((opcode) >> 4) & 3)
66 #define OP_SRCDST(opcode) ((opcode) >> 4)
67 #define OP_ROP(opcode) ((opcode) & 0x0f)
69 #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */
71 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
73 { OP(PAT,DST,GXclear) }, /* 0x00 0 */
74 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */
75 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */
76 { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */
77 { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */
78 { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */
79 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */
80 { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */
81 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */
82 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */
83 { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */
84 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */
85 { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */
86 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */
87 { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */
88 { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */
89 { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */
90 { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */
91 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */
92 { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */
93 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */
94 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */
95 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
96 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
97 OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */
98 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
99 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
100 OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/
101 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
102 OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */
103 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
104 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */
105 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
106 OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */
107 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
108 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */
109 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
110 OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */
111 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
112 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */
113 { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */
114 { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */
115 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */
116 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */
117 { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */
118 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */
119 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
120 OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */
121 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
122 OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */
123 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
124 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
125 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXequiv),
126 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */
127 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */
128 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
129 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
130 OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */
131 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */
132 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
133 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
134 OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/
135 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
136 OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */
137 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */
138 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
139 OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */
140 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */
141 { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */
142 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */
143 { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
144 OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */
145 { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */
146 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
147 OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */
148 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
149 OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */
150 { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */
151 { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */
152 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
153 OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */
154 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */
155 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
156 OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */
157 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */
158 { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */
159 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
160 OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */
161 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
162 OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */
163 { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */
164 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */
165 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */
166 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
167 OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */
168 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
169 OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */
170 { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */
171 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */
172 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
173 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */
174 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
175 OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */
176 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */
177 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
178 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
179 OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */
180 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
181 OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */
182 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */
183 { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */
184 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
185 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
186 OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/
187 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
188 OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */
189 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */
190 { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */
191 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */
192 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
193 OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */
194 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
195 OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */
196 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */
197 { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */
198 { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */
199 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */
200 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
201 OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */
202 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */
203 { OP(PAT,DST,GXxor) }, /* 0x5a D^P */
204 { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
205 OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */
206 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
207 OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */
208 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */
209 { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
210 OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */
211 { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */
212 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */
213 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
214 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
215 OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */
216 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
217 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */
218 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */
219 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
220 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */
221 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */
222 { OP(SRC,DST,GXxor) }, /* 0x66 S^D */
223 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
224 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */
225 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
226 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
227 OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/
228 { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */
229 { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */
230 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
231 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
232 OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */
233 { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */
234 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
235 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
236 OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */
237 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
238 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */
239 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */
240 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */
241 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
242 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
243 OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/
244 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
245 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */
246 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */
247 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
248 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */
249 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */
250 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
251 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */
252 { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */
253 { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */
254 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
255 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
256 OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */
257 { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
258 OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */
259 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */
260 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
261 OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */
262 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */
263 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
264 OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */
265 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */
266 { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */
267 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
268 OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */
269 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */
270 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
271 OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */
272 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */
273 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
274 OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */
275 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
276 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
277 OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */
278 { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */
279 { OP(SRC,DST,GXand) }, /* 0x88 S&D */
280 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
281 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */
282 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */
283 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
284 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */
285 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */
286 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
287 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */
288 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
289 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
290 OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/
291 { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */
292 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */
293 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
294 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */
295 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
296 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
297 OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */
298 { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */
299 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
300 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
301 OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */
302 { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */
303 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */
304 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
305 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
306 OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */
307 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
308 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */
309 { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */
310 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */
311 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
312 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */
313 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */
314 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
315 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */
316 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
317 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
318 OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */
319 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */
320 { OP(PAT,DST,GXand) }, /* 0xa0 D&P */
321 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
322 OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */
323 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */
324 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
325 OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */
326 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
327 OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */
328 { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */
329 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */
330 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
331 OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */
332 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */
333 { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */
334 { OP(PAT,DST,GXnoop) }, /* 0xaa D */
335 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */
336 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
337 OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */
338 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
339 OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */
340 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */
341 { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */
342 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */
343 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
344 OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */
345 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
346 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
347 OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/
348 { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */
349 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */
350 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
351 OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */
352 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
353 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
354 OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */
355 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */
356 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
357 OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */
358 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
359 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */
360 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */
361 { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */
362 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
363 OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */
364 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
365 OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */
366 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */
367 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */
368 { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */
369 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
370 OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */
371 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
372 OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */
373 { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */
374 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */
375 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
376 OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */
377 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */
378 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
379 OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */
380 { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */
381 { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */
382 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
383 OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */
384 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
385 OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */
386 { OP(SRC,DST,GXcopy) }, /* 0xcc S */
387 { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */
388 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */
389 { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */
390 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */
391 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
392 OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */
393 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */
394 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
395 OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */
396 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
397 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
398 OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/
399 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */
400 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
401 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
402 OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */
403 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */
404 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
405 OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */
406 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
407 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */
408 { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
409 OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */
410 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
411 OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */
412 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */
413 { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */
414 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */
415 { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */
416 { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */
417 { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */
418 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
419 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */
420 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
421 OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */
422 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
423 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */
424 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
425 OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */
426 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
427 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */
428 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
429 OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */
430 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
431 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
432 OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/
433 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
434 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
435 OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/
436 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */
437 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */
438 { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */
439 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */
440 { OP(SRC,DST,GXor) }, /* 0xee S|D */
441 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */
442 { OP(PAT,DST,GXcopy) }, /* 0xf0 P */
443 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */
444 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */
445 { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */
446 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */
447 { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */
448 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */
449 { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */
450 { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */
451 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */
452 { OP(PAT,DST,GXor) }, /* 0xfa D|P */
453 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */
454 { OP(PAT,SRC,GXor) }, /* 0xfc P|S */
455 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */
456 { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */
457 { OP(PAT,DST,GXset) } /* 0xff 1 */
460 static const unsigned char bit_swap[256] =
462 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
463 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
464 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
465 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
466 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
467 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
468 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
469 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
470 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
471 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
472 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
473 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
474 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
475 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
476 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
477 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
478 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
479 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
480 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
481 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
482 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
483 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
484 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
485 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
486 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
487 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
488 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
489 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
490 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
491 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
492 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
493 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
496 #ifdef WORDS_BIGENDIAN
497 static const unsigned int zeropad_masks[32] =
499 0xffffffff, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000, 0xfc000000, 0xfe000000,
500 0xff000000, 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000,
501 0xffff0000, 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
502 0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8, 0xfffffffc, 0xfffffffe
505 static const unsigned int zeropad_masks[32] =
507 0xffffffff, 0x00000080, 0x000000c0, 0x000000e0, 0x000000f0, 0x000000f8, 0x000000fc, 0x000000fe,
508 0x000000ff, 0x000080ff, 0x0000c0ff, 0x0000e0ff, 0x0000f0ff, 0x0000f8ff, 0x0000fcff, 0x0000feff,
509 0x0000ffff, 0x0080ffff, 0x00c0ffff, 0x00e0ffff, 0x00f0ffff, 0x00f8ffff, 0x00fcffff, 0x00feffff,
510 0x00ffffff, 0x80ffffff, 0xc0ffffff, 0xe0ffffff, 0xf0ffffff, 0xf8ffffff, 0xfcffffff, 0xfeffffff
514 #ifdef BITBLT_TEST /* Opcodes test */
516 static int do_bitop( int s, int d, int rop )
521 case GXclear: res = 0; break;
522 case GXand: res = s & d; break;
523 case GXandReverse: res = s & ~d; break;
524 case GXcopy: res = s; break;
525 case GXandInverted: res = ~s & d; break;
526 case GXnoop: res = d; break;
527 case GXxor: res = s ^ d; break;
528 case GXor: res = s | d; break;
529 case GXnor: res = ~(s | d); break;
530 case GXequiv: res = ~s ^ d; break;
531 case GXinvert: res = ~d; break;
532 case GXorReverse: res = s | ~d; break;
533 case GXcopyInverted: res = ~s; break;
534 case GXorInverted: res = ~s | d; break;
535 case GXnand: res = ~(s & d); break;
536 case GXset: res = 1; break;
543 int rop, i, res, src, dst, pat, tmp, dstUsed;
544 const unsigned char *opcode;
546 for (rop = 0; rop < 256; rop++)
549 for (i = 0; i < 8; i++)
554 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
558 case OP_ARGS(DST,TMP):
559 tmp = do_bitop( dst, tmp, *opcode & 0xf );
561 case OP_ARGS(DST,SRC):
562 src = do_bitop( dst, src, *opcode & 0xf );
564 case OP_ARGS(SRC,TMP):
565 tmp = do_bitop( src, tmp, *opcode & 0xf );
567 case OP_ARGS(SRC,DST):
568 dst = do_bitop( src, dst, *opcode & 0xf );
571 case OP_ARGS(PAT,DST):
572 dst = do_bitop( pat, dst, *opcode & 0xf );
575 case OP_ARGS(PAT,SRC):
576 src = do_bitop( pat, src, *opcode & 0xf );
578 case OP_ARGS(TMP,DST):
579 dst = do_bitop( tmp, dst, *opcode & 0xf );
582 case OP_ARGS(TMP,SRC):
583 src = do_bitop( tmp, src, *opcode & 0xf );
586 printf( "Invalid opcode %x\n", *opcode );
589 if (!dstUsed) dst = src;
590 if (dst) res |= 1 << i;
592 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
598 #endif /* BITBLT_TEST */
601 /* handler for XGetImage BadMatch errors */
602 static int XGetImage_handler( Display *dpy, XErrorEvent *event, void *arg )
604 return (event->request_code == X_GetImage && event->error_code == BadMatch);
607 /***********************************************************************
610 * Retrieve an area from the destination DC, mapping all the
611 * pixels to Windows colors.
613 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, const RECT *visRectDst)
616 INT width = visRectDst->right - visRectDst->left;
617 INT height = visRectDst->bottom - visRectDst->top;
619 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
620 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
622 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
623 physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
624 width, height, 0, 0 );
632 /* Make sure we don't get a BadMatch error */
633 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
634 physDev->dc_rect.left + visRectDst->left,
635 physDev->dc_rect.top + visRectDst->top,
636 width, height, 0, 0);
638 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
639 AllPlanes, ZPixmap );
642 for (y = 0; y < height; y++)
643 for (x = 0; x < width; x++)
644 XPutPixel( image, x, y,
645 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
646 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
647 XDestroyImage( image );
654 /***********************************************************************
657 * Put an area back into the destination DC, mapping the pixel
658 * colors to X pixels.
660 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, const RECT *visRectDst)
663 INT width = visRectDst->right - visRectDst->left;
664 INT height = visRectDst->bottom - visRectDst->top;
666 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
668 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
669 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
671 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
672 physDev->dc_rect.left + visRectDst->left,
673 physDev->dc_rect.top + visRectDst->top );
679 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
680 AllPlanes, ZPixmap );
681 for (y = 0; y < height; y++)
682 for (x = 0; x < width; x++)
684 XPutPixel( image, x, y,
685 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
687 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
688 physDev->dc_rect.left + visRectDst->left,
689 physDev->dc_rect.top + visRectDst->top, width, height );
690 XDestroyImage( image );
695 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
697 if (physDevSrc->depth != physDevDst->depth) return FALSE;
698 if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
699 if (physDevSrc->color_shifts && physDevDst->color_shifts)
700 return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
704 void execute_rop( X11DRV_PDEVICE *physdev, Pixmap src_pixmap, GC gc, const RECT *visrect, DWORD rop )
707 Pixmap result = src_pixmap;
709 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
710 BOOL use_pat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
711 BOOL use_dst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
712 int width = visrect->right - visrect->left;
713 int height = visrect->bottom - visrect->top;
715 pixmaps[SRC] = src_pixmap;
717 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
719 if (use_dst) BITBLT_GetDstArea( physdev, pixmaps[DST], gc, visrect );
720 null_brush = use_pat && !X11DRV_SetupGCForPatBlt( physdev, gc, TRUE );
722 for ( ; *opcode; opcode++)
724 if (OP_DST(*opcode) == DST) result = pixmaps[DST];
725 XSetFunction( gdi_display, gc, OP_ROP(*opcode) );
726 switch(OP_SRCDST(*opcode))
728 case OP_ARGS(DST,TMP):
729 case OP_ARGS(SRC,TMP):
731 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
733 case OP_ARGS(DST,SRC):
734 case OP_ARGS(SRC,DST):
735 case OP_ARGS(TMP,SRC):
736 case OP_ARGS(TMP,DST):
737 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)], pixmaps[OP_DST(*opcode)], gc,
738 0, 0, width, height, 0, 0 );
740 case OP_ARGS(PAT,DST):
741 case OP_ARGS(PAT,SRC):
743 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)], gc, 0, 0, width, height );
747 XSetFunction( gdi_display, physdev->gc, GXcopy );
748 physdev->exposures += BITBLT_PutDstArea( physdev, result, visrect );
749 XFreePixmap( gdi_display, pixmaps[DST] );
750 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
751 add_device_bounds( physdev, visrect );
754 /***********************************************************************
757 BOOL X11DRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
759 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
760 BOOL usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
761 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
763 if (usePat && !X11DRV_SetupGCForBrush( physDev )) return TRUE;
765 XSetFunction( gdi_display, physDev->gc, OP_ROP(*opcode) );
767 switch(rop) /* a few special cases */
769 case BLACKNESS: /* 0x00 */
770 case WHITENESS: /* 0xff */
771 if ((physDev->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
773 XSetFunction( gdi_display, physDev->gc, GXcopy );
774 if (rop == BLACKNESS)
775 XSetForeground( gdi_display, physDev->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
777 XSetForeground( gdi_display, physDev->gc,
778 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
779 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
782 case DSTINVERT: /* 0x55 */
783 if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
785 /* Xor is much better when we do not have full colormap. */
786 /* Using white^black ensures that we invert at least black */
788 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
789 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
790 XSetFunction( gdi_display, physDev->gc, GXxor );
791 XSetForeground( gdi_display, physDev->gc, xor_pix);
792 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
796 XFillRectangle( gdi_display, physDev->drawable, physDev->gc,
797 physDev->dc_rect.left + dst->visrect.left,
798 physDev->dc_rect.top + dst->visrect.top,
799 dst->visrect.right - dst->visrect.left,
800 dst->visrect.bottom - dst->visrect.top );
801 add_device_bounds( physDev, &dst->visrect );
806 /***********************************************************************
809 BOOL X11DRV_StretchBlt( PHYSDEV dst_dev, struct bitblt_coords *dst,
810 PHYSDEV src_dev, struct bitblt_coords *src, DWORD rop )
812 X11DRV_PDEVICE *physDevDst = get_x11drv_dev( dst_dev );
813 X11DRV_PDEVICE *physDevSrc = get_x11drv_dev( src_dev );
819 if (src_dev->funcs != dst_dev->funcs ||
820 src->width != dst->width || src->height != dst->height || /* no stretching with core X11 */
821 (physDevDst->depth == 1 && physDevSrc->depth != 1) || /* color -> mono done by hand */
822 (X11DRV_PALETTE_XPixelToPalette && physDevSrc->depth != 1)) /* needs palette mapping */
824 dst_dev = GET_NEXT_PHYSDEV( dst_dev, pStretchBlt );
825 return dst_dev->funcs->pStretchBlt( dst_dev, dst, src_dev, src, rop );
828 width = dst->visrect.right - dst->visrect.left;
829 height = dst->visrect.bottom - dst->visrect.top;
830 opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
832 add_device_bounds( physDevDst, &dst->visrect );
834 /* a few optimizations for single-op ROPs */
835 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
837 if (same_format(physDevSrc, physDevDst))
839 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
840 XCopyArea( gdi_display, physDevSrc->drawable,
841 physDevDst->drawable, physDevDst->gc,
842 physDevSrc->dc_rect.left + src->visrect.left,
843 physDevSrc->dc_rect.top + src->visrect.top,
845 physDevDst->dc_rect.left + dst->visrect.left,
846 physDevDst->dc_rect.top + dst->visrect.top );
847 physDevDst->exposures++;
850 if (physDevSrc->depth == 1)
852 int text_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetTextColor(physDevDst->dev.hdc) );
853 int bkgnd_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetBkColor(physDevDst->dev.hdc) );
855 XSetBackground( gdi_display, physDevDst->gc, text_pixel );
856 XSetForeground( gdi_display, physDevDst->gc, bkgnd_pixel );
857 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
858 XCopyPlane( gdi_display, physDevSrc->drawable,
859 physDevDst->drawable, physDevDst->gc,
860 physDevSrc->dc_rect.left + src->visrect.left,
861 physDevSrc->dc_rect.top + src->visrect.top,
863 physDevDst->dc_rect.left + dst->visrect.left,
864 physDevDst->dc_rect.top + dst->visrect.top, 1 );
865 physDevDst->exposures++;
870 gc = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
871 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
872 XSetGraphicsExposures( gdi_display, gc, False );
874 /* retrieve the source */
876 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, physDevDst->depth );
877 if (physDevSrc->depth == 1)
879 /* MSDN says if StretchBlt must convert a bitmap from monochrome
880 to color or vice versa, the foreground and background color of
881 the device context are used. In fact, it also applies to the
882 case when it is converted from mono to mono. */
883 int text_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetTextColor(physDevDst->dev.hdc) );
884 int bkgnd_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, GetBkColor(physDevDst->dev.hdc) );
886 if (X11DRV_PALETTE_XPixelToPalette && physDevDst->depth != 1)
888 XSetBackground( gdi_display, gc, X11DRV_PALETTE_XPixelToPalette[text_pixel] );
889 XSetForeground( gdi_display, gc, X11DRV_PALETTE_XPixelToPalette[bkgnd_pixel]);
893 XSetBackground( gdi_display, gc, text_pixel );
894 XSetForeground( gdi_display, gc, bkgnd_pixel );
896 XCopyPlane( gdi_display, physDevSrc->drawable, src_pixmap, gc,
897 physDevSrc->dc_rect.left + src->visrect.left,
898 physDevSrc->dc_rect.top + src->visrect.top,
899 width, height, 0, 0, 1 );
901 else /* color -> color */
903 XCopyArea( gdi_display, physDevSrc->drawable, src_pixmap, gc,
904 physDevSrc->dc_rect.left + src->visrect.left,
905 physDevSrc->dc_rect.top + src->visrect.top,
906 width, height, 0, 0 );
909 execute_rop( physDevDst, src_pixmap, gc, &dst->visrect, rop );
911 XFreePixmap( gdi_display, src_pixmap );
912 XFreeGC( gdi_display, gc );
917 static void free_heap_bits( struct gdi_image_bits *bits )
919 HeapFree( GetProcessHeap(), 0, bits->ptr );
922 static void free_ximage_bits( struct gdi_image_bits *bits )
927 /* only for use on sanitized BITMAPINFO structures */
928 static inline int get_dib_info_size( const BITMAPINFO *info, UINT coloruse )
930 if (info->bmiHeader.biCompression == BI_BITFIELDS)
931 return sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD);
932 if (coloruse == DIB_PAL_COLORS)
933 return sizeof(BITMAPINFOHEADER) + info->bmiHeader.biClrUsed * sizeof(WORD);
934 return FIELD_OFFSET( BITMAPINFO, bmiColors[info->bmiHeader.biClrUsed] );
937 static inline int get_dib_stride( int width, int bpp )
939 return ((width * bpp + 31) >> 3) & ~3;
942 static inline int get_dib_image_size( const BITMAPINFO *info )
944 return get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount )
945 * abs( info->bmiHeader.biHeight );
948 /* store the palette or color mask data in the bitmap info structure */
949 static void set_color_info( const XVisualInfo *vis, BITMAPINFO *info, BOOL has_alpha )
951 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
953 info->bmiHeader.biCompression = BI_RGB;
954 info->bmiHeader.biClrUsed = 0;
956 switch (info->bmiHeader.biBitCount)
961 RGBQUAD *rgb = (RGBQUAD *)colors;
962 PALETTEENTRY palette[256];
965 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
966 count = X11DRV_GetSystemPaletteEntries( NULL, 0, info->bmiHeader.biClrUsed, palette );
967 for (i = 0; i < count; i++)
969 rgb[i].rgbRed = palette[i].peRed;
970 rgb[i].rgbGreen = palette[i].peGreen;
971 rgb[i].rgbBlue = palette[i].peBlue;
972 rgb[i].rgbReserved = 0;
974 memset( &rgb[count], 0, (info->bmiHeader.biClrUsed - count) * sizeof(*rgb) );
978 colors[0] = vis->red_mask;
979 colors[1] = vis->green_mask;
980 colors[2] = vis->blue_mask;
981 info->bmiHeader.biCompression = BI_BITFIELDS;
984 colors[0] = vis->red_mask;
985 colors[1] = vis->green_mask;
986 colors[2] = vis->blue_mask;
987 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff || !has_alpha)
988 info->bmiHeader.biCompression = BI_BITFIELDS;
993 /* check if the specified color info is suitable for PutImage */
994 static BOOL matching_color_info( const XVisualInfo *vis, const BITMAPINFO *info )
996 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
998 switch (info->bmiHeader.biBitCount)
1001 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1002 return !info->bmiHeader.biClrUsed; /* color map not allowed */
1006 RGBQUAD *rgb = (RGBQUAD *)colors;
1007 PALETTEENTRY palette[256];
1010 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1011 count = X11DRV_GetSystemPaletteEntries( NULL, 0, 1 << info->bmiHeader.biBitCount, palette );
1012 if (count != info->bmiHeader.biClrUsed) return FALSE;
1013 for (i = 0; i < count; i++)
1015 if (rgb[i].rgbRed != palette[i].peRed ||
1016 rgb[i].rgbGreen != palette[i].peGreen ||
1017 rgb[i].rgbBlue != palette[i].peBlue) return FALSE;
1022 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1023 return (vis->red_mask == colors[0] &&
1024 vis->green_mask == colors[1] &&
1025 vis->blue_mask == colors[2]);
1026 if (info->bmiHeader.biCompression == BI_RGB)
1027 return (vis->red_mask == 0x7c00 && vis->green_mask == 0x03e0 && vis->blue_mask == 0x001f);
1030 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1031 return (vis->red_mask == colors[0] &&
1032 vis->green_mask == colors[1] &&
1033 vis->blue_mask == colors[2]);
1036 if (info->bmiHeader.biCompression == BI_RGB)
1037 return (vis->red_mask == 0xff0000 && vis->green_mask == 0x00ff00 && vis->blue_mask == 0x0000ff);
1043 static inline BOOL is_r8g8b8( const XVisualInfo *vis )
1045 return vis->depth == 24 && vis->red_mask == 0xff0000 && vis->blue_mask == 0x0000ff;
1048 static inline BOOL image_needs_byteswap( XImage *image, BOOL is_r8g8b8, int bit_count )
1050 #ifdef WORDS_BIGENDIAN
1051 static const int client_byte_order = MSBFirst;
1053 static const int client_byte_order = LSBFirst;
1058 case 1: return image->bitmap_bit_order != MSBFirst;
1059 case 4: return image->byte_order != MSBFirst;
1061 case 32: return image->byte_order != client_byte_order;
1062 case 24: return (image->byte_order == MSBFirst) ^ !is_r8g8b8;
1063 default: return FALSE;
1067 /* copy image bits with byte swapping and/or pixel mapping */
1068 static void copy_image_byteswap( BITMAPINFO *info, const unsigned char *src, unsigned char *dst,
1069 int src_stride, int dst_stride, int height,
1070 BOOL byteswap, const int *mapping, unsigned int zeropad_mask )
1072 int x, y, padding_pos = abs(dst_stride) / sizeof(unsigned int) - 1;
1074 if (!byteswap && !mapping) /* simply copy */
1078 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1080 memcpy( dst, src, src_stride );
1081 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1084 else if (zeropad_mask != ~0u) /* only need to clear the padding */
1086 for (y = 0; y < height; y++, dst += dst_stride)
1087 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1092 switch (info->bmiHeader.biBitCount)
1095 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1097 for (x = 0; x < src_stride; x++) dst[x] = bit_swap[src[x]];
1098 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1102 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1107 for (x = 0; x < src_stride; x++)
1108 dst[x] = (mapping[src[x] & 0x0f] << 4) | mapping[src[x] >> 4];
1110 for (x = 0; x < src_stride; x++)
1111 dst[x] = mapping[src[x] & 0x0f] | (mapping[src[x] >> 4] << 4);
1114 for (x = 0; x < src_stride; x++)
1115 dst[x] = (src[x] << 4) | (src[x] >> 4);
1116 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1120 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1122 for (x = 0; x < src_stride; x++) dst[x] = mapping[src[x]];
1123 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1127 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1129 for (x = 0; x < info->bmiHeader.biWidth; x++)
1130 ((USHORT *)dst)[x] = RtlUshortByteSwap( ((const USHORT *)src)[x] );
1131 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1135 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1137 for (x = 0; x < info->bmiHeader.biWidth; x++)
1139 unsigned char tmp = src[3 * x];
1140 dst[3 * x] = src[3 * x + 2];
1141 dst[3 * x + 1] = src[3 * x + 1];
1142 dst[3 * x + 2] = tmp;
1144 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1148 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1149 for (x = 0; x < info->bmiHeader.biWidth; x++)
1150 ((ULONG *)dst)[x] = RtlUlongByteSwap( ((const ULONG *)src)[x] );
1155 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1156 DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image,
1157 const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
1158 struct bitblt_coords *coords, const int *mapping, unsigned int zeropad_mask )
1160 BOOL need_byteswap = image_needs_byteswap( image, is_r8g8b8, info->bmiHeader.biBitCount );
1161 int height = coords->visrect.bottom - coords->visrect.top;
1162 int width_bytes = image->bytes_per_line;
1163 unsigned char *src, *dst;
1165 src = src_bits->ptr;
1166 if (info->bmiHeader.biHeight > 0)
1167 src += (info->bmiHeader.biHeight - coords->visrect.bottom) * width_bytes;
1169 src += coords->visrect.top * width_bytes;
1171 if ((need_byteswap && !src_bits->is_copy) || /* need to swap bytes */
1172 (zeropad_mask != ~0u && !src_bits->is_copy) || /* need to clear padding bytes */
1173 (mapping && !src_bits->is_copy) || /* need to remap pixels */
1174 (width_bytes & 3) || /* need to fixup line alignment */
1175 (info->bmiHeader.biHeight > 0)) /* need to flip vertically */
1177 width_bytes = (width_bytes + 3) & ~3;
1178 info->bmiHeader.biSizeImage = height * width_bytes;
1179 if (!(dst_bits->ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
1180 return ERROR_OUTOFMEMORY;
1181 dst_bits->is_copy = TRUE;
1182 dst_bits->free = free_heap_bits;
1186 /* swap bits in place */
1187 dst_bits->ptr = src;
1188 dst_bits->is_copy = src_bits->is_copy;
1189 dst_bits->free = NULL;
1190 if (!need_byteswap && zeropad_mask == ~0u && !mapping) return ERROR_SUCCESS; /* nothing to do */
1193 dst = dst_bits->ptr;
1195 if (info->bmiHeader.biHeight > 0)
1197 dst += (height - 1) * width_bytes;
1198 width_bytes = -width_bytes;
1201 copy_image_byteswap( info, src, dst, image->bytes_per_line, width_bytes, height,
1202 need_byteswap, mapping, zeropad_mask );
1203 return ERROR_SUCCESS;
1206 /***********************************************************************
1209 DWORD X11DRV_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
1210 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1211 struct bitblt_coords *dst, DWORD rop )
1213 X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1216 XVisualInfo vis = default_visual;
1217 struct gdi_image_bits dst_bits;
1218 const XPixmapFormatValues *format;
1219 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1220 const int *mapping = NULL;
1222 vis.depth = physdev->depth;
1223 if (physdev->color_shifts)
1225 vis.red_mask = physdev->color_shifts->logicalRed.max << physdev->color_shifts->logicalRed.shift;
1226 vis.green_mask = physdev->color_shifts->logicalGreen.max << physdev->color_shifts->logicalGreen.shift;
1227 vis.blue_mask = physdev->color_shifts->logicalBlue.max << physdev->color_shifts->logicalBlue.shift;
1229 format = pixmap_formats[vis.depth];
1231 if (info->bmiHeader.biPlanes != 1) goto update_format;
1232 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1233 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1234 if (!matching_color_info( &vis, info )) goto update_format;
1235 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1236 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
1238 image = XCreateImage( gdi_display, vis.visual, vis.depth, ZPixmap, 0, NULL,
1239 info->bmiHeader.biWidth, src->visrect.bottom - src->visrect.top, 32, 0 );
1240 if (!image) return ERROR_OUTOFMEMORY;
1242 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1244 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1245 mapping = X11DRV_PALETTE_PaletteToXPixel;
1248 ret = copy_image_bits( info, is_r8g8b8(&vis), image, bits, &dst_bits, src, mapping, ~0u );
1252 BOOL restore_region = add_extra_clipping_region( physdev, clip );
1253 int width = dst->visrect.right - dst->visrect.left;
1254 int height = dst->visrect.bottom - dst->visrect.top;
1256 image->data = dst_bits.ptr;
1258 /* optimization for single-op ROPs */
1259 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1261 XSetFunction( gdi_display, physdev->gc, OP_ROP(*opcode) );
1262 XPutImage( gdi_display, physdev->drawable, physdev->gc, image, src->visrect.left, 0,
1263 physdev->dc_rect.left + dst->visrect.left,
1264 physdev->dc_rect.top + dst->visrect.top, width, height );
1268 GC gc = XCreateGC( gdi_display, physdev->drawable, 0, NULL );
1269 Pixmap src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, vis.depth );
1271 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1272 XSetGraphicsExposures( gdi_display, gc, False );
1273 XPutImage( gdi_display, src_pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1275 execute_rop( physdev, src_pixmap, gc, &dst->visrect, rop );
1277 XFreePixmap( gdi_display, src_pixmap );
1278 XFreeGC( gdi_display, gc );
1281 if (restore_region) restore_clipping_region( physdev );
1282 add_device_bounds( physdev, &dst->visrect );
1286 XDestroyImage( image );
1287 if (dst_bits.free) dst_bits.free( &dst_bits );
1291 info->bmiHeader.biPlanes = 1;
1292 info->bmiHeader.biBitCount = format->bits_per_pixel;
1293 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1294 set_color_info( &vis, info, FALSE );
1295 return ERROR_BAD_FORMAT;
1298 /***********************************************************************
1301 DWORD X11DRV_GetImage( PHYSDEV dev, BITMAPINFO *info,
1302 struct gdi_image_bits *bits, struct bitblt_coords *src )
1304 X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1305 DWORD ret = ERROR_SUCCESS;
1307 XVisualInfo vis = default_visual;
1308 UINT align, x, y, width, height;
1309 struct gdi_image_bits src_bits;
1310 const XPixmapFormatValues *format;
1311 const int *mapping = NULL;
1313 vis.depth = physdev->depth;
1314 if (physdev->color_shifts)
1316 vis.red_mask = physdev->color_shifts->logicalRed.max << physdev->color_shifts->logicalRed.shift;
1317 vis.green_mask = physdev->color_shifts->logicalGreen.max << physdev->color_shifts->logicalGreen.shift;
1318 vis.blue_mask = physdev->color_shifts->logicalBlue.max << physdev->color_shifts->logicalBlue.shift;
1320 format = pixmap_formats[vis.depth];
1322 /* align start and width to 32-bit boundary */
1323 switch (format->bits_per_pixel)
1325 case 1: align = 32; break;
1326 case 4: align = 8; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1327 case 8: align = 4; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1328 case 16: align = 2; break;
1329 case 24: align = 4; break;
1330 case 32: align = 1; break;
1332 FIXME( "depth %u bpp %u not supported yet\n", vis.depth, format->bits_per_pixel );
1333 return ERROR_BAD_FORMAT;
1336 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1337 info->bmiHeader.biPlanes = 1;
1338 info->bmiHeader.biBitCount = format->bits_per_pixel;
1339 info->bmiHeader.biXPelsPerMeter = 0;
1340 info->bmiHeader.biYPelsPerMeter = 0;
1341 info->bmiHeader.biClrImportant = 0;
1342 set_color_info( &vis, info, FALSE );
1344 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
1346 x = src->visrect.left & ~(align - 1);
1347 y = src->visrect.top;
1348 width = src->visrect.right - x;
1349 height = src->visrect.bottom - src->visrect.top;
1350 if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1);
1351 /* make the source rectangle relative to the returned bits */
1354 OffsetRect( &src->visrect, -x, -y );
1356 X11DRV_expect_error( gdi_display, XGetImage_handler, NULL );
1357 image = XGetImage( gdi_display, physdev->drawable,
1358 physdev->dc_rect.left + x, physdev->dc_rect.top + y,
1359 width, height, AllPlanes, ZPixmap );
1360 if (X11DRV_check_error())
1362 /* use a temporary pixmap to avoid the BadMatch error */
1363 Pixmap pixmap = XCreatePixmap( gdi_display, root_window, width, height, vis.depth );
1364 GC gc = XCreateGC( gdi_display, pixmap, 0, NULL );
1366 XSetGraphicsExposures( gdi_display, gc, False );
1367 XCopyArea( gdi_display, physdev->drawable, pixmap, gc,
1368 physdev->dc_rect.left + x, physdev->dc_rect.top + y, width, height, 0, 0 );
1369 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1370 XFreePixmap( gdi_display, pixmap );
1371 XFreeGC( gdi_display, gc );
1374 if (!image) return ERROR_OUTOFMEMORY;
1376 info->bmiHeader.biWidth = width;
1377 info->bmiHeader.biHeight = -height;
1378 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1380 src_bits.ptr = image->data;
1381 src_bits.is_copy = TRUE;
1382 ret = copy_image_bits( info, is_r8g8b8(&vis), image, &src_bits, bits, src, mapping,
1383 zeropad_masks[(width * image->bits_per_pixel) & 31] );
1385 if (!ret && bits->ptr == image->data)
1387 bits->free = free_ximage_bits;
1390 XDestroyImage( image );
1395 /***********************************************************************
1398 * Simplified equivalent of X11DRV_PutImage that writes directly to a pixmap.
1400 static DWORD put_pixmap_image( Pixmap pixmap, const XVisualInfo *vis,
1401 BITMAPINFO *info, const struct gdi_image_bits *bits )
1406 struct bitblt_coords coords;
1407 struct gdi_image_bits dst_bits;
1408 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1409 const int *mapping = NULL;
1411 if (!format) return ERROR_INVALID_PARAMETER;
1412 if (info->bmiHeader.biPlanes != 1) goto update_format;
1413 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1414 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1415 if (!matching_color_info( vis, info )) goto update_format;
1416 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1420 coords.width = info->bmiHeader.biWidth;
1421 coords.height = abs( info->bmiHeader.biHeight );
1422 SetRect( &coords.visrect, 0, 0, coords.width, coords.height );
1424 image = XCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, 0, NULL,
1425 coords.width, coords.height, 32, 0 );
1426 if (!image) return ERROR_OUTOFMEMORY;
1428 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1429 mapping = X11DRV_PALETTE_PaletteToXPixel;
1431 if (!(ret = copy_image_bits( info, is_r8g8b8(vis), image, bits, &dst_bits, &coords, mapping, ~0u )))
1433 image->data = dst_bits.ptr;
1434 gc = XCreateGC( gdi_display, pixmap, 0, NULL );
1435 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, coords.width, coords.height );
1436 XFreeGC( gdi_display, gc );
1440 XDestroyImage( image );
1441 if (dst_bits.free) dst_bits.free( &dst_bits );
1445 info->bmiHeader.biPlanes = 1;
1446 info->bmiHeader.biBitCount = format->bits_per_pixel;
1447 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1448 set_color_info( vis, info, FALSE );
1449 return ERROR_BAD_FORMAT;
1453 /***********************************************************************
1454 * create_pixmap_from_image
1456 Pixmap create_pixmap_from_image( HDC hdc, const XVisualInfo *vis, const BITMAPINFO *info,
1457 const struct gdi_image_bits *bits, UINT coloruse )
1459 static const RGBQUAD default_colortable[2] = { { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff } };
1460 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1461 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1462 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
1463 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
1464 struct gdi_image_bits dst_bits;
1469 pixmap = XCreatePixmap( gdi_display, root_window,
1470 info->bmiHeader.biWidth, abs(info->bmiHeader.biHeight), vis->depth );
1471 if (!pixmap) return 0;
1473 memcpy( src_info, info, get_dib_info_size( info, coloruse ));
1474 memcpy( dst_info, info, get_dib_info_size( info, coloruse ));
1476 if (coloruse == DIB_PAL_COLORS ||
1477 (err = put_pixmap_image( pixmap, vis, dst_info, bits )) == ERROR_BAD_FORMAT)
1479 if (dst_info->bmiHeader.biBitCount == 1) /* set a default color table for 1-bpp */
1480 memcpy( dst_info->bmiColors, default_colortable, sizeof(default_colortable) );
1481 dib = CreateDIBSection( hdc, dst_info, coloruse, &dst_bits.ptr, 0, 0 );
1484 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
1485 memcpy( src_info->bmiColors, default_colortable, sizeof(default_colortable) );
1486 SetDIBits( hdc, dib, 0, abs(info->bmiHeader.biHeight), bits->ptr, src_info, coloruse );
1487 dst_bits.free = NULL;
1488 dst_bits.is_copy = TRUE;
1489 err = put_pixmap_image( pixmap, vis, dst_info, &dst_bits );
1490 DeleteObject( dib );
1492 else err = ERROR_OUTOFMEMORY;
1495 if (!err) return pixmap;
1497 XFreePixmap( gdi_display, pixmap );
1503 /***********************************************************************
1506 * Equivalent of X11DRV_GetImage that reads directly from a pixmap.
1508 DWORD get_pixmap_image( Pixmap pixmap, int width, int height, const XVisualInfo *vis,
1509 BITMAPINFO *info, struct gdi_image_bits *bits )
1511 DWORD ret = ERROR_SUCCESS;
1513 struct gdi_image_bits src_bits;
1514 struct bitblt_coords coords;
1515 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1516 const int *mapping = NULL;
1518 if (!format) return ERROR_INVALID_PARAMETER;
1520 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1521 info->bmiHeader.biWidth = width;
1522 info->bmiHeader.biHeight = -height;
1523 info->bmiHeader.biPlanes = 1;
1524 info->bmiHeader.biBitCount = format->bits_per_pixel;
1525 info->bmiHeader.biXPelsPerMeter = 0;
1526 info->bmiHeader.biYPelsPerMeter = 0;
1527 info->bmiHeader.biClrImportant = 0;
1528 set_color_info( vis, info, FALSE );
1530 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
1534 coords.width = width;
1535 coords.height = height;
1536 SetRect( &coords.visrect, 0, 0, width, height );
1538 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1539 if (!image) return ERROR_OUTOFMEMORY;
1541 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1543 src_bits.ptr = image->data;
1544 src_bits.is_copy = TRUE;
1545 ret = copy_image_bits( info, is_r8g8b8(vis), image, &src_bits, bits, &coords, mapping,
1546 zeropad_masks[(width * image->bits_per_pixel) & 31] );
1548 if (!ret && bits->ptr == image->data)
1550 bits->free = free_ximage_bits;
1553 XDestroyImage( image );
1558 struct x11drv_window_surface
1560 struct window_surface header;
1570 #ifdef HAVE_LIBXXSHM
1571 XShmSegmentInfo shminfo;
1573 CRITICAL_SECTION crit;
1574 BITMAPINFO info; /* variable size, must be last */
1577 static struct x11drv_window_surface *get_x11_surface( struct window_surface *surface )
1579 return (struct x11drv_window_surface *)surface;
1582 static inline UINT get_color_component( UINT color, UINT mask )
1585 for (shift = 0; !(mask & 1); shift++) mask >>= 1;
1586 return (color * mask / 255) << shift;
1589 static inline void flush_rgn_data( HRGN rgn, RGNDATA *data )
1591 HRGN tmp = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data );
1592 CombineRgn( rgn, rgn, tmp, RGN_OR );
1593 DeleteObject( tmp );
1594 data->rdh.nCount = 0;
1597 static inline void add_row( HRGN rgn, RGNDATA *data, int x, int y, int len )
1599 RECT *rect = (RECT *)data->Buffer + data->rdh.nCount;
1601 if (len <= 0) return;
1604 rect->right = x + len;
1605 rect->bottom = y + 1;
1607 if (data->rdh.nCount * sizeof(RECT) > data->rdh.nRgnSize - sizeof(RECT))
1608 flush_rgn_data( rgn, data );
1611 /***********************************************************************
1612 * update_surface_region
1614 static void update_surface_region( struct x11drv_window_surface *surface )
1616 #ifdef HAVE_LIBXSHAPE
1618 RGNDATA *data = (RGNDATA *)buffer;
1619 BITMAPINFO *info = &surface->info;
1620 UINT *masks = (UINT *)info->bmiColors;
1621 int x, y, start, width;
1624 if (!shape_layered_windows) return;
1626 if (!surface->is_argb && surface->color_key == CLR_INVALID)
1628 XShapeCombineMask( gdi_display, surface->window, ShapeBounding, 0, 0, None, ShapeSet );
1632 data->rdh.dwSize = sizeof(data->rdh);
1633 data->rdh.iType = RDH_RECTANGLES;
1634 data->rdh.nCount = 0;
1635 data->rdh.nRgnSize = sizeof(buffer) - sizeof(data->rdh);
1637 rgn = CreateRectRgn( 0, 0, 0, 0 );
1638 width = surface->header.rect.right - surface->header.rect.left;
1640 switch (info->bmiHeader.biBitCount)
1644 WORD *bits = surface->bits;
1645 int stride = (width + 1) & ~1;
1646 UINT mask = masks[0] | masks[1] | masks[2];
1648 for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += stride)
1653 while (x < width && (bits[x] & mask) == surface->color_key) x++;
1655 while (x < width && (bits[x] & mask) != surface->color_key) x++;
1656 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1663 BYTE *bits = surface->bits;
1664 int stride = (width * 3 + 3) & ~3;
1666 for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += stride)
1672 (bits[x * 3] == GetBValue(surface->color_key)) &&
1673 (bits[x * 3 + 1] == GetGValue(surface->color_key)) &&
1674 (bits[x * 3 + 2] == GetRValue(surface->color_key)))
1678 ((bits[x * 3] != GetBValue(surface->color_key)) ||
1679 (bits[x * 3 + 1] != GetGValue(surface->color_key)) ||
1680 (bits[x * 3 + 2] != GetRValue(surface->color_key))))
1682 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1689 DWORD *bits = surface->bits;
1691 if (info->bmiHeader.biCompression == BI_RGB)
1693 for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += width)
1699 ((bits[x] & 0xffffff) == surface->color_key ||
1700 (surface->is_argb && !(bits[x] & 0xff000000)))) x++;
1703 !((bits[x] & 0xffffff) == surface->color_key ||
1704 (surface->is_argb && !(bits[x] & 0xff000000)))) x++;
1705 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1711 UINT mask = masks[0] | masks[1] | masks[2];
1712 for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += width)
1717 while (x < width && (bits[x] & mask) == surface->color_key) x++;
1719 while (x < width && (bits[x] & mask) != surface->color_key) x++;
1720 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1730 if (data->rdh.nCount) flush_rgn_data( rgn, data );
1732 if ((data = X11DRV_GetRegionData( rgn, 0 )))
1734 XShapeCombineRectangles( gdi_display, surface->window, ShapeBounding, 0, 0,
1735 (XRectangle *)data->Buffer, data->rdh.nCount, ShapeSet, YXBanded );
1736 HeapFree( GetProcessHeap(), 0, data );
1739 DeleteObject( rgn );
1743 /***********************************************************************
1746 static void set_color_key( struct x11drv_window_surface *surface, COLORREF key )
1748 UINT *masks = (UINT *)surface->info.bmiColors;
1750 if (key == CLR_INVALID)
1751 surface->color_key = CLR_INVALID;
1752 else if (surface->info.bmiHeader.biBitCount <= 8)
1753 surface->color_key = CLR_INVALID;
1754 else if (key & (1 << 24)) /* PALETTEINDEX */
1755 surface->color_key = 0;
1756 else if (key >> 16 == 0x10ff) /* DIBINDEX */
1757 surface->color_key = 0;
1758 else if (surface->info.bmiHeader.biBitCount == 24)
1759 surface->color_key = key;
1760 else if (surface->info.bmiHeader.biCompression == BI_RGB)
1761 surface->color_key = (GetRValue(key) << 16) | (GetGValue(key) << 8) | GetBValue(key);
1763 surface->color_key = get_color_component( GetRValue(key), masks[0] ) |
1764 get_color_component( GetGValue(key), masks[1] ) |
1765 get_color_component( GetBValue(key), masks[2] );
1768 #ifdef HAVE_LIBXXSHM
1769 static int xshm_error_handler( Display *display, XErrorEvent *event, void *arg )
1771 return 1; /* FIXME: should check event contents */
1774 static XImage *create_shm_image( const XVisualInfo *vis, int width, int height, XShmSegmentInfo *shminfo )
1778 shminfo->shmid = -1;
1779 image = XShmCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, NULL, shminfo, width, height );
1780 if (!image) return NULL;
1781 if (image->bytes_per_line & 3) goto failed; /* we need 32-bit alignment */
1783 shminfo->shmid = shmget( IPC_PRIVATE, image->bytes_per_line * height, IPC_CREAT | 0700 );
1784 if (shminfo->shmid == -1) goto failed;
1786 shminfo->shmaddr = shmat( shminfo->shmid, 0, 0 );
1787 if (shminfo->shmaddr != (char *)-1)
1791 shminfo->readOnly = True;
1792 X11DRV_expect_error( gdi_display, xshm_error_handler, NULL );
1793 ok = (XShmAttach( gdi_display, shminfo ) != 0);
1794 XSync( gdi_display, False );
1795 if (!X11DRV_check_error() && ok)
1797 image->data = shminfo->shmaddr;
1798 shmctl( shminfo->shmid, IPC_RMID, 0 );
1801 shmdt( shminfo->shmaddr );
1803 shmctl( shminfo->shmid, IPC_RMID, 0 );
1804 shminfo->shmid = -1;
1807 XDestroyImage( image );
1810 #endif /* HAVE_LIBXXSHM */
1812 /***********************************************************************
1813 * x11drv_surface_lock
1815 static void x11drv_surface_lock( struct window_surface *window_surface )
1817 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1819 EnterCriticalSection( &surface->crit );
1822 /***********************************************************************
1823 * x11drv_surface_unlock
1825 static void x11drv_surface_unlock( struct window_surface *window_surface )
1827 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1829 LeaveCriticalSection( &surface->crit );
1832 /***********************************************************************
1833 * x11drv_surface_get_bitmap_info
1835 static void *x11drv_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
1837 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1839 memcpy( info, &surface->info, get_dib_info_size( &surface->info, DIB_RGB_COLORS ));
1840 return surface->bits;
1843 /***********************************************************************
1844 * x11drv_surface_get_bounds
1846 static RECT *x11drv_surface_get_bounds( struct window_surface *window_surface )
1848 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1850 return &surface->bounds;
1853 /***********************************************************************
1854 * x11drv_surface_set_region
1856 static void x11drv_surface_set_region( struct window_surface *window_surface, HRGN region )
1859 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1861 TRACE( "updating surface %p with %p\n", surface, region );
1863 window_surface->funcs->lock( window_surface );
1866 if (surface->region) DeleteObject( surface->region );
1867 surface->region = 0;
1868 XSetClipMask( gdi_display, surface->gc, None );
1872 if (!surface->region) surface->region = CreateRectRgn( 0, 0, 0, 0 );
1873 CombineRgn( surface->region, region, 0, RGN_COPY );
1874 if ((data = X11DRV_GetRegionData( surface->region, 0 )))
1876 XSetClipRectangles( gdi_display, surface->gc, 0, 0,
1877 (XRectangle *)data->Buffer, data->rdh.nCount, YXBanded );
1878 HeapFree( GetProcessHeap(), 0, data );
1881 window_surface->funcs->unlock( window_surface );
1884 /***********************************************************************
1885 * x11drv_surface_flush
1887 static void x11drv_surface_flush( struct window_surface *window_surface )
1889 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1890 unsigned char *src = surface->bits;
1891 unsigned char *dst = (unsigned char *)surface->image->data;
1892 struct bitblt_coords coords;
1894 window_surface->funcs->lock( window_surface );
1897 coords.width = surface->header.rect.right - surface->header.rect.left;
1898 coords.height = surface->header.rect.bottom - surface->header.rect.top;
1899 SetRect( &coords.visrect, 0, 0, coords.width, coords.height );
1900 if (IntersectRect( &coords.visrect, &coords.visrect, &surface->bounds ))
1902 TRACE( "flushing %p %dx%d bounds %s bits %p\n",
1903 surface, coords.width, coords.height,
1904 wine_dbgstr_rect( &surface->bounds ), surface->bits );
1906 if (surface->is_argb || surface->color_key != CLR_INVALID) update_surface_region( surface );
1910 const int *mapping = NULL;
1911 int width_bytes = surface->image->bytes_per_line;
1913 if (surface->image->bits_per_pixel == 4 || surface->image->bits_per_pixel == 8)
1914 mapping = X11DRV_PALETTE_PaletteToXPixel;
1916 src += coords.visrect.top * width_bytes;
1917 dst += coords.visrect.top * width_bytes;
1918 copy_image_byteswap( &surface->info, src, dst, width_bytes, width_bytes,
1919 coords.visrect.bottom - coords.visrect.top,
1920 surface->byteswap, mapping, ~0u );
1923 #ifdef HAVE_LIBXXSHM
1924 if (surface->shminfo.shmid != -1)
1925 XShmPutImage( gdi_display, surface->window, surface->gc, surface->image,
1926 coords.visrect.left, coords.visrect.top,
1927 surface->header.rect.left + coords.visrect.left,
1928 surface->header.rect.top + coords.visrect.top,
1929 coords.visrect.right - coords.visrect.left,
1930 coords.visrect.bottom - coords.visrect.top, False );
1933 XPutImage( gdi_display, surface->window, surface->gc, surface->image,
1934 coords.visrect.left, coords.visrect.top,
1935 surface->header.rect.left + coords.visrect.left,
1936 surface->header.rect.top + coords.visrect.top,
1937 coords.visrect.right - coords.visrect.left,
1938 coords.visrect.bottom - coords.visrect.top );
1940 reset_bounds( &surface->bounds );
1941 window_surface->funcs->unlock( window_surface );
1944 /***********************************************************************
1945 * x11drv_surface_destroy
1947 static void x11drv_surface_destroy( struct window_surface *window_surface )
1949 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1951 TRACE( "freeing %p bits %p\n", surface, surface->bits );
1952 if (surface->gc) XFreeGC( gdi_display, surface->gc );
1955 if (surface->image->data != surface->bits) HeapFree( GetProcessHeap(), 0, surface->bits );
1956 #ifdef HAVE_LIBXXSHM
1957 if (surface->shminfo.shmid != -1)
1959 XShmDetach( gdi_display, &surface->shminfo );
1960 shmdt( surface->shminfo.shmaddr );
1964 HeapFree( GetProcessHeap(), 0, surface->image->data );
1965 surface->image->data = NULL;
1966 XDestroyImage( surface->image );
1968 surface->crit.DebugInfo->Spare[0] = 0;
1969 DeleteCriticalSection( &surface->crit );
1970 if (surface->region) DeleteObject( surface->region );
1971 HeapFree( GetProcessHeap(), 0, surface );
1974 static const struct window_surface_funcs x11drv_surface_funcs =
1976 x11drv_surface_lock,
1977 x11drv_surface_unlock,
1978 x11drv_surface_get_bitmap_info,
1979 x11drv_surface_get_bounds,
1980 x11drv_surface_set_region,
1981 x11drv_surface_flush,
1982 x11drv_surface_destroy
1985 /***********************************************************************
1988 struct window_surface *create_surface( Window window, const XVisualInfo *vis, const RECT *rect,
1989 COLORREF color_key, BOOL use_alpha )
1991 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1992 struct x11drv_window_surface *surface;
1993 int width = rect->right - rect->left, height = rect->bottom - rect->top;
1994 int colors = format->bits_per_pixel <= 8 ? 1 << format->bits_per_pixel : 3;
1996 surface = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1997 FIELD_OFFSET( struct x11drv_window_surface, info.bmiColors[colors] ));
1998 if (!surface) return NULL;
1999 surface->info.bmiHeader.biSize = sizeof(surface->info.bmiHeader);
2000 surface->info.bmiHeader.biWidth = width;
2001 surface->info.bmiHeader.biHeight = -height; /* top-down */
2002 surface->info.bmiHeader.biPlanes = 1;
2003 surface->info.bmiHeader.biBitCount = format->bits_per_pixel;
2004 surface->info.bmiHeader.biSizeImage = get_dib_image_size( &surface->info );
2005 set_color_info( vis, &surface->info, use_alpha );
2007 InitializeCriticalSection( &surface->crit );
2008 surface->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": surface");
2010 surface->header.funcs = &x11drv_surface_funcs;
2011 surface->header.rect = *rect;
2012 surface->header.ref = 1;
2013 surface->window = window;
2014 surface->is_argb = (use_alpha && vis->depth == 32 && surface->info.bmiHeader.biCompression == BI_RGB);
2015 set_color_key( surface, color_key );
2016 reset_bounds( &surface->bounds );
2018 #ifdef HAVE_LIBXXSHM
2019 surface->image = create_shm_image( vis, width, height, &surface->shminfo );
2020 if (!surface->image)
2023 surface->image = XCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, 0, NULL,
2024 width, height, 32, 0 );
2025 if (!surface->image) goto failed;
2026 surface->image->data = HeapAlloc( GetProcessHeap(), 0, surface->info.bmiHeader.biSizeImage );
2027 if (!surface->image->data) goto failed;
2030 surface->gc = XCreateGC( gdi_display, window, 0, NULL );
2031 surface->byteswap = image_needs_byteswap( surface->image, is_r8g8b8(vis), format->bits_per_pixel );
2033 if (surface->byteswap || format->bits_per_pixel == 4 || format->bits_per_pixel == 8)
2035 /* allocate separate surface bits if byte swapping or palette mapping is required */
2036 if (!(surface->bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
2037 surface->info.bmiHeader.biSizeImage )))
2040 else surface->bits = surface->image->data;
2042 TRACE( "created %p for %lx %s bits %p-%p image %p\n", surface, window, wine_dbgstr_rect(rect),
2043 surface->bits, (char *)surface->bits + surface->info.bmiHeader.biSizeImage,
2044 surface->image->data );
2046 return &surface->header;
2049 x11drv_surface_destroy( &surface->header );
2053 /***********************************************************************
2054 * set_surface_color_key
2056 void set_surface_color_key( struct window_surface *window_surface, COLORREF color_key )
2058 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
2061 window_surface->funcs->lock( window_surface );
2062 prev = surface->color_key;
2063 set_color_key( surface, color_key );
2064 if (surface->color_key != prev) update_surface_region( surface );
2065 window_surface->funcs->unlock( window_surface );
2068 /***********************************************************************
2071 HRGN expose_surface( struct window_surface *window_surface, const RECT *rect )
2073 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
2076 window_surface->funcs->lock( window_surface );
2077 add_bounds_rect( &surface->bounds, rect );
2078 if (surface->region)
2080 region = CreateRectRgnIndirect( rect );
2081 if (CombineRgn( region, region, surface->region, RGN_DIFF ) <= NULLREGION)
2083 DeleteObject( region );
2087 window_surface->funcs->unlock( window_surface );