wow32: Use spec file imports.
[wine.git] / dlls / winex11.drv / bitblt.c
blob94aa06773a7fb40d9011766ab6199ad754acf89c
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 #if 0
23 #pragma makedep unix
24 #endif
26 #include "config.h"
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
33 #include <X11/Xlib.h>
34 #include <X11/Xresource.h>
35 #include <X11/Xutil.h>
36 #ifdef HAVE_X11_EXTENSIONS_SHAPE_H
37 #include <X11/extensions/shape.h>
38 #endif
39 #ifdef HAVE_X11_EXTENSIONS_XSHM_H
40 # include <X11/extensions/XShm.h>
41 # ifdef HAVE_SYS_SHM_H
42 # include <sys/shm.h>
43 # endif
44 # ifdef HAVE_SYS_IPC_H
45 # include <sys/ipc.h>
46 # endif
47 #endif
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 DWORD text_color, bk_color;
853 int text_pixel, bkgnd_pixel;
855 NtGdiGetDCDword( physDevDst->dev.hdc, NtGdiGetTextColor, &text_color );
856 text_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, text_color );
858 NtGdiGetDCDword( physDevDst->dev.hdc, NtGdiGetBkColor, &bk_color );
859 bkgnd_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, bk_color );
861 XSetBackground( gdi_display, physDevDst->gc, text_pixel );
862 XSetForeground( gdi_display, physDevDst->gc, bkgnd_pixel );
863 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
864 XCopyPlane( gdi_display, physDevSrc->drawable,
865 physDevDst->drawable, physDevDst->gc,
866 physDevSrc->dc_rect.left + src->visrect.left,
867 physDevSrc->dc_rect.top + src->visrect.top,
868 width, height,
869 physDevDst->dc_rect.left + dst->visrect.left,
870 physDevDst->dc_rect.top + dst->visrect.top, 1 );
871 physDevDst->exposures++;
872 return TRUE;
876 gc = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
877 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
878 XSetGraphicsExposures( gdi_display, gc, False );
880 /* retrieve the source */
882 src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, physDevDst->depth );
883 if (physDevSrc->depth == 1)
885 /* MSDN says if StretchBlt must convert a bitmap from monochrome
886 to color or vice versa, the foreground and background color of
887 the device context are used. In fact, it also applies to the
888 case when it is converted from mono to mono. */
889 DWORD text_color, bk_color;
890 int text_pixel, bkgnd_pixel;
892 NtGdiGetDCDword( physDevDst->dev.hdc, NtGdiGetTextColor, &text_color );
893 text_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, text_color );
895 NtGdiGetDCDword( physDevDst->dev.hdc, NtGdiGetBkColor, &bk_color );
896 bkgnd_pixel = X11DRV_PALETTE_ToPhysical( physDevDst, bk_color );
898 if (X11DRV_PALETTE_XPixelToPalette && physDevDst->depth != 1)
900 XSetBackground( gdi_display, gc, X11DRV_PALETTE_XPixelToPalette[text_pixel] );
901 XSetForeground( gdi_display, gc, X11DRV_PALETTE_XPixelToPalette[bkgnd_pixel]);
903 else
905 XSetBackground( gdi_display, gc, text_pixel );
906 XSetForeground( gdi_display, gc, bkgnd_pixel );
908 XCopyPlane( gdi_display, physDevSrc->drawable, src_pixmap, gc,
909 physDevSrc->dc_rect.left + src->visrect.left,
910 physDevSrc->dc_rect.top + src->visrect.top,
911 width, height, 0, 0, 1 );
913 else /* color -> color */
915 XCopyArea( gdi_display, physDevSrc->drawable, src_pixmap, gc,
916 physDevSrc->dc_rect.left + src->visrect.left,
917 physDevSrc->dc_rect.top + src->visrect.top,
918 width, height, 0, 0 );
921 execute_rop( physDevDst, src_pixmap, gc, &dst->visrect, rop );
923 XFreePixmap( gdi_display, src_pixmap );
924 XFreeGC( gdi_display, gc );
925 return TRUE;
929 static void free_heap_bits( struct gdi_image_bits *bits )
931 free( bits->ptr );
934 static void free_ximage_bits( struct gdi_image_bits *bits )
936 XFree( bits->ptr );
939 static inline int get_dib_info_size( const BITMAPINFO *info, UINT coloruse )
941 if (info->bmiHeader.biCompression == BI_BITFIELDS)
942 return sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD);
943 if (coloruse == DIB_PAL_COLORS)
944 return sizeof(BITMAPINFOHEADER) + info->bmiHeader.biClrUsed * sizeof(WORD);
945 if (!info->bmiHeader.biClrUsed && info->bmiHeader.biBitCount <= 8)
946 return FIELD_OFFSET( BITMAPINFO, bmiColors[1 << info->bmiHeader.biBitCount] );
947 return FIELD_OFFSET( BITMAPINFO, bmiColors[info->bmiHeader.biClrUsed] );
950 static inline int get_dib_stride( int width, int bpp )
952 return ((width * bpp + 31) >> 3) & ~3;
955 static inline int get_dib_image_size( const BITMAPINFO *info )
957 return get_dib_stride( info->bmiHeader.biWidth, info->bmiHeader.biBitCount )
958 * abs( info->bmiHeader.biHeight );
961 /* store the palette or color mask data in the bitmap info structure */
962 static void set_color_info( const XVisualInfo *vis, BITMAPINFO *info, BOOL has_alpha )
964 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
966 info->bmiHeader.biCompression = BI_RGB;
967 info->bmiHeader.biClrUsed = 0;
969 switch (info->bmiHeader.biBitCount)
971 case 4:
972 case 8:
974 RGBQUAD *rgb = (RGBQUAD *)colors;
975 PALETTEENTRY palette[256];
976 UINT i, count;
978 info->bmiHeader.biClrUsed = 1 << info->bmiHeader.biBitCount;
979 count = X11DRV_GetSystemPaletteEntries( NULL, 0, info->bmiHeader.biClrUsed, palette );
980 for (i = 0; i < count; i++)
982 rgb[i].rgbRed = palette[i].peRed;
983 rgb[i].rgbGreen = palette[i].peGreen;
984 rgb[i].rgbBlue = palette[i].peBlue;
985 rgb[i].rgbReserved = 0;
987 memset( &rgb[count], 0, (info->bmiHeader.biClrUsed - count) * sizeof(*rgb) );
988 break;
990 case 16:
991 colors[0] = vis->red_mask;
992 colors[1] = vis->green_mask;
993 colors[2] = vis->blue_mask;
994 info->bmiHeader.biCompression = BI_BITFIELDS;
995 break;
996 case 32:
997 colors[0] = vis->red_mask;
998 colors[1] = vis->green_mask;
999 colors[2] = vis->blue_mask;
1000 if (colors[0] != 0xff0000 || colors[1] != 0x00ff00 || colors[2] != 0x0000ff || !has_alpha)
1001 info->bmiHeader.biCompression = BI_BITFIELDS;
1002 break;
1006 /* check if the specified color info is suitable for PutImage */
1007 static BOOL matching_color_info( const XVisualInfo *vis, const BITMAPINFO *info )
1009 DWORD *colors = (DWORD *)((char *)info + info->bmiHeader.biSize);
1011 switch (info->bmiHeader.biBitCount)
1013 case 1:
1014 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1015 return !info->bmiHeader.biClrUsed; /* color map not allowed */
1016 case 4:
1017 case 8:
1019 RGBQUAD *rgb = (RGBQUAD *)colors;
1020 PALETTEENTRY palette[256];
1021 UINT i, count;
1023 if (info->bmiHeader.biCompression != BI_RGB) return FALSE;
1024 count = X11DRV_GetSystemPaletteEntries( NULL, 0, 1 << info->bmiHeader.biBitCount, palette );
1025 if (count != info->bmiHeader.biClrUsed) return FALSE;
1026 for (i = 0; i < count; i++)
1028 if (rgb[i].rgbRed != palette[i].peRed ||
1029 rgb[i].rgbGreen != palette[i].peGreen ||
1030 rgb[i].rgbBlue != palette[i].peBlue) return FALSE;
1032 return TRUE;
1034 case 16:
1035 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1036 return (vis->red_mask == colors[0] &&
1037 vis->green_mask == colors[1] &&
1038 vis->blue_mask == colors[2]);
1039 if (info->bmiHeader.biCompression == BI_RGB)
1040 return (vis->red_mask == 0x7c00 && vis->green_mask == 0x03e0 && vis->blue_mask == 0x001f);
1041 break;
1042 case 32:
1043 if (info->bmiHeader.biCompression == BI_BITFIELDS)
1044 return (vis->red_mask == colors[0] &&
1045 vis->green_mask == colors[1] &&
1046 vis->blue_mask == colors[2]);
1047 /* fall through */
1048 case 24:
1049 if (info->bmiHeader.biCompression == BI_RGB)
1050 return (vis->red_mask == 0xff0000 && vis->green_mask == 0x00ff00 && vis->blue_mask == 0x0000ff);
1051 break;
1053 return FALSE;
1056 static inline BOOL is_r8g8b8( const XVisualInfo *vis )
1058 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1059 return format->bits_per_pixel == 24 && vis->red_mask == 0xff0000 && vis->blue_mask == 0x0000ff;
1062 static inline BOOL image_needs_byteswap( XImage *image, BOOL is_r8g8b8, int bit_count )
1064 #ifdef WORDS_BIGENDIAN
1065 static const int client_byte_order = MSBFirst;
1066 #else
1067 static const int client_byte_order = LSBFirst;
1068 #endif
1070 switch (bit_count)
1072 case 1: return image->bitmap_bit_order != MSBFirst;
1073 case 4: return image->byte_order != MSBFirst;
1074 case 16:
1075 case 32: return image->byte_order != client_byte_order;
1076 case 24: return (image->byte_order == MSBFirst) ^ !is_r8g8b8;
1077 default: return FALSE;
1081 /* copy image bits with byte swapping and/or pixel mapping */
1082 static void copy_image_byteswap( BITMAPINFO *info, const unsigned char *src, unsigned char *dst,
1083 int src_stride, int dst_stride, int height, BOOL byteswap,
1084 const int *mapping, unsigned int zeropad_mask, unsigned int alpha_bits )
1086 int x, y, padding_pos = abs(dst_stride) / sizeof(unsigned int) - 1;
1088 if (!byteswap && !mapping) /* simply copy */
1090 if (src != dst)
1092 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1094 memcpy( dst, src, src_stride );
1095 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1098 else if (zeropad_mask != ~0u) /* only need to clear the padding */
1100 for (y = 0; y < height; y++, dst += dst_stride)
1101 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1103 return;
1106 switch (info->bmiHeader.biBitCount)
1108 case 1:
1109 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1111 for (x = 0; x < src_stride; x++) dst[x] = bit_swap[src[x]];
1112 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1114 break;
1115 case 4:
1116 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1118 if (mapping)
1120 if (byteswap)
1121 for (x = 0; x < src_stride; x++)
1122 dst[x] = (mapping[src[x] & 0x0f] << 4) | mapping[src[x] >> 4];
1123 else
1124 for (x = 0; x < src_stride; x++)
1125 dst[x] = mapping[src[x] & 0x0f] | (mapping[src[x] >> 4] << 4);
1127 else
1128 for (x = 0; x < src_stride; x++)
1129 dst[x] = (src[x] << 4) | (src[x] >> 4);
1130 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1132 break;
1133 case 8:
1134 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1136 for (x = 0; x < src_stride; x++) dst[x] = mapping[src[x]];
1137 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1139 break;
1140 case 16:
1141 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1143 for (x = 0; x < info->bmiHeader.biWidth; x++)
1144 ((USHORT *)dst)[x] = RtlUshortByteSwap( ((const USHORT *)src)[x] );
1145 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1147 break;
1148 case 24:
1149 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1151 for (x = 0; x < info->bmiHeader.biWidth; x++)
1153 unsigned char tmp = src[3 * x];
1154 dst[3 * x] = src[3 * x + 2];
1155 dst[3 * x + 1] = src[3 * x + 1];
1156 dst[3 * x + 2] = tmp;
1158 ((unsigned int *)dst)[padding_pos] &= zeropad_mask;
1160 break;
1161 case 32:
1162 for (y = 0; y < height; y++, src += src_stride, dst += dst_stride)
1163 for (x = 0; x < info->bmiHeader.biWidth; x++)
1164 ((ULONG *)dst)[x] = RtlUlongByteSwap( ((const ULONG *)src)[x] | alpha_bits );
1165 break;
1169 /* copy the image bits, fixing up alignment and byte swapping as necessary */
1170 DWORD copy_image_bits( BITMAPINFO *info, BOOL is_r8g8b8, XImage *image,
1171 const struct gdi_image_bits *src_bits, struct gdi_image_bits *dst_bits,
1172 struct bitblt_coords *coords, const int *mapping, unsigned int zeropad_mask )
1174 BOOL need_byteswap = image_needs_byteswap( image, is_r8g8b8, info->bmiHeader.biBitCount );
1175 int height = coords->visrect.bottom - coords->visrect.top;
1176 int width_bytes = image->bytes_per_line;
1177 unsigned char *src, *dst;
1179 src = src_bits->ptr;
1180 if (info->bmiHeader.biHeight > 0)
1181 src += (info->bmiHeader.biHeight - coords->visrect.bottom) * width_bytes;
1182 else
1183 src += coords->visrect.top * width_bytes;
1185 if ((need_byteswap && !src_bits->is_copy) || /* need to swap bytes */
1186 (zeropad_mask != ~0u && !src_bits->is_copy) || /* need to clear padding bytes */
1187 (mapping && !src_bits->is_copy) || /* need to remap pixels */
1188 (width_bytes & 3) || /* need to fixup line alignment */
1189 (info->bmiHeader.biHeight > 0)) /* need to flip vertically */
1191 width_bytes = (width_bytes + 3) & ~3;
1192 info->bmiHeader.biSizeImage = height * width_bytes;
1193 if (!(dst_bits->ptr = malloc( info->bmiHeader.biSizeImage )))
1194 return ERROR_OUTOFMEMORY;
1195 dst_bits->is_copy = TRUE;
1196 dst_bits->free = free_heap_bits;
1198 else
1200 /* swap bits in place */
1201 dst_bits->ptr = src;
1202 dst_bits->is_copy = src_bits->is_copy;
1203 dst_bits->free = NULL;
1204 if (!need_byteswap && zeropad_mask == ~0u && !mapping) return ERROR_SUCCESS; /* nothing to do */
1207 dst = dst_bits->ptr;
1209 if (info->bmiHeader.biHeight > 0)
1211 dst += (height - 1) * width_bytes;
1212 width_bytes = -width_bytes;
1215 copy_image_byteswap( info, src, dst, image->bytes_per_line, width_bytes, height,
1216 need_byteswap, mapping, zeropad_mask, 0 );
1217 return ERROR_SUCCESS;
1220 /***********************************************************************
1221 * X11DRV_PutImage
1223 DWORD X11DRV_PutImage( PHYSDEV dev, HRGN clip, BITMAPINFO *info,
1224 const struct gdi_image_bits *bits, struct bitblt_coords *src,
1225 struct bitblt_coords *dst, DWORD rop )
1227 X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1228 DWORD ret;
1229 XImage *image;
1230 XVisualInfo vis = default_visual;
1231 struct gdi_image_bits dst_bits;
1232 const XPixmapFormatValues *format;
1233 const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1234 const int *mapping = NULL;
1236 vis.depth = physdev->depth;
1237 if (physdev->color_shifts)
1239 vis.red_mask = physdev->color_shifts->logicalRed.max << physdev->color_shifts->logicalRed.shift;
1240 vis.green_mask = physdev->color_shifts->logicalGreen.max << physdev->color_shifts->logicalGreen.shift;
1241 vis.blue_mask = physdev->color_shifts->logicalBlue.max << physdev->color_shifts->logicalBlue.shift;
1243 format = pixmap_formats[vis.depth];
1245 if (info->bmiHeader.biPlanes != 1) goto update_format;
1246 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1247 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1248 if (!matching_color_info( &vis, info )) goto update_format;
1249 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1250 if ((src->width != dst->width) || (src->height != dst->height)) return ERROR_TRANSFORM_NOT_SUPPORTED;
1252 image = XCreateImage( gdi_display, vis.visual, vis.depth, ZPixmap, 0, NULL,
1253 info->bmiHeader.biWidth, src->visrect.bottom - src->visrect.top, 32, 0 );
1254 if (!image) return ERROR_OUTOFMEMORY;
1256 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1258 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1259 mapping = X11DRV_PALETTE_PaletteToXPixel;
1262 ret = copy_image_bits( info, is_r8g8b8(&vis), image, bits, &dst_bits, src, mapping, ~0u );
1264 if (!ret)
1266 BOOL restore_region = add_extra_clipping_region( physdev, clip );
1267 int width = dst->visrect.right - dst->visrect.left;
1268 int height = dst->visrect.bottom - dst->visrect.top;
1270 image->data = dst_bits.ptr;
1272 /* optimization for single-op ROPs */
1273 if (!opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST))
1275 XSetFunction( gdi_display, physdev->gc, OP_ROP(*opcode) );
1276 XPutImage( gdi_display, physdev->drawable, physdev->gc, image, src->visrect.left, 0,
1277 physdev->dc_rect.left + dst->visrect.left,
1278 physdev->dc_rect.top + dst->visrect.top, width, height );
1280 else
1282 GC gc = XCreateGC( gdi_display, physdev->drawable, 0, NULL );
1283 Pixmap src_pixmap = XCreatePixmap( gdi_display, root_window, width, height, vis.depth );
1285 XSetSubwindowMode( gdi_display, gc, IncludeInferiors );
1286 XSetGraphicsExposures( gdi_display, gc, False );
1287 XPutImage( gdi_display, src_pixmap, gc, image, src->visrect.left, 0, 0, 0, width, height );
1289 execute_rop( physdev, src_pixmap, gc, &dst->visrect, rop );
1291 XFreePixmap( gdi_display, src_pixmap );
1292 XFreeGC( gdi_display, gc );
1295 if (restore_region) restore_clipping_region( physdev );
1296 add_device_bounds( physdev, &dst->visrect );
1297 image->data = NULL;
1300 XDestroyImage( image );
1301 if (dst_bits.free) dst_bits.free( &dst_bits );
1302 return ret;
1304 update_format:
1305 info->bmiHeader.biPlanes = 1;
1306 info->bmiHeader.biBitCount = format->bits_per_pixel;
1307 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1308 set_color_info( &vis, info, FALSE );
1309 return ERROR_BAD_FORMAT;
1312 /***********************************************************************
1313 * X11DRV_GetImage
1315 DWORD X11DRV_GetImage( PHYSDEV dev, BITMAPINFO *info,
1316 struct gdi_image_bits *bits, struct bitblt_coords *src )
1318 X11DRV_PDEVICE *physdev = get_x11drv_dev( dev );
1319 DWORD ret = ERROR_SUCCESS;
1320 XImage *image;
1321 XVisualInfo vis = default_visual;
1322 UINT align, x, y, width, height;
1323 struct gdi_image_bits src_bits;
1324 const XPixmapFormatValues *format;
1325 const int *mapping = NULL;
1327 vis.depth = physdev->depth;
1328 if (physdev->color_shifts)
1330 vis.red_mask = physdev->color_shifts->logicalRed.max << physdev->color_shifts->logicalRed.shift;
1331 vis.green_mask = physdev->color_shifts->logicalGreen.max << physdev->color_shifts->logicalGreen.shift;
1332 vis.blue_mask = physdev->color_shifts->logicalBlue.max << physdev->color_shifts->logicalBlue.shift;
1334 format = pixmap_formats[vis.depth];
1336 /* align start and width to 32-bit boundary */
1337 switch (format->bits_per_pixel)
1339 case 1: align = 32; break;
1340 case 4: align = 8; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1341 case 8: align = 4; mapping = X11DRV_PALETTE_XPixelToPalette; break;
1342 case 16: align = 2; break;
1343 case 24: align = 4; break;
1344 case 32: align = 1; break;
1345 default:
1346 FIXME( "depth %u bpp %u not supported yet\n", vis.depth, format->bits_per_pixel );
1347 return ERROR_BAD_FORMAT;
1350 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1351 info->bmiHeader.biPlanes = 1;
1352 info->bmiHeader.biBitCount = format->bits_per_pixel;
1353 info->bmiHeader.biXPelsPerMeter = 0;
1354 info->bmiHeader.biYPelsPerMeter = 0;
1355 info->bmiHeader.biClrImportant = 0;
1356 set_color_info( &vis, info, FALSE );
1358 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
1360 x = src->visrect.left & ~(align - 1);
1361 y = src->visrect.top;
1362 width = src->visrect.right - x;
1363 height = src->visrect.bottom - src->visrect.top;
1364 if (format->scanline_pad != 32) width = (width + (align - 1)) & ~(align - 1);
1365 /* make the source rectangle relative to the returned bits */
1366 src->x -= x;
1367 src->y -= y;
1368 OffsetRect( &src->visrect, -x, -y );
1370 X11DRV_expect_error( gdi_display, XGetImage_handler, NULL );
1371 image = XGetImage( gdi_display, physdev->drawable,
1372 physdev->dc_rect.left + x, physdev->dc_rect.top + y,
1373 width, height, AllPlanes, ZPixmap );
1374 if (X11DRV_check_error())
1376 /* use a temporary pixmap to avoid the BadMatch error */
1377 Pixmap pixmap = XCreatePixmap( gdi_display, root_window, width, height, vis.depth );
1378 GC gc = XCreateGC( gdi_display, pixmap, 0, NULL );
1380 XSetGraphicsExposures( gdi_display, gc, False );
1381 XCopyArea( gdi_display, physdev->drawable, pixmap, gc,
1382 physdev->dc_rect.left + x, physdev->dc_rect.top + y, width, height, 0, 0 );
1383 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1384 XFreePixmap( gdi_display, pixmap );
1385 XFreeGC( gdi_display, gc );
1388 if (!image) return ERROR_OUTOFMEMORY;
1390 info->bmiHeader.biWidth = width;
1391 info->bmiHeader.biHeight = -height;
1392 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1394 src_bits.ptr = image->data;
1395 src_bits.is_copy = TRUE;
1396 ret = copy_image_bits( info, is_r8g8b8(&vis), image, &src_bits, bits, src, mapping,
1397 zeropad_masks[(width * image->bits_per_pixel) & 31] );
1399 if (!ret && bits->ptr == image->data)
1401 bits->free = free_ximage_bits;
1402 image->data = NULL;
1404 XDestroyImage( image );
1405 return ret;
1409 /***********************************************************************
1410 * put_pixmap_image
1412 * Simplified equivalent of X11DRV_PutImage that writes directly to a pixmap.
1414 static DWORD put_pixmap_image( Pixmap pixmap, const XVisualInfo *vis,
1415 BITMAPINFO *info, const struct gdi_image_bits *bits )
1417 DWORD ret;
1418 XImage *image;
1419 GC gc;
1420 struct bitblt_coords coords;
1421 struct gdi_image_bits dst_bits;
1422 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1423 const int *mapping = NULL;
1425 if (!format) return ERROR_INVALID_PARAMETER;
1426 if (info->bmiHeader.biPlanes != 1) goto update_format;
1427 if (info->bmiHeader.biBitCount != format->bits_per_pixel) goto update_format;
1428 /* FIXME: could try to handle 1-bpp using XCopyPlane */
1429 if (!matching_color_info( vis, info )) goto update_format;
1430 if (!bits) return ERROR_SUCCESS; /* just querying the format */
1432 coords.x = 0;
1433 coords.y = 0;
1434 coords.width = info->bmiHeader.biWidth;
1435 coords.height = abs( info->bmiHeader.biHeight );
1436 SetRect( &coords.visrect, 0, 0, coords.width, coords.height );
1438 image = XCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, 0, NULL,
1439 coords.width, coords.height, 32, 0 );
1440 if (!image) return ERROR_OUTOFMEMORY;
1442 if (image->bits_per_pixel == 4 || image->bits_per_pixel == 8)
1443 mapping = X11DRV_PALETTE_PaletteToXPixel;
1445 if (!(ret = copy_image_bits( info, is_r8g8b8(vis), image, bits, &dst_bits, &coords, mapping, ~0u )))
1447 image->data = dst_bits.ptr;
1448 gc = XCreateGC( gdi_display, pixmap, 0, NULL );
1449 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, coords.width, coords.height );
1450 XFreeGC( gdi_display, gc );
1451 image->data = NULL;
1452 if (dst_bits.free) dst_bits.free( &dst_bits );
1455 XDestroyImage( image );
1456 return ret;
1458 update_format:
1459 info->bmiHeader.biPlanes = 1;
1460 info->bmiHeader.biBitCount = format->bits_per_pixel;
1461 if (info->bmiHeader.biHeight > 0) info->bmiHeader.biHeight = -info->bmiHeader.biHeight;
1462 set_color_info( vis, info, FALSE );
1463 return ERROR_BAD_FORMAT;
1467 /***********************************************************************
1468 * create_pixmap_from_image
1470 Pixmap create_pixmap_from_image( HDC hdc, const XVisualInfo *vis, const BITMAPINFO *info,
1471 const struct gdi_image_bits *bits, UINT coloruse )
1473 static const RGBQUAD default_colortable[2] = { { 0x00, 0x00, 0x00 }, { 0xff, 0xff, 0xff } };
1474 char dst_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1475 char src_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
1476 BITMAPINFO *dst_info = (BITMAPINFO *)dst_buffer;
1477 BITMAPINFO *src_info = (BITMAPINFO *)src_buffer;
1478 struct gdi_image_bits dst_bits;
1479 Pixmap pixmap;
1480 DWORD err;
1481 HBITMAP dib;
1483 pixmap = XCreatePixmap( gdi_display, root_window,
1484 info->bmiHeader.biWidth, abs(info->bmiHeader.biHeight), vis->depth );
1485 if (!pixmap) return 0;
1487 memcpy( src_info, info, get_dib_info_size( info, coloruse ));
1488 memcpy( dst_info, info, get_dib_info_size( info, coloruse ));
1490 if (coloruse == DIB_PAL_COLORS ||
1491 (err = put_pixmap_image( pixmap, vis, dst_info, bits )) == ERROR_BAD_FORMAT)
1493 if (dst_info->bmiHeader.biBitCount == 1) /* set a default color table for 1-bpp */
1494 memcpy( dst_info->bmiColors, default_colortable, sizeof(default_colortable) );
1495 dib = NtGdiCreateDIBSection( hdc, 0, 0, dst_info, coloruse, 0, 0, 0, &dst_bits.ptr );
1496 if (dib)
1498 if (src_info->bmiHeader.biBitCount == 1 && !src_info->bmiHeader.biClrUsed)
1499 memcpy( src_info->bmiColors, default_colortable, sizeof(default_colortable) );
1500 NtGdiSetDIBitsToDeviceInternal( hdc, 0, 0, 0, 0, 0, 0, 0,
1501 abs(info->bmiHeader.biHeight), bits->ptr, src_info, coloruse,
1502 0, 0, FALSE, dib ); /* SetDIBits */
1503 dst_bits.free = NULL;
1504 dst_bits.is_copy = TRUE;
1505 err = put_pixmap_image( pixmap, vis, dst_info, &dst_bits );
1506 NtGdiDeleteObjectApp( dib );
1508 else err = ERROR_OUTOFMEMORY;
1511 if (!err) return pixmap;
1513 XFreePixmap( gdi_display, pixmap );
1514 return 0;
1519 /***********************************************************************
1520 * get_pixmap_image
1522 * Equivalent of X11DRV_GetImage that reads directly from a pixmap.
1524 DWORD get_pixmap_image( Pixmap pixmap, int width, int height, const XVisualInfo *vis,
1525 BITMAPINFO *info, struct gdi_image_bits *bits )
1527 DWORD ret = ERROR_SUCCESS;
1528 XImage *image;
1529 struct gdi_image_bits src_bits;
1530 struct bitblt_coords coords;
1531 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
1532 const int *mapping = NULL;
1534 if (!format) return ERROR_INVALID_PARAMETER;
1536 info->bmiHeader.biSize = sizeof(info->bmiHeader);
1537 info->bmiHeader.biWidth = width;
1538 info->bmiHeader.biHeight = -height;
1539 info->bmiHeader.biPlanes = 1;
1540 info->bmiHeader.biBitCount = format->bits_per_pixel;
1541 info->bmiHeader.biXPelsPerMeter = 0;
1542 info->bmiHeader.biYPelsPerMeter = 0;
1543 info->bmiHeader.biClrImportant = 0;
1544 set_color_info( vis, info, FALSE );
1546 if (!bits) return ERROR_SUCCESS; /* just querying the color information */
1548 coords.x = 0;
1549 coords.y = 0;
1550 coords.width = width;
1551 coords.height = height;
1552 SetRect( &coords.visrect, 0, 0, width, height );
1554 image = XGetImage( gdi_display, pixmap, 0, 0, width, height, AllPlanes, ZPixmap );
1555 if (!image) return ERROR_OUTOFMEMORY;
1557 info->bmiHeader.biSizeImage = height * image->bytes_per_line;
1559 src_bits.ptr = image->data;
1560 src_bits.is_copy = TRUE;
1561 ret = copy_image_bits( info, is_r8g8b8(vis), image, &src_bits, bits, &coords, mapping,
1562 zeropad_masks[(width * image->bits_per_pixel) & 31] );
1564 if (!ret && bits->ptr == image->data)
1566 bits->free = free_ximage_bits;
1567 image->data = NULL;
1569 XDestroyImage( image );
1570 return ret;
1574 struct x11drv_window_surface
1576 struct window_surface header;
1577 Window window;
1578 GC gc;
1579 XImage *image;
1580 RECT bounds;
1581 BOOL byteswap;
1582 BOOL is_argb;
1583 DWORD alpha_bits;
1584 COLORREF color_key;
1585 HRGN region;
1586 void *bits;
1587 #ifdef HAVE_LIBXXSHM
1588 XShmSegmentInfo shminfo;
1589 #endif
1590 pthread_mutex_t mutex;
1591 BITMAPINFO info; /* variable size, must be last */
1594 static struct x11drv_window_surface *get_x11_surface( struct window_surface *surface )
1596 return (struct x11drv_window_surface *)surface;
1599 static inline UINT get_color_component( UINT color, UINT mask )
1601 int shift;
1602 for (shift = 0; !(mask & 1); shift++) mask >>= 1;
1603 return (color * mask / 255) << shift;
1606 #ifdef HAVE_LIBXSHAPE
1607 static inline void flush_rgn_data( HRGN rgn, RGNDATA *data )
1609 HRGN tmp = NtGdiExtCreateRegion( NULL, data->rdh.dwSize + data->rdh.nRgnSize, data );
1610 NtGdiCombineRgn( rgn, rgn, tmp, RGN_OR );
1611 NtGdiDeleteObjectApp( tmp );
1612 data->rdh.nCount = 0;
1615 static inline void add_row( HRGN rgn, RGNDATA *data, int x, int y, int len )
1617 RECT *rect = (RECT *)data->Buffer + data->rdh.nCount;
1619 if (len <= 0) return;
1620 rect->left = x;
1621 rect->top = y;
1622 rect->right = x + len;
1623 rect->bottom = y + 1;
1624 data->rdh.nCount++;
1625 if (data->rdh.nCount * sizeof(RECT) > data->rdh.nRgnSize - sizeof(RECT))
1626 flush_rgn_data( rgn, data );
1628 #endif
1630 /***********************************************************************
1631 * update_surface_region
1633 static void update_surface_region( struct x11drv_window_surface *surface )
1635 #ifdef HAVE_LIBXSHAPE
1636 char buffer[4096];
1637 RGNDATA *data = (RGNDATA *)buffer;
1638 BITMAPINFO *info = &surface->info;
1639 UINT *masks = (UINT *)info->bmiColors;
1640 int x, y, start, width;
1641 HRGN rgn;
1643 if (!shape_layered_windows) return;
1645 if (!surface->is_argb && surface->color_key == CLR_INVALID)
1647 XShapeCombineMask( gdi_display, surface->window, ShapeBounding, 0, 0, None, ShapeSet );
1648 return;
1651 data->rdh.dwSize = sizeof(data->rdh);
1652 data->rdh.iType = RDH_RECTANGLES;
1653 data->rdh.nCount = 0;
1654 data->rdh.nRgnSize = sizeof(buffer) - sizeof(data->rdh);
1656 rgn = NtGdiCreateRectRgn( 0, 0, 0, 0 );
1657 width = surface->header.rect.right - surface->header.rect.left;
1659 switch (info->bmiHeader.biBitCount)
1661 case 16:
1663 WORD *bits = surface->bits;
1664 int stride = (width + 1) & ~1;
1665 UINT mask = masks[0] | masks[1] | masks[2];
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 && (bits[x] & mask) == surface->color_key) x++;
1673 start = x;
1674 while (x < width && (bits[x] & mask) != surface->color_key) x++;
1675 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1678 break;
1680 case 24:
1682 BYTE *bits = surface->bits;
1683 int stride = (width * 3 + 3) & ~3;
1685 for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += stride)
1687 x = 0;
1688 while (x < width)
1690 while (x < width &&
1691 (bits[x * 3] == GetBValue(surface->color_key)) &&
1692 (bits[x * 3 + 1] == GetGValue(surface->color_key)) &&
1693 (bits[x * 3 + 2] == GetRValue(surface->color_key)))
1694 x++;
1695 start = x;
1696 while (x < width &&
1697 ((bits[x * 3] != GetBValue(surface->color_key)) ||
1698 (bits[x * 3 + 1] != GetGValue(surface->color_key)) ||
1699 (bits[x * 3 + 2] != GetRValue(surface->color_key))))
1700 x++;
1701 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1704 break;
1706 case 32:
1708 DWORD *bits = surface->bits;
1710 if (info->bmiHeader.biCompression == BI_RGB)
1712 for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += width)
1714 x = 0;
1715 while (x < width)
1717 while (x < width &&
1718 ((bits[x] & 0xffffff) == surface->color_key ||
1719 (surface->is_argb && !(bits[x] & 0xff000000)))) x++;
1720 start = x;
1721 while (x < width &&
1722 !((bits[x] & 0xffffff) == surface->color_key ||
1723 (surface->is_argb && !(bits[x] & 0xff000000)))) x++;
1724 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1728 else
1730 UINT mask = masks[0] | masks[1] | masks[2];
1731 for (y = surface->header.rect.top; y < surface->header.rect.bottom; y++, bits += width)
1733 x = 0;
1734 while (x < width)
1736 while (x < width && (bits[x] & mask) == surface->color_key) x++;
1737 start = x;
1738 while (x < width && (bits[x] & mask) != surface->color_key) x++;
1739 add_row( rgn, data, surface->header.rect.left + start, y, x - start );
1743 break;
1745 default:
1746 assert(0);
1749 if (data->rdh.nCount) flush_rgn_data( rgn, data );
1751 if ((data = X11DRV_GetRegionData( rgn, 0 )))
1753 XShapeCombineRectangles( gdi_display, surface->window, ShapeBounding, 0, 0,
1754 (XRectangle *)data->Buffer, data->rdh.nCount, ShapeSet, YXBanded );
1755 free( data );
1758 NtGdiDeleteObjectApp( rgn );
1759 #endif
1762 /***********************************************************************
1763 * set_color_key
1765 static void set_color_key( struct x11drv_window_surface *surface, COLORREF key )
1767 UINT *masks = (UINT *)surface->info.bmiColors;
1769 if (key == CLR_INVALID)
1770 surface->color_key = CLR_INVALID;
1771 else if (surface->info.bmiHeader.biBitCount <= 8)
1772 surface->color_key = CLR_INVALID;
1773 else if (key & (1 << 24)) /* PALETTEINDEX */
1774 surface->color_key = 0;
1775 else if (key >> 16 == 0x10ff) /* DIBINDEX */
1776 surface->color_key = 0;
1777 else if (surface->info.bmiHeader.biBitCount == 24)
1778 surface->color_key = key;
1779 else if (surface->info.bmiHeader.biCompression == BI_RGB)
1780 surface->color_key = (GetRValue(key) << 16) | (GetGValue(key) << 8) | GetBValue(key);
1781 else
1782 surface->color_key = get_color_component( GetRValue(key), masks[0] ) |
1783 get_color_component( GetGValue(key), masks[1] ) |
1784 get_color_component( GetBValue(key), masks[2] );
1787 #ifdef HAVE_LIBXXSHM
1788 static int xshm_error_handler( Display *display, XErrorEvent *event, void *arg )
1790 return 1; /* FIXME: should check event contents */
1793 static XImage *create_shm_image( const XVisualInfo *vis, int width, int height, XShmSegmentInfo *shminfo )
1795 XImage *image;
1797 shminfo->shmid = -1;
1798 image = XShmCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, NULL, shminfo, width, height );
1799 if (!image) return NULL;
1800 if (image->bytes_per_line & 3) goto failed; /* we need 32-bit alignment */
1802 shminfo->shmid = shmget( IPC_PRIVATE, image->bytes_per_line * height, IPC_CREAT | 0700 );
1803 if (shminfo->shmid == -1) goto failed;
1805 shminfo->shmaddr = shmat( shminfo->shmid, 0, 0 );
1806 if (shminfo->shmaddr != (char *)-1)
1808 BOOL ok;
1810 shminfo->readOnly = True;
1811 X11DRV_expect_error( gdi_display, xshm_error_handler, NULL );
1812 ok = (XShmAttach( gdi_display, shminfo ) != 0);
1813 XSync( gdi_display, False );
1814 if (!X11DRV_check_error() && ok)
1816 image->data = shminfo->shmaddr;
1817 shmctl( shminfo->shmid, IPC_RMID, 0 );
1818 return image;
1820 shmdt( shminfo->shmaddr );
1822 shmctl( shminfo->shmid, IPC_RMID, 0 );
1823 shminfo->shmid = -1;
1825 failed:
1826 XDestroyImage( image );
1827 return NULL;
1829 #endif /* HAVE_LIBXXSHM */
1831 /***********************************************************************
1832 * x11drv_surface_lock
1834 static void x11drv_surface_lock( struct window_surface *window_surface )
1836 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1838 pthread_mutex_lock( &surface->mutex );
1841 /***********************************************************************
1842 * x11drv_surface_unlock
1844 static void x11drv_surface_unlock( struct window_surface *window_surface )
1846 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1848 pthread_mutex_unlock( &surface->mutex );
1851 /***********************************************************************
1852 * x11drv_surface_get_bitmap_info
1854 static void *x11drv_surface_get_bitmap_info( struct window_surface *window_surface, BITMAPINFO *info )
1856 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1858 memcpy( info, &surface->info, get_dib_info_size( &surface->info, DIB_RGB_COLORS ));
1859 return surface->bits;
1862 /***********************************************************************
1863 * x11drv_surface_get_bounds
1865 static RECT *x11drv_surface_get_bounds( struct window_surface *window_surface )
1867 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1869 return &surface->bounds;
1872 /***********************************************************************
1873 * x11drv_surface_set_region
1875 static void x11drv_surface_set_region( struct window_surface *window_surface, HRGN region )
1877 RGNDATA *data;
1878 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1880 TRACE( "updating surface %p with %p\n", surface, region );
1882 window_surface->funcs->lock( window_surface );
1883 if (!region)
1885 if (surface->region) NtGdiDeleteObjectApp( surface->region );
1886 surface->region = 0;
1887 XSetClipMask( gdi_display, surface->gc, None );
1889 else
1891 if (!surface->region) surface->region = NtGdiCreateRectRgn( 0, 0, 0, 0 );
1892 NtGdiCombineRgn( surface->region, region, 0, RGN_COPY );
1893 if ((data = X11DRV_GetRegionData( surface->region, 0 )))
1895 XSetClipRectangles( gdi_display, surface->gc, 0, 0,
1896 (XRectangle *)data->Buffer, data->rdh.nCount, YXBanded );
1897 free( data );
1900 window_surface->funcs->unlock( window_surface );
1903 /***********************************************************************
1904 * x11drv_surface_flush
1906 static void x11drv_surface_flush( struct window_surface *window_surface )
1908 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1909 unsigned char *src = surface->bits;
1910 unsigned char *dst = (unsigned char *)surface->image->data;
1911 struct bitblt_coords coords;
1913 window_surface->funcs->lock( window_surface );
1914 coords.x = 0;
1915 coords.y = 0;
1916 coords.width = surface->header.rect.right - surface->header.rect.left;
1917 coords.height = surface->header.rect.bottom - surface->header.rect.top;
1918 SetRect( &coords.visrect, 0, 0, coords.width, coords.height );
1919 if (intersect_rect( &coords.visrect, &coords.visrect, &surface->bounds ))
1921 TRACE( "flushing %p %dx%d bounds %s bits %p\n",
1922 surface, coords.width, coords.height,
1923 wine_dbgstr_rect( &surface->bounds ), surface->bits );
1925 if (surface->is_argb || surface->color_key != CLR_INVALID) update_surface_region( surface );
1927 if (src != dst)
1929 int map[256], *mapping = get_window_surface_mapping( surface->image->bits_per_pixel, map );
1930 int width_bytes = surface->image->bytes_per_line;
1932 src += coords.visrect.top * width_bytes;
1933 dst += coords.visrect.top * width_bytes;
1934 copy_image_byteswap( &surface->info, src, dst, width_bytes, width_bytes,
1935 coords.visrect.bottom - coords.visrect.top,
1936 surface->byteswap, mapping, ~0u, surface->alpha_bits );
1938 else if (surface->alpha_bits)
1940 int x, y, stride = surface->image->bytes_per_line / sizeof(ULONG);
1941 ULONG *ptr = (ULONG *)dst + coords.visrect.top * stride;
1943 for (y = coords.visrect.top; y < coords.visrect.bottom; y++, ptr += stride)
1944 for (x = coords.visrect.left; x < coords.visrect.right; x++)
1945 ptr[x] |= surface->alpha_bits;
1948 #ifdef HAVE_LIBXXSHM
1949 if (surface->shminfo.shmid != -1)
1950 XShmPutImage( gdi_display, surface->window, surface->gc, surface->image,
1951 coords.visrect.left, coords.visrect.top,
1952 surface->header.rect.left + coords.visrect.left,
1953 surface->header.rect.top + coords.visrect.top,
1954 coords.visrect.right - coords.visrect.left,
1955 coords.visrect.bottom - coords.visrect.top, False );
1956 else
1957 #endif
1958 XPutImage( gdi_display, surface->window, surface->gc, surface->image,
1959 coords.visrect.left, coords.visrect.top,
1960 surface->header.rect.left + coords.visrect.left,
1961 surface->header.rect.top + coords.visrect.top,
1962 coords.visrect.right - coords.visrect.left,
1963 coords.visrect.bottom - coords.visrect.top );
1964 XFlush( gdi_display );
1966 reset_bounds( &surface->bounds );
1967 window_surface->funcs->unlock( window_surface );
1970 /***********************************************************************
1971 * x11drv_surface_destroy
1973 static void x11drv_surface_destroy( struct window_surface *window_surface )
1975 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
1977 TRACE( "freeing %p bits %p\n", surface, surface->bits );
1978 if (surface->gc) XFreeGC( gdi_display, surface->gc );
1979 if (surface->image)
1981 if (surface->image->data != surface->bits) free( surface->bits );
1982 #ifdef HAVE_LIBXXSHM
1983 if (surface->shminfo.shmid != -1)
1985 XShmDetach( gdi_display, &surface->shminfo );
1986 shmdt( surface->shminfo.shmaddr );
1988 else
1989 #endif
1990 free( surface->image->data );
1991 surface->image->data = NULL;
1992 XDestroyImage( surface->image );
1994 if (surface->region) NtGdiDeleteObjectApp( surface->region );
1995 free( surface );
1998 static const struct window_surface_funcs x11drv_surface_funcs =
2000 x11drv_surface_lock,
2001 x11drv_surface_unlock,
2002 x11drv_surface_get_bitmap_info,
2003 x11drv_surface_get_bounds,
2004 x11drv_surface_set_region,
2005 x11drv_surface_flush,
2006 x11drv_surface_destroy
2009 /***********************************************************************
2010 * create_surface
2012 struct window_surface *create_surface( Window window, const XVisualInfo *vis, const RECT *rect,
2013 COLORREF color_key, BOOL use_alpha )
2015 const XPixmapFormatValues *format = pixmap_formats[vis->depth];
2016 struct x11drv_window_surface *surface;
2017 int width = rect->right - rect->left, height = rect->bottom - rect->top;
2018 int colors = format->bits_per_pixel <= 8 ? 1 << format->bits_per_pixel : 3;
2020 surface = calloc( 1, FIELD_OFFSET( struct x11drv_window_surface, info.bmiColors[colors] ));
2021 if (!surface) return NULL;
2022 surface->info.bmiHeader.biSize = sizeof(surface->info.bmiHeader);
2023 surface->info.bmiHeader.biWidth = width;
2024 surface->info.bmiHeader.biHeight = -height; /* top-down */
2025 surface->info.bmiHeader.biPlanes = 1;
2026 surface->info.bmiHeader.biBitCount = format->bits_per_pixel;
2027 surface->info.bmiHeader.biSizeImage = get_dib_image_size( &surface->info );
2028 if (format->bits_per_pixel > 8) set_color_info( vis, &surface->info, use_alpha );
2030 init_recursive_mutex( &surface->mutex );
2032 surface->header.funcs = &x11drv_surface_funcs;
2033 surface->header.rect = *rect;
2034 surface->header.ref = 1;
2035 surface->window = window;
2036 surface->is_argb = (use_alpha && vis->depth == 32 && surface->info.bmiHeader.biCompression == BI_RGB);
2037 set_color_key( surface, color_key );
2038 reset_bounds( &surface->bounds );
2040 #ifdef HAVE_LIBXXSHM
2041 surface->image = create_shm_image( vis, width, height, &surface->shminfo );
2042 if (!surface->image)
2043 #endif
2045 surface->image = XCreateImage( gdi_display, vis->visual, vis->depth, ZPixmap, 0, NULL,
2046 width, height, 32, 0 );
2047 if (!surface->image) goto failed;
2048 surface->image->data = malloc( surface->info.bmiHeader.biSizeImage );
2049 if (!surface->image->data) goto failed;
2052 surface->gc = XCreateGC( gdi_display, window, 0, NULL );
2053 XSetSubwindowMode( gdi_display, surface->gc, IncludeInferiors );
2054 surface->byteswap = image_needs_byteswap( surface->image, is_r8g8b8(vis), format->bits_per_pixel );
2056 if (vis->depth == 32 && !surface->is_argb)
2057 surface->alpha_bits = ~(vis->red_mask | vis->green_mask | vis->blue_mask);
2059 if (surface->byteswap || format->bits_per_pixel == 4 || format->bits_per_pixel == 8)
2061 /* allocate separate surface bits if byte swapping or palette mapping is required */
2062 if (!(surface->bits = calloc( 1, surface->info.bmiHeader.biSizeImage )))
2063 goto failed;
2065 else surface->bits = surface->image->data;
2067 TRACE( "created %p for %lx %s bits %p-%p image %p\n", surface, window, wine_dbgstr_rect(rect),
2068 surface->bits, (char *)surface->bits + surface->info.bmiHeader.biSizeImage,
2069 surface->image->data );
2071 return &surface->header;
2073 failed:
2074 x11drv_surface_destroy( &surface->header );
2075 return NULL;
2078 /***********************************************************************
2079 * set_surface_color_key
2081 void set_surface_color_key( struct window_surface *window_surface, COLORREF color_key )
2083 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
2084 COLORREF prev;
2086 if (window_surface->funcs != &x11drv_surface_funcs) return; /* we may get the null surface */
2088 window_surface->funcs->lock( window_surface );
2089 prev = surface->color_key;
2090 set_color_key( surface, color_key );
2091 if (surface->color_key != prev) update_surface_region( surface );
2092 window_surface->funcs->unlock( window_surface );
2095 /***********************************************************************
2096 * expose_surface
2098 HRGN expose_surface( struct window_surface *window_surface, const RECT *rect )
2100 struct x11drv_window_surface *surface = get_x11_surface( window_surface );
2101 HRGN region = 0;
2102 RECT rc = *rect;
2104 if (window_surface->funcs != &x11drv_surface_funcs) return 0; /* we may get the null surface */
2106 window_surface->funcs->lock( window_surface );
2107 OffsetRect( &rc, -window_surface->rect.left, -window_surface->rect.top );
2108 add_bounds_rect( &surface->bounds, &rc );
2109 if (surface->region)
2111 region = NtGdiCreateRectRgn( rect->left, rect->top, rect->right, rect->bottom );
2112 if (NtGdiCombineRgn( region, region, surface->region, RGN_DIFF ) <= NULLREGION)
2114 NtGdiDeleteObjectApp( region );
2115 region = 0;
2118 window_surface->funcs->unlock( window_surface );
2119 return region;