Prevent garbage being passed for windows directory.
[wine/multimedia.git] / dlls / x11drv / bitblt.c
blob3a559ad6f500449d7bc357c1f028ac8d9fb097a4
1 /*
2 * GDI bit-blit operations
4 * Copyright 1993, 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <X11/Intrinsic.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winreg.h"
33 #include "winuser.h"
34 #include "x11drv.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
40 #define DST 0 /* Destination drawable */
41 #define SRC 1 /* Source drawable */
42 #define TMP 2 /* Temporary drawable */
43 #define PAT 3 /* Pattern (brush) in destination DC */
45 #define OP(src,dst,rop) (OP_ARGS(src,dst) << 4 | (rop))
46 #define OP_ARGS(src,dst) (((src) << 2) | (dst))
48 #define OP_SRC(opcode) ((opcode) >> 6)
49 #define OP_DST(opcode) (((opcode) >> 4) & 3)
50 #define OP_SRCDST(opcode) ((opcode) >> 4)
51 #define OP_ROP(opcode) ((opcode) & 0x0f)
53 #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */
55 #define SWAP_INT32(i1,i2) \
56 do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
58 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
60 { OP(PAT,DST,GXclear) }, /* 0x00 0 */
61 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */
62 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */
63 { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */
64 { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */
65 { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */
66 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */
67 { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */
68 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */
69 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */
70 { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */
71 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */
72 { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */
73 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */
74 { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */
75 { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */
76 { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */
77 { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */
78 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */
79 { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */
80 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */
81 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */
82 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
83 OP(TMP,DST,GXand), OP(SRC,DST,GXxor),
84 OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */
85 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
86 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
87 OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/
88 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
89 OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */
90 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
91 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */
92 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
93 OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */
94 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXxor),
95 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */
96 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
97 OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */
98 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
99 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */
100 { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */
101 { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */
102 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */
103 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */
104 { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */
105 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */
106 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
107 OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */
108 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
109 OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */
110 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
111 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
112 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXequiv),
113 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */
114 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */
115 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
116 OP(TMP,DST,GXor), OP(SRC,DST,GXxor),
117 OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */
118 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */
119 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
120 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
121 OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/
122 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
123 OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */
124 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */
125 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
126 OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */
127 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */
128 { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */
129 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */
130 { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
131 OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */
132 { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */
133 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
134 OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */
135 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
136 OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */
137 { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */
138 { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */
139 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
140 OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */
141 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */
142 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
143 OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */
144 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */
145 { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */
146 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
147 OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */
148 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
149 OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */
150 { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */
151 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */
152 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */
153 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
154 OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */
155 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
156 OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */
157 { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */
158 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */
159 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
160 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */
161 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
162 OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */
163 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */
164 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
165 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
166 OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */
167 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
168 OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */
169 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */
170 { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */
171 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
172 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
173 OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/
174 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
175 OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */
176 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */
177 { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */
178 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */
179 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
180 OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */
181 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
182 OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */
183 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */
184 { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */
185 { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */
186 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */
187 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
188 OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */
189 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */
190 { OP(PAT,DST,GXxor) }, /* 0x5a D^P */
191 { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
192 OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */
193 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
194 OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */
195 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */
196 { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
197 OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */
198 { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */
199 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */
200 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
201 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
202 OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */
203 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
204 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */
205 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */
206 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
207 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */
208 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */
209 { OP(SRC,DST,GXxor) }, /* 0x66 S^D */
210 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
211 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */
212 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
213 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
214 OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/
215 { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */
216 { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */
217 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
218 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
219 OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */
220 { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */
221 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
222 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
223 OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */
224 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
225 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */
226 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */
227 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */
228 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
229 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
230 OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/
231 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
232 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */
233 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */
234 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
235 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */
236 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */
237 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
238 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */
239 { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */
240 { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */
241 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
242 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
243 OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */
244 { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
245 OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */
246 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */
247 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
248 OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */
249 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */
250 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
251 OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */
252 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */
253 { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */
254 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
255 OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */
256 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */
257 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
258 OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */
259 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */
260 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
261 OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */
262 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
263 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
264 OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */
265 { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */
266 { OP(SRC,DST,GXand) }, /* 0x88 S&D */
267 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
268 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */
269 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */
270 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
271 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */
272 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */
273 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
274 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */
275 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
276 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
277 OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/
278 { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */
279 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */
280 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
281 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */
282 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
283 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
284 OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */
285 { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */
286 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
287 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
288 OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */
289 { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */
290 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */
291 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
292 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
293 OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */
294 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
295 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */
296 { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */
297 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */
298 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
299 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */
300 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */
301 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
302 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */
303 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
304 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
305 OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */
306 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */
307 { OP(PAT,DST,GXand) }, /* 0xa0 D&P */
308 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
309 OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */
310 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */
311 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
312 OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */
313 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
314 OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */
315 { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */
316 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */
317 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
318 OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */
319 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */
320 { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */
321 { OP(SRC,DST,GXnoop) }, /* 0xaa D */
322 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */
323 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
324 OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */
325 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
326 OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */
327 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */
328 { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */
329 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */
330 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
331 OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */
332 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
333 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
334 OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/
335 { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */
336 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */
337 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
338 OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */
339 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
340 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
341 OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */
342 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */
343 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
344 OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */
345 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
346 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */
347 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */
348 { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */
349 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
350 OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */
351 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
352 OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */
353 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */
354 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */
355 { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */
356 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
357 OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */
358 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
359 OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */
360 { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */
361 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */
362 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
363 OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */
364 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */
365 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
366 OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */
367 { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */
368 { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */
369 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
370 OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */
371 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
372 OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */
373 { OP(SRC,DST,GXcopy) }, /* 0xcc S */
374 { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */
375 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */
376 { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */
377 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */
378 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
379 OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */
380 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */
381 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
382 OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */
383 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
384 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
385 OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/
386 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */
387 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
388 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
389 OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */
390 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */
391 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
392 OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */
393 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
394 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */
395 { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
396 OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */
397 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
398 OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */
399 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */
400 { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */
401 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */
402 { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */
403 { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */
404 { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */
405 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
406 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */
407 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
408 OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */
409 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
410 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */
411 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
412 OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */
413 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
414 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */
415 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
416 OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */
417 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
418 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
419 OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/
420 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
421 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
422 OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/
423 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */
424 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */
425 { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */
426 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */
427 { OP(SRC,DST,GXor) }, /* 0xee S|D */
428 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */
429 { OP(PAT,DST,GXcopy) }, /* 0xf0 P */
430 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */
431 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */
432 { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */
433 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */
434 { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */
435 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */
436 { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */
437 { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */
438 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */
439 { OP(PAT,DST,GXor) }, /* 0xfa D|P */
440 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */
441 { OP(PAT,SRC,GXor) }, /* 0xfc P|S */
442 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */
443 { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */
444 { OP(PAT,DST,GXset) } /* 0xff 1 */
448 #ifdef BITBLT_TEST /* Opcodes test */
450 static int do_bitop( int s, int d, int rop )
452 int res;
453 switch(rop)
455 case GXclear: res = 0; break;
456 case GXand: res = s & d; break;
457 case GXandReverse: res = s & ~d; break;
458 case GXcopy: res = s; break;
459 case GXandInverted: res = ~s & d; break;
460 case GXnoop: res = d; break;
461 case GXxor: res = s ^ d; break;
462 case GXor: res = s | d; break;
463 case GXnor: res = ~(s | d); break;
464 case GXequiv: res = ~s ^ d; break;
465 case GXinvert: res = ~d; break;
466 case GXorReverse: res = s | ~d; break;
467 case GXcopyInverted: res = ~s; break;
468 case GXorInverted: res = ~s | d; break;
469 case GXnand: res = ~(s & d); break;
470 case GXset: res = 1; break;
472 return res & 1;
475 int main()
477 int rop, i, res, src, dst, pat, tmp, dstUsed;
478 const BYTE *opcode;
480 for (rop = 0; rop < 256; rop++)
482 res = dstUsed = 0;
483 for (i = 0; i < 8; i++)
485 pat = (i >> 2) & 1;
486 src = (i >> 1) & 1;
487 dst = i & 1;
488 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
490 switch(*opcode >> 4)
492 case OP_ARGS(DST,TMP):
493 tmp = do_bitop( dst, tmp, *opcode & 0xf );
494 break;
495 case OP_ARGS(DST,SRC):
496 src = do_bitop( dst, src, *opcode & 0xf );
497 break;
498 case OP_ARGS(SRC,TMP):
499 tmp = do_bitop( src, tmp, *opcode & 0xf );
500 break;
501 case OP_ARGS(SRC,DST):
502 dst = do_bitop( src, dst, *opcode & 0xf );
503 dstUsed = 1;
504 break;
505 case OP_ARGS(PAT,TMP):
506 tmp = do_bitop( pat, tmp, *opcode & 0xf );
507 break;
508 case OP_ARGS(PAT,DST):
509 dst = do_bitop( pat, dst, *opcode & 0xf );
510 dstUsed = 1;
511 break;
512 case OP_ARGS(PAT,SRC):
513 src = do_bitop( pat, src, *opcode & 0xf );
514 break;
515 case OP_ARGS(TMP,DST):
516 dst = do_bitop( tmp, dst, *opcode & 0xf );
517 dstUsed = 1;
518 break;
519 case OP_ARGS(TMP,SRC):
520 src = do_bitop( tmp, src, *opcode & 0xf );
521 break;
522 default:
523 printf( "Invalid opcode %x\n", *opcode );
526 if (!dstUsed) dst = src;
527 if (dst) res |= 1 << i;
529 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
532 return 0;
535 #endif /* BITBLT_TEST */
538 /***********************************************************************
539 * perfect_graphics
541 * Favor correctness or speed?
543 static int perfect_graphics(void)
545 static int perfect = -1;
546 if (perfect == -1)
548 HKEY hkey;
549 char buffer[20];
550 /* default value */
551 perfect = 0;
552 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
554 DWORD type, count = sizeof(buffer);
555 if(!RegQueryValueExA(hkey, "PerfectGraphics", 0, &type, buffer, &count))
557 char ch = buffer[0];
558 perfect = (ch == 'y' || ch == 'Y' || ch == 't' || ch == 'T' || ch == '1');
560 RegCloseKey(hkey);
563 return perfect;
566 /***********************************************************************
567 * BITBLT_StretchRow
569 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
571 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
572 INT startDst, INT widthDst,
573 INT xinc, INT xoff, WORD mode )
575 register INT xsrc = xinc * startDst + xoff;
576 rowDst += startDst;
577 switch(mode)
579 case STRETCH_ANDSCANS:
580 for(; widthDst > 0; widthDst--, xsrc += xinc)
581 *rowDst++ &= rowSrc[xsrc >> 16];
582 break;
583 case STRETCH_ORSCANS:
584 for(; widthDst > 0; widthDst--, xsrc += xinc)
585 *rowDst++ |= rowSrc[xsrc >> 16];
586 break;
587 case STRETCH_DELETESCANS:
588 for(; widthDst > 0; widthDst--, xsrc += xinc)
589 *rowDst++ = rowSrc[xsrc >> 16];
590 break;
595 /***********************************************************************
596 * BITBLT_ShrinkRow
598 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
600 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
601 INT startSrc, INT widthSrc,
602 INT xinc, INT xoff, WORD mode )
604 register INT xdst = xinc * startSrc + xoff;
605 rowSrc += startSrc;
606 switch(mode)
608 case STRETCH_ORSCANS:
609 for(; widthSrc > 0; widthSrc--, xdst += xinc)
610 rowDst[xdst >> 16] |= *rowSrc++;
611 break;
612 case STRETCH_ANDSCANS:
613 for(; widthSrc > 0; widthSrc--, xdst += xinc)
614 rowDst[xdst >> 16] &= *rowSrc++;
615 break;
616 case STRETCH_DELETESCANS:
617 for(; widthSrc > 0; widthSrc--, xdst += xinc)
618 rowDst[xdst >> 16] = *rowSrc++;
619 break;
624 /***********************************************************************
625 * BITBLT_GetRow
627 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
629 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
630 INT start, INT width, INT depthDst,
631 int fg, int bg, BOOL swap)
633 register INT i;
635 assert( (row >= 0) && (row < image->height) );
636 assert( (start >= 0) && (width <= image->width) );
638 pdata += swap ? start+width-1 : start;
639 if (image->depth == depthDst) /* color -> color */
641 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
642 if (swap) for (i = 0; i < width; i++)
643 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
644 else for (i = 0; i < width; i++)
645 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
646 else
647 if (swap) for (i = 0; i < width; i++)
648 *pdata-- = XGetPixel( image, i, row );
649 else for (i = 0; i < width; i++)
650 *pdata++ = XGetPixel( image, i, row );
652 else
654 if (image->depth == 1) /* monochrome -> color */
656 if (X11DRV_PALETTE_XPixelToPalette)
658 fg = X11DRV_PALETTE_XPixelToPalette[fg];
659 bg = X11DRV_PALETTE_XPixelToPalette[bg];
661 if (swap) for (i = 0; i < width; i++)
662 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
663 else for (i = 0; i < width; i++)
664 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
666 else /* color -> monochrome */
668 if (swap) for (i = 0; i < width; i++)
669 *pdata-- = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
670 else for (i = 0; i < width; i++)
671 *pdata++ = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
677 /***********************************************************************
678 * BITBLT_StretchImage
680 * Stretch an X image.
681 * FIXME: does not work for full 32-bit coordinates.
683 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
684 INT widthSrc, INT heightSrc,
685 INT widthDst, INT heightDst,
686 RECT *visRectSrc, RECT *visRectDst,
687 int foreground, int background, WORD mode )
689 int *rowSrc, *rowDst, *pixel;
690 char *pdata;
691 INT xinc, xoff, yinc, ysrc, ydst;
692 register INT x, y;
693 BOOL hstretch, vstretch, hswap, vswap;
695 hswap = ((int)widthSrc * widthDst) < 0;
696 vswap = ((int)heightSrc * heightDst) < 0;
697 widthSrc = abs(widthSrc);
698 heightSrc = abs(heightSrc);
699 widthDst = abs(widthDst);
700 heightDst = abs(heightDst);
702 if (!(rowSrc = (int *)HeapAlloc( GetProcessHeap(), 0,
703 (widthSrc+widthDst)*sizeof(int) ))) return;
704 rowDst = rowSrc + widthSrc;
706 /* When stretching, all modes are the same, and DELETESCANS is faster */
707 if ((widthSrc < widthDst) && (heightSrc < heightDst))
708 mode = STRETCH_DELETESCANS;
710 if (mode == STRETCH_HALFTONE) /* FIXME */
711 mode = STRETCH_DELETESCANS;
713 if (mode != STRETCH_DELETESCANS)
714 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
715 widthDst*sizeof(int) );
717 hstretch = (widthSrc < widthDst);
718 vstretch = (heightSrc < heightDst);
720 if (hstretch)
722 xinc = ((int)widthSrc << 16) / widthDst;
723 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
725 else
727 xinc = ((int)widthDst << 16) / widthSrc;
728 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
731 if (vstretch)
733 yinc = ((int)heightSrc << 16) / heightDst;
734 ydst = visRectDst->top;
735 if (vswap)
737 ysrc = yinc * (heightDst - ydst - 1);
738 yinc = -yinc;
740 else
741 ysrc = yinc * ydst;
743 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
745 if (((ysrc >> 16) < visRectSrc->top) ||
746 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
748 /* Retrieve a source row */
749 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
750 hswap ? widthSrc - visRectSrc->right
751 : visRectSrc->left,
752 visRectSrc->right - visRectSrc->left,
753 dstImage->depth, foreground, background, hswap );
755 /* Stretch or shrink it */
756 if (hstretch)
757 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
758 visRectDst->right - visRectDst->left,
759 xinc, xoff, mode );
760 else BITBLT_ShrinkRow( rowSrc, rowDst,
761 hswap ? widthSrc - visRectSrc->right
762 : visRectSrc->left,
763 visRectSrc->right - visRectSrc->left,
764 xinc, xoff, mode );
766 /* Store the destination row */
767 pixel = rowDst + visRectDst->right - 1;
768 y = ydst - visRectDst->top;
769 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
770 XPutPixel( dstImage, x, y, *pixel-- );
771 if (mode != STRETCH_DELETESCANS)
772 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
773 widthDst*sizeof(int) );
775 /* Make copies of the destination row */
777 pdata = dstImage->data + dstImage->bytes_per_line * y;
778 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
779 (ydst < visRectDst->bottom-1))
781 memcpy( pdata + dstImage->bytes_per_line, pdata,
782 dstImage->bytes_per_line );
783 pdata += dstImage->bytes_per_line;
784 ysrc += yinc;
785 ydst++;
789 else /* Shrinking */
791 yinc = ((int)heightDst << 16) / heightSrc;
792 ysrc = visRectSrc->top;
793 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
794 if (vswap)
796 ydst += yinc * (heightSrc - ysrc - 1);
797 yinc = -yinc;
799 else
800 ydst += yinc * ysrc;
802 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
804 if (((ydst >> 16) < visRectDst->top) ||
805 ((ydst >> 16) >= visRectDst->bottom)) continue;
807 /* Retrieve a source row */
808 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
809 hswap ? widthSrc - visRectSrc->right
810 : visRectSrc->left,
811 visRectSrc->right - visRectSrc->left,
812 dstImage->depth, foreground, background, hswap );
814 /* Stretch or shrink it */
815 if (hstretch)
816 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
817 visRectDst->right - visRectDst->left,
818 xinc, xoff, mode );
819 else BITBLT_ShrinkRow( rowSrc, rowDst,
820 hswap ? widthSrc - visRectSrc->right
821 : visRectSrc->left,
822 visRectSrc->right - visRectSrc->left,
823 xinc, xoff, mode );
825 /* Merge several source rows into the destination */
826 if (mode == STRETCH_DELETESCANS)
828 /* Simply skip the overlapping rows */
829 while (((ydst + yinc) >> 16 == ydst >> 16) &&
830 (ysrc < visRectSrc->bottom-1))
832 ydst += yinc;
833 ysrc++;
836 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
837 (ysrc < visRectSrc->bottom-1))
838 continue; /* Restart loop for next overlapping row */
840 /* Store the destination row */
841 pixel = rowDst + visRectDst->right - 1;
842 y = (ydst >> 16) - visRectDst->top;
843 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
844 XPutPixel( dstImage, x, y, *pixel-- );
845 if (mode != STRETCH_DELETESCANS)
846 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
847 widthDst*sizeof(int) );
850 HeapFree( GetProcessHeap(), 0, rowSrc );
854 /***********************************************************************
855 * BITBLT_GetSrcAreaStretch
857 * Retrieve an area from the source DC, stretching and mapping all the
858 * pixels to Windows colors.
860 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
861 Pixmap pixmap, GC gc,
862 INT xSrc, INT ySrc,
863 INT widthSrc, INT heightSrc,
864 INT xDst, INT yDst,
865 INT widthDst, INT heightDst,
866 RECT *visRectSrc, RECT *visRectDst )
868 XImage *imageSrc, *imageDst;
869 RECT rectSrc = *visRectSrc;
870 RECT rectDst = *visRectDst;
872 if (widthSrc < 0) xSrc += widthSrc;
873 if (widthDst < 0) xDst += widthDst;
874 if (heightSrc < 0) ySrc += heightSrc;
875 if (heightDst < 0) yDst += heightDst;
876 rectSrc.left -= xSrc;
877 rectSrc.right -= xSrc;
878 rectSrc.top -= ySrc;
879 rectSrc.bottom -= ySrc;
880 rectDst.left -= xDst;
881 rectDst.right -= xDst;
882 rectDst.top -= yDst;
883 rectDst.bottom -= yDst;
885 /* FIXME: avoid BadMatch errors */
886 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
887 physDevSrc->org.x + visRectSrc->left,
888 physDevSrc->org.y + visRectSrc->top,
889 visRectSrc->right - visRectSrc->left,
890 visRectSrc->bottom - visRectSrc->top,
891 AllPlanes, ZPixmap );
892 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
893 rectDst.bottom - rectDst.top, physDevDst->depth );
894 BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
895 widthDst, heightDst, &rectSrc, &rectDst,
896 physDevDst->textPixel, physDevDst->depth != 1 ?
897 physDevDst->backgroundPixel :
898 physDevSrc->backgroundPixel,
899 GetStretchBltMode(physDevDst->hdc) );
900 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
901 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
902 XDestroyImage( imageSrc );
903 XDestroyImage( imageDst );
904 return 0; /* no exposure events generated */
908 /***********************************************************************
909 * BITBLT_GetSrcArea
911 * Retrieve an area from the source DC, mapping all the
912 * pixels to Windows colors.
914 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
915 Pixmap pixmap, GC gc, INT xSrc, INT ySrc, RECT *visRectSrc )
917 XImage *imageSrc, *imageDst;
918 register INT x, y;
919 int exposures = 0;
920 INT width = visRectSrc->right - visRectSrc->left;
921 INT height = visRectSrc->bottom - visRectSrc->top;
923 if (physDevSrc->depth == physDevDst->depth)
925 if (!X11DRV_PALETTE_XPixelToPalette ||
926 (physDevDst->depth == 1)) /* monochrome -> monochrome */
928 if (physDevDst->depth == 1)
930 /* MSDN says if StretchBlt must convert a bitmap from monochrome
931 to color or vice versa, the forground and background color of
932 the device context are used. In fact, it also applies to the
933 case when it is converted from mono to mono. */
934 XSetBackground( gdi_display, gc, physDevDst->textPixel );
935 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
936 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
937 physDevSrc->org.x + visRectSrc->left,
938 physDevSrc->org.y + visRectSrc->top,
939 width, height, 0, 0, 1);
941 else
942 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
943 physDevSrc->org.x + visRectSrc->left,
944 physDevSrc->org.y + visRectSrc->top,
945 width, height, 0, 0);
946 exposures++;
948 else /* color -> color */
950 if (GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
951 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
952 physDevSrc->org.x + visRectSrc->left,
953 physDevSrc->org.y + visRectSrc->top,
954 width, height, AllPlanes, ZPixmap );
955 else
957 /* Make sure we don't get a BadMatch error */
958 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
959 physDevSrc->org.x + visRectSrc->left,
960 physDevSrc->org.y + visRectSrc->top,
961 width, height, 0, 0);
962 exposures++;
963 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
964 AllPlanes, ZPixmap );
966 for (y = 0; y < height; y++)
967 for (x = 0; x < width; x++)
968 XPutPixel(imageSrc, x, y,
969 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
970 XPutImage( gdi_display, pixmap, gc, imageSrc,
971 0, 0, 0, 0, width, height );
972 XDestroyImage( imageSrc );
975 else
977 if (physDevSrc->depth == 1) /* monochrome -> color */
979 if (X11DRV_PALETTE_XPixelToPalette)
981 XSetBackground( gdi_display, gc,
982 X11DRV_PALETTE_XPixelToPalette[physDevDst->textPixel] );
983 XSetForeground( gdi_display, gc,
984 X11DRV_PALETTE_XPixelToPalette[physDevDst->backgroundPixel]);
986 else
988 XSetBackground( gdi_display, gc, physDevDst->textPixel );
989 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
991 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
992 physDevSrc->org.x + visRectSrc->left,
993 physDevSrc->org.y + visRectSrc->top,
994 width, height, 0, 0, 1 );
995 exposures++;
997 else /* color -> monochrome */
999 /* FIXME: avoid BadMatch error */
1000 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1001 physDevSrc->org.x + visRectSrc->left,
1002 physDevSrc->org.y + visRectSrc->top,
1003 width, height, AllPlanes, ZPixmap );
1004 if (!imageSrc)
1006 return exposures;
1008 imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1009 if (!imageDst)
1011 XDestroyImage(imageSrc);
1012 return exposures;
1014 for (y = 0; y < height; y++)
1015 for (x = 0; x < width; x++)
1016 XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1017 physDevSrc->backgroundPixel) );
1018 XPutImage( gdi_display, pixmap, gc, imageDst,
1019 0, 0, 0, 0, width, height );
1020 XDestroyImage( imageSrc );
1021 XDestroyImage( imageDst );
1024 return exposures;
1028 /***********************************************************************
1029 * BITBLT_GetDstArea
1031 * Retrieve an area from the destination DC, mapping all the
1032 * pixels to Windows colors.
1034 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1036 int exposures = 0;
1037 INT width = visRectDst->right - visRectDst->left;
1038 INT height = visRectDst->bottom - visRectDst->top;
1040 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1041 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1043 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1044 physDev->org.x + visRectDst->left, physDev->org.y + visRectDst->top,
1045 width, height, 0, 0 );
1046 exposures++;
1048 else
1050 register INT x, y;
1051 XImage *image;
1053 if (GetObjectType( physDev->hdc ) == OBJ_MEMDC)
1054 image = XGetImage( gdi_display, physDev->drawable,
1055 physDev->org.x + visRectDst->left,
1056 physDev->org.y + visRectDst->top,
1057 width, height, AllPlanes, ZPixmap );
1058 else
1060 /* Make sure we don't get a BadMatch error */
1061 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1062 physDev->org.x + visRectDst->left,
1063 physDev->org.y + visRectDst->top,
1064 width, height, 0, 0);
1065 exposures++;
1066 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1067 AllPlanes, ZPixmap );
1069 for (y = 0; y < height; y++)
1070 for (x = 0; x < width; x++)
1071 XPutPixel( image, x, y,
1072 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1073 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1074 XDestroyImage( image );
1076 return exposures;
1080 /***********************************************************************
1081 * BITBLT_PutDstArea
1083 * Put an area back into the destination DC, mapping the pixel
1084 * colors to X pixels.
1086 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1088 int exposures = 0;
1089 INT width = visRectDst->right - visRectDst->left;
1090 INT height = visRectDst->bottom - visRectDst->top;
1092 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1094 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1095 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1097 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1098 physDev->org.x + visRectDst->left,
1099 physDev->org.y + visRectDst->top );
1100 exposures++;
1102 else
1104 register INT x, y;
1105 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1106 AllPlanes, ZPixmap );
1107 for (y = 0; y < height; y++)
1108 for (x = 0; x < width; x++)
1110 XPutPixel( image, x, y,
1111 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1113 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1114 physDev->org.x + visRectDst->left,
1115 physDev->org.y + visRectDst->top, width, height );
1116 XDestroyImage( image );
1118 return exposures;
1122 /***********************************************************************
1123 * BITBLT_GetVisRectangles
1125 * Get the source and destination visible rectangles for StretchBlt().
1126 * Return FALSE if one of the rectangles is empty.
1128 static BOOL BITBLT_GetVisRectangles( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1129 INT widthDst, INT heightDst,
1130 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1131 INT widthSrc, INT heightSrc,
1132 RECT *visRectSrc, RECT *visRectDst )
1134 RECT rect, clipRect;
1136 /* Get the destination visible rectangle */
1138 rect.left = xDst;
1139 rect.top = yDst;
1140 rect.right = xDst + widthDst;
1141 rect.bottom = yDst + heightDst;
1142 if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1143 if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1144 GetRgnBox( physDevDst->region, &clipRect );
1145 if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1147 /* Get the source visible rectangle */
1149 if (!physDevSrc) return TRUE;
1150 rect.left = xSrc;
1151 rect.top = ySrc;
1152 rect.right = xSrc + widthSrc;
1153 rect.bottom = ySrc + heightSrc;
1154 if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1155 if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1156 /* Apparently the clipping and visible regions are only for output,
1157 so just check against dc extent here to avoid BadMatch errors */
1158 if (GetObjectType( physDevSrc->hdc ) == OBJ_MEMDC)
1160 BITMAP bm;
1161 GetObjectW( GetCurrentObject(physDevSrc->hdc,OBJ_BITMAP), sizeof(bm), &bm );
1162 SetRect( &clipRect, 0, 0, bm.bmWidth, bm.bmHeight );
1164 else SetRect( &clipRect, 0, 0, screen_width, screen_height );
1165 if (!IntersectRect( visRectSrc, &rect, &clipRect ))
1166 return FALSE;
1168 /* Intersect the rectangles */
1170 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1172 visRectSrc->left += xDst - xSrc;
1173 visRectSrc->right += xDst - xSrc;
1174 visRectSrc->top += yDst - ySrc;
1175 visRectSrc->bottom += yDst - ySrc;
1176 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1177 *visRectSrc = *visRectDst = rect;
1178 visRectSrc->left += xSrc - xDst;
1179 visRectSrc->right += xSrc - xDst;
1180 visRectSrc->top += ySrc - yDst;
1181 visRectSrc->bottom += ySrc - yDst;
1183 else /* stretching */
1185 /* Map source rectangle into destination coordinates */
1186 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1187 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1188 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1189 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1190 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1191 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1193 /* Avoid rounding errors */
1194 rect.left--;
1195 rect.top--;
1196 rect.right++;
1197 rect.bottom++;
1198 if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1200 /* Map destination rectangle back to source coordinates */
1201 rect = *visRectDst;
1202 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1203 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1204 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1205 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1206 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1207 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1209 /* Avoid rounding errors */
1210 rect.left--;
1211 rect.top--;
1212 rect.right++;
1213 rect.bottom++;
1214 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1216 return TRUE;
1220 /***********************************************************************
1221 * BITBLT_InternalStretchBlt
1223 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1225 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1226 INT widthDst, INT heightDst,
1227 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1228 INT widthSrc, INT heightSrc,
1229 DWORD rop )
1231 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1232 RECT visRectDst, visRectSrc;
1233 INT width, height;
1234 const BYTE *opcode;
1235 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1236 GC tmpGC = 0;
1237 POINT pts[2];
1239 /* compensate for off-by-one shifting for negative widths and heights */
1240 if (widthDst < 0)
1241 ++xDst;
1242 if (heightDst < 0)
1243 ++yDst;
1244 if (widthSrc < 0)
1245 ++xSrc;
1246 if (heightSrc < 0)
1247 ++ySrc;
1249 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1250 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1251 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1252 if (!physDevSrc && useSrc) return FALSE;
1254 /* Map the coordinates to device coords */
1256 pts[0].x = xDst;
1257 pts[0].y = yDst;
1258 pts[1].x = xDst + widthDst;
1259 pts[1].y = yDst + heightDst;
1260 LPtoDP(physDevDst->hdc, pts, 2);
1261 xDst = pts[0].x;
1262 yDst = pts[0].y;
1263 widthDst = pts[1].x - pts[0].x;
1264 heightDst = pts[1].y - pts[0].y;
1266 TRACE(" rectdst=%d,%d-%d,%d orgdst=%ld,%ld\n",
1267 xDst, yDst, widthDst, heightDst,
1268 physDevDst->org.x, physDevDst->org.y );
1270 if (useSrc)
1272 pts[0].x = xSrc;
1273 pts[0].y = ySrc;
1274 pts[1].x = xSrc + widthSrc;
1275 pts[1].y = ySrc + heightSrc;
1276 LPtoDP(physDevSrc->hdc, pts, 2);
1277 xSrc = pts[0].x;
1278 ySrc = pts[0].y;
1279 widthSrc = pts[1].x - pts[0].x;
1280 heightSrc = pts[1].y - pts[0].y;
1282 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1283 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%ld,%ld\n",
1284 xSrc, ySrc, widthSrc, heightSrc,
1285 physDevSrc->org.x, physDevSrc->org.y );
1286 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1287 physDevSrc, xSrc, ySrc, widthSrc, heightSrc,
1288 &visRectSrc, &visRectDst ))
1289 return TRUE;
1290 TRACE(" vissrc=%ld,%ld-%ld,%ld visdst=%ld,%ld-%ld,%ld\n",
1291 visRectSrc.left, visRectSrc.top,
1292 visRectSrc.right, visRectSrc.bottom,
1293 visRectDst.left, visRectDst.top,
1294 visRectDst.right, visRectDst.bottom );
1296 else
1298 fStretch = FALSE;
1299 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1300 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1301 return TRUE;
1302 TRACE(" vissrc=none visdst=%ld,%ld-%ld,%ld\n",
1303 visRectDst.left, visRectDst.top,
1304 visRectDst.right, visRectDst.bottom );
1307 width = visRectDst.right - visRectDst.left;
1308 height = visRectDst.bottom - visRectDst.top;
1310 if (!fStretch) switch(rop) /* A few optimisations */
1312 case BLACKNESS: /* 0x00 */
1313 wine_tsx11_lock();
1314 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1315 XSetFunction( gdi_display, physDevDst->gc, GXclear );
1316 else
1318 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1319 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1320 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1322 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1323 physDevDst->org.x + visRectDst.left,
1324 physDevDst->org.y + visRectDst.top,
1325 width, height );
1326 wine_tsx11_unlock();
1327 return TRUE;
1329 case DSTINVERT: /* 0x55 */
1330 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel ||
1331 !perfect_graphics())
1333 wine_tsx11_lock();
1334 XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1336 if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1337 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1338 else
1340 /* Xor is much better when we do not have full colormap. */
1341 /* Using white^black ensures that we invert at least black */
1342 /* and white. */
1343 Pixel xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1344 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1345 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1346 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1347 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1349 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1350 physDevDst->org.x + visRectDst.left,
1351 physDevDst->org.y + visRectDst.top,
1352 width, height );
1353 wine_tsx11_unlock();
1354 return TRUE;
1356 break;
1358 case PATINVERT: /* 0x5a */
1359 if (perfect_graphics()) break;
1360 if (X11DRV_SetupGCForBrush( physDevDst ))
1362 wine_tsx11_lock();
1363 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1364 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1365 physDevDst->org.x + visRectDst.left,
1366 physDevDst->org.y + visRectDst.top,
1367 width, height );
1368 wine_tsx11_unlock();
1370 return TRUE;
1372 case 0xa50065:
1373 if (perfect_graphics()) break;
1374 if (X11DRV_SetupGCForBrush( physDevDst ))
1376 wine_tsx11_lock();
1377 XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1378 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1379 physDevDst->org.x + visRectDst.left,
1380 physDevDst->org.y + visRectDst.top,
1381 width, height );
1382 wine_tsx11_unlock();
1384 return TRUE;
1386 case SRCCOPY: /* 0xcc */
1387 if (physDevSrc->depth == physDevDst->depth)
1389 wine_tsx11_lock();
1390 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1391 XCopyArea( gdi_display, physDevSrc->drawable,
1392 physDevDst->drawable, physDevDst->gc,
1393 physDevSrc->org.x + visRectSrc.left,
1394 physDevSrc->org.y + visRectSrc.top,
1395 width, height,
1396 physDevDst->org.x + visRectDst.left,
1397 physDevDst->org.y + visRectDst.top );
1398 physDevDst->exposures++;
1399 wine_tsx11_unlock();
1400 return TRUE;
1402 if (physDevSrc->depth == 1)
1404 wine_tsx11_lock();
1405 XSetBackground( gdi_display, physDevDst->gc, physDevDst->textPixel );
1406 XSetForeground( gdi_display, physDevDst->gc, physDevDst->backgroundPixel );
1407 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1408 XCopyPlane( gdi_display, physDevSrc->drawable,
1409 physDevDst->drawable, physDevDst->gc,
1410 physDevSrc->org.x + visRectSrc.left,
1411 physDevSrc->org.y + visRectSrc.top,
1412 width, height,
1413 physDevDst->org.x + visRectDst.left,
1414 physDevDst->org.y + visRectDst.top, 1 );
1415 physDevDst->exposures++;
1416 wine_tsx11_unlock();
1417 return TRUE;
1419 break;
1421 case PATCOPY: /* 0xf0 */
1422 if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1423 wine_tsx11_lock();
1424 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1425 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1426 physDevDst->org.x + visRectDst.left,
1427 physDevDst->org.y + visRectDst.top,
1428 width, height );
1429 wine_tsx11_unlock();
1430 return TRUE;
1432 case WHITENESS: /* 0xff */
1433 wine_tsx11_lock();
1434 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1435 XSetFunction( gdi_display, physDevDst->gc, GXset );
1436 else
1438 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1439 XSetForeground( gdi_display, physDevDst->gc,
1440 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1441 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1443 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1444 physDevDst->org.x + visRectDst.left,
1445 physDevDst->org.y + visRectDst.top,
1446 width, height );
1447 wine_tsx11_unlock();
1448 return TRUE;
1451 wine_tsx11_lock();
1453 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1454 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1455 XSetGraphicsExposures( gdi_display, tmpGC, False );
1456 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1457 physDevDst->depth );
1458 if (useSrc)
1460 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1461 physDevDst->depth );
1462 if (fStretch)
1463 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1464 xSrc, ySrc, widthSrc, heightSrc,
1465 xDst, yDst, widthDst, heightDst,
1466 &visRectSrc, &visRectDst );
1467 else
1468 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1469 xSrc, ySrc, &visRectSrc );
1472 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1473 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1474 else fNullBrush = FALSE;
1475 destUsed = FALSE;
1477 for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1479 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1480 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1481 switch(OP_SRCDST(*opcode))
1483 case OP_ARGS(DST,TMP):
1484 case OP_ARGS(SRC,TMP):
1485 if (!pixmaps[TMP])
1486 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1487 width, height, physDevDst->depth );
1488 /* fall through */
1489 case OP_ARGS(DST,SRC):
1490 case OP_ARGS(SRC,DST):
1491 case OP_ARGS(TMP,SRC):
1492 case OP_ARGS(TMP,DST):
1493 if (useSrc)
1494 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1495 pixmaps[OP_DST(*opcode)], tmpGC,
1496 0, 0, width, height, 0, 0 );
1497 break;
1499 case OP_ARGS(PAT,TMP):
1500 if (!pixmaps[TMP] && !fNullBrush)
1501 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1502 width, height, physDevDst->depth );
1503 /* fall through */
1504 case OP_ARGS(PAT,DST):
1505 case OP_ARGS(PAT,SRC):
1506 if (!fNullBrush)
1507 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1508 tmpGC, 0, 0, width, height );
1509 break;
1512 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1513 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1514 &visRectDst );
1515 XFreePixmap( gdi_display, pixmaps[DST] );
1516 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1517 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1518 XFreeGC( gdi_display, tmpGC );
1519 wine_tsx11_unlock();
1520 return TRUE;
1524 /***********************************************************************
1525 * X11DRV_PatBlt
1527 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1529 BOOL result;
1531 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1532 result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1533 X11DRV_UnlockDIBSection( physDev, TRUE );
1534 return result;
1538 /***********************************************************************
1539 * X11DRV_BitBlt
1541 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1542 INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1543 INT xSrc, INT ySrc, DWORD rop )
1545 BOOL result = FALSE;
1546 INT sSrc, sDst;
1547 RECT visRectDst, visRectSrc;
1549 if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1550 /* FIXME: seems the ROP doesn't include destination;
1551 * now if the destination area include the entire dcDst,
1552 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1553 * which may avoid a copy in some situations */
1556 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1557 if (physDevDst != physDevSrc)
1558 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1559 else
1560 sSrc = sDst;
1562 if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1563 (physDevSrc->depth == physDevDst->depth))
1565 POINT pts[2];
1566 /* do everything ourselves; map coordinates */
1568 pts[0].x = xSrc;
1569 pts[0].y = ySrc;
1570 pts[1].x = xSrc + width;
1571 pts[1].y = ySrc + height;
1573 LPtoDP(physDevSrc->hdc, pts, 2);
1574 width = pts[1].x - pts[0].x;
1575 height = pts[1].y - pts[0].y;
1576 xSrc = pts[0].x;
1577 ySrc = pts[0].y;
1579 pts[0].x = xDst;
1580 pts[0].y = yDst;
1581 LPtoDP(physDevDst->hdc, pts, 1);
1583 xDst = pts[0].x;
1584 yDst = pts[0].y;
1586 /* Perform basic clipping */
1587 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, width, height,
1588 physDevSrc, xSrc, ySrc, width, height,
1589 &visRectSrc, &visRectDst ))
1590 goto END;
1592 xSrc = visRectSrc.left;
1593 ySrc = visRectSrc.top;
1594 xDst = visRectDst.left;
1595 yDst = visRectDst.top;
1596 width = visRectDst.right - visRectDst.left;
1597 height = visRectDst.bottom - visRectDst.top;
1599 if (sDst == DIB_Status_AppMod) {
1600 FIXME("potential optimization - client-side DIB copy\n");
1602 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1604 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1605 result = TRUE;
1606 goto END;
1609 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1610 if (physDevDst != physDevSrc)
1611 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1613 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1614 physDevSrc, xSrc, ySrc, width, height, rop );
1616 END:
1617 if (physDevDst != physDevSrc)
1618 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1619 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1621 return result;
1625 /***********************************************************************
1626 * X11DRV_StretchBlt
1628 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1629 INT widthDst, INT heightDst,
1630 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1631 INT widthSrc, INT heightSrc, DWORD rop )
1633 BOOL result;
1635 X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1636 if (physDevDst != physDevSrc)
1637 X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1639 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1640 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1642 if (physDevDst != physDevSrc)
1643 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1644 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1645 return result;