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
27 #include <X11/Intrinsic.h>
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
42 #define DST 0 /* Destination drawable */
43 #define SRC 1 /* Source drawable */
44 #define TMP 2 /* Temporary drawable */
45 #define PAT 3 /* Pattern (brush) in destination DC */
47 #define OP(src,dst,rop) (OP_ARGS(src,dst) << 4 | (rop))
48 #define OP_ARGS(src,dst) (((src) << 2) | (dst))
50 #define OP_SRC(opcode) ((opcode) >> 6)
51 #define OP_DST(opcode) (((opcode) >> 4) & 3)
52 #define OP_SRCDST(opcode) ((opcode) >> 4)
53 #define OP_ROP(opcode) ((opcode) & 0x0f)
55 #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */
57 #define SWAP_INT32(i1,i2) \
58 do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
60 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
62 { OP(PAT,DST,GXclear) }, /* 0x00 0 */
63 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */
64 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */
65 { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */
66 { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */
67 { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */
68 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */
69 { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */
70 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */
71 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */
72 { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */
73 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */
74 { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */
75 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */
76 { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */
77 { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */
78 { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */
79 { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */
80 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */
81 { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */
82 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */
83 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */
84 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
85 OP(TMP,DST,GXand), OP(SRC,DST,GXxor),
86 OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */
87 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
88 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
89 OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/
90 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
91 OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */
92 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
93 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */
94 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
95 OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */
96 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXxor),
97 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */
98 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
99 OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */
100 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
101 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */
102 { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */
103 { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */
104 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */
105 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */
106 { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */
107 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */
108 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
109 OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */
110 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
111 OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */
112 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
113 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
114 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXequiv),
115 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */
116 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */
117 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
118 OP(TMP,DST,GXor), OP(SRC,DST,GXxor),
119 OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */
120 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */
121 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
122 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
123 OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/
124 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
125 OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */
126 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */
127 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
128 OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */
129 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */
130 { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */
131 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */
132 { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
133 OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */
134 { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */
135 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
136 OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */
137 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
138 OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */
139 { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */
140 { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */
141 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
142 OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */
143 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */
144 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
145 OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */
146 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */
147 { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */
148 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
149 OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */
150 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
151 OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */
152 { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */
153 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */
154 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */
155 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
156 OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */
157 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
158 OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */
159 { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */
160 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */
161 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
162 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */
163 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
164 OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */
165 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */
166 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
167 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
168 OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */
169 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
170 OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */
171 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */
172 { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */
173 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
174 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
175 OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/
176 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
177 OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */
178 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */
179 { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */
180 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */
181 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
182 OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */
183 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
184 OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */
185 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */
186 { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */
187 { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */
188 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */
189 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
190 OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */
191 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */
192 { OP(PAT,DST,GXxor) }, /* 0x5a D^P */
193 { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
194 OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */
195 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
196 OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */
197 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */
198 { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
199 OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */
200 { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */
201 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */
202 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
203 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
204 OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */
205 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
206 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */
207 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */
208 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
209 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */
210 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */
211 { OP(SRC,DST,GXxor) }, /* 0x66 S^D */
212 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
213 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */
214 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
215 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
216 OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/
217 { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */
218 { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */
219 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
220 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
221 OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */
222 { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */
223 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
224 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
225 OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */
226 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
227 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */
228 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */
229 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */
230 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
231 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
232 OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/
233 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
234 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */
235 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */
236 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
237 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */
238 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */
239 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
240 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */
241 { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */
242 { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */
243 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
244 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
245 OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */
246 { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
247 OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */
248 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */
249 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
250 OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */
251 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */
252 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
253 OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */
254 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */
255 { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */
256 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
257 OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */
258 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */
259 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
260 OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */
261 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */
262 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
263 OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */
264 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
265 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
266 OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */
267 { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */
268 { OP(SRC,DST,GXand) }, /* 0x88 S&D */
269 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
270 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */
271 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */
272 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
273 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */
274 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */
275 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
276 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */
277 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
278 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
279 OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/
280 { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */
281 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */
282 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
283 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */
284 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
285 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
286 OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */
287 { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */
288 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
289 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
290 OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */
291 { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */
292 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */
293 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
294 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
295 OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */
296 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
297 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */
298 { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */
299 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */
300 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
301 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */
302 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */
303 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
304 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */
305 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
306 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
307 OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */
308 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */
309 { OP(PAT,DST,GXand) }, /* 0xa0 D&P */
310 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
311 OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */
312 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */
313 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
314 OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */
315 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
316 OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */
317 { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */
318 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */
319 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
320 OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */
321 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */
322 { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */
323 { OP(SRC,DST,GXnoop) }, /* 0xaa D */
324 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */
325 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
326 OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */
327 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
328 OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */
329 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */
330 { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */
331 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */
332 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
333 OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */
334 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
335 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
336 OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/
337 { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */
338 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */
339 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
340 OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */
341 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
342 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
343 OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */
344 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */
345 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
346 OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */
347 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
348 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */
349 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */
350 { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */
351 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
352 OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */
353 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
354 OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */
355 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */
356 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */
357 { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */
358 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
359 OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */
360 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
361 OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */
362 { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */
363 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */
364 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
365 OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */
366 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */
367 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
368 OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */
369 { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */
370 { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */
371 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
372 OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */
373 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
374 OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */
375 { OP(SRC,DST,GXcopy) }, /* 0xcc S */
376 { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */
377 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */
378 { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */
379 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */
380 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
381 OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */
382 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */
383 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
384 OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */
385 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
386 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
387 OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/
388 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */
389 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
390 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
391 OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */
392 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */
393 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
394 OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */
395 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
396 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */
397 { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
398 OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */
399 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
400 OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */
401 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */
402 { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */
403 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */
404 { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */
405 { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */
406 { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */
407 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
408 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */
409 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
410 OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */
411 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
412 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */
413 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
414 OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */
415 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
416 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */
417 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
418 OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */
419 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
420 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
421 OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/
422 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
423 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
424 OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/
425 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */
426 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */
427 { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */
428 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */
429 { OP(SRC,DST,GXor) }, /* 0xee S|D */
430 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */
431 { OP(PAT,DST,GXcopy) }, /* 0xf0 P */
432 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */
433 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */
434 { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */
435 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */
436 { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */
437 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */
438 { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */
439 { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */
440 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */
441 { OP(PAT,DST,GXor) }, /* 0xfa D|P */
442 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */
443 { OP(PAT,SRC,GXor) }, /* 0xfc P|S */
444 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */
445 { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */
446 { OP(PAT,DST,GXset) } /* 0xff 1 */
450 #ifdef BITBLT_TEST /* Opcodes test */
452 static int do_bitop( int s, int d, int rop )
457 case GXclear: res = 0; break;
458 case GXand: res = s & d; break;
459 case GXandReverse: res = s & ~d; break;
460 case GXcopy: res = s; break;
461 case GXandInverted: res = ~s & d; break;
462 case GXnoop: res = d; break;
463 case GXxor: res = s ^ d; break;
464 case GXor: res = s | d; break;
465 case GXnor: res = ~(s | d); break;
466 case GXequiv: res = ~s ^ d; break;
467 case GXinvert: res = ~d; break;
468 case GXorReverse: res = s | ~d; break;
469 case GXcopyInverted: res = ~s; break;
470 case GXorInverted: res = ~s | d; break;
471 case GXnand: res = ~(s & d); break;
472 case GXset: res = 1; break;
479 int rop, i, res, src, dst, pat, tmp, dstUsed;
482 for (rop = 0; rop < 256; rop++)
485 for (i = 0; i < 8; i++)
490 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
494 case OP_ARGS(DST,TMP):
495 tmp = do_bitop( dst, tmp, *opcode & 0xf );
497 case OP_ARGS(DST,SRC):
498 src = do_bitop( dst, src, *opcode & 0xf );
500 case OP_ARGS(SRC,TMP):
501 tmp = do_bitop( src, tmp, *opcode & 0xf );
503 case OP_ARGS(SRC,DST):
504 dst = do_bitop( src, dst, *opcode & 0xf );
507 case OP_ARGS(PAT,TMP):
508 tmp = do_bitop( pat, tmp, *opcode & 0xf );
510 case OP_ARGS(PAT,DST):
511 dst = do_bitop( pat, dst, *opcode & 0xf );
514 case OP_ARGS(PAT,SRC):
515 src = do_bitop( pat, src, *opcode & 0xf );
517 case OP_ARGS(TMP,DST):
518 dst = do_bitop( tmp, dst, *opcode & 0xf );
521 case OP_ARGS(TMP,SRC):
522 src = do_bitop( tmp, src, *opcode & 0xf );
525 printf( "Invalid opcode %x\n", *opcode );
528 if (!dstUsed) dst = src;
529 if (dst) res |= 1 << i;
531 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
537 #endif /* BITBLT_TEST */
540 /***********************************************************************
543 * Favor correctness or speed?
545 static int perfect_graphics(void)
547 static int perfect = -1;
554 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
556 DWORD type, count = sizeof(buffer);
557 if(!RegQueryValueExA(hkey, "PerfectGraphics", 0, &type, buffer, &count))
560 perfect = (ch == 'y' || ch == 'Y' || ch == 't' || ch == 'T' || ch == '1');
568 /***********************************************************************
571 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
573 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
574 INT startDst, INT widthDst,
575 INT xinc, INT xoff, WORD mode )
577 register INT xsrc = xinc * startDst + xoff;
581 case STRETCH_ANDSCANS:
582 for(; widthDst > 0; widthDst--, xsrc += xinc)
583 *rowDst++ &= rowSrc[xsrc >> 16];
585 case STRETCH_ORSCANS:
586 for(; widthDst > 0; widthDst--, xsrc += xinc)
587 *rowDst++ |= rowSrc[xsrc >> 16];
589 case STRETCH_DELETESCANS:
590 for(; widthDst > 0; widthDst--, xsrc += xinc)
591 *rowDst++ = rowSrc[xsrc >> 16];
597 /***********************************************************************
600 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
602 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
603 INT startSrc, INT widthSrc,
604 INT xinc, INT xoff, WORD mode )
606 register INT xdst = xinc * startSrc + xoff;
610 case STRETCH_ORSCANS:
611 for(; widthSrc > 0; widthSrc--, xdst += xinc)
612 rowDst[xdst >> 16] |= *rowSrc++;
614 case STRETCH_ANDSCANS:
615 for(; widthSrc > 0; widthSrc--, xdst += xinc)
616 rowDst[xdst >> 16] &= *rowSrc++;
618 case STRETCH_DELETESCANS:
619 for(; widthSrc > 0; widthSrc--, xdst += xinc)
620 rowDst[xdst >> 16] = *rowSrc++;
626 /***********************************************************************
629 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
631 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
632 INT start, INT width, INT depthDst,
633 int fg, int bg, BOOL swap)
637 assert( (row >= 0) && (row < image->height) );
638 assert( (start >= 0) && (width <= image->width) );
640 pdata += swap ? start+width-1 : start;
641 if (image->depth == depthDst) /* color -> color */
643 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
644 if (swap) for (i = 0; i < width; i++)
645 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
646 else for (i = 0; i < width; i++)
647 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
649 if (swap) for (i = 0; i < width; i++)
650 *pdata-- = XGetPixel( image, i, row );
651 else for (i = 0; i < width; i++)
652 *pdata++ = XGetPixel( image, i, row );
656 if (image->depth == 1) /* monochrome -> color */
658 if (X11DRV_PALETTE_XPixelToPalette)
660 fg = X11DRV_PALETTE_XPixelToPalette[fg];
661 bg = X11DRV_PALETTE_XPixelToPalette[bg];
663 if (swap) for (i = 0; i < width; i++)
664 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
665 else for (i = 0; i < width; i++)
666 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
668 else /* color -> monochrome */
670 if (swap) for (i = 0; i < width; i++)
671 *pdata-- = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
672 else for (i = 0; i < width; i++)
673 *pdata++ = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
679 /***********************************************************************
680 * BITBLT_StretchImage
682 * Stretch an X image.
683 * FIXME: does not work for full 32-bit coordinates.
685 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
686 INT widthSrc, INT heightSrc,
687 INT widthDst, INT heightDst,
688 RECT *visRectSrc, RECT *visRectDst,
689 int foreground, int background, WORD mode )
691 int *rowSrc, *rowDst, *pixel;
693 INT xinc, xoff, yinc, ysrc, ydst;
695 BOOL hstretch, vstretch, hswap, vswap;
697 hswap = ((int)widthSrc * widthDst) < 0;
698 vswap = ((int)heightSrc * heightDst) < 0;
699 widthSrc = abs(widthSrc);
700 heightSrc = abs(heightSrc);
701 widthDst = abs(widthDst);
702 heightDst = abs(heightDst);
704 if (!(rowSrc = (int *)HeapAlloc( GetProcessHeap(), 0,
705 (widthSrc+widthDst)*sizeof(int) ))) return;
706 rowDst = rowSrc + widthSrc;
708 /* When stretching, all modes are the same, and DELETESCANS is faster */
709 if ((widthSrc < widthDst) && (heightSrc < heightDst))
710 mode = STRETCH_DELETESCANS;
712 if (mode == STRETCH_HALFTONE) /* FIXME */
713 mode = STRETCH_DELETESCANS;
715 if (mode != STRETCH_DELETESCANS)
716 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
717 widthDst*sizeof(int) );
719 hstretch = (widthSrc < widthDst);
720 vstretch = (heightSrc < heightDst);
724 xinc = ((int)widthSrc << 16) / widthDst;
725 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
729 xinc = ((int)widthDst << 16) / widthSrc;
730 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
735 yinc = ((int)heightSrc << 16) / heightDst;
736 ydst = visRectDst->top;
739 ysrc = yinc * (heightDst - ydst - 1);
745 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
747 if (((ysrc >> 16) < visRectSrc->top) ||
748 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
750 /* Retrieve a source row */
751 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
752 hswap ? widthSrc - visRectSrc->right
754 visRectSrc->right - visRectSrc->left,
755 dstImage->depth, foreground, background, hswap );
757 /* Stretch or shrink it */
759 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
760 visRectDst->right - visRectDst->left,
762 else BITBLT_ShrinkRow( rowSrc, rowDst,
763 hswap ? widthSrc - visRectSrc->right
765 visRectSrc->right - visRectSrc->left,
768 /* Store the destination row */
769 pixel = rowDst + visRectDst->right - 1;
770 y = ydst - visRectDst->top;
771 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
772 XPutPixel( dstImage, x, y, *pixel-- );
773 if (mode != STRETCH_DELETESCANS)
774 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
775 widthDst*sizeof(int) );
777 /* Make copies of the destination row */
779 pdata = dstImage->data + dstImage->bytes_per_line * y;
780 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
781 (ydst < visRectDst->bottom-1))
783 memcpy( pdata + dstImage->bytes_per_line, pdata,
784 dstImage->bytes_per_line );
785 pdata += dstImage->bytes_per_line;
793 yinc = ((int)heightDst << 16) / heightSrc;
794 ysrc = visRectSrc->top;
795 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
798 ydst += yinc * (heightSrc - ysrc - 1);
804 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
806 if (((ydst >> 16) < visRectDst->top) ||
807 ((ydst >> 16) >= visRectDst->bottom)) continue;
809 /* Retrieve a source row */
810 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
811 hswap ? widthSrc - visRectSrc->right
813 visRectSrc->right - visRectSrc->left,
814 dstImage->depth, foreground, background, hswap );
816 /* Stretch or shrink it */
818 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
819 visRectDst->right - visRectDst->left,
821 else BITBLT_ShrinkRow( rowSrc, rowDst,
822 hswap ? widthSrc - visRectSrc->right
824 visRectSrc->right - visRectSrc->left,
827 /* Merge several source rows into the destination */
828 if (mode == STRETCH_DELETESCANS)
830 /* Simply skip the overlapping rows */
831 while (((ydst + yinc) >> 16 == ydst >> 16) &&
832 (ysrc < visRectSrc->bottom-1))
838 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
839 (ysrc < visRectSrc->bottom-1))
840 continue; /* Restart loop for next overlapping row */
842 /* Store the destination row */
843 pixel = rowDst + visRectDst->right - 1;
844 y = (ydst >> 16) - visRectDst->top;
845 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
846 XPutPixel( dstImage, x, y, *pixel-- );
847 if (mode != STRETCH_DELETESCANS)
848 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
849 widthDst*sizeof(int) );
852 HeapFree( GetProcessHeap(), 0, rowSrc );
856 /***********************************************************************
857 * BITBLT_GetSrcAreaStretch
859 * Retrieve an area from the source DC, stretching and mapping all the
860 * pixels to Windows colors.
862 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
863 Pixmap pixmap, GC gc,
865 INT widthSrc, INT heightSrc,
867 INT widthDst, INT heightDst,
868 RECT *visRectSrc, RECT *visRectDst )
870 XImage *imageSrc, *imageDst;
871 DC *dcDst = physDevDst->dc;
873 RECT rectSrc = *visRectSrc;
874 RECT rectDst = *visRectDst;
876 if (widthSrc < 0) xSrc += widthSrc;
877 if (widthDst < 0) xDst += widthDst;
878 if (heightSrc < 0) ySrc += heightSrc;
879 if (heightDst < 0) yDst += heightDst;
880 rectSrc.left -= xSrc;
881 rectSrc.right -= xSrc;
883 rectSrc.bottom -= ySrc;
884 rectDst.left -= xDst;
885 rectDst.right -= xDst;
887 rectDst.bottom -= yDst;
889 /* FIXME: avoid BadMatch errors */
890 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
891 physDevSrc->org.x + visRectSrc->left,
892 physDevSrc->org.y + visRectSrc->top,
893 visRectSrc->right - visRectSrc->left,
894 visRectSrc->bottom - visRectSrc->top,
895 AllPlanes, ZPixmap );
896 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
897 rectDst.bottom - rectDst.top, dcDst->bitsPerPixel );
898 BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
899 widthDst, heightDst, &rectSrc, &rectDst,
900 physDevDst->textPixel, dcDst->bitsPerPixel != 1 ?
901 physDevDst->backgroundPixel :
902 physDevSrc->backgroundPixel,
903 dcDst->stretchBltMode );
904 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
905 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
906 XDestroyImage( imageSrc );
907 XDestroyImage( imageDst );
908 return 0; /* no exposure events generated */
912 /***********************************************************************
915 * Retrieve an area from the source DC, mapping all the
916 * pixels to Windows colors.
918 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
919 Pixmap pixmap, GC gc, INT xSrc, INT ySrc, RECT *visRectSrc )
921 XImage *imageSrc, *imageDst;
924 INT width = visRectSrc->right - visRectSrc->left;
925 INT height = visRectSrc->bottom - visRectSrc->top;
926 DC *dcSrc = physDevSrc->dc;
927 DC *dcDst = physDevDst->dc;
929 if (dcSrc->bitsPerPixel == dcDst->bitsPerPixel)
931 if (!X11DRV_PALETTE_XPixelToPalette ||
932 (dcDst->bitsPerPixel == 1)) /* monochrome -> monochrome */
934 if (dcDst->bitsPerPixel == 1)
936 /* MSDN says if StretchBlt must convert a bitmap from monochrome
937 to color or vice versa, the forground and background color of
938 the device context are used. In fact, it also applies to the
939 case when it is converted from mono to mono. */
940 XSetBackground( gdi_display, gc, physDevDst->textPixel );
941 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
942 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
943 physDevSrc->org.x + visRectSrc->left,
944 physDevSrc->org.y + visRectSrc->top,
945 width, height, 0, 0, 1);
948 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
949 physDevSrc->org.x + visRectSrc->left,
950 physDevSrc->org.y + visRectSrc->top,
951 width, height, 0, 0);
954 else /* color -> color */
956 if (GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
957 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
958 physDevSrc->org.x + visRectSrc->left,
959 physDevSrc->org.y + visRectSrc->top,
960 width, height, AllPlanes, ZPixmap );
963 /* Make sure we don't get a BadMatch error */
964 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
965 physDevSrc->org.x + visRectSrc->left,
966 physDevSrc->org.y + visRectSrc->top,
967 width, height, 0, 0);
969 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
970 AllPlanes, ZPixmap );
972 for (y = 0; y < height; y++)
973 for (x = 0; x < width; x++)
974 XPutPixel(imageSrc, x, y,
975 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
976 XPutImage( gdi_display, pixmap, gc, imageSrc,
977 0, 0, 0, 0, width, height );
978 XDestroyImage( imageSrc );
983 if (dcSrc->bitsPerPixel == 1) /* monochrome -> color */
985 if (X11DRV_PALETTE_XPixelToPalette)
987 XSetBackground( gdi_display, gc,
988 X11DRV_PALETTE_XPixelToPalette[physDevDst->textPixel] );
989 XSetForeground( gdi_display, gc,
990 X11DRV_PALETTE_XPixelToPalette[physDevDst->backgroundPixel]);
994 XSetBackground( gdi_display, gc, physDevDst->textPixel );
995 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
997 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
998 physDevSrc->org.x + visRectSrc->left,
999 physDevSrc->org.y + visRectSrc->top,
1000 width, height, 0, 0, 1 );
1003 else /* color -> monochrome */
1005 /* FIXME: avoid BadMatch error */
1006 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1007 physDevSrc->org.x + visRectSrc->left,
1008 physDevSrc->org.y + visRectSrc->top,
1009 width, height, AllPlanes, ZPixmap );
1014 imageDst = X11DRV_DIB_CreateXImage( width, height, dcDst->bitsPerPixel );
1017 XDestroyImage(imageSrc);
1020 for (y = 0; y < height; y++)
1021 for (x = 0; x < width; x++)
1022 XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1023 physDevSrc->backgroundPixel) );
1024 XPutImage( gdi_display, pixmap, gc, imageDst,
1025 0, 0, 0, 0, width, height );
1026 XDestroyImage( imageSrc );
1027 XDestroyImage( imageDst );
1034 /***********************************************************************
1037 * Retrieve an area from the destination DC, mapping all the
1038 * pixels to Windows colors.
1040 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1043 INT width = visRectDst->right - visRectDst->left;
1044 INT height = visRectDst->bottom - visRectDst->top;
1046 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->dc->bitsPerPixel == 1) ||
1047 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1049 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1050 physDev->org.x + visRectDst->left, physDev->org.y + visRectDst->top,
1051 width, height, 0, 0 );
1059 if (GetObjectType( physDev->hdc ) == OBJ_MEMDC)
1060 image = XGetImage( gdi_display, physDev->drawable,
1061 physDev->org.x + visRectDst->left,
1062 physDev->org.y + visRectDst->top,
1063 width, height, AllPlanes, ZPixmap );
1066 /* Make sure we don't get a BadMatch error */
1067 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1068 physDev->org.x + visRectDst->left,
1069 physDev->org.y + visRectDst->top,
1070 width, height, 0, 0);
1072 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1073 AllPlanes, ZPixmap );
1075 for (y = 0; y < height; y++)
1076 for (x = 0; x < width; x++)
1077 XPutPixel( image, x, y,
1078 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1079 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1080 XDestroyImage( image );
1086 /***********************************************************************
1089 * Put an area back into the destination DC, mapping the pixel
1090 * colors to X pixels.
1092 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1095 INT width = visRectDst->right - visRectDst->left;
1096 INT height = visRectDst->bottom - visRectDst->top;
1098 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1100 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->dc->bitsPerPixel == 1) ||
1101 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1103 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1104 physDev->org.x + visRectDst->left,
1105 physDev->org.y + visRectDst->top );
1111 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1112 AllPlanes, ZPixmap );
1113 for (y = 0; y < height; y++)
1114 for (x = 0; x < width; x++)
1116 XPutPixel( image, x, y,
1117 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1119 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1120 physDev->org.x + visRectDst->left,
1121 physDev->org.y + visRectDst->top, width, height );
1122 XDestroyImage( image );
1128 /***********************************************************************
1129 * BITBLT_GetVisRectangles
1131 * Get the source and destination visible rectangles for StretchBlt().
1132 * Return FALSE if one of the rectangles is empty.
1134 static BOOL BITBLT_GetVisRectangles( DC *dcDst, INT xDst, INT yDst,
1135 INT widthDst, INT heightDst,
1136 DC *dcSrc, INT xSrc, INT ySrc,
1137 INT widthSrc, INT heightSrc,
1138 RECT *visRectSrc, RECT *visRectDst )
1140 RECT rect, clipRect;
1142 /* Get the destination visible rectangle */
1146 rect.right = xDst + widthDst;
1147 rect.bottom = yDst + heightDst;
1148 if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1149 if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1150 GetRgnBox( dcDst->hGCClipRgn, &clipRect );
1151 if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1153 /* Get the source visible rectangle */
1155 if (!dcSrc) return TRUE;
1158 rect.right = xSrc + widthSrc;
1159 rect.bottom = ySrc + heightSrc;
1160 if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1161 if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1162 /* Apparently the clipping and visible regions are only for output,
1163 so just check against totalExtent here to avoid BadMatch errors */
1164 if (!IntersectRect( visRectSrc, &rect, &dcSrc->totalExtent ))
1167 /* Intersect the rectangles */
1169 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1171 visRectSrc->left += xDst - xSrc;
1172 visRectSrc->right += xDst - xSrc;
1173 visRectSrc->top += yDst - ySrc;
1174 visRectSrc->bottom += yDst - ySrc;
1175 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1176 *visRectSrc = *visRectDst = rect;
1177 visRectSrc->left += xSrc - xDst;
1178 visRectSrc->right += xSrc - xDst;
1179 visRectSrc->top += ySrc - yDst;
1180 visRectSrc->bottom += ySrc - yDst;
1182 else /* stretching */
1184 /* Map source rectangle into destination coordinates */
1185 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1186 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1187 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1188 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1189 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1190 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1192 /* Avoid rounding errors */
1197 if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1199 /* Map destination rectangle back to source coordinates */
1201 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1202 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1203 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1204 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1205 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1206 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1208 /* Avoid rounding errors */
1213 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1219 /***********************************************************************
1220 * BITBLT_InternalStretchBlt
1222 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1224 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1225 INT widthDst, INT heightDst,
1226 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1227 INT widthSrc, INT heightSrc,
1230 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1231 RECT visRectDst, visRectSrc;
1234 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1237 DC *dcSrc = physDevSrc ? physDevSrc->dc : NULL;
1238 DC *dcDst = physDevDst->dc;
1240 /* compensate for off-by-one shifting for negative widths and heights */
1250 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1251 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1252 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1253 if (!dcSrc && useSrc) return FALSE;
1255 /* Map the coordinates to device coords */
1259 pts[1].x = xDst + widthDst;
1260 pts[1].y = yDst + heightDst;
1261 LPtoDP(physDevDst->hdc, pts, 2);
1264 widthDst = pts[1].x - pts[0].x;
1265 heightDst = pts[1].y - pts[0].y;
1267 TRACE(" vportdst=%d,%d-%d,%d wnddst=%d,%d-%d,%d\n",
1268 dcDst->vportOrgX, dcDst->vportOrgY,
1269 dcDst->vportExtX, dcDst->vportExtY,
1270 dcDst->wndOrgX, dcDst->wndOrgY,
1271 dcDst->wndExtX, dcDst->wndExtY );
1272 TRACE(" rectdst=%d,%d-%d,%d orgdst=%ld,%ld\n",
1273 xDst, yDst, widthDst, heightDst,
1274 physDevDst->org.x, physDevDst->org.y );
1280 pts[1].x = xSrc + widthSrc;
1281 pts[1].y = ySrc + heightSrc;
1282 LPtoDP(physDevSrc->hdc, pts, 2);
1285 widthSrc = pts[1].x - pts[0].x;
1286 heightSrc = pts[1].y - pts[0].y;
1288 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1289 TRACE(" vportsrc=%d,%d-%d,%d wndsrc=%d,%d-%d,%d\n",
1290 dcSrc->vportOrgX, dcSrc->vportOrgY,
1291 dcSrc->vportExtX, dcSrc->vportExtY,
1292 dcSrc->wndOrgX, dcSrc->wndOrgY,
1293 dcSrc->wndExtX, dcSrc->wndExtY );
1294 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%ld,%ld\n",
1295 xSrc, ySrc, widthSrc, heightSrc,
1296 physDevSrc->org.x, physDevSrc->org.y );
1297 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1298 dcSrc, xSrc, ySrc, widthSrc, heightSrc,
1299 &visRectSrc, &visRectDst ))
1301 TRACE(" vissrc=%ld,%ld-%ld,%ld visdst=%ld,%ld-%ld,%ld\n",
1302 visRectSrc.left, visRectSrc.top,
1303 visRectSrc.right, visRectSrc.bottom,
1304 visRectDst.left, visRectDst.top,
1305 visRectDst.right, visRectDst.bottom );
1310 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1311 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1313 TRACE(" vissrc=none visdst=%ld,%ld-%ld,%ld\n",
1314 visRectDst.left, visRectDst.top,
1315 visRectDst.right, visRectDst.bottom );
1318 width = visRectDst.right - visRectDst.left;
1319 height = visRectDst.bottom - visRectDst.top;
1321 if (!fStretch) switch(rop) /* A few optimisations */
1323 case BLACKNESS: /* 0x00 */
1325 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1326 XSetFunction( gdi_display, physDevDst->gc, GXclear );
1329 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1330 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1331 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1333 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1334 physDevDst->org.x + visRectDst.left,
1335 physDevDst->org.y + visRectDst.top,
1337 wine_tsx11_unlock();
1340 case DSTINVERT: /* 0x55 */
1341 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel ||
1342 !perfect_graphics())
1345 XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1347 if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1348 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1351 /* Xor is much better when we do not have full colormap. */
1352 /* Using white^black ensures that we invert at least black */
1354 Pixel xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1355 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1356 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1357 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1358 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1360 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1361 physDevDst->org.x + visRectDst.left,
1362 physDevDst->org.y + visRectDst.top,
1364 wine_tsx11_unlock();
1369 case PATINVERT: /* 0x5a */
1370 if (perfect_graphics()) break;
1371 if (X11DRV_SetupGCForBrush( physDevDst ))
1374 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1375 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1376 physDevDst->org.x + visRectDst.left,
1377 physDevDst->org.y + visRectDst.top,
1379 wine_tsx11_unlock();
1384 if (perfect_graphics()) break;
1385 if (X11DRV_SetupGCForBrush( physDevDst ))
1388 XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1389 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1390 physDevDst->org.x + visRectDst.left,
1391 physDevDst->org.y + visRectDst.top,
1393 wine_tsx11_unlock();
1397 case SRCCOPY: /* 0xcc */
1398 if (dcSrc->bitsPerPixel == dcDst->bitsPerPixel)
1401 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1402 XCopyArea( gdi_display, physDevSrc->drawable,
1403 physDevDst->drawable, physDevDst->gc,
1404 physDevSrc->org.x + visRectSrc.left,
1405 physDevSrc->org.y + visRectSrc.top,
1407 physDevDst->org.x + visRectDst.left,
1408 physDevDst->org.y + visRectDst.top );
1409 physDevDst->exposures++;
1410 wine_tsx11_unlock();
1413 if (dcSrc->bitsPerPixel == 1)
1416 XSetBackground( gdi_display, physDevDst->gc, physDevDst->textPixel );
1417 XSetForeground( gdi_display, physDevDst->gc, physDevDst->backgroundPixel );
1418 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1419 XCopyPlane( gdi_display, physDevSrc->drawable,
1420 physDevDst->drawable, physDevDst->gc,
1421 physDevSrc->org.x + visRectSrc.left,
1422 physDevSrc->org.y + visRectSrc.top,
1424 physDevDst->org.x + visRectDst.left,
1425 physDevDst->org.y + visRectDst.top, 1 );
1426 physDevDst->exposures++;
1427 wine_tsx11_unlock();
1432 case PATCOPY: /* 0xf0 */
1433 if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1435 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1436 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1437 physDevDst->org.x + visRectDst.left,
1438 physDevDst->org.y + visRectDst.top,
1440 wine_tsx11_unlock();
1443 case WHITENESS: /* 0xff */
1445 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1446 XSetFunction( gdi_display, physDevDst->gc, GXset );
1449 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1450 XSetForeground( gdi_display, physDevDst->gc,
1451 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1452 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1454 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1455 physDevDst->org.x + visRectDst.left,
1456 physDevDst->org.y + visRectDst.top,
1458 wine_tsx11_unlock();
1464 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1465 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1466 XSetGraphicsExposures( gdi_display, tmpGC, False );
1467 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1468 dcDst->bitsPerPixel );
1471 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1472 dcDst->bitsPerPixel );
1474 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1475 xSrc, ySrc, widthSrc, heightSrc,
1476 xDst, yDst, widthDst, heightDst,
1477 &visRectSrc, &visRectDst );
1479 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1480 xSrc, ySrc, &visRectSrc );
1483 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1484 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1485 else fNullBrush = FALSE;
1488 for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1490 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1491 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1492 switch(OP_SRCDST(*opcode))
1494 case OP_ARGS(DST,TMP):
1495 case OP_ARGS(SRC,TMP):
1497 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1499 dcDst->bitsPerPixel );
1501 case OP_ARGS(DST,SRC):
1502 case OP_ARGS(SRC,DST):
1503 case OP_ARGS(TMP,SRC):
1504 case OP_ARGS(TMP,DST):
1506 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1507 pixmaps[OP_DST(*opcode)], tmpGC,
1508 0, 0, width, height, 0, 0 );
1511 case OP_ARGS(PAT,TMP):
1512 if (!pixmaps[TMP] && !fNullBrush)
1513 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1515 dcDst->bitsPerPixel );
1517 case OP_ARGS(PAT,DST):
1518 case OP_ARGS(PAT,SRC):
1520 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1521 tmpGC, 0, 0, width, height );
1525 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1526 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1528 XFreePixmap( gdi_display, pixmaps[DST] );
1529 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1530 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1531 XFreeGC( gdi_display, tmpGC );
1532 wine_tsx11_unlock();
1537 /***********************************************************************
1540 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1544 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1545 result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1546 X11DRV_UnlockDIBSection( physDev, TRUE );
1551 /***********************************************************************
1554 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1555 INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1556 INT xSrc, INT ySrc, DWORD rop )
1558 BOOL result = FALSE;
1560 RECT visRectDst, visRectSrc;
1561 DC *dcSrc = physDevSrc ? physDevSrc->dc : NULL;
1562 DC *dcDst = physDevDst->dc;
1564 if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1565 /* FIXME: seems the ROP doesn't include destination;
1566 * now if the destination area include the entire dcDst,
1567 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1568 * which may avoid a copy in some situations */
1570 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1571 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1573 if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1574 (dcSrc->bitsPerPixel == dcDst->bitsPerPixel))
1577 /* do everything ourselves; map coordinates */
1581 pts[1].x = xSrc + width;
1582 pts[1].y = ySrc + height;
1584 LPtoDP(physDevSrc->hdc, pts, 2);
1585 width = pts[1].x - pts[0].x;
1586 height = pts[1].y - pts[0].y;
1592 LPtoDP(physDevDst->hdc, pts, 1);
1597 /* Perform basic clipping */
1598 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, width, height,
1599 dcSrc, xSrc, ySrc, width, height,
1600 &visRectSrc, &visRectDst ))
1603 xSrc = visRectSrc.left;
1604 ySrc = visRectSrc.top;
1605 xDst = visRectDst.left;
1606 yDst = visRectDst.top;
1607 width = visRectDst.right - visRectDst.left;
1608 height = visRectDst.bottom - visRectDst.top;
1610 if (sDst == DIB_Status_AppMod) {
1611 FIXME("potential optimization - client-side DIB copy\n");
1613 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1615 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1620 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1621 if (physDevDst != physDevSrc)
1622 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1624 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1625 physDevSrc, xSrc, ySrc, width, height, rop );
1628 if (physDevDst != physDevSrc)
1629 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1630 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1636 /***********************************************************************
1639 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1640 INT widthDst, INT heightDst,
1641 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1642 INT widthSrc, INT heightSrc, DWORD rop )
1646 X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1647 if (physDevDst != physDevSrc)
1648 X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1650 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1651 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1653 if (physDevDst != physDevSrc)
1654 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1655 X11DRV_UnlockDIBSection( physDevDst, TRUE );