ntdll: Use an __ms_va_list in sscanf (Clang).
[wine/multimedia.git] / dlls / winex11.drv / bitblt.c
blob2fc7c9484b1ffbb34cdf6d705a4186024ae5a018
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 <X11/Xlib.h>
30 #include <X11/Xresource.h>
31 #include <X11/Xutil.h>
32 #ifdef HAVE_X11_EXTENSIONS_SHAPE_H
33 #include <X11/extensions/shape.h>
34 #endif
35 #ifdef HAVE_X11_EXTENSIONS_XSHM_H
36 # include <X11/extensions/XShm.h>
37 # ifdef HAVE_SYS_SHM_H
38 # include <sys/shm.h>
39 # endif
40 # ifdef HAVE_SYS_IPC_H
41 # include <sys/ipc.h>
42 # endif
43 #endif
45 #include "windef.h"
46 #include "winbase.h"
47 #include "wingdi.h"
48 #include "winuser.h"
49 #include "x11drv.h"
50 #include "winternl.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
504 #else
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
512 #endif
514 #ifdef BITBLT_TEST /* Opcodes test */
516 static int do_bitop( int s, int d, int rop )
518 int res;
519 switch(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;
538 return res & 1;
541 int main()
543 int rop, i, res, src, dst, pat, tmp, dstUsed;
544 const unsigned char *opcode;
546 for (rop = 0; rop < 256; rop++)
548 res = dstUsed = 0;
549 for (i = 0; i < 8; i++)
551 pat = (i >> 2) & 1;
552 src = (i >> 1) & 1;
553 dst = i & 1;
554 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
556 switch(*opcode >> 4)
558 case OP_ARGS(DST,TMP):
559 tmp = do_bitop( dst, tmp, *opcode & 0xf );
560 break;
561 case OP_ARGS(DST,SRC):
562 src = do_bitop( dst, src, *opcode & 0xf );
563 break;
564 case OP_ARGS(SRC,TMP):
565 tmp = do_bitop( src, tmp, *opcode & 0xf );
566 break;
567 case OP_ARGS(SRC,DST):
568 dst = do_bitop( src, dst, *opcode & 0xf );
569 dstUsed = 1;
570 break;
571 case OP_ARGS(PAT,DST):
572 dst = do_bitop( pat, dst, *opcode & 0xf );
573 dstUsed = 1;
574 break;
575 case OP_ARGS(PAT,SRC):
576 src = do_bitop( pat, src, *opcode & 0xf );
577 break;
578 case OP_ARGS(TMP,DST):
579 dst = do_bitop( tmp, dst, *opcode & 0xf );
580 dstUsed = 1;
581 break;
582 case OP_ARGS(TMP,SRC):
583 src = do_bitop( tmp, src, *opcode & 0xf );
584 break;
585 default:
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 );
595 return 0;
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 /***********************************************************************
608 * BITBLT_GetDstArea
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)
615 int exposures = 0;
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 );
625 exposures++;
627 else
629 INT x, y;
630 XImage *image;
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);
637 exposures++;
638 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
639 AllPlanes, ZPixmap );
640 if (image)
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 );
650 return exposures;
654 /***********************************************************************
655 * BITBLT_PutDstArea
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)
662 int exposures = 0;
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 );
674 exposures++;
676 else
678 register INT x, y;
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 );
692 return exposures;
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));
701 return FALSE;
704 void execute_rop( X11DRV_PDEVICE *physdev, Pixmap src_pixmap, GC gc, const RECT *visrect, DWORD rop )
706 Pixmap pixmaps[3];
707 Pixmap result = src_pixmap;
708 BOOL null_brush;
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;
716 pixmaps[TMP] = 0;
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):
730 if (!pixmaps[TMP])
731 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window, width, height, physdev->depth );
732 /* fall through */
733 case OP_ARGS(DST,SRC):
734 case OP_ARGS(SRC,DST):
735 case OP_ARGS(TMP,SRC):
736 case OP_ARGS(TMP,DST):
737 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)], pixmaps[OP_DST(*opcode)], gc,
738 0, 0, width, height, 0, 0 );
739 break;
740 case OP_ARGS(PAT,DST):
741 case OP_ARGS(PAT,SRC):
742 if (!null_brush)
743 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)], gc, 0, 0, width, height );
744 break;
747 XSetFunction( gdi_display, physdev->gc, GXcopy );
748 physdev->exposures += BITBLT_PutDstArea( physdev, result, visrect );
749 XFreePixmap( gdi_display, pixmaps[DST] );
750 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
751 add_device_bounds( physdev, visrect );
754 /***********************************************************************
755 * X11DRV_PatBlt
757 BOOL X11DRV_PatBlt( PHYSDEV dev, struct bitblt_coords *dst, DWORD rop )
759 X11DRV_PDEVICE *physDev = get_x11drv_dev( dev );
760 BOOL usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
761 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
763 if (usePat && !X11DRV_SetupGCForBrush( physDev )) return TRUE;
765 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] );
776 else
777 XSetForeground( gdi_display, physDev->gc,
778 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
779 XSetFillStyle( gdi_display, physDev->gc, FillSolid );
781 break;
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 */
787 /* and white. */
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 );
794 break;
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 );
802 return TRUE;
806 /***********************************************************************
807 * X11DRV_StretchBlt
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 );
814 INT width, height;
815 const BYTE *opcode;
816 Pixmap src_pixmap;
817 GC gc;
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,
844 width, height,
845 physDevDst->dc_rect.left + dst->visrect.left,
846 physDevDst->dc_rect.top + dst->visrect.top );
847 physDevDst->exposures++;
848 return TRUE;
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,
862 width, height,
863 physDevDst->dc_rect.left + dst->visrect.left,
864 physDevDst->dc_rect.top + dst->visrect.top, 1 );
865 physDevDst->exposures++;
866 return TRUE;
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]);
891 else
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 );
913 return TRUE;
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 )
924 XFree( bits->ptr );
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)
958 case 4:
959 case 8:
961 RGBQUAD *rgb = (RGBQUAD *)colors;
962 PALETTEENTRY palette[256];
963 UINT i, count;
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) );
975 break;
977 case 16:
978 colors[0] = vis->red_mask;
979 colors[1] = vis->green_mask;
980 colors[2] = vis->blue_mask;
981 info->bmiHeader.biCompression = BI_BITFIELDS;
982 break;
983 case 32:
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;
989 break;
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)
1000 case 1:
1001 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1002 return !info->bmiHeader.biClrUsed; /* color map not allowed */
1003 case 4:
1004 case 8:
1006 RGBQUAD *rgb = (RGBQUAD *)colors;
1007 PALETTEENTRY palette[256];
1008 UINT i, count;
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;
1019 return TRUE;
1021 case 16:
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);
1028 break;
1029 case 32:
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]);
1034 /* fall through */
1035 case 24:
1036 if (info->bmiHeader.biCompression == BI_RGB)
1037 return (vis->red_mask == 0xff0000 && vis->green_mask == 0x00ff00 && vis->blue_mask == 0x0000ff);
1038 break;
1040 return FALSE;
1043 static inline BOOL is_r8g8b8( const XVisualInfo *vis )
1045 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1046 return format->bits_per_pixel == 24 && vis->red_mask == 0xff0000 && vis->blue_mask == 0x0000ff;
1049 static inline BOOL image_needs_byteswap( XImage *image, BOOL is_r8g8b8, int bit_count )
1051 #ifdef WORDS_BIGENDIAN
1052 static const int client_byte_order = MSBFirst;
1053 #else
1054 static const int client_byte_order = LSBFirst;
1055 #endif
1057 switch (bit_count)
1059 case 1: return image->bitmap_bit_order != MSBFirst;
1060 case 4: return image->byte_order != MSBFirst;
1061 case 16:
1062 case 32: return image->byte_order != client_byte_order;
1063 case 24: return (image->byte_order == MSBFirst) ^ !is_r8g8b8;
1064 default: return FALSE;
1068 /* copy image bits with byte swapping and/or pixel mapping */
1069 static void copy_image_byteswap( BITMAPINFO *info, const unsigned char *src, unsigned char *dst,
1070 int src_stride, int dst_stride, int height,
1071 BOOL byteswap, const int *mapping, unsigned int zeropad_mask )
1073 int x, y, padding_pos = abs(dst_stride) / sizeof(unsigned int) - 1;
1075 if (!byteswap && !mapping) /* simply copy */
1077 if (src != dst)
1079 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1081 memcpy( dst, src, src_stride );
1082 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1085 else if (zeropad_mask != ~0u) /* only need to clear the padding */
1087 for (y = 0; y < height; y++, dst += dst_stride)
1088 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1090 return;
1093 switch (info->bmiHeader.biBitCount)
1095 case 1:
1096 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1098 for (x = 0; x < src_stride; x++) dst[x] = bit_swap[src[x]];
1099 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1101 break;
1102 case 4:
1103 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1105 if (mapping)
1107 if (byteswap)
1108 for (x = 0; x < src_stride; x++)
1109 dst[x] = (mapping[src[x] & 0x0f] << 4) | mapping[src[x] >> 4];
1110 else
1111 for (x = 0; x < src_stride; x++)
1112 dst[x] = mapping[src[x] & 0x0f] | (mapping[src[x] >> 4] << 4);
1114 else
1115 for (x = 0; x < src_stride; x++)
1116 dst[x] = (src[x] << 4) | (src[x] >> 4);
1117 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1119 break;
1120 case 8:
1121 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1123 for (x = 0; x < src_stride; x++) dst[x] = mapping[src[x]];
1124 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1126 break;
1127 case 16:
1128 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1130 for (x = 0; x < info->bmiHeader.biWidth; x++)
1131 ((USHORT *)dst)[x] = RtlUshortByteSwap( ((const USHORT *)src)[x] );
1132 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1134 break;
1135 case 24:
1136 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1138 for (x = 0; x < info->bmiHeader.biWidth; x++)
1140 unsigned char tmp = src[3 * x];
1141 dst[3 * x] = src[3 * x + 2];
1142 dst[3 * x + 1] = src[3 * x + 1];
1143 dst[3 * x + 2] = tmp;
1145 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1147 break;
1148 case 32:
1149 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1150 for (x = 0; x < info->bmiHeader.biWidth; x++)
1151 ((ULONG *)dst)[x] = RtlUlongByteSwap( ((const ULONG *)src)[x] );
1152 break;
1156 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1157 DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image,
1158 const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
1159 struct bitblt_coords *coords, const int *mapping, unsigned int zeropad_mask )
1161 BOOL need_byteswap = image_needs_byteswap( image, is_r8g8b8, info->bmiHeader.biBitCount );
1162 int height = coords->visrect.bottom - coords->visrect.top;
1163 int width_bytes = image->bytes_per_line;
1164 unsigned char *src, *dst;
1166 src = src_bits->ptr;
1167 if (info->bmiHeader.biHeight > 0)
1168 src += (info->bmiHeader.biHeight - coords->visrect.bottom) * width_bytes;
1169 else
1170 src += coords->visrect.top * width_bytes;
1172 if ((need_byteswap && !src_bits->is_copy) || /* need to swap bytes */
1173 (zeropad_mask != ~0u && !src_bits->is_copy) || /* need to clear padding bytes */
1174 (mapping && !src_bits->is_copy) || /* need to remap pixels */
1175 (width_bytes & 3) || /* need to fixup line alignment */
1176 (info->bmiHeader.biHeight > 0)) /* need to flip vertically */
1178 width_bytes = (width_bytes + 3) & ~3;
1179 info->bmiHeader.biSizeImage = height * width_bytes;
1180 if (!(dst_bits->ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
1181 return ERROR_OUTOFMEMORY;
1182 dst_bits->is_copy = TRUE;
1183 dst_bits->free = free_heap_bits;
1185 else
1187 /* swap bits in place */
1188 dst_bits->ptr = src;
1189 dst_bits->is_copy = src_bits->is_copy;
1190 dst_bits->free = NULL;
1191 if (!need_byteswap && zeropad_mask == ~0u && !mapping) return ERROR_SUCCESS; /* nothing to do */
1194 dst = dst_bits->ptr;
1196 if (info->bmiHeader.biHeight > 0)
1198 dst += (height - 1) * width_bytes;
1199 width_bytes = -width_bytes;
1202 copy_image_byteswap( info, src, dst, image->bytes_per_line, width_bytes, height,
1203 need_byteswap, mapping, zeropad_mask );
1204 return ERROR_SUCCESS;
1207 /***********************************************************************
1208 * X11DRV_PutImage
1210 DWORD X11DRV_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
1211 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1212 struct bitblt_coords *dst, DWORD rop )
1214 X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1215 DWORD ret;
1216 XImage *image;
1217 XVisualInfo vis = default_visual;
1218 struct gdi_image_bits dst_bits;
1219 const XPixmapFormatValues *format;
1220 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1221 const int *mapping = NULL;
1223 vis.depth = physdev->depth;
1224 if (physdev->color_shifts)
1226 vis.red_mask = physdev->color_shifts->logicalRed.max << physdev->color_shifts->logicalRed.shift;
1227 vis.green_mask = physdev->color_shifts->logicalGreen.max << physdev->color_shifts->logicalGreen.shift;
1228 vis.blue_mask = physdev->color_shifts->logicalBlue.max << physdev->color_shifts->logicalBlue.shift;
1230 format = pixmap_formats[vis.depth];
1232 if (info->bmiHeader.biPlanes != 1) goto update_format;
1233 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1234 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1235 if (!matching_color_info( &vis, info )) goto update_format;
1236 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1237 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
1239 image = XCreateImage( gdi_display, vis.visual, vis.depth, ZPixmap, 0, NULL,
1240 info->bmiHeader.biWidth, src->visrect.bottom - src->visrect.top, 32, 0 );
1241 if (!image) return ERROR_OUTOFMEMORY;
1243 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1245 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1246 mapping = X11DRV_PALETTE_PaletteToXPixel;
1249 ret = copy_image_bits( info, is_r8g8b8(&vis), image, bits, &dst_bits, src, mapping, ~0u );
1251 if (!ret)
1253 BOOL restore_region = add_extra_clipping_region( physdev, clip );
1254 int width = dst->visrect.right - dst->visrect.left;
1255 int height = dst->visrect.bottom - dst->visrect.top;
1257 image->data = dst_bits.ptr;
1259 /* optimization for single-op ROPs */
1260 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1262 XSetFunction( gdi_display, physdev->gc, OP_ROP(*opcode) );
1263 XPutImage( gdi_display, physdev->drawable, physdev->gc, image, src->visrect.left, 0,
1264 physdev->dc_rect.left + dst->visrect.left,
1265 physdev->dc_rect.top + dst->visrect.top, width, height );
1267 else
1269 GC gc = XCreateGC( gdi_display, physdev->drawable, 0, NULL );
1270 Pixmap src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, vis.depth );
1272 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1273 XSetGraphicsExposures( gdi_display, gc, False );
1274 XPutImage( gdi_display, src_pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1276 execute_rop( physdev, src_pixmap, gc, &dst->visrect, rop );
1278 XFreePixmap( gdi_display, src_pixmap );
1279 XFreeGC( gdi_display, gc );
1282 if (restore_region) restore_clipping_region( physdev );
1283 add_device_bounds( physdev, &dst->visrect );
1284 image->data = NULL;
1287 XDestroyImage( image );
1288 if (dst_bits.free) dst_bits.free( &dst_bits );
1289 return ret;
1291 update_format:
1292 info->bmiHeader.biPlanes = 1;
1293 info->bmiHeader.biBitCount = format->bits_per_pixel;
1294 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1295 set_color_info( &vis, info, FALSE );
1296 return ERROR_BAD_FORMAT;
1299 /***********************************************************************
1300 * X11DRV_GetImage
1302 DWORD X11DRV_GetImage( PHYSDEV dev, BITMAPINFO *info,
1303 struct gdi_image_bits *bits, struct bitblt_coords *src )
1305 X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1306 DWORD ret = ERROR_SUCCESS;
1307 XImage *image;
1308 XVisualInfo vis = default_visual;
1309 UINT align, x, y, width, height;
1310 struct gdi_image_bits src_bits;
1311 const XPixmapFormatValues *format;
1312 const int *mapping = NULL;
1314 vis.depth = physdev->depth;
1315 if (physdev->color_shifts)
1317 vis.red_mask = physdev->color_shifts->logicalRed.max << physdev->color_shifts->logicalRed.shift;
1318 vis.green_mask = physdev->color_shifts->logicalGreen.max << physdev->color_shifts->logicalGreen.shift;
1319 vis.blue_mask = physdev->color_shifts->logicalBlue.max << physdev->color_shifts->logicalBlue.shift;
1321 format = pixmap_formats[vis.depth];
1323 /* align start and width to 32-bit boundary */
1324 switch (format->bits_per_pixel)
1326 case 1: align = 32; break;
1327 case 4: align = 8; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1328 case 8: align = 4; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1329 case 16: align = 2; break;
1330 case 24: align = 4; break;
1331 case 32: align = 1; break;
1332 default:
1333 FIXME( "depth %u bpp %u not supported yet\n", vis.depth, format->bits_per_pixel );
1334 return ERROR_BAD_FORMAT;
1337 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1338 info->bmiHeader.biPlanes = 1;
1339 info->bmiHeader.biBitCount = format->bits_per_pixel;
1340 info->bmiHeader.biXPelsPerMeter = 0;
1341 info->bmiHeader.biYPelsPerMeter = 0;
1342 info->bmiHeader.biClrImportant = 0;
1343 set_color_info( &vis, info, FALSE );
1345 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
1347 x = src->visrect.left & ~(align - 1);
1348 y = src->visrect.top;
1349 width = src->visrect.right - x;
1350 height = src->visrect.bottom - src->visrect.top;
1351 if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1);
1352 /* make the source rectangle relative to the returned bits */
1353 src->x -= x;
1354 src->y -= y;
1355 OffsetRect( &src->visrect, -x, -y );
1357 X11DRV_expect_error( gdi_display, XGetImage_handler, NULL );
1358 image = XGetImage( gdi_display, physdev->drawable,
1359 physdev->dc_rect.left + x, physdev->dc_rect.top + y,
1360 width, height, AllPlanes, ZPixmap );
1361 if (X11DRV_check_error())
1363 /* use a temporary pixmap to avoid the BadMatch error */
1364 Pixmap pixmap = XCreatePixmap( gdi_display, root_window, width, height, vis.depth );
1365 GC gc = XCreateGC( gdi_display, pixmap, 0, NULL );
1367 XSetGraphicsExposures( gdi_display, gc, False );
1368 XCopyArea( gdi_display, physdev->drawable, pixmap, gc,
1369 physdev->dc_rect.left + x, physdev->dc_rect.top + y, width, height, 0, 0 );
1370 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1371 XFreePixmap( gdi_display, pixmap );
1372 XFreeGC( gdi_display, gc );
1375 if (!image) return ERROR_OUTOFMEMORY;
1377 info->bmiHeader.biWidth = width;
1378 info->bmiHeader.biHeight = -height;
1379 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1381 src_bits.ptr = image->data;
1382 src_bits.is_copy = TRUE;
1383 ret = copy_image_bits( info, is_r8g8b8(&vis), image, &src_bits, bits, src, mapping,
1384 zeropad_masks[(width * image->bits_per_pixel) & 31] );
1386 if (!ret && bits->ptr == image->data)
1388 bits->free = free_ximage_bits;
1389 image->data = NULL;
1391 XDestroyImage( image );
1392 return ret;
1396 /***********************************************************************
1397 * put_pixmap_image
1399 * Simplified equivalent of X11DRV_PutImage that writes directly to a pixmap.
1401 static DWORD put_pixmap_image( Pixmap pixmap, const XVisualInfo *vis,
1402 BITMAPINFO *info, const struct gdi_image_bits *bits )
1404 DWORD ret;
1405 XImage *image;
1406 GC gc;
1407 struct bitblt_coords coords;
1408 struct gdi_image_bits dst_bits;
1409 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1410 const int *mapping = NULL;
1412 if (!format) return ERROR_INVALID_PARAMETER;
1413 if (info->bmiHeader.biPlanes != 1) goto update_format;
1414 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1415 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1416 if (!matching_color_info( vis, info )) goto update_format;
1417 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1419 coords.x = 0;
1420 coords.y = 0;
1421 coords.width = info->bmiHeader.biWidth;
1422 coords.height = abs( info->bmiHeader.biHeight );
1423 SetRect( &coords.visrect, 0, 0, coords.width, coords.height );
1425 image = XCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, 0, NULL,
1426 coords.width, coords.height, 32, 0 );
1427 if (!image) return ERROR_OUTOFMEMORY;
1429 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1430 mapping = X11DRV_PALETTE_PaletteToXPixel;
1432 if (!(ret = copy_image_bits( info, is_r8g8b8(vis), image, bits, &dst_bits, &coords, mapping, ~0u )))
1434 image->data = dst_bits.ptr;
1435 gc = XCreateGC( gdi_display, pixmap, 0, NULL );
1436 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, coords.width, coords.height );
1437 XFreeGC( gdi_display, gc );
1438 image->data = NULL;
1441 XDestroyImage( image );
1442 if (dst_bits.free) dst_bits.free( &dst_bits );
1443 return ret;
1445 update_format:
1446 info->bmiHeader.biPlanes = 1;
1447 info->bmiHeader.biBitCount = format->bits_per_pixel;
1448 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1449 set_color_info( vis, info, FALSE );
1450 return ERROR_BAD_FORMAT;
1454 /***********************************************************************
1455 * create_pixmap_from_image
1457 Pixmap create_pixmap_from_image( HDC hdc, const XVisualInfo *vis, const BITMAPINFO *info,
1458 const struct gdi_image_bits *bits, UINT coloruse )
1460 static const RGBQUAD default_colortable[2] = { { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff } };
1461 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1462 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1463 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
1464 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
1465 struct gdi_image_bits dst_bits;
1466 Pixmap pixmap;
1467 DWORD err;
1468 HBITMAP dib;
1470 pixmap = XCreatePixmap( gdi_display, root_window,
1471 info->bmiHeader.biWidth, abs(info->bmiHeader.biHeight), vis->depth );
1472 if (!pixmap) return 0;
1474 memcpy( src_info, info, get_dib_info_size( info, coloruse ));
1475 memcpy( dst_info, info, get_dib_info_size( info, coloruse ));
1477 if (coloruse == DIB_PAL_COLORS ||
1478 (err = put_pixmap_image( pixmap, vis, dst_info, bits )) == ERROR_BAD_FORMAT)
1480 if (dst_info->bmiHeader.biBitCount == 1) /* set a default color table for 1-bpp */
1481 memcpy( dst_info->bmiColors, default_colortable, sizeof(default_colortable) );
1482 dib = CreateDIBSection( hdc, dst_info, coloruse, &dst_bits.ptr, 0, 0 );
1483 if (dib)
1485 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
1486 memcpy( src_info->bmiColors, default_colortable, sizeof(default_colortable) );
1487 SetDIBits( hdc, dib, 0, abs(info->bmiHeader.biHeight), bits->ptr, src_info, coloruse );
1488 dst_bits.free = NULL;
1489 dst_bits.is_copy = TRUE;
1490 err = put_pixmap_image( pixmap, vis, dst_info, &dst_bits );
1491 DeleteObject( dib );
1493 else err = ERROR_OUTOFMEMORY;
1496 if (!err) return pixmap;
1498 XFreePixmap( gdi_display, pixmap );
1499 return 0;
1504 /***********************************************************************
1505 * get_pixmap_image
1507 * Equivalent of X11DRV_GetImage that reads directly from a pixmap.
1509 DWORD get_pixmap_image( Pixmap pixmap, int width, int height, const XVisualInfo *vis,
1510 BITMAPINFO *info, struct gdi_image_bits *bits )
1512 DWORD ret = ERROR_SUCCESS;
1513 XImage *image;
1514 struct gdi_image_bits src_bits;
1515 struct bitblt_coords coords;
1516 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1517 const int *mapping = NULL;
1519 if (!format) return ERROR_INVALID_PARAMETER;
1521 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1522 info->bmiHeader.biWidth = width;
1523 info->bmiHeader.biHeight = -height;
1524 info->bmiHeader.biPlanes = 1;
1525 info->bmiHeader.biBitCount = format->bits_per_pixel;
1526 info->bmiHeader.biXPelsPerMeter = 0;
1527 info->bmiHeader.biYPelsPerMeter = 0;
1528 info->bmiHeader.biClrImportant = 0;
1529 set_color_info( vis, info, FALSE );
1531 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
1533 coords.x = 0;
1534 coords.y = 0;
1535 coords.width = width;
1536 coords.height = height;
1537 SetRect( &coords.visrect, 0, 0, width, height );
1539 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1540 if (!image) return ERROR_OUTOFMEMORY;
1542 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1544 src_bits.ptr = image->data;
1545 src_bits.is_copy = TRUE;
1546 ret = copy_image_bits( info, is_r8g8b8(vis), image, &src_bits, bits, &coords, mapping,
1547 zeropad_masks[(width * image->bits_per_pixel) & 31] );
1549 if (!ret && bits->ptr == image->data)
1551 bits->free = free_ximage_bits;
1552 image->data = NULL;
1554 XDestroyImage( image );
1555 return ret;
1559 struct x11drv_window_surface
1561 struct window_surface header;
1562 Window window;
1563 GC gc;
1564 XImage *image;
1565 RECT bounds;
1566 BOOL byteswap;
1567 BOOL is_argb;
1568 COLORREF color_key;
1569 HRGN region;
1570 void *bits;
1571 #ifdef HAVE_LIBXXSHM
1572 XShmSegmentInfo shminfo;
1573 #endif
1574 CRITICAL_SECTION crit;
1575 BITMAPINFO info; /* variable size, must be last */
1578 static struct x11drv_window_surface *get_x11_surface( struct window_surface *surface )
1580 return (struct x11drv_window_surface *)surface;
1583 static inline UINT get_color_component( UINT color, UINT mask )
1585 int shift;
1586 for (shift = 0; !(mask & 1); shift++) mask >>= 1;
1587 return (color * mask / 255) << shift;
1590 static inline void flush_rgn_data( HRGN rgn, RGNDATA *data )
1592 HRGN tmp = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data );
1593 CombineRgn( rgn, rgn, tmp, RGN_OR );
1594 DeleteObject( tmp );
1595 data->rdh.nCount = 0;
1598 static inline void add_row( HRGN rgn, RGNDATA *data, int x, int y, int len )
1600 RECT *rect = (RECT *)data->Buffer + data->rdh.nCount;
1602 if (len <= 0) return;
1603 rect->left = x;
1604 rect->top = y;
1605 rect->right = x + len;
1606 rect->bottom = y + 1;
1607 data->rdh.nCount++;
1608 if (data->rdh.nCount * sizeof(RECT) > data->rdh.nRgnSize - sizeof(RECT))
1609 flush_rgn_data( rgn, data );
1612 /***********************************************************************
1613 * update_surface_region
1615 static void update_surface_region( struct x11drv_window_surface *surface )
1617 #ifdef HAVE_LIBXSHAPE
1618 char buffer[4096];
1619 RGNDATA *data = (RGNDATA *)buffer;
1620 BITMAPINFO *info = &surface->info;
1621 UINT *masks = (UINT *)info->bmiColors;
1622 int x, y, start, width;
1623 HRGN rgn;
1625 if (!shape_layered_windows) return;
1627 if (!surface->is_argb && surface->color_key == CLR_INVALID)
1629 XShapeCombineMask( gdi_display, surface->window, ShapeBounding, 0, 0, None, ShapeSet );
1630 return;
1633 data->rdh.dwSize = sizeof(data->rdh);
1634 data->rdh.iType = RDH_RECTANGLES;
1635 data->rdh.nCount = 0;
1636 data->rdh.nRgnSize = sizeof(buffer) - sizeof(data->rdh);
1638 rgn = CreateRectRgn( 0, 0, 0, 0 );
1639 width = surface->header.rect.right - surface->header.rect.left;
1641 switch (info->bmiHeader.biBitCount)
1643 case 16:
1645 WORD *bits = surface->bits;
1646 int stride = (width + 1) & ~1;
1647 UINT mask = masks[0] | masks[1] | masks[2];
1649 for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += stride)
1651 x = 0;
1652 while (x < width)
1654 while (x < width && (bits[x] & mask) == surface->color_key) x++;
1655 start = x;
1656 while (x < width && (bits[x] & mask) != surface->color_key) x++;
1657 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1660 break;
1662 case 24:
1664 BYTE *bits = surface->bits;
1665 int stride = (width * 3 + 3) & ~3;
1667 for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += stride)
1669 x = 0;
1670 while (x < width)
1672 while (x < width &&
1673 (bits[x * 3] == GetBValue(surface->color_key)) &&
1674 (bits[x * 3 + 1] == GetGValue(surface->color_key)) &&
1675 (bits[x * 3 + 2] == GetRValue(surface->color_key)))
1676 x++;
1677 start = x;
1678 while (x < width &&
1679 ((bits[x * 3] != GetBValue(surface->color_key)) ||
1680 (bits[x * 3 + 1] != GetGValue(surface->color_key)) ||
1681 (bits[x * 3 + 2] != GetRValue(surface->color_key))))
1682 x++;
1683 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1686 break;
1688 case 32:
1690 DWORD *bits = surface->bits;
1692 if (info->bmiHeader.biCompression == BI_RGB)
1694 for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += width)
1696 x = 0;
1697 while (x < width)
1699 while (x < width &&
1700 ((bits[x] & 0xffffff) == surface->color_key ||
1701 (surface->is_argb && !(bits[x] & 0xff000000)))) x++;
1702 start = x;
1703 while (x < width &&
1704 !((bits[x] & 0xffffff) == surface->color_key ||
1705 (surface->is_argb && !(bits[x] & 0xff000000)))) x++;
1706 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1710 else
1712 UINT mask = masks[0] | masks[1] | masks[2];
1713 for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += width)
1715 x = 0;
1716 while (x < width)
1718 while (x < width && (bits[x] & mask) == surface->color_key) x++;
1719 start = x;
1720 while (x < width && (bits[x] & mask) != surface->color_key) x++;
1721 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1725 break;
1727 default:
1728 assert(0);
1731 if (data->rdh.nCount) flush_rgn_data( rgn, data );
1733 if ((data = X11DRV_GetRegionData( rgn, 0 )))
1735 XShapeCombineRectangles( gdi_display, surface->window, ShapeBounding, 0, 0,
1736 (XRectangle *)data->Buffer, data->rdh.nCount, ShapeSet, YXBanded );
1737 HeapFree( GetProcessHeap(), 0, data );
1740 DeleteObject( rgn );
1741 #endif
1744 /***********************************************************************
1745 * set_color_key
1747 static void set_color_key( struct x11drv_window_surface *surface, COLORREF key )
1749 UINT *masks = (UINT *)surface->info.bmiColors;
1751 if (key == CLR_INVALID)
1752 surface->color_key = CLR_INVALID;
1753 else if (surface->info.bmiHeader.biBitCount <= 8)
1754 surface->color_key = CLR_INVALID;
1755 else if (key & (1 << 24)) /* PALETTEINDEX */
1756 surface->color_key = 0;
1757 else if (key >> 16 == 0x10ff) /* DIBINDEX */
1758 surface->color_key = 0;
1759 else if (surface->info.bmiHeader.biBitCount == 24)
1760 surface->color_key = key;
1761 else if (surface->info.bmiHeader.biCompression == BI_RGB)
1762 surface->color_key = (GetRValue(key) << 16) | (GetGValue(key) << 8) | GetBValue(key);
1763 else
1764 surface->color_key = get_color_component( GetRValue(key), masks[0] ) |
1765 get_color_component( GetGValue(key), masks[1] ) |
1766 get_color_component( GetBValue(key), masks[2] );
1769 #ifdef HAVE_LIBXXSHM
1770 static int xshm_error_handler( Display *display, XErrorEvent *event, void *arg )
1772 return 1; /* FIXME: should check event contents */
1775 static XImage *create_shm_image( const XVisualInfo *vis, int width, int height, XShmSegmentInfo *shminfo )
1777 XImage *image;
1779 shminfo->shmid = -1;
1780 image = XShmCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, NULL, shminfo, width, height );
1781 if (!image) return NULL;
1782 if (image->bytes_per_line & 3) goto failed; /* we need 32-bit alignment */
1784 shminfo->shmid = shmget( IPC_PRIVATE, image->bytes_per_line * height, IPC_CREAT | 0700 );
1785 if (shminfo->shmid == -1) goto failed;
1787 shminfo->shmaddr = shmat( shminfo->shmid, 0, 0 );
1788 if (shminfo->shmaddr != (char *)-1)
1790 BOOL ok;
1792 shminfo->readOnly = True;
1793 X11DRV_expect_error( gdi_display, xshm_error_handler, NULL );
1794 ok = (XShmAttach( gdi_display, shminfo ) != 0);
1795 XSync( gdi_display, False );
1796 if (!X11DRV_check_error() && ok)
1798 image->data = shminfo->shmaddr;
1799 shmctl( shminfo->shmid, IPC_RMID, 0 );
1800 return image;
1802 shmdt( shminfo->shmaddr );
1804 shmctl( shminfo->shmid, IPC_RMID, 0 );
1805 shminfo->shmid = -1;
1807 failed:
1808 XDestroyImage( image );
1809 return NULL;
1811 #endif /* HAVE_LIBXXSHM */
1813 /***********************************************************************
1814 * x11drv_surface_lock
1816 static void x11drv_surface_lock( struct window_surface *window_surface )
1818 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1820 EnterCriticalSection( &surface->crit );
1823 /***********************************************************************
1824 * x11drv_surface_unlock
1826 static void x11drv_surface_unlock( struct window_surface *window_surface )
1828 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1830 LeaveCriticalSection( &surface->crit );
1833 /***********************************************************************
1834 * x11drv_surface_get_bitmap_info
1836 static void *x11drv_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
1838 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1840 memcpy( info, &surface->info, get_dib_info_size( &surface->info, DIB_RGB_COLORS ));
1841 return surface->bits;
1844 /***********************************************************************
1845 * x11drv_surface_get_bounds
1847 static RECT *x11drv_surface_get_bounds( struct window_surface *window_surface )
1849 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1851 return &surface->bounds;
1854 /***********************************************************************
1855 * x11drv_surface_set_region
1857 static void x11drv_surface_set_region( struct window_surface *window_surface, HRGN region )
1859 RGNDATA *data;
1860 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1862 TRACE( "updating surface %p with %p\n", surface, region );
1864 window_surface->funcs->lock( window_surface );
1865 if (!region)
1867 if (surface->region) DeleteObject( surface->region );
1868 surface->region = 0;
1869 XSetClipMask( gdi_display, surface->gc, None );
1871 else
1873 if (!surface->region) surface->region = CreateRectRgn( 0, 0, 0, 0 );
1874 CombineRgn( surface->region, region, 0, RGN_COPY );
1875 if ((data = X11DRV_GetRegionData( surface->region, 0 )))
1877 XSetClipRectangles( gdi_display, surface->gc, 0, 0,
1878 (XRectangle *)data->Buffer, data->rdh.nCount, YXBanded );
1879 HeapFree( GetProcessHeap(), 0, data );
1882 window_surface->funcs->unlock( window_surface );
1885 /***********************************************************************
1886 * x11drv_surface_flush
1888 static void x11drv_surface_flush( struct window_surface *window_surface )
1890 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1891 unsigned char *src = surface->bits;
1892 unsigned char *dst = (unsigned char *)surface->image->data;
1893 struct bitblt_coords coords;
1895 window_surface->funcs->lock( window_surface );
1896 coords.x = 0;
1897 coords.y = 0;
1898 coords.width = surface->header.rect.right - surface->header.rect.left;
1899 coords.height = surface->header.rect.bottom - surface->header.rect.top;
1900 SetRect( &coords.visrect, 0, 0, coords.width, coords.height );
1901 if (IntersectRect( &coords.visrect, &coords.visrect, &surface->bounds ))
1903 TRACE( "flushing %p %dx%d bounds %s bits %p\n",
1904 surface, coords.width, coords.height,
1905 wine_dbgstr_rect( &surface->bounds ), surface->bits );
1907 if (surface->is_argb || surface->color_key != CLR_INVALID) update_surface_region( surface );
1909 if (src != dst)
1911 const int *mapping = NULL;
1912 int width_bytes = surface->image->bytes_per_line;
1914 if (surface->image->bits_per_pixel == 4 || surface->image->bits_per_pixel == 8)
1915 mapping = X11DRV_PALETTE_PaletteToXPixel;
1917 src += coords.visrect.top * width_bytes;
1918 dst += coords.visrect.top * width_bytes;
1919 copy_image_byteswap( &surface->info, src, dst, width_bytes, width_bytes,
1920 coords.visrect.bottom - coords.visrect.top,
1921 surface->byteswap, mapping, ~0u );
1924 #ifdef HAVE_LIBXXSHM
1925 if (surface->shminfo.shmid != -1)
1926 XShmPutImage( gdi_display, surface->window, surface->gc, surface->image,
1927 coords.visrect.left, coords.visrect.top,
1928 surface->header.rect.left + coords.visrect.left,
1929 surface->header.rect.top + coords.visrect.top,
1930 coords.visrect.right - coords.visrect.left,
1931 coords.visrect.bottom - coords.visrect.top, False );
1932 else
1933 #endif
1934 XPutImage( gdi_display, surface->window, surface->gc, surface->image,
1935 coords.visrect.left, coords.visrect.top,
1936 surface->header.rect.left + coords.visrect.left,
1937 surface->header.rect.top + coords.visrect.top,
1938 coords.visrect.right - coords.visrect.left,
1939 coords.visrect.bottom - coords.visrect.top );
1941 reset_bounds( &surface->bounds );
1942 window_surface->funcs->unlock( window_surface );
1945 /***********************************************************************
1946 * x11drv_surface_destroy
1948 static void x11drv_surface_destroy( struct window_surface *window_surface )
1950 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1952 TRACE( "freeing %p bits %p\n", surface, surface->bits );
1953 if (surface->gc) XFreeGC( gdi_display, surface->gc );
1954 if (surface->image)
1956 if (surface->image->data != surface->bits) HeapFree( GetProcessHeap(), 0, surface->bits );
1957 #ifdef HAVE_LIBXXSHM
1958 if (surface->shminfo.shmid != -1)
1960 XShmDetach( gdi_display, &surface->shminfo );
1961 shmdt( surface->shminfo.shmaddr );
1963 else
1964 #endif
1965 HeapFree( GetProcessHeap(), 0, surface->image->data );
1966 surface->image->data = NULL;
1967 XDestroyImage( surface->image );
1969 surface->crit.DebugInfo->Spare[0] = 0;
1970 DeleteCriticalSection( &surface->crit );
1971 if (surface->region) DeleteObject( surface->region );
1972 HeapFree( GetProcessHeap(), 0, surface );
1975 static const struct window_surface_funcs x11drv_surface_funcs =
1977 x11drv_surface_lock,
1978 x11drv_surface_unlock,
1979 x11drv_surface_get_bitmap_info,
1980 x11drv_surface_get_bounds,
1981 x11drv_surface_set_region,
1982 x11drv_surface_flush,
1983 x11drv_surface_destroy
1986 /***********************************************************************
1987 * create_surface
1989 struct window_surface *create_surface( Window window, const XVisualInfo *vis, const RECT *rect,
1990 COLORREF color_key, BOOL use_alpha )
1992 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1993 struct x11drv_window_surface *surface;
1994 int width = rect->right - rect->left, height = rect->bottom - rect->top;
1995 int colors = format->bits_per_pixel <= 8 ? 1 << format->bits_per_pixel : 3;
1997 surface = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1998 FIELD_OFFSET( struct x11drv_window_surface, info.bmiColors[colors] ));
1999 if (!surface) return NULL;
2000 surface->info.bmiHeader.biSize = sizeof(surface->info.bmiHeader);
2001 surface->info.bmiHeader.biWidth = width;
2002 surface->info.bmiHeader.biHeight = -height; /* top-down */
2003 surface->info.bmiHeader.biPlanes = 1;
2004 surface->info.bmiHeader.biBitCount = format->bits_per_pixel;
2005 surface->info.bmiHeader.biSizeImage = get_dib_image_size( &surface->info );
2006 set_color_info( vis, &surface->info, use_alpha );
2008 InitializeCriticalSection( &surface->crit );
2009 surface->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": surface");
2011 surface->header.funcs = &x11drv_surface_funcs;
2012 surface->header.rect = *rect;
2013 surface->header.ref = 1;
2014 surface->window = window;
2015 surface->is_argb = (use_alpha && vis->depth == 32 && surface->info.bmiHeader.biCompression == BI_RGB);
2016 set_color_key( surface, color_key );
2017 reset_bounds( &surface->bounds );
2019 #ifdef HAVE_LIBXXSHM
2020 surface->image = create_shm_image( vis, width, height, &surface->shminfo );
2021 if (!surface->image)
2022 #endif
2024 surface->image = XCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, 0, NULL,
2025 width, height, 32, 0 );
2026 if (!surface->image) goto failed;
2027 surface->image->data = HeapAlloc( GetProcessHeap(), 0, surface->info.bmiHeader.biSizeImage );
2028 if (!surface->image->data) goto failed;
2031 surface->gc = XCreateGC( gdi_display, window, 0, NULL );
2032 XSetSubwindowMode( gdi_display, surface->gc, IncludeInferiors );
2033 surface->byteswap = image_needs_byteswap( surface->image, is_r8g8b8(vis), format->bits_per_pixel );
2035 if (surface->byteswap || format->bits_per_pixel == 4 || format->bits_per_pixel == 8)
2037 /* allocate separate surface bits if byte swapping or palette mapping is required */
2038 if (!(surface->bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
2039 surface->info.bmiHeader.biSizeImage )))
2040 goto failed;
2042 else surface->bits = surface->image->data;
2044 TRACE( "created %p for %lx %s bits %p-%p image %p\n", surface, window, wine_dbgstr_rect(rect),
2045 surface->bits, (char *)surface->bits + surface->info.bmiHeader.biSizeImage,
2046 surface->image->data );
2048 return &surface->header;
2050 failed:
2051 x11drv_surface_destroy( &surface->header );
2052 return NULL;
2055 /***********************************************************************
2056 * set_surface_color_key
2058 void set_surface_color_key( struct window_surface *window_surface, COLORREF color_key )
2060 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
2061 COLORREF prev;
2063 if (window_surface->funcs != &x11drv_surface_funcs) return; /* we may get the null surface */
2065 window_surface->funcs->lock( window_surface );
2066 prev = surface->color_key;
2067 set_color_key( surface, color_key );
2068 if (surface->color_key != prev) update_surface_region( surface );
2069 window_surface->funcs->unlock( window_surface );
2072 /***********************************************************************
2073 * expose_surface
2075 HRGN expose_surface( struct window_surface *window_surface, const RECT *rect )
2077 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
2078 HRGN region = 0;
2080 if (window_surface->funcs != &x11drv_surface_funcs) return 0; /* we may get the null surface */
2082 window_surface->funcs->lock( window_surface );
2083 add_bounds_rect( &surface->bounds, rect );
2084 if (surface->region)
2086 region = CreateRectRgnIndirect( rect );
2087 if (CombineRgn( region, region, surface->region, RGN_DIFF ) <= NULLREGION)
2089 DeleteObject( region );
2090 region = 0;
2093 window_surface->funcs->unlock( window_surface );
2094 return region;