msvcrt: Remove MSVCRT_ prefix from ctype.c functions.
[wine.git] / dlls / winex11.drv / bitblt.c
blobfad183b0b0113dfa8d727f7746303cb8acff10b0
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 CDECL 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 CDECL 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 CDECL free_heap_bits( struct gdi_image_bits *bits )
919 HeapFree( GetProcessHeap(), 0, bits->ptr );
922 static void CDECL free_ximage_bits( struct gdi_image_bits *bits )
924 XFree( bits->ptr );
927 static inline int get_dib_info_size( const BITMAPINFO *info, UINT coloruse )
929 if (info->bmiHeader.biCompression == BI_BITFIELDS)
930 return sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD);
931 if (coloruse == DIB_PAL_COLORS)
932 return sizeof(BITMAPINFOHEADER) + info->bmiHeader.biClrUsed * sizeof(WORD);
933 if (!info->bmiHeader.biClrUsed && info->bmiHeader.biBitCount <= 8)
934 return FIELD_OFFSET( BITMAPINFO, bmiColors[1 << info->bmiHeader.biBitCount] );
935 return FIELD_OFFSET( BITMAPINFO, bmiColors[info->bmiHeader.biClrUsed] );
938 static inline int get_dib_stride( int width, int bpp )
940 return ((width * bpp + 31) >> 3) & ~3;
943 static inline int get_dib_image_size( const BITMAPINFO *info )
945 return get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount )
946 * abs( info->bmiHeader.biHeight );
949 /* store the palette or color mask data in the bitmap info structure */
950 static void set_color_info( const XVisualInfo *vis, BITMAPINFO *info, BOOL has_alpha )
952 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
954 info->bmiHeader.biCompression = BI_RGB;
955 info->bmiHeader.biClrUsed = 0;
957 switch (info->bmiHeader.biBitCount)
959 case 4:
960 case 8:
962 RGBQUAD *rgb = (RGBQUAD *)colors;
963 PALETTEENTRY palette[256];
964 UINT i, count;
966 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
967 count = X11DRV_GetSystemPaletteEntries( NULL, 0, info->bmiHeader.biClrUsed, palette );
968 for (i = 0; i < count; i++)
970 rgb[i].rgbRed = palette[i].peRed;
971 rgb[i].rgbGreen = palette[i].peGreen;
972 rgb[i].rgbBlue = palette[i].peBlue;
973 rgb[i].rgbReserved = 0;
975 memset( &rgb[count], 0, (info->bmiHeader.biClrUsed - count) * sizeof(*rgb) );
976 break;
978 case 16:
979 colors[0] = vis->red_mask;
980 colors[1] = vis->green_mask;
981 colors[2] = vis->blue_mask;
982 info->bmiHeader.biCompression = BI_BITFIELDS;
983 break;
984 case 32:
985 colors[0] = vis->red_mask;
986 colors[1] = vis->green_mask;
987 colors[2] = vis->blue_mask;
988 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff || !has_alpha)
989 info->bmiHeader.biCompression = BI_BITFIELDS;
990 break;
994 /* check if the specified color info is suitable for PutImage */
995 static BOOL matching_color_info( const XVisualInfo *vis, const BITMAPINFO *info )
997 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
999 switch (info->bmiHeader.biBitCount)
1001 case 1:
1002 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1003 return !info->bmiHeader.biClrUsed; /* color map not allowed */
1004 case 4:
1005 case 8:
1007 RGBQUAD *rgb = (RGBQUAD *)colors;
1008 PALETTEENTRY palette[256];
1009 UINT i, count;
1011 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1012 count = X11DRV_GetSystemPaletteEntries( NULL, 0, 1 << info->bmiHeader.biBitCount, palette );
1013 if (count != info->bmiHeader.biClrUsed) return FALSE;
1014 for (i = 0; i < count; i++)
1016 if (rgb[i].rgbRed != palette[i].peRed ||
1017 rgb[i].rgbGreen != palette[i].peGreen ||
1018 rgb[i].rgbBlue != palette[i].peBlue) return FALSE;
1020 return TRUE;
1022 case 16:
1023 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1024 return (vis->red_mask == colors[0] &&
1025 vis->green_mask == colors[1] &&
1026 vis->blue_mask == colors[2]);
1027 if (info->bmiHeader.biCompression == BI_RGB)
1028 return (vis->red_mask == 0x7c00 && vis->green_mask == 0x03e0 && vis->blue_mask == 0x001f);
1029 break;
1030 case 32:
1031 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1032 return (vis->red_mask == colors[0] &&
1033 vis->green_mask == colors[1] &&
1034 vis->blue_mask == colors[2]);
1035 /* fall through */
1036 case 24:
1037 if (info->bmiHeader.biCompression == BI_RGB)
1038 return (vis->red_mask == 0xff0000 && vis->green_mask == 0x00ff00 && vis->blue_mask == 0x0000ff);
1039 break;
1041 return FALSE;
1044 static inline BOOL is_r8g8b8( const XVisualInfo *vis )
1046 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1047 return format->bits_per_pixel == 24 && vis->red_mask == 0xff0000 && vis->blue_mask == 0x0000ff;
1050 static inline BOOL image_needs_byteswap( XImage *image, BOOL is_r8g8b8, int bit_count )
1052 #ifdef WORDS_BIGENDIAN
1053 static const int client_byte_order = MSBFirst;
1054 #else
1055 static const int client_byte_order = LSBFirst;
1056 #endif
1058 switch (bit_count)
1060 case 1: return image->bitmap_bit_order != MSBFirst;
1061 case 4: return image->byte_order != MSBFirst;
1062 case 16:
1063 case 32: return image->byte_order != client_byte_order;
1064 case 24: return (image->byte_order == MSBFirst) ^ !is_r8g8b8;
1065 default: return FALSE;
1069 /* copy image bits with byte swapping and/or pixel mapping */
1070 static void copy_image_byteswap( BITMAPINFO *info, const unsigned char *src, unsigned char *dst,
1071 int src_stride, int dst_stride, int height, BOOL byteswap,
1072 const int *mapping, unsigned int zeropad_mask, unsigned int alpha_bits )
1074 int x, y, padding_pos = abs(dst_stride) / sizeof(unsigned int) - 1;
1076 if (!byteswap && !mapping) /* simply copy */
1078 if (src != dst)
1080 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1082 memcpy( dst, src, src_stride );
1083 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1086 else if (zeropad_mask != ~0u) /* only need to clear the padding */
1088 for (y = 0; y < height; y++, dst += dst_stride)
1089 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1091 return;
1094 switch (info->bmiHeader.biBitCount)
1096 case 1:
1097 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1099 for (x = 0; x < src_stride; x++) dst[x] = bit_swap[src[x]];
1100 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1102 break;
1103 case 4:
1104 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1106 if (mapping)
1108 if (byteswap)
1109 for (x = 0; x < src_stride; x++)
1110 dst[x] = (mapping[src[x] & 0x0f] << 4) | mapping[src[x] >> 4];
1111 else
1112 for (x = 0; x < src_stride; x++)
1113 dst[x] = mapping[src[x] & 0x0f] | (mapping[src[x] >> 4] << 4);
1115 else
1116 for (x = 0; x < src_stride; x++)
1117 dst[x] = (src[x] << 4) | (src[x] >> 4);
1118 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1120 break;
1121 case 8:
1122 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1124 for (x = 0; x < src_stride; x++) dst[x] = mapping[src[x]];
1125 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1127 break;
1128 case 16:
1129 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1131 for (x = 0; x < info->bmiHeader.biWidth; x++)
1132 ((USHORT *)dst)[x] = RtlUshortByteSwap( ((const USHORT *)src)[x] );
1133 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1135 break;
1136 case 24:
1137 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1139 for (x = 0; x < info->bmiHeader.biWidth; x++)
1141 unsigned char tmp = src[3 * x];
1142 dst[3 * x] = src[3 * x + 2];
1143 dst[3 * x + 1] = src[3 * x + 1];
1144 dst[3 * x + 2] = tmp;
1146 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1148 break;
1149 case 32:
1150 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1151 for (x = 0; x < info->bmiHeader.biWidth; x++)
1152 ((ULONG *)dst)[x] = RtlUlongByteSwap( ((const ULONG *)src)[x] | alpha_bits );
1153 break;
1157 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1158 DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image,
1159 const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
1160 struct bitblt_coords *coords, const int *mapping, unsigned int zeropad_mask )
1162 BOOL need_byteswap = image_needs_byteswap( image, is_r8g8b8, info->bmiHeader.biBitCount );
1163 int height = coords->visrect.bottom - coords->visrect.top;
1164 int width_bytes = image->bytes_per_line;
1165 unsigned char *src, *dst;
1167 src = src_bits->ptr;
1168 if (info->bmiHeader.biHeight > 0)
1169 src += (info->bmiHeader.biHeight - coords->visrect.bottom) * width_bytes;
1170 else
1171 src += coords->visrect.top * width_bytes;
1173 if ((need_byteswap && !src_bits->is_copy) || /* need to swap bytes */
1174 (zeropad_mask != ~0u && !src_bits->is_copy) || /* need to clear padding bytes */
1175 (mapping && !src_bits->is_copy) || /* need to remap pixels */
1176 (width_bytes & 3) || /* need to fixup line alignment */
1177 (info->bmiHeader.biHeight > 0)) /* need to flip vertically */
1179 width_bytes = (width_bytes + 3) & ~3;
1180 info->bmiHeader.biSizeImage = height * width_bytes;
1181 if (!(dst_bits->ptr = HeapAlloc( GetProcessHeap(), 0, info->bmiHeader.biSizeImage )))
1182 return ERROR_OUTOFMEMORY;
1183 dst_bits->is_copy = TRUE;
1184 dst_bits->free = free_heap_bits;
1186 else
1188 /* swap bits in place */
1189 dst_bits->ptr = src;
1190 dst_bits->is_copy = src_bits->is_copy;
1191 dst_bits->free = NULL;
1192 if (!need_byteswap && zeropad_mask == ~0u && !mapping) return ERROR_SUCCESS; /* nothing to do */
1195 dst = dst_bits->ptr;
1197 if (info->bmiHeader.biHeight > 0)
1199 dst += (height - 1) * width_bytes;
1200 width_bytes = -width_bytes;
1203 copy_image_byteswap( info, src, dst, image->bytes_per_line, width_bytes, height,
1204 need_byteswap, mapping, zeropad_mask, 0 );
1205 return ERROR_SUCCESS;
1208 /***********************************************************************
1209 * X11DRV_PutImage
1211 DWORD CDECL X11DRV_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
1212 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1213 struct bitblt_coords *dst, DWORD rop )
1215 X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1216 DWORD ret;
1217 XImage *image;
1218 XVisualInfo vis = default_visual;
1219 struct gdi_image_bits dst_bits;
1220 const XPixmapFormatValues *format;
1221 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1222 const int *mapping = NULL;
1224 vis.depth = physdev->depth;
1225 if (physdev->color_shifts)
1227 vis.red_mask = physdev->color_shifts->logicalRed.max << physdev->color_shifts->logicalRed.shift;
1228 vis.green_mask = physdev->color_shifts->logicalGreen.max << physdev->color_shifts->logicalGreen.shift;
1229 vis.blue_mask = physdev->color_shifts->logicalBlue.max << physdev->color_shifts->logicalBlue.shift;
1231 format = pixmap_formats[vis.depth];
1233 if (info->bmiHeader.biPlanes != 1) goto update_format;
1234 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1235 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1236 if (!matching_color_info( &vis, info )) goto update_format;
1237 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1238 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
1240 image = XCreateImage( gdi_display, vis.visual, vis.depth, ZPixmap, 0, NULL,
1241 info->bmiHeader.biWidth, src->visrect.bottom - src->visrect.top, 32, 0 );
1242 if (!image) return ERROR_OUTOFMEMORY;
1244 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1246 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1247 mapping = X11DRV_PALETTE_PaletteToXPixel;
1250 ret = copy_image_bits( info, is_r8g8b8(&vis), image, bits, &dst_bits, src, mapping, ~0u );
1252 if (!ret)
1254 BOOL restore_region = add_extra_clipping_region( physdev, clip );
1255 int width = dst->visrect.right - dst->visrect.left;
1256 int height = dst->visrect.bottom - dst->visrect.top;
1258 image->data = dst_bits.ptr;
1260 /* optimization for single-op ROPs */
1261 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1263 XSetFunction( gdi_display, physdev->gc, OP_ROP(*opcode) );
1264 XPutImage( gdi_display, physdev->drawable, physdev->gc, image, src->visrect.left, 0,
1265 physdev->dc_rect.left + dst->visrect.left,
1266 physdev->dc_rect.top + dst->visrect.top, width, height );
1268 else
1270 GC gc = XCreateGC( gdi_display, physdev->drawable, 0, NULL );
1271 Pixmap src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, vis.depth );
1273 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1274 XSetGraphicsExposures( gdi_display, gc, False );
1275 XPutImage( gdi_display, src_pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1277 execute_rop( physdev, src_pixmap, gc, &dst->visrect, rop );
1279 XFreePixmap( gdi_display, src_pixmap );
1280 XFreeGC( gdi_display, gc );
1283 if (restore_region) restore_clipping_region( physdev );
1284 add_device_bounds( physdev, &dst->visrect );
1285 image->data = NULL;
1288 XDestroyImage( image );
1289 if (dst_bits.free) dst_bits.free( &dst_bits );
1290 return ret;
1292 update_format:
1293 info->bmiHeader.biPlanes = 1;
1294 info->bmiHeader.biBitCount = format->bits_per_pixel;
1295 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1296 set_color_info( &vis, info, FALSE );
1297 return ERROR_BAD_FORMAT;
1300 /***********************************************************************
1301 * X11DRV_GetImage
1303 DWORD CDECL X11DRV_GetImage( PHYSDEV dev, BITMAPINFO *info,
1304 struct gdi_image_bits *bits, struct bitblt_coords *src )
1306 X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1307 DWORD ret = ERROR_SUCCESS;
1308 XImage *image;
1309 XVisualInfo vis = default_visual;
1310 UINT align, x, y, width, height;
1311 struct gdi_image_bits src_bits;
1312 const XPixmapFormatValues *format;
1313 const int *mapping = NULL;
1315 vis.depth = physdev->depth;
1316 if (physdev->color_shifts)
1318 vis.red_mask = physdev->color_shifts->logicalRed.max << physdev->color_shifts->logicalRed.shift;
1319 vis.green_mask = physdev->color_shifts->logicalGreen.max << physdev->color_shifts->logicalGreen.shift;
1320 vis.blue_mask = physdev->color_shifts->logicalBlue.max << physdev->color_shifts->logicalBlue.shift;
1322 format = pixmap_formats[vis.depth];
1324 /* align start and width to 32-bit boundary */
1325 switch (format->bits_per_pixel)
1327 case 1: align = 32; break;
1328 case 4: align = 8; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1329 case 8: align = 4; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1330 case 16: align = 2; break;
1331 case 24: align = 4; break;
1332 case 32: align = 1; break;
1333 default:
1334 FIXME( "depth %u bpp %u not supported yet\n", vis.depth, format->bits_per_pixel );
1335 return ERROR_BAD_FORMAT;
1338 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1339 info->bmiHeader.biPlanes = 1;
1340 info->bmiHeader.biBitCount = format->bits_per_pixel;
1341 info->bmiHeader.biXPelsPerMeter = 0;
1342 info->bmiHeader.biYPelsPerMeter = 0;
1343 info->bmiHeader.biClrImportant = 0;
1344 set_color_info( &vis, info, FALSE );
1346 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
1348 x = src->visrect.left & ~(align - 1);
1349 y = src->visrect.top;
1350 width = src->visrect.right - x;
1351 height = src->visrect.bottom - src->visrect.top;
1352 if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1);
1353 /* make the source rectangle relative to the returned bits */
1354 src->x -= x;
1355 src->y -= y;
1356 OffsetRect( &src->visrect, -x, -y );
1358 X11DRV_expect_error( gdi_display, XGetImage_handler, NULL );
1359 image = XGetImage( gdi_display, physdev->drawable,
1360 physdev->dc_rect.left + x, physdev->dc_rect.top + y,
1361 width, height, AllPlanes, ZPixmap );
1362 if (X11DRV_check_error())
1364 /* use a temporary pixmap to avoid the BadMatch error */
1365 Pixmap pixmap = XCreatePixmap( gdi_display, root_window, width, height, vis.depth );
1366 GC gc = XCreateGC( gdi_display, pixmap, 0, NULL );
1368 XSetGraphicsExposures( gdi_display, gc, False );
1369 XCopyArea( gdi_display, physdev->drawable, pixmap, gc,
1370 physdev->dc_rect.left + x, physdev->dc_rect.top + y, width, height, 0, 0 );
1371 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1372 XFreePixmap( gdi_display, pixmap );
1373 XFreeGC( gdi_display, gc );
1376 if (!image) return ERROR_OUTOFMEMORY;
1378 info->bmiHeader.biWidth = width;
1379 info->bmiHeader.biHeight = -height;
1380 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1382 src_bits.ptr = image->data;
1383 src_bits.is_copy = TRUE;
1384 ret = copy_image_bits( info, is_r8g8b8(&vis), image, &src_bits, bits, src, mapping,
1385 zeropad_masks[(width * image->bits_per_pixel) & 31] );
1387 if (!ret && bits->ptr == image->data)
1389 bits->free = free_ximage_bits;
1390 image->data = NULL;
1392 XDestroyImage( image );
1393 return ret;
1397 /***********************************************************************
1398 * put_pixmap_image
1400 * Simplified equivalent of X11DRV_PutImage that writes directly to a pixmap.
1402 static DWORD put_pixmap_image( Pixmap pixmap, const XVisualInfo *vis,
1403 BITMAPINFO *info, const struct gdi_image_bits *bits )
1405 DWORD ret;
1406 XImage *image;
1407 GC gc;
1408 struct bitblt_coords coords;
1409 struct gdi_image_bits dst_bits;
1410 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1411 const int *mapping = NULL;
1413 if (!format) return ERROR_INVALID_PARAMETER;
1414 if (info->bmiHeader.biPlanes != 1) goto update_format;
1415 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1416 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1417 if (!matching_color_info( vis, info )) goto update_format;
1418 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1420 coords.x = 0;
1421 coords.y = 0;
1422 coords.width = info->bmiHeader.biWidth;
1423 coords.height = abs( info->bmiHeader.biHeight );
1424 SetRect( &coords.visrect, 0, 0, coords.width, coords.height );
1426 image = XCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, 0, NULL,
1427 coords.width, coords.height, 32, 0 );
1428 if (!image) return ERROR_OUTOFMEMORY;
1430 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1431 mapping = X11DRV_PALETTE_PaletteToXPixel;
1433 if (!(ret = copy_image_bits( info, is_r8g8b8(vis), image, bits, &dst_bits, &coords, mapping, ~0u )))
1435 image->data = dst_bits.ptr;
1436 gc = XCreateGC( gdi_display, pixmap, 0, NULL );
1437 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, coords.width, coords.height );
1438 XFreeGC( gdi_display, gc );
1439 image->data = NULL;
1440 if (dst_bits.free) dst_bits.free( &dst_bits );
1443 XDestroyImage( image );
1444 return ret;
1446 update_format:
1447 info->bmiHeader.biPlanes = 1;
1448 info->bmiHeader.biBitCount = format->bits_per_pixel;
1449 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1450 set_color_info( vis, info, FALSE );
1451 return ERROR_BAD_FORMAT;
1455 /***********************************************************************
1456 * create_pixmap_from_image
1458 Pixmap create_pixmap_from_image( HDC hdc, const XVisualInfo *vis, const BITMAPINFO *info,
1459 const struct gdi_image_bits *bits, UINT coloruse )
1461 static const RGBQUAD default_colortable[2] = { { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff } };
1462 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1463 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1464 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
1465 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
1466 struct gdi_image_bits dst_bits;
1467 Pixmap pixmap;
1468 DWORD err;
1469 HBITMAP dib;
1471 pixmap = XCreatePixmap( gdi_display, root_window,
1472 info->bmiHeader.biWidth, abs(info->bmiHeader.biHeight), vis->depth );
1473 if (!pixmap) return 0;
1475 memcpy( src_info, info, get_dib_info_size( info, coloruse ));
1476 memcpy( dst_info, info, get_dib_info_size( info, coloruse ));
1478 if (coloruse == DIB_PAL_COLORS ||
1479 (err = put_pixmap_image( pixmap, vis, dst_info, bits )) == ERROR_BAD_FORMAT)
1481 if (dst_info->bmiHeader.biBitCount == 1) /* set a default color table for 1-bpp */
1482 memcpy( dst_info->bmiColors, default_colortable, sizeof(default_colortable) );
1483 dib = CreateDIBSection( hdc, dst_info, coloruse, &dst_bits.ptr, 0, 0 );
1484 if (dib)
1486 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
1487 memcpy( src_info->bmiColors, default_colortable, sizeof(default_colortable) );
1488 SetDIBits( hdc, dib, 0, abs(info->bmiHeader.biHeight), bits->ptr, src_info, coloruse );
1489 dst_bits.free = NULL;
1490 dst_bits.is_copy = TRUE;
1491 err = put_pixmap_image( pixmap, vis, dst_info, &dst_bits );
1492 DeleteObject( dib );
1494 else err = ERROR_OUTOFMEMORY;
1497 if (!err) return pixmap;
1499 XFreePixmap( gdi_display, pixmap );
1500 return 0;
1505 /***********************************************************************
1506 * get_pixmap_image
1508 * Equivalent of X11DRV_GetImage that reads directly from a pixmap.
1510 DWORD get_pixmap_image( Pixmap pixmap, int width, int height, const XVisualInfo *vis,
1511 BITMAPINFO *info, struct gdi_image_bits *bits )
1513 DWORD ret = ERROR_SUCCESS;
1514 XImage *image;
1515 struct gdi_image_bits src_bits;
1516 struct bitblt_coords coords;
1517 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1518 const int *mapping = NULL;
1520 if (!format) return ERROR_INVALID_PARAMETER;
1522 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1523 info->bmiHeader.biWidth = width;
1524 info->bmiHeader.biHeight = -height;
1525 info->bmiHeader.biPlanes = 1;
1526 info->bmiHeader.biBitCount = format->bits_per_pixel;
1527 info->bmiHeader.biXPelsPerMeter = 0;
1528 info->bmiHeader.biYPelsPerMeter = 0;
1529 info->bmiHeader.biClrImportant = 0;
1530 set_color_info( vis, info, FALSE );
1532 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
1534 coords.x = 0;
1535 coords.y = 0;
1536 coords.width = width;
1537 coords.height = height;
1538 SetRect( &coords.visrect, 0, 0, width, height );
1540 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1541 if (!image) return ERROR_OUTOFMEMORY;
1543 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1545 src_bits.ptr = image->data;
1546 src_bits.is_copy = TRUE;
1547 ret = copy_image_bits( info, is_r8g8b8(vis), image, &src_bits, bits, &coords, mapping,
1548 zeropad_masks[(width * image->bits_per_pixel) & 31] );
1550 if (!ret && bits->ptr == image->data)
1552 bits->free = free_ximage_bits;
1553 image->data = NULL;
1555 XDestroyImage( image );
1556 return ret;
1560 struct x11drv_window_surface
1562 struct window_surface header;
1563 Window window;
1564 GC gc;
1565 XImage *image;
1566 RECT bounds;
1567 BOOL byteswap;
1568 BOOL is_argb;
1569 DWORD alpha_bits;
1570 COLORREF color_key;
1571 HRGN region;
1572 void *bits;
1573 #ifdef HAVE_LIBXXSHM
1574 XShmSegmentInfo shminfo;
1575 #endif
1576 CRITICAL_SECTION crit;
1577 BITMAPINFO info; /* variable size, must be last */
1580 static struct x11drv_window_surface *get_x11_surface( struct window_surface *surface )
1582 return (struct x11drv_window_surface *)surface;
1585 static inline UINT get_color_component( UINT color, UINT mask )
1587 int shift;
1588 for (shift = 0; !(mask & 1); shift++) mask >>= 1;
1589 return (color * mask / 255) << shift;
1592 #ifdef HAVE_LIBXSHAPE
1593 static inline void flush_rgn_data( HRGN rgn, RGNDATA *data )
1595 HRGN tmp = ExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data );
1596 CombineRgn( rgn, rgn, tmp, RGN_OR );
1597 DeleteObject( tmp );
1598 data->rdh.nCount = 0;
1601 static inline void add_row( HRGN rgn, RGNDATA *data, int x, int y, int len )
1603 RECT *rect = (RECT *)data->Buffer + data->rdh.nCount;
1605 if (len <= 0) return;
1606 rect->left = x;
1607 rect->top = y;
1608 rect->right = x + len;
1609 rect->bottom = y + 1;
1610 data->rdh.nCount++;
1611 if (data->rdh.nCount * sizeof(RECT) > data->rdh.nRgnSize - sizeof(RECT))
1612 flush_rgn_data( rgn, data );
1614 #endif
1616 /***********************************************************************
1617 * update_surface_region
1619 static void update_surface_region( struct x11drv_window_surface *surface )
1621 #ifdef HAVE_LIBXSHAPE
1622 char buffer[4096];
1623 RGNDATA *data = (RGNDATA *)buffer;
1624 BITMAPINFO *info = &surface->info;
1625 UINT *masks = (UINT *)info->bmiColors;
1626 int x, y, start, width;
1627 HRGN rgn;
1629 if (!shape_layered_windows) return;
1631 if (!surface->is_argb && surface->color_key == CLR_INVALID)
1633 XShapeCombineMask( gdi_display, surface->window, ShapeBounding, 0, 0, None, ShapeSet );
1634 return;
1637 data->rdh.dwSize = sizeof(data->rdh);
1638 data->rdh.iType = RDH_RECTANGLES;
1639 data->rdh.nCount = 0;
1640 data->rdh.nRgnSize = sizeof(buffer) - sizeof(data->rdh);
1642 rgn = CreateRectRgn( 0, 0, 0, 0 );
1643 width = surface->header.rect.right - surface->header.rect.left;
1645 switch (info->bmiHeader.biBitCount)
1647 case 16:
1649 WORD *bits = surface->bits;
1650 int stride = (width + 1) & ~1;
1651 UINT mask = masks[0] | masks[1] | masks[2];
1653 for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += stride)
1655 x = 0;
1656 while (x < width)
1658 while (x < width && (bits[x] & mask) == surface->color_key) x++;
1659 start = x;
1660 while (x < width && (bits[x] & mask) != surface->color_key) x++;
1661 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1664 break;
1666 case 24:
1668 BYTE *bits = surface->bits;
1669 int stride = (width * 3 + 3) & ~3;
1671 for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += stride)
1673 x = 0;
1674 while (x < width)
1676 while (x < width &&
1677 (bits[x * 3] == GetBValue(surface->color_key)) &&
1678 (bits[x * 3 + 1] == GetGValue(surface->color_key)) &&
1679 (bits[x * 3 + 2] == GetRValue(surface->color_key)))
1680 x++;
1681 start = x;
1682 while (x < width &&
1683 ((bits[x * 3] != GetBValue(surface->color_key)) ||
1684 (bits[x * 3 + 1] != GetGValue(surface->color_key)) ||
1685 (bits[x * 3 + 2] != GetRValue(surface->color_key))))
1686 x++;
1687 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1690 break;
1692 case 32:
1694 DWORD *bits = surface->bits;
1696 if (info->bmiHeader.biCompression == BI_RGB)
1698 for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += width)
1700 x = 0;
1701 while (x < width)
1703 while (x < width &&
1704 ((bits[x] & 0xffffff) == surface->color_key ||
1705 (surface->is_argb && !(bits[x] & 0xff000000)))) x++;
1706 start = x;
1707 while (x < width &&
1708 !((bits[x] & 0xffffff) == surface->color_key ||
1709 (surface->is_argb && !(bits[x] & 0xff000000)))) x++;
1710 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1714 else
1716 UINT mask = masks[0] | masks[1] | masks[2];
1717 for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += width)
1719 x = 0;
1720 while (x < width)
1722 while (x < width && (bits[x] & mask) == surface->color_key) x++;
1723 start = x;
1724 while (x < width && (bits[x] & mask) != surface->color_key) x++;
1725 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1729 break;
1731 default:
1732 assert(0);
1735 if (data->rdh.nCount) flush_rgn_data( rgn, data );
1737 if ((data = X11DRV_GetRegionData( rgn, 0 )))
1739 XShapeCombineRectangles( gdi_display, surface->window, ShapeBounding, 0, 0,
1740 (XRectangle *)data->Buffer, data->rdh.nCount, ShapeSet, YXBanded );
1741 HeapFree( GetProcessHeap(), 0, data );
1744 DeleteObject( rgn );
1745 #endif
1748 /***********************************************************************
1749 * set_color_key
1751 static void set_color_key( struct x11drv_window_surface *surface, COLORREF key )
1753 UINT *masks = (UINT *)surface->info.bmiColors;
1755 if (key == CLR_INVALID)
1756 surface->color_key = CLR_INVALID;
1757 else if (surface->info.bmiHeader.biBitCount <= 8)
1758 surface->color_key = CLR_INVALID;
1759 else if (key & (1 << 24)) /* PALETTEINDEX */
1760 surface->color_key = 0;
1761 else if (key >> 16 == 0x10ff) /* DIBINDEX */
1762 surface->color_key = 0;
1763 else if (surface->info.bmiHeader.biBitCount == 24)
1764 surface->color_key = key;
1765 else if (surface->info.bmiHeader.biCompression == BI_RGB)
1766 surface->color_key = (GetRValue(key) << 16) | (GetGValue(key) << 8) | GetBValue(key);
1767 else
1768 surface->color_key = get_color_component( GetRValue(key), masks[0] ) |
1769 get_color_component( GetGValue(key), masks[1] ) |
1770 get_color_component( GetBValue(key), masks[2] );
1773 #ifdef HAVE_LIBXXSHM
1774 static int xshm_error_handler( Display *display, XErrorEvent *event, void *arg )
1776 return 1; /* FIXME: should check event contents */
1779 static XImage *create_shm_image( const XVisualInfo *vis, int width, int height, XShmSegmentInfo *shminfo )
1781 XImage *image;
1783 shminfo->shmid = -1;
1784 image = XShmCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, NULL, shminfo, width, height );
1785 if (!image) return NULL;
1786 if (image->bytes_per_line & 3) goto failed; /* we need 32-bit alignment */
1788 shminfo->shmid = shmget( IPC_PRIVATE, image->bytes_per_line * height, IPC_CREAT | 0700 );
1789 if (shminfo->shmid == -1) goto failed;
1791 shminfo->shmaddr = shmat( shminfo->shmid, 0, 0 );
1792 if (shminfo->shmaddr != (char *)-1)
1794 BOOL ok;
1796 shminfo->readOnly = True;
1797 X11DRV_expect_error( gdi_display, xshm_error_handler, NULL );
1798 ok = (XShmAttach( gdi_display, shminfo ) != 0);
1799 XSync( gdi_display, False );
1800 if (!X11DRV_check_error() && ok)
1802 image->data = shminfo->shmaddr;
1803 shmctl( shminfo->shmid, IPC_RMID, 0 );
1804 return image;
1806 shmdt( shminfo->shmaddr );
1808 shmctl( shminfo->shmid, IPC_RMID, 0 );
1809 shminfo->shmid = -1;
1811 failed:
1812 XDestroyImage( image );
1813 return NULL;
1815 #endif /* HAVE_LIBXXSHM */
1817 /***********************************************************************
1818 * x11drv_surface_lock
1820 static void CDECL x11drv_surface_lock( struct window_surface *window_surface )
1822 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1824 EnterCriticalSection( &surface->crit );
1827 /***********************************************************************
1828 * x11drv_surface_unlock
1830 static void CDECL x11drv_surface_unlock( struct window_surface *window_surface )
1832 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1834 LeaveCriticalSection( &surface->crit );
1837 /***********************************************************************
1838 * x11drv_surface_get_bitmap_info
1840 static void *CDECL x11drv_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
1842 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1844 memcpy( info, &surface->info, get_dib_info_size( &surface->info, DIB_RGB_COLORS ));
1845 return surface->bits;
1848 /***********************************************************************
1849 * x11drv_surface_get_bounds
1851 static RECT *CDECL x11drv_surface_get_bounds( struct window_surface *window_surface )
1853 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1855 return &surface->bounds;
1858 /***********************************************************************
1859 * x11drv_surface_set_region
1861 static void CDECL x11drv_surface_set_region( struct window_surface *window_surface, HRGN region )
1863 RGNDATA *data;
1864 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1866 TRACE( "updating surface %p with %p\n", surface, region );
1868 window_surface->funcs->lock( window_surface );
1869 if (!region)
1871 if (surface->region) DeleteObject( surface->region );
1872 surface->region = 0;
1873 XSetClipMask( gdi_display, surface->gc, None );
1875 else
1877 if (!surface->region) surface->region = CreateRectRgn( 0, 0, 0, 0 );
1878 CombineRgn( surface->region, region, 0, RGN_COPY );
1879 if ((data = X11DRV_GetRegionData( surface->region, 0 )))
1881 XSetClipRectangles( gdi_display, surface->gc, 0, 0,
1882 (XRectangle *)data->Buffer, data->rdh.nCount, YXBanded );
1883 HeapFree( GetProcessHeap(), 0, data );
1886 window_surface->funcs->unlock( window_surface );
1889 /***********************************************************************
1890 * x11drv_surface_flush
1892 static void CDECL x11drv_surface_flush( struct window_surface *window_surface )
1894 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1895 unsigned char *src = surface->bits;
1896 unsigned char *dst = (unsigned char *)surface->image->data;
1897 struct bitblt_coords coords;
1899 window_surface->funcs->lock( window_surface );
1900 coords.x = 0;
1901 coords.y = 0;
1902 coords.width = surface->header.rect.right - surface->header.rect.left;
1903 coords.height = surface->header.rect.bottom - surface->header.rect.top;
1904 SetRect( &coords.visrect, 0, 0, coords.width, coords.height );
1905 if (IntersectRect( &coords.visrect, &coords.visrect, &surface->bounds ))
1907 TRACE( "flushing %p %dx%d bounds %s bits %p\n",
1908 surface, coords.width, coords.height,
1909 wine_dbgstr_rect( &surface->bounds ), surface->bits );
1911 if (surface->is_argb || surface->color_key != CLR_INVALID) update_surface_region( surface );
1913 if (src != dst)
1915 int map[256], *mapping = get_window_surface_mapping( surface->image->bits_per_pixel, map );
1916 int width_bytes = surface->image->bytes_per_line;
1918 src += coords.visrect.top * width_bytes;
1919 dst += coords.visrect.top * width_bytes;
1920 copy_image_byteswap( &surface->info, src, dst, width_bytes, width_bytes,
1921 coords.visrect.bottom - coords.visrect.top,
1922 surface->byteswap, mapping, ~0u, surface->alpha_bits );
1924 else if (surface->alpha_bits)
1926 int x, y, stride = surface->image->bytes_per_line / sizeof(ULONG);
1927 ULONG *ptr = (ULONG *)dst + coords.visrect.top * stride;
1929 for (y = coords.visrect.top; y < coords.visrect.bottom; y++, ptr += stride)
1930 for (x = coords.visrect.left; x < coords.visrect.right; x++)
1931 ptr[x] |= surface->alpha_bits;
1934 #ifdef HAVE_LIBXXSHM
1935 if (surface->shminfo.shmid != -1)
1936 XShmPutImage( gdi_display, surface->window, surface->gc, surface->image,
1937 coords.visrect.left, coords.visrect.top,
1938 surface->header.rect.left + coords.visrect.left,
1939 surface->header.rect.top + coords.visrect.top,
1940 coords.visrect.right - coords.visrect.left,
1941 coords.visrect.bottom - coords.visrect.top, False );
1942 else
1943 #endif
1944 XPutImage( gdi_display, surface->window, surface->gc, surface->image,
1945 coords.visrect.left, coords.visrect.top,
1946 surface->header.rect.left + coords.visrect.left,
1947 surface->header.rect.top + coords.visrect.top,
1948 coords.visrect.right - coords.visrect.left,
1949 coords.visrect.bottom - coords.visrect.top );
1950 XFlush( gdi_display );
1952 reset_bounds( &surface->bounds );
1953 window_surface->funcs->unlock( window_surface );
1956 /***********************************************************************
1957 * x11drv_surface_destroy
1959 static void CDECL x11drv_surface_destroy( struct window_surface *window_surface )
1961 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1963 TRACE( "freeing %p bits %p\n", surface, surface->bits );
1964 if (surface->gc) XFreeGC( gdi_display, surface->gc );
1965 if (surface->image)
1967 if (surface->image->data != surface->bits) HeapFree( GetProcessHeap(), 0, surface->bits );
1968 #ifdef HAVE_LIBXXSHM
1969 if (surface->shminfo.shmid != -1)
1971 XShmDetach( gdi_display, &surface->shminfo );
1972 shmdt( surface->shminfo.shmaddr );
1974 else
1975 #endif
1976 HeapFree( GetProcessHeap(), 0, surface->image->data );
1977 surface->image->data = NULL;
1978 XDestroyImage( surface->image );
1980 surface->crit.DebugInfo->Spare[0] = 0;
1981 DeleteCriticalSection( &surface->crit );
1982 if (surface->region) DeleteObject( surface->region );
1983 HeapFree( GetProcessHeap(), 0, surface );
1986 static const struct window_surface_funcs x11drv_surface_funcs =
1988 x11drv_surface_lock,
1989 x11drv_surface_unlock,
1990 x11drv_surface_get_bitmap_info,
1991 x11drv_surface_get_bounds,
1992 x11drv_surface_set_region,
1993 x11drv_surface_flush,
1994 x11drv_surface_destroy
1997 /***********************************************************************
1998 * create_surface
2000 struct window_surface *create_surface( Window window, const XVisualInfo *vis, const RECT *rect,
2001 COLORREF color_key, BOOL use_alpha )
2003 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
2004 struct x11drv_window_surface *surface;
2005 int width = rect->right - rect->left, height = rect->bottom - rect->top;
2006 int colors = format->bits_per_pixel <= 8 ? 1 << format->bits_per_pixel : 3;
2008 surface = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
2009 FIELD_OFFSET( struct x11drv_window_surface, info.bmiColors[colors] ));
2010 if (!surface) return NULL;
2011 surface->info.bmiHeader.biSize = sizeof(surface->info.bmiHeader);
2012 surface->info.bmiHeader.biWidth = width;
2013 surface->info.bmiHeader.biHeight = -height; /* top-down */
2014 surface->info.bmiHeader.biPlanes = 1;
2015 surface->info.bmiHeader.biBitCount = format->bits_per_pixel;
2016 surface->info.bmiHeader.biSizeImage = get_dib_image_size( &surface->info );
2017 if (format->bits_per_pixel > 8) set_color_info( vis, &surface->info, use_alpha );
2019 InitializeCriticalSection( &surface->crit );
2020 surface->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": surface");
2022 surface->header.funcs = &x11drv_surface_funcs;
2023 surface->header.rect = *rect;
2024 surface->header.ref = 1;
2025 surface->window = window;
2026 surface->is_argb = (use_alpha && vis->depth == 32 && surface->info.bmiHeader.biCompression == BI_RGB);
2027 set_color_key( surface, color_key );
2028 reset_bounds( &surface->bounds );
2030 #ifdef HAVE_LIBXXSHM
2031 surface->image = create_shm_image( vis, width, height, &surface->shminfo );
2032 if (!surface->image)
2033 #endif
2035 surface->image = XCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, 0, NULL,
2036 width, height, 32, 0 );
2037 if (!surface->image) goto failed;
2038 surface->image->data = HeapAlloc( GetProcessHeap(), 0, surface->info.bmiHeader.biSizeImage );
2039 if (!surface->image->data) goto failed;
2042 surface->gc = XCreateGC( gdi_display, window, 0, NULL );
2043 XSetSubwindowMode( gdi_display, surface->gc, IncludeInferiors );
2044 surface->byteswap = image_needs_byteswap( surface->image, is_r8g8b8(vis), format->bits_per_pixel );
2046 if (vis->depth == 32 && !surface->is_argb)
2047 surface->alpha_bits = ~(vis->red_mask | vis->green_mask | vis->blue_mask);
2049 if (surface->byteswap || format->bits_per_pixel == 4 || format->bits_per_pixel == 8)
2051 /* allocate separate surface bits if byte swapping or palette mapping is required */
2052 if (!(surface->bits = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
2053 surface->info.bmiHeader.biSizeImage )))
2054 goto failed;
2056 else surface->bits = surface->image->data;
2058 TRACE( "created %p for %lx %s bits %p-%p image %p\n", surface, window, wine_dbgstr_rect(rect),
2059 surface->bits, (char *)surface->bits + surface->info.bmiHeader.biSizeImage,
2060 surface->image->data );
2062 return &surface->header;
2064 failed:
2065 x11drv_surface_destroy( &surface->header );
2066 return NULL;
2069 /***********************************************************************
2070 * set_surface_color_key
2072 void set_surface_color_key( struct window_surface *window_surface, COLORREF color_key )
2074 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
2075 COLORREF prev;
2077 if (window_surface->funcs != &x11drv_surface_funcs) return; /* we may get the null surface */
2079 window_surface->funcs->lock( window_surface );
2080 prev = surface->color_key;
2081 set_color_key( surface, color_key );
2082 if (surface->color_key != prev) update_surface_region( surface );
2083 window_surface->funcs->unlock( window_surface );
2086 /***********************************************************************
2087 * expose_surface
2089 HRGN expose_surface( struct window_surface *window_surface, const RECT *rect )
2091 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
2092 HRGN region = 0;
2093 RECT rc = *rect;
2095 if (window_surface->funcs != &x11drv_surface_funcs) return 0; /* we may get the null surface */
2097 window_surface->funcs->lock( window_surface );
2098 OffsetRect( &rc, -window_surface->rect.left, -window_surface->rect.top );
2099 add_bounds_rect( &surface->bounds, &rc );
2100 if (surface->region)
2102 region = CreateRectRgnIndirect( rect );
2103 if (CombineRgn( region, region, surface->region, RGN_DIFF ) <= NULLREGION)
2105 DeleteObject( region );
2106 region = 0;
2109 window_surface->funcs->unlock( window_surface );
2110 return region;