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
23 #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 (dcSrc->flags & DC_MEMORY)
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 );
1010 imageDst = X11DRV_DIB_CreateXImage( width, height, dcDst->bitsPerPixel );
1011 for (y = 0; y < height; y++)
1012 for (x = 0; x < width; x++)
1013 XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1014 physDevSrc->backgroundPixel) );
1015 XPutImage( gdi_display, pixmap, gc, imageDst,
1016 0, 0, 0, 0, width, height );
1017 XDestroyImage( imageSrc );
1018 XDestroyImage( imageDst );
1025 /***********************************************************************
1028 * Retrieve an area from the destination DC, mapping all the
1029 * pixels to Windows colors.
1031 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1034 INT width = visRectDst->right - visRectDst->left;
1035 INT height = visRectDst->bottom - visRectDst->top;
1037 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->dc->bitsPerPixel == 1) ||
1038 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1040 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1041 physDev->org.x + visRectDst->left, physDev->org.y + visRectDst->top,
1042 width, height, 0, 0 );
1050 if (physDev->dc->flags & DC_MEMORY)
1051 image = XGetImage( gdi_display, physDev->drawable,
1052 physDev->org.x + visRectDst->left,
1053 physDev->org.y + visRectDst->top,
1054 width, height, AllPlanes, ZPixmap );
1057 /* Make sure we don't get a BadMatch error */
1058 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1059 physDev->org.x + visRectDst->left,
1060 physDev->org.y + visRectDst->top,
1061 width, height, 0, 0);
1063 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1064 AllPlanes, ZPixmap );
1066 for (y = 0; y < height; y++)
1067 for (x = 0; x < width; x++)
1068 XPutPixel( image, x, y,
1069 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1070 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1071 XDestroyImage( image );
1077 /***********************************************************************
1080 * Put an area back into the destination DC, mapping the pixel
1081 * colors to X pixels.
1083 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1086 INT width = visRectDst->right - visRectDst->left;
1087 INT height = visRectDst->bottom - visRectDst->top;
1089 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1091 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->dc->bitsPerPixel == 1) ||
1092 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1094 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1095 physDev->org.x + visRectDst->left,
1096 physDev->org.y + visRectDst->top );
1102 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1103 AllPlanes, ZPixmap );
1104 for (y = 0; y < height; y++)
1105 for (x = 0; x < width; x++)
1107 XPutPixel( image, x, y,
1108 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1110 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1111 physDev->org.x + visRectDst->left,
1112 physDev->org.y + visRectDst->top, width, height );
1113 XDestroyImage( image );
1119 /***********************************************************************
1120 * BITBLT_GetVisRectangles
1122 * Get the source and destination visible rectangles for StretchBlt().
1123 * Return FALSE if one of the rectangles is empty.
1125 static BOOL BITBLT_GetVisRectangles( DC *dcDst, INT xDst, INT yDst,
1126 INT widthDst, INT heightDst,
1127 DC *dcSrc, INT xSrc, INT ySrc,
1128 INT widthSrc, INT heightSrc,
1129 RECT *visRectSrc, RECT *visRectDst )
1131 RECT rect, clipRect;
1133 /* Get the destination visible rectangle */
1137 rect.right = xDst + widthDst;
1138 rect.bottom = yDst + heightDst;
1139 if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1140 if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1141 GetRgnBox( dcDst->hGCClipRgn, &clipRect );
1142 if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1144 /* Get the source visible rectangle */
1146 if (!dcSrc) return TRUE;
1149 rect.right = xSrc + widthSrc;
1150 rect.bottom = ySrc + heightSrc;
1151 if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1152 if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1153 /* Apparently the clipping and visible regions are only for output,
1154 so just check against totalExtent here to avoid BadMatch errors */
1155 if (!IntersectRect( visRectSrc, &rect, &dcSrc->totalExtent ))
1158 /* Intersect the rectangles */
1160 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1162 visRectSrc->left += xDst - xSrc;
1163 visRectSrc->right += xDst - xSrc;
1164 visRectSrc->top += yDst - ySrc;
1165 visRectSrc->bottom += yDst - ySrc;
1166 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1167 *visRectSrc = *visRectDst = rect;
1168 visRectSrc->left += xSrc - xDst;
1169 visRectSrc->right += xSrc - xDst;
1170 visRectSrc->top += ySrc - yDst;
1171 visRectSrc->bottom += ySrc - yDst;
1173 else /* stretching */
1175 /* Map source rectangle into destination coordinates */
1176 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1177 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1178 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1179 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1180 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1181 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1183 /* Avoid rounding errors */
1188 if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1190 /* Map destination rectangle back to source coordinates */
1192 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1193 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1194 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1195 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1196 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1197 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1199 /* Avoid rounding errors */
1204 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1210 /***********************************************************************
1211 * BITBLT_InternalStretchBlt
1213 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1215 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1216 INT widthDst, INT heightDst,
1217 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1218 INT widthSrc, INT heightSrc,
1221 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1222 RECT visRectDst, visRectSrc;
1225 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1227 DC *dcSrc = physDevSrc ? physDevSrc->dc : NULL;
1228 DC *dcDst = physDevDst->dc;
1230 /* compensate for off-by-one shifting for negative widths and heights */
1240 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1241 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1242 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1243 if (!dcSrc && useSrc) return FALSE;
1245 /* Map the coordinates to device coords */
1247 xDst = XLPTODP( dcDst, xDst );
1248 yDst = YLPTODP( dcDst, yDst );
1250 /* Here we have to round to integers, not truncate */
1251 widthDst = MulDiv(widthDst, dcDst->vportExtX, dcDst->wndExtX);
1252 heightDst = MulDiv(heightDst, dcDst->vportExtY, dcDst->wndExtY);
1254 TRACE(" vportdst=%d,%d-%d,%d wnddst=%d,%d-%d,%d\n",
1255 dcDst->vportOrgX, dcDst->vportOrgY,
1256 dcDst->vportExtX, dcDst->vportExtY,
1257 dcDst->wndOrgX, dcDst->wndOrgY,
1258 dcDst->wndExtX, dcDst->wndExtY );
1259 TRACE(" rectdst=%d,%d-%d,%d orgdst=%ld,%ld\n",
1260 xDst, yDst, widthDst, heightDst,
1261 physDevDst->org.x, physDevDst->org.y );
1265 xSrc = XLPTODP( dcSrc, xSrc );
1266 ySrc = YLPTODP( dcSrc, ySrc );
1267 widthSrc = widthSrc * dcSrc->vportExtX / dcSrc->wndExtX;
1268 heightSrc = heightSrc * dcSrc->vportExtY / dcSrc->wndExtY;
1269 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1270 TRACE(" vportsrc=%d,%d-%d,%d wndsrc=%d,%d-%d,%d\n",
1271 dcSrc->vportOrgX, dcSrc->vportOrgY,
1272 dcSrc->vportExtX, dcSrc->vportExtY,
1273 dcSrc->wndOrgX, dcSrc->wndOrgY,
1274 dcSrc->wndExtX, dcSrc->wndExtY );
1275 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%ld,%ld\n",
1276 xSrc, ySrc, widthSrc, heightSrc,
1277 physDevSrc->org.x, physDevSrc->org.y );
1278 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1279 dcSrc, xSrc, ySrc, widthSrc, heightSrc,
1280 &visRectSrc, &visRectDst ))
1282 TRACE(" vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1283 visRectSrc.left, visRectSrc.top,
1284 visRectSrc.right, visRectSrc.bottom,
1285 visRectDst.left, visRectDst.top,
1286 visRectDst.right, visRectDst.bottom );
1291 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1292 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1294 TRACE(" vissrc=none visdst=%d,%d-%d,%d\n",
1295 visRectDst.left, visRectDst.top,
1296 visRectDst.right, visRectDst.bottom );
1299 width = visRectDst.right - visRectDst.left;
1300 height = visRectDst.bottom - visRectDst.top;
1302 if (!fStretch) switch(rop) /* A few optimisations */
1304 case BLACKNESS: /* 0x00 */
1306 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1307 XSetFunction( gdi_display, physDevDst->gc, GXclear );
1310 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1311 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1312 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1314 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1315 physDevDst->org.x + visRectDst.left,
1316 physDevDst->org.y + visRectDst.top,
1318 wine_tsx11_unlock();
1321 case DSTINVERT: /* 0x55 */
1322 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel ||
1323 !perfect_graphics())
1326 XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1328 if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1329 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1332 /* Xor is much better when we do not have full colormap. */
1333 /* Using white^black ensures that we invert at least black */
1335 Pixel xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1336 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1337 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1338 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1339 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1341 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1342 physDevDst->org.x + visRectDst.left,
1343 physDevDst->org.y + visRectDst.top,
1345 wine_tsx11_unlock();
1350 case PATINVERT: /* 0x5a */
1351 if (perfect_graphics()) break;
1352 if (X11DRV_SetupGCForBrush( physDevDst ))
1355 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1356 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1357 physDevDst->org.x + visRectDst.left,
1358 physDevDst->org.y + visRectDst.top,
1360 wine_tsx11_unlock();
1365 if (perfect_graphics()) break;
1366 if (X11DRV_SetupGCForBrush( physDevDst ))
1369 XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1370 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1371 physDevDst->org.x + visRectDst.left,
1372 physDevDst->org.y + visRectDst.top,
1374 wine_tsx11_unlock();
1378 case SRCCOPY: /* 0xcc */
1379 if (dcSrc->bitsPerPixel == dcDst->bitsPerPixel)
1382 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1383 XCopyArea( gdi_display, physDevSrc->drawable,
1384 physDevDst->drawable, physDevDst->gc,
1385 physDevSrc->org.x + visRectSrc.left,
1386 physDevSrc->org.y + visRectSrc.top,
1388 physDevDst->org.x + visRectDst.left,
1389 physDevDst->org.y + visRectDst.top );
1390 physDevDst->exposures++;
1391 wine_tsx11_unlock();
1394 if (dcSrc->bitsPerPixel == 1)
1397 XSetBackground( gdi_display, physDevDst->gc, physDevDst->textPixel );
1398 XSetForeground( gdi_display, physDevDst->gc, physDevDst->backgroundPixel );
1399 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1400 XCopyPlane( gdi_display, physDevSrc->drawable,
1401 physDevDst->drawable, physDevDst->gc,
1402 physDevSrc->org.x + visRectSrc.left,
1403 physDevSrc->org.y + visRectSrc.top,
1405 physDevDst->org.x + visRectDst.left,
1406 physDevDst->org.y + visRectDst.top, 1 );
1407 physDevDst->exposures++;
1408 wine_tsx11_unlock();
1413 case PATCOPY: /* 0xf0 */
1414 if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1416 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1417 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1418 physDevDst->org.x + visRectDst.left,
1419 physDevDst->org.y + visRectDst.top,
1421 wine_tsx11_unlock();
1424 case WHITENESS: /* 0xff */
1426 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1427 XSetFunction( gdi_display, physDevDst->gc, GXset );
1430 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1431 XSetForeground( gdi_display, physDevDst->gc,
1432 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1433 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1435 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1436 physDevDst->org.x + visRectDst.left,
1437 physDevDst->org.y + visRectDst.top,
1439 wine_tsx11_unlock();
1445 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1446 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1447 XSetGraphicsExposures( gdi_display, tmpGC, False );
1448 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1449 dcDst->bitsPerPixel );
1452 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1453 dcDst->bitsPerPixel );
1455 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1456 xSrc, ySrc, widthSrc, heightSrc,
1457 xDst, yDst, widthDst, heightDst,
1458 &visRectSrc, &visRectDst );
1460 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1461 xSrc, ySrc, &visRectSrc );
1464 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1465 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1466 else fNullBrush = FALSE;
1469 for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1471 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1472 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1473 switch(OP_SRCDST(*opcode))
1475 case OP_ARGS(DST,TMP):
1476 case OP_ARGS(SRC,TMP):
1478 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1480 dcDst->bitsPerPixel );
1482 case OP_ARGS(DST,SRC):
1483 case OP_ARGS(SRC,DST):
1484 case OP_ARGS(TMP,SRC):
1485 case OP_ARGS(TMP,DST):
1486 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1487 pixmaps[OP_DST(*opcode)], tmpGC,
1488 0, 0, width, height, 0, 0 );
1491 case OP_ARGS(PAT,TMP):
1492 if (!pixmaps[TMP] && !fNullBrush)
1493 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1495 dcDst->bitsPerPixel );
1497 case OP_ARGS(PAT,DST):
1498 case OP_ARGS(PAT,SRC):
1500 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1501 tmpGC, 0, 0, width, height );
1505 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1506 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1508 XFreePixmap( gdi_display, pixmaps[DST] );
1509 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1510 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1511 XFreeGC( gdi_display, tmpGC );
1512 wine_tsx11_unlock();
1517 /***********************************************************************
1520 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1524 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1525 result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1526 X11DRV_UnlockDIBSection( physDev, TRUE );
1531 /***********************************************************************
1534 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1535 INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1536 INT xSrc, INT ySrc, DWORD rop )
1538 BOOL result = FALSE;
1540 RECT visRectDst, visRectSrc;
1541 DC *dcSrc = physDevSrc ? physDevSrc->dc : NULL;
1542 DC *dcDst = physDevDst->dc;
1544 if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1545 /* FIXME: seems the ROP doesn't include destination;
1546 * now if the destination area include the entire dcDst,
1547 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1548 * which may avoid a copy in some situations */
1550 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1551 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1553 if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1554 (dcSrc->bitsPerPixel == dcDst->bitsPerPixel))
1556 /* do everything ourselves; map coordinates */
1557 xSrc = XLPTODP( dcSrc, xSrc );
1558 ySrc = YLPTODP( dcSrc, ySrc );
1559 xDst = XLPTODP( dcDst, xDst );
1560 yDst = YLPTODP( dcDst, yDst );
1561 width = MulDiv(width, dcDst->vportExtX, dcDst->wndExtX);
1562 height = MulDiv(height, dcDst->vportExtY, dcDst->wndExtY);
1564 /* Perform basic clipping */
1565 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, width, height,
1566 dcSrc, xSrc, ySrc, width, height,
1567 &visRectSrc, &visRectDst ))
1570 xSrc = visRectSrc.left;
1571 ySrc = visRectSrc.top;
1572 xDst = visRectDst.left;
1573 yDst = visRectDst.top;
1574 width = visRectDst.right - visRectDst.left;
1575 height = visRectDst.bottom - visRectDst.top;
1577 if (sDst == DIB_Status_AppMod) {
1578 FIXME("potential optimization - client-side DIB copy\n");
1580 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1582 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1587 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1588 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1590 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1591 physDevSrc, xSrc, ySrc, width, height, rop );
1594 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1595 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1601 /***********************************************************************
1604 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1605 INT widthDst, INT heightDst,
1606 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1607 INT widthSrc, INT heightSrc, DWORD rop )
1611 X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1612 X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1614 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1615 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1617 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1618 X11DRV_UnlockDIBSection( physDevDst, TRUE );