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>
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
44 #define DST 0 /* Destination drawable */
45 #define SRC 1 /* Source drawable */
46 #define TMP 2 /* Temporary drawable */
47 #define PAT 3 /* Pattern (brush) in destination DC */
49 #define OP(src,dst,rop) (OP_ARGS(src,dst) << 4 | (rop))
50 #define OP_ARGS(src,dst) (((src) << 2) | (dst))
52 #define OP_SRC(opcode) ((opcode) >> 6)
53 #define OP_DST(opcode) (((opcode) >> 4) & 3)
54 #define OP_SRCDST(opcode) ((opcode) >> 4)
55 #define OP_ROP(opcode) ((opcode) & 0x0f)
57 #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */
59 #define SWAP_INT32(i1,i2) \
60 do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
62 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
64 { OP(PAT,DST,GXclear) }, /* 0x00 0 */
65 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */
66 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */
67 { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */
68 { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */
69 { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */
70 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */
71 { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */
72 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */
73 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */
74 { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */
75 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */
76 { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */
77 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */
78 { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */
79 { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */
80 { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */
81 { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */
82 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */
83 { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */
84 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */
85 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */
86 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
87 OP(TMP,DST,GXand), OP(SRC,DST,GXxor),
88 OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */
89 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
90 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
91 OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/
92 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
93 OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */
94 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
95 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */
96 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
97 OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */
98 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXxor),
99 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */
100 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
101 OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */
102 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
103 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */
104 { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */
105 { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */
106 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */
107 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */
108 { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */
109 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */
110 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
111 OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */
112 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
113 OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */
114 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
115 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
116 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXequiv),
117 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */
118 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */
119 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
120 OP(TMP,DST,GXor), OP(SRC,DST,GXxor),
121 OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */
122 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */
123 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
124 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
125 OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/
126 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
127 OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */
128 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */
129 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
130 OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */
131 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */
132 { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */
133 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */
134 { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
135 OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */
136 { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */
137 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
138 OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */
139 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
140 OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */
141 { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */
142 { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */
143 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
144 OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */
145 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */
146 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
147 OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */
148 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */
149 { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */
150 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
151 OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */
152 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
153 OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */
154 { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */
155 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */
156 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */
157 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
158 OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */
159 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
160 OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */
161 { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */
162 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */
163 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
164 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */
165 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
166 OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */
167 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */
168 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
169 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
170 OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */
171 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
172 OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */
173 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */
174 { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */
175 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
176 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
177 OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/
178 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
179 OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */
180 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */
181 { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */
182 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */
183 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
184 OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */
185 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
186 OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */
187 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */
188 { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */
189 { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */
190 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */
191 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
192 OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */
193 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */
194 { OP(PAT,DST,GXxor) }, /* 0x5a D^P */
195 { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
196 OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */
197 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
198 OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */
199 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */
200 { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
201 OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */
202 { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */
203 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */
204 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
205 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
206 OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */
207 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
208 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */
209 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */
210 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
211 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */
212 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */
213 { OP(SRC,DST,GXxor) }, /* 0x66 S^D */
214 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
215 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */
216 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
217 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
218 OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/
219 { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */
220 { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */
221 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
222 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
223 OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */
224 { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */
225 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
226 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
227 OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */
228 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
229 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */
230 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */
231 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */
232 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
233 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
234 OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/
235 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
236 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */
237 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */
238 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
239 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */
240 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */
241 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
242 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */
243 { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */
244 { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */
245 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
246 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
247 OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */
248 { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
249 OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */
250 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */
251 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
252 OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */
253 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */
254 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
255 OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */
256 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */
257 { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */
258 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
259 OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */
260 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */
261 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
262 OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */
263 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */
264 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
265 OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */
266 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
267 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
268 OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */
269 { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */
270 { OP(SRC,DST,GXand) }, /* 0x88 S&D */
271 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
272 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */
273 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */
274 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
275 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */
276 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */
277 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
278 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */
279 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
280 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
281 OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/
282 { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */
283 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */
284 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
285 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */
286 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
287 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
288 OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */
289 { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */
290 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
291 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
292 OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */
293 { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */
294 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */
295 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
296 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
297 OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */
298 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
299 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */
300 { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */
301 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */
302 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
303 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */
304 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */
305 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
306 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */
307 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
308 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
309 OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */
310 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */
311 { OP(PAT,DST,GXand) }, /* 0xa0 D&P */
312 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
313 OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */
314 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */
315 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
316 OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */
317 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
318 OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */
319 { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */
320 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */
321 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
322 OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */
323 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */
324 { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */
325 { OP(SRC,DST,GXnoop) }, /* 0xaa D */
326 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */
327 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
328 OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */
329 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
330 OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */
331 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */
332 { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */
333 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */
334 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
335 OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */
336 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
337 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
338 OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/
339 { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */
340 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */
341 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
342 OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */
343 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
344 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
345 OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */
346 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */
347 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
348 OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */
349 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
350 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */
351 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */
352 { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */
353 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
354 OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */
355 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
356 OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */
357 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */
358 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */
359 { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */
360 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
361 OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */
362 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
363 OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */
364 { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */
365 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */
366 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
367 OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */
368 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */
369 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
370 OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */
371 { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */
372 { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */
373 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
374 OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */
375 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
376 OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */
377 { OP(SRC,DST,GXcopy) }, /* 0xcc S */
378 { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */
379 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */
380 { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */
381 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */
382 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
383 OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */
384 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */
385 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
386 OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */
387 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
388 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
389 OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/
390 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */
391 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
392 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
393 OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */
394 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */
395 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
396 OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */
397 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
398 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */
399 { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
400 OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */
401 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
402 OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */
403 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */
404 { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */
405 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */
406 { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */
407 { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */
408 { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */
409 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
410 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */
411 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
412 OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */
413 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
414 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */
415 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
416 OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */
417 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
418 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */
419 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
420 OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */
421 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
422 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
423 OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/
424 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
425 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
426 OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/
427 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */
428 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */
429 { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */
430 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */
431 { OP(SRC,DST,GXor) }, /* 0xee S|D */
432 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */
433 { OP(PAT,DST,GXcopy) }, /* 0xf0 P */
434 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */
435 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */
436 { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */
437 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */
438 { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */
439 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */
440 { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */
441 { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */
442 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */
443 { OP(PAT,DST,GXor) }, /* 0xfa D|P */
444 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */
445 { OP(PAT,SRC,GXor) }, /* 0xfc P|S */
446 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */
447 { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */
448 { OP(PAT,DST,GXset) } /* 0xff 1 */
452 #ifdef BITBLT_TEST /* Opcodes test */
454 static int do_bitop( int s, int d, int rop )
459 case GXclear: res = 0; break;
460 case GXand: res = s & d; break;
461 case GXandReverse: res = s & ~d; break;
462 case GXcopy: res = s; break;
463 case GXandInverted: res = ~s & d; break;
464 case GXnoop: res = d; break;
465 case GXxor: res = s ^ d; break;
466 case GXor: res = s | d; break;
467 case GXnor: res = ~(s | d); break;
468 case GXequiv: res = ~s ^ d; break;
469 case GXinvert: res = ~d; break;
470 case GXorReverse: res = s | ~d; break;
471 case GXcopyInverted: res = ~s; break;
472 case GXorInverted: res = ~s | d; break;
473 case GXnand: res = ~(s & d); break;
474 case GXset: res = 1; break;
481 int rop, i, res, src, dst, pat, tmp, dstUsed;
484 for (rop = 0; rop < 256; rop++)
487 for (i = 0; i < 8; i++)
492 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
496 case OP_ARGS(DST,TMP):
497 tmp = do_bitop( dst, tmp, *opcode & 0xf );
499 case OP_ARGS(DST,SRC):
500 src = do_bitop( dst, src, *opcode & 0xf );
502 case OP_ARGS(SRC,TMP):
503 tmp = do_bitop( src, tmp, *opcode & 0xf );
505 case OP_ARGS(SRC,DST):
506 dst = do_bitop( src, dst, *opcode & 0xf );
509 case OP_ARGS(PAT,TMP):
510 tmp = do_bitop( pat, tmp, *opcode & 0xf );
512 case OP_ARGS(PAT,DST):
513 dst = do_bitop( pat, dst, *opcode & 0xf );
516 case OP_ARGS(PAT,SRC):
517 src = do_bitop( pat, src, *opcode & 0xf );
519 case OP_ARGS(TMP,DST):
520 dst = do_bitop( tmp, dst, *opcode & 0xf );
523 case OP_ARGS(TMP,SRC):
524 src = do_bitop( tmp, src, *opcode & 0xf );
527 printf( "Invalid opcode %x\n", *opcode );
530 if (!dstUsed) dst = src;
531 if (dst) res |= 1 << i;
533 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
539 #endif /* BITBLT_TEST */
542 /***********************************************************************
545 * Favor correctness or speed?
547 static int perfect_graphics(void)
549 static int perfect = -1;
556 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
558 DWORD type, count = sizeof(buffer);
559 if(!RegQueryValueExA(hkey, "PerfectGraphics", 0, &type, buffer, &count))
562 perfect = (ch == 'y' || ch == 'Y' || ch == 't' || ch == 'T' || ch == '1');
570 /***********************************************************************
573 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
575 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
576 INT startDst, INT widthDst,
577 INT xinc, INT xoff, WORD mode )
579 register INT xsrc = xinc * startDst + xoff;
583 case STRETCH_ANDSCANS:
584 for(; widthDst > 0; widthDst--, xsrc += xinc)
585 *rowDst++ &= rowSrc[xsrc >> 16];
587 case STRETCH_ORSCANS:
588 for(; widthDst > 0; widthDst--, xsrc += xinc)
589 *rowDst++ |= rowSrc[xsrc >> 16];
591 case STRETCH_DELETESCANS:
592 for(; widthDst > 0; widthDst--, xsrc += xinc)
593 *rowDst++ = rowSrc[xsrc >> 16];
599 /***********************************************************************
602 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
604 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
605 INT startSrc, INT widthSrc,
606 INT xinc, INT xoff, WORD mode )
608 register INT xdst = xinc * startSrc + xoff;
612 case STRETCH_ORSCANS:
613 for(; widthSrc > 0; widthSrc--, xdst += xinc)
614 rowDst[xdst >> 16] |= *rowSrc++;
616 case STRETCH_ANDSCANS:
617 for(; widthSrc > 0; widthSrc--, xdst += xinc)
618 rowDst[xdst >> 16] &= *rowSrc++;
620 case STRETCH_DELETESCANS:
621 for(; widthSrc > 0; widthSrc--, xdst += xinc)
622 rowDst[xdst >> 16] = *rowSrc++;
628 /***********************************************************************
631 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
633 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
634 INT start, INT width, INT depthDst,
635 int fg, int bg, BOOL swap)
639 assert( (row >= 0) && (row < image->height) );
640 assert( (start >= 0) && (width <= image->width) );
642 pdata += swap ? start+width-1 : start;
643 if (image->depth == depthDst) /* color -> color */
645 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
646 if (swap) for (i = 0; i < width; i++)
647 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
648 else for (i = 0; i < width; i++)
649 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
651 if (swap) for (i = 0; i < width; i++)
652 *pdata-- = XGetPixel( image, i, row );
653 else for (i = 0; i < width; i++)
654 *pdata++ = XGetPixel( image, i, row );
658 if (image->depth == 1) /* monochrome -> color */
660 if (X11DRV_PALETTE_XPixelToPalette)
662 fg = X11DRV_PALETTE_XPixelToPalette[fg];
663 bg = X11DRV_PALETTE_XPixelToPalette[bg];
665 if (swap) for (i = 0; i < width; i++)
666 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
667 else for (i = 0; i < width; i++)
668 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
670 else /* color -> monochrome */
672 if (swap) for (i = 0; i < width; i++)
673 *pdata-- = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
674 else for (i = 0; i < width; i++)
675 *pdata++ = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
681 /***********************************************************************
682 * BITBLT_StretchImage
684 * Stretch an X image.
685 * FIXME: does not work for full 32-bit coordinates.
687 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
688 INT widthSrc, INT heightSrc,
689 INT widthDst, INT heightDst,
690 RECT *visRectSrc, RECT *visRectDst,
691 int foreground, int background, WORD mode )
693 int *rowSrc, *rowDst, *pixel;
695 INT xinc, xoff, yinc, ysrc, ydst;
697 BOOL hstretch, vstretch, hswap, vswap;
699 hswap = ((int)widthSrc * widthDst) < 0;
700 vswap = ((int)heightSrc * heightDst) < 0;
701 widthSrc = abs(widthSrc);
702 heightSrc = abs(heightSrc);
703 widthDst = abs(widthDst);
704 heightDst = abs(heightDst);
706 if (!(rowSrc = (int *)HeapAlloc( GetProcessHeap(), 0,
707 (widthSrc+widthDst)*sizeof(int) ))) return;
708 rowDst = rowSrc + widthSrc;
710 /* When stretching, all modes are the same, and DELETESCANS is faster */
711 if ((widthSrc < widthDst) && (heightSrc < heightDst))
712 mode = STRETCH_DELETESCANS;
714 if (mode == STRETCH_HALFTONE) /* FIXME */
715 mode = STRETCH_DELETESCANS;
717 if (mode != STRETCH_DELETESCANS)
718 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
719 widthDst*sizeof(int) );
721 hstretch = (widthSrc < widthDst);
722 vstretch = (heightSrc < heightDst);
726 xinc = ((int)widthSrc << 16) / widthDst;
727 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
731 xinc = ((int)widthDst << 16) / widthSrc;
732 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
737 yinc = ((int)heightSrc << 16) / heightDst;
738 ydst = visRectDst->top;
741 ysrc = yinc * (heightDst - ydst - 1);
747 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
749 if (((ysrc >> 16) < visRectSrc->top) ||
750 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
752 /* Retrieve a source row */
753 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
754 hswap ? widthSrc - visRectSrc->right
756 visRectSrc->right - visRectSrc->left,
757 dstImage->depth, foreground, background, hswap );
759 /* Stretch or shrink it */
761 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
762 visRectDst->right - visRectDst->left,
764 else BITBLT_ShrinkRow( rowSrc, rowDst,
765 hswap ? widthSrc - visRectSrc->right
767 visRectSrc->right - visRectSrc->left,
770 /* Store the destination row */
771 pixel = rowDst + visRectDst->right - 1;
772 y = ydst - visRectDst->top;
773 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
774 XPutPixel( dstImage, x, y, *pixel-- );
775 if (mode != STRETCH_DELETESCANS)
776 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
777 widthDst*sizeof(int) );
779 /* Make copies of the destination row */
781 pdata = dstImage->data + dstImage->bytes_per_line * y;
782 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
783 (ydst < visRectDst->bottom-1))
785 memcpy( pdata + dstImage->bytes_per_line, pdata,
786 dstImage->bytes_per_line );
787 pdata += dstImage->bytes_per_line;
795 yinc = ((int)heightDst << 16) / heightSrc;
796 ysrc = visRectSrc->top;
797 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
800 ydst += yinc * (heightSrc - ysrc - 1);
806 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
808 if (((ydst >> 16) < visRectDst->top) ||
809 ((ydst >> 16) >= visRectDst->bottom)) continue;
811 /* Retrieve a source row */
812 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
813 hswap ? widthSrc - visRectSrc->right
815 visRectSrc->right - visRectSrc->left,
816 dstImage->depth, foreground, background, hswap );
818 /* Stretch or shrink it */
820 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
821 visRectDst->right - visRectDst->left,
823 else BITBLT_ShrinkRow( rowSrc, rowDst,
824 hswap ? widthSrc - visRectSrc->right
826 visRectSrc->right - visRectSrc->left,
829 /* Merge several source rows into the destination */
830 if (mode == STRETCH_DELETESCANS)
832 /* Simply skip the overlapping rows */
833 while (((ydst + yinc) >> 16 == ydst >> 16) &&
834 (ysrc < visRectSrc->bottom-1))
840 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
841 (ysrc < visRectSrc->bottom-1))
842 continue; /* Restart loop for next overlapping row */
844 /* Store the destination row */
845 pixel = rowDst + visRectDst->right - 1;
846 y = (ydst >> 16) - visRectDst->top;
847 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
848 XPutPixel( dstImage, x, y, *pixel-- );
849 if (mode != STRETCH_DELETESCANS)
850 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
851 widthDst*sizeof(int) );
854 HeapFree( GetProcessHeap(), 0, rowSrc );
858 /***********************************************************************
859 * BITBLT_GetSrcAreaStretch
861 * Retrieve an area from the source DC, stretching and mapping all the
862 * pixels to Windows colors.
864 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
865 Pixmap pixmap, GC gc,
867 INT widthSrc, INT heightSrc,
869 INT widthDst, INT heightDst,
870 RECT *visRectSrc, RECT *visRectDst )
872 XImage *imageSrc, *imageDst;
873 DC *dcDst = physDevDst->dc;
875 RECT rectSrc = *visRectSrc;
876 RECT rectDst = *visRectDst;
878 if (widthSrc < 0) xSrc += widthSrc;
879 if (widthDst < 0) xDst += widthDst;
880 if (heightSrc < 0) ySrc += heightSrc;
881 if (heightDst < 0) yDst += heightDst;
882 rectSrc.left -= xSrc;
883 rectSrc.right -= xSrc;
885 rectSrc.bottom -= ySrc;
886 rectDst.left -= xDst;
887 rectDst.right -= xDst;
889 rectDst.bottom -= yDst;
891 /* FIXME: avoid BadMatch errors */
892 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
893 physDevSrc->org.x + visRectSrc->left,
894 physDevSrc->org.y + visRectSrc->top,
895 visRectSrc->right - visRectSrc->left,
896 visRectSrc->bottom - visRectSrc->top,
897 AllPlanes, ZPixmap );
898 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
899 rectDst.bottom - rectDst.top, dcDst->bitsPerPixel );
900 BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
901 widthDst, heightDst, &rectSrc, &rectDst,
902 physDevDst->textPixel, dcDst->bitsPerPixel != 1 ?
903 physDevDst->backgroundPixel :
904 physDevSrc->backgroundPixel,
905 dcDst->stretchBltMode );
906 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
907 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
908 XDestroyImage( imageSrc );
909 XDestroyImage( imageDst );
910 return 0; /* no exposure events generated */
914 /***********************************************************************
917 * Retrieve an area from the source DC, mapping all the
918 * pixels to Windows colors.
920 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
921 Pixmap pixmap, GC gc, INT xSrc, INT ySrc, RECT *visRectSrc )
923 XImage *imageSrc, *imageDst;
926 INT width = visRectSrc->right - visRectSrc->left;
927 INT height = visRectSrc->bottom - visRectSrc->top;
928 DC *dcSrc = physDevSrc->dc;
929 DC *dcDst = physDevDst->dc;
931 if (dcSrc->bitsPerPixel == dcDst->bitsPerPixel)
933 if (!X11DRV_PALETTE_XPixelToPalette ||
934 (dcDst->bitsPerPixel == 1)) /* monochrome -> monochrome */
936 if (dcDst->bitsPerPixel == 1)
938 /* MSDN says if StretchBlt must convert a bitmap from monochrome
939 to color or vice versa, the forground and background color of
940 the device context are used. In fact, it also applies to the
941 case when it is converted from mono to mono. */
942 XSetBackground( gdi_display, gc, physDevDst->textPixel );
943 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
944 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
945 physDevSrc->org.x + visRectSrc->left,
946 physDevSrc->org.y + visRectSrc->top,
947 width, height, 0, 0, 1);
950 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
951 physDevSrc->org.x + visRectSrc->left,
952 physDevSrc->org.y + visRectSrc->top,
953 width, height, 0, 0);
956 else /* color -> color */
958 if (GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
959 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
960 physDevSrc->org.x + visRectSrc->left,
961 physDevSrc->org.y + visRectSrc->top,
962 width, height, AllPlanes, ZPixmap );
965 /* Make sure we don't get a BadMatch error */
966 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
967 physDevSrc->org.x + visRectSrc->left,
968 physDevSrc->org.y + visRectSrc->top,
969 width, height, 0, 0);
971 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
972 AllPlanes, ZPixmap );
974 for (y = 0; y < height; y++)
975 for (x = 0; x < width; x++)
976 XPutPixel(imageSrc, x, y,
977 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
978 XPutImage( gdi_display, pixmap, gc, imageSrc,
979 0, 0, 0, 0, width, height );
980 XDestroyImage( imageSrc );
985 if (dcSrc->bitsPerPixel == 1) /* monochrome -> color */
987 if (X11DRV_PALETTE_XPixelToPalette)
989 XSetBackground( gdi_display, gc,
990 X11DRV_PALETTE_XPixelToPalette[physDevDst->textPixel] );
991 XSetForeground( gdi_display, gc,
992 X11DRV_PALETTE_XPixelToPalette[physDevDst->backgroundPixel]);
996 XSetBackground( gdi_display, gc, physDevDst->textPixel );
997 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
999 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
1000 physDevSrc->org.x + visRectSrc->left,
1001 physDevSrc->org.y + visRectSrc->top,
1002 width, height, 0, 0, 1 );
1005 else /* color -> monochrome */
1007 /* FIXME: avoid BadMatch error */
1008 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1009 physDevSrc->org.x + visRectSrc->left,
1010 physDevSrc->org.y + visRectSrc->top,
1011 width, height, AllPlanes, ZPixmap );
1012 imageDst = X11DRV_DIB_CreateXImage( width, height, dcDst->bitsPerPixel );
1013 for (y = 0; y < height; y++)
1014 for (x = 0; x < width; x++)
1015 XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1016 physDevSrc->backgroundPixel) );
1017 XPutImage( gdi_display, pixmap, gc, imageDst,
1018 0, 0, 0, 0, width, height );
1019 XDestroyImage( imageSrc );
1020 XDestroyImage( imageDst );
1027 /***********************************************************************
1030 * Retrieve an area from the destination DC, mapping all the
1031 * pixels to Windows colors.
1033 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1036 INT width = visRectDst->right - visRectDst->left;
1037 INT height = visRectDst->bottom - visRectDst->top;
1039 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->dc->bitsPerPixel == 1) ||
1040 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1042 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1043 physDev->org.x + visRectDst->left, physDev->org.y + visRectDst->top,
1044 width, height, 0, 0 );
1052 if (GetObjectType( physDev->hdc ) == OBJ_MEMDC)
1053 image = XGetImage( gdi_display, physDev->drawable,
1054 physDev->org.x + visRectDst->left,
1055 physDev->org.y + visRectDst->top,
1056 width, height, AllPlanes, ZPixmap );
1059 /* Make sure we don't get a BadMatch error */
1060 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1061 physDev->org.x + visRectDst->left,
1062 physDev->org.y + visRectDst->top,
1063 width, height, 0, 0);
1065 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1066 AllPlanes, ZPixmap );
1068 for (y = 0; y < height; y++)
1069 for (x = 0; x < width; x++)
1070 XPutPixel( image, x, y,
1071 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1072 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1073 XDestroyImage( image );
1079 /***********************************************************************
1082 * Put an area back into the destination DC, mapping the pixel
1083 * colors to X pixels.
1085 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1088 INT width = visRectDst->right - visRectDst->left;
1089 INT height = visRectDst->bottom - visRectDst->top;
1091 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1093 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->dc->bitsPerPixel == 1) ||
1094 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1096 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1097 physDev->org.x + visRectDst->left,
1098 physDev->org.y + visRectDst->top );
1104 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1105 AllPlanes, ZPixmap );
1106 for (y = 0; y < height; y++)
1107 for (x = 0; x < width; x++)
1109 XPutPixel( image, x, y,
1110 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1112 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1113 physDev->org.x + visRectDst->left,
1114 physDev->org.y + visRectDst->top, width, height );
1115 XDestroyImage( image );
1121 /***********************************************************************
1122 * BITBLT_GetVisRectangles
1124 * Get the source and destination visible rectangles for StretchBlt().
1125 * Return FALSE if one of the rectangles is empty.
1127 static BOOL BITBLT_GetVisRectangles( DC *dcDst, INT xDst, INT yDst,
1128 INT widthDst, INT heightDst,
1129 DC *dcSrc, INT xSrc, INT ySrc,
1130 INT widthSrc, INT heightSrc,
1131 RECT *visRectSrc, RECT *visRectDst )
1133 RECT rect, clipRect;
1135 /* Get the destination visible rectangle */
1139 rect.right = xDst + widthDst;
1140 rect.bottom = yDst + heightDst;
1141 if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1142 if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1143 GetRgnBox( dcDst->hGCClipRgn, &clipRect );
1144 if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1146 /* Get the source visible rectangle */
1148 if (!dcSrc) return TRUE;
1151 rect.right = xSrc + widthSrc;
1152 rect.bottom = ySrc + heightSrc;
1153 if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1154 if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1155 /* Apparently the clipping and visible regions are only for output,
1156 so just check against totalExtent here to avoid BadMatch errors */
1157 if (!IntersectRect( visRectSrc, &rect, &dcSrc->totalExtent ))
1160 /* Intersect the rectangles */
1162 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1164 visRectSrc->left += xDst - xSrc;
1165 visRectSrc->right += xDst - xSrc;
1166 visRectSrc->top += yDst - ySrc;
1167 visRectSrc->bottom += yDst - ySrc;
1168 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1169 *visRectSrc = *visRectDst = rect;
1170 visRectSrc->left += xSrc - xDst;
1171 visRectSrc->right += xSrc - xDst;
1172 visRectSrc->top += ySrc - yDst;
1173 visRectSrc->bottom += ySrc - yDst;
1175 else /* stretching */
1177 /* Map source rectangle into destination coordinates */
1178 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1179 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1180 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1181 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1182 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1183 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1185 /* Avoid rounding errors */
1190 if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1192 /* Map destination rectangle back to source coordinates */
1194 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1195 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1196 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1197 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1198 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1199 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1201 /* Avoid rounding errors */
1206 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1212 /***********************************************************************
1213 * BITBLT_InternalStretchBlt
1215 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1217 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1218 INT widthDst, INT heightDst,
1219 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1220 INT widthSrc, INT heightSrc,
1223 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1224 RECT visRectDst, visRectSrc;
1227 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1230 DC *dcSrc = physDevSrc ? physDevSrc->dc : NULL;
1231 DC *dcDst = physDevDst->dc;
1233 /* compensate for off-by-one shifting for negative widths and heights */
1243 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1244 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1245 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1246 if (!dcSrc && useSrc) return FALSE;
1248 /* Map the coordinates to device coords */
1252 pts[1].x = xDst + widthDst;
1253 pts[1].y = yDst + heightDst;
1254 LPtoDP(physDevDst->hdc, pts, 2);
1257 widthDst = pts[1].x - pts[0].x;
1258 heightDst = pts[1].y - pts[0].y;
1260 TRACE(" vportdst=%d,%d-%d,%d wnddst=%d,%d-%d,%d\n",
1261 dcDst->vportOrgX, dcDst->vportOrgY,
1262 dcDst->vportExtX, dcDst->vportExtY,
1263 dcDst->wndOrgX, dcDst->wndOrgY,
1264 dcDst->wndExtX, dcDst->wndExtY );
1265 TRACE(" rectdst=%d,%d-%d,%d orgdst=%ld,%ld\n",
1266 xDst, yDst, widthDst, heightDst,
1267 physDevDst->org.x, physDevDst->org.y );
1273 pts[1].x = xSrc + widthSrc;
1274 pts[1].y = ySrc + heightSrc;
1275 LPtoDP(physDevSrc->hdc, pts, 2);
1278 widthSrc = pts[1].x - pts[0].x;
1279 heightSrc = pts[1].y - pts[0].y;
1281 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1282 TRACE(" vportsrc=%d,%d-%d,%d wndsrc=%d,%d-%d,%d\n",
1283 dcSrc->vportOrgX, dcSrc->vportOrgY,
1284 dcSrc->vportExtX, dcSrc->vportExtY,
1285 dcSrc->wndOrgX, dcSrc->wndOrgY,
1286 dcSrc->wndExtX, dcSrc->wndExtY );
1287 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%ld,%ld\n",
1288 xSrc, ySrc, widthSrc, heightSrc,
1289 physDevSrc->org.x, physDevSrc->org.y );
1290 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1291 dcSrc, xSrc, ySrc, widthSrc, heightSrc,
1292 &visRectSrc, &visRectDst ))
1294 TRACE(" vissrc=%ld,%ld-%ld,%ld visdst=%ld,%ld-%ld,%ld\n",
1295 visRectSrc.left, visRectSrc.top,
1296 visRectSrc.right, visRectSrc.bottom,
1297 visRectDst.left, visRectDst.top,
1298 visRectDst.right, visRectDst.bottom );
1303 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1304 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1306 TRACE(" vissrc=none visdst=%ld,%ld-%ld,%ld\n",
1307 visRectDst.left, visRectDst.top,
1308 visRectDst.right, visRectDst.bottom );
1311 width = visRectDst.right - visRectDst.left;
1312 height = visRectDst.bottom - visRectDst.top;
1314 if (!fStretch) switch(rop) /* A few optimisations */
1316 case BLACKNESS: /* 0x00 */
1318 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1319 XSetFunction( gdi_display, physDevDst->gc, GXclear );
1322 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1323 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1324 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1326 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1327 physDevDst->org.x + visRectDst.left,
1328 physDevDst->org.y + visRectDst.top,
1330 wine_tsx11_unlock();
1333 case DSTINVERT: /* 0x55 */
1334 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel ||
1335 !perfect_graphics())
1338 XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1340 if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1341 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1344 /* Xor is much better when we do not have full colormap. */
1345 /* Using white^black ensures that we invert at least black */
1347 Pixel xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1348 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1349 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1350 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1351 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1353 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1354 physDevDst->org.x + visRectDst.left,
1355 physDevDst->org.y + visRectDst.top,
1357 wine_tsx11_unlock();
1362 case PATINVERT: /* 0x5a */
1363 if (perfect_graphics()) break;
1364 if (X11DRV_SetupGCForBrush( physDevDst ))
1367 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1368 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1369 physDevDst->org.x + visRectDst.left,
1370 physDevDst->org.y + visRectDst.top,
1372 wine_tsx11_unlock();
1377 if (perfect_graphics()) break;
1378 if (X11DRV_SetupGCForBrush( physDevDst ))
1381 XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1382 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1383 physDevDst->org.x + visRectDst.left,
1384 physDevDst->org.y + visRectDst.top,
1386 wine_tsx11_unlock();
1390 case SRCCOPY: /* 0xcc */
1391 if (dcSrc->bitsPerPixel == dcDst->bitsPerPixel)
1394 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1395 XCopyArea( gdi_display, physDevSrc->drawable,
1396 physDevDst->drawable, physDevDst->gc,
1397 physDevSrc->org.x + visRectSrc.left,
1398 physDevSrc->org.y + visRectSrc.top,
1400 physDevDst->org.x + visRectDst.left,
1401 physDevDst->org.y + visRectDst.top );
1402 physDevDst->exposures++;
1403 wine_tsx11_unlock();
1406 if (dcSrc->bitsPerPixel == 1)
1409 XSetBackground( gdi_display, physDevDst->gc, physDevDst->textPixel );
1410 XSetForeground( gdi_display, physDevDst->gc, physDevDst->backgroundPixel );
1411 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1412 XCopyPlane( gdi_display, physDevSrc->drawable,
1413 physDevDst->drawable, physDevDst->gc,
1414 physDevSrc->org.x + visRectSrc.left,
1415 physDevSrc->org.y + visRectSrc.top,
1417 physDevDst->org.x + visRectDst.left,
1418 physDevDst->org.y + visRectDst.top, 1 );
1419 physDevDst->exposures++;
1420 wine_tsx11_unlock();
1425 case PATCOPY: /* 0xf0 */
1426 if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1428 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1429 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1430 physDevDst->org.x + visRectDst.left,
1431 physDevDst->org.y + visRectDst.top,
1433 wine_tsx11_unlock();
1436 case WHITENESS: /* 0xff */
1438 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1439 XSetFunction( gdi_display, physDevDst->gc, GXset );
1442 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1443 XSetForeground( gdi_display, physDevDst->gc,
1444 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1445 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1447 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1448 physDevDst->org.x + visRectDst.left,
1449 physDevDst->org.y + visRectDst.top,
1451 wine_tsx11_unlock();
1457 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1458 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1459 XSetGraphicsExposures( gdi_display, tmpGC, False );
1460 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1461 dcDst->bitsPerPixel );
1464 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1465 dcDst->bitsPerPixel );
1467 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1468 xSrc, ySrc, widthSrc, heightSrc,
1469 xDst, yDst, widthDst, heightDst,
1470 &visRectSrc, &visRectDst );
1472 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1473 xSrc, ySrc, &visRectSrc );
1476 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1477 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1478 else fNullBrush = FALSE;
1481 for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1483 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1484 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1485 switch(OP_SRCDST(*opcode))
1487 case OP_ARGS(DST,TMP):
1488 case OP_ARGS(SRC,TMP):
1490 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1492 dcDst->bitsPerPixel );
1494 case OP_ARGS(DST,SRC):
1495 case OP_ARGS(SRC,DST):
1496 case OP_ARGS(TMP,SRC):
1497 case OP_ARGS(TMP,DST):
1498 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1499 pixmaps[OP_DST(*opcode)], tmpGC,
1500 0, 0, width, height, 0, 0 );
1503 case OP_ARGS(PAT,TMP):
1504 if (!pixmaps[TMP] && !fNullBrush)
1505 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1507 dcDst->bitsPerPixel );
1509 case OP_ARGS(PAT,DST):
1510 case OP_ARGS(PAT,SRC):
1512 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1513 tmpGC, 0, 0, width, height );
1517 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1518 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1520 XFreePixmap( gdi_display, pixmaps[DST] );
1521 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1522 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1523 XFreeGC( gdi_display, tmpGC );
1524 wine_tsx11_unlock();
1529 /***********************************************************************
1532 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1536 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1537 result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1538 X11DRV_UnlockDIBSection( physDev, TRUE );
1543 /***********************************************************************
1546 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1547 INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1548 INT xSrc, INT ySrc, DWORD rop )
1550 BOOL result = FALSE;
1552 RECT visRectDst, visRectSrc;
1553 DC *dcSrc = physDevSrc ? physDevSrc->dc : NULL;
1554 DC *dcDst = physDevDst->dc;
1556 if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1557 /* FIXME: seems the ROP doesn't include destination;
1558 * now if the destination area include the entire dcDst,
1559 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1560 * which may avoid a copy in some situations */
1562 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1563 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1565 if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1566 (dcSrc->bitsPerPixel == dcDst->bitsPerPixel))
1569 /* do everything ourselves; map coordinates */
1573 pts[1].x = xSrc + width;
1574 pts[1].y = ySrc + height;
1576 LPtoDP(physDevSrc->hdc, pts, 2);
1577 width = pts[1].x - pts[0].x;
1578 height = pts[1].y - pts[0].y;
1584 LPtoDP(physDevDst->hdc, pts, 1);
1589 /* Perform basic clipping */
1590 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, width, height,
1591 dcSrc, xSrc, ySrc, width, height,
1592 &visRectSrc, &visRectDst ))
1595 xSrc = visRectSrc.left;
1596 ySrc = visRectSrc.top;
1597 xDst = visRectDst.left;
1598 yDst = visRectDst.top;
1599 width = visRectDst.right - visRectDst.left;
1600 height = visRectDst.bottom - visRectDst.top;
1602 if (sDst == DIB_Status_AppMod) {
1603 FIXME("potential optimization - client-side DIB copy\n");
1605 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1607 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1612 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1613 if (physDevDst != physDevSrc)
1614 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1616 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1617 physDevSrc, xSrc, ySrc, width, height, rop );
1620 if (physDevDst != physDevSrc)
1621 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1622 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1628 /***********************************************************************
1631 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1632 INT widthDst, INT heightDst,
1633 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1634 INT widthSrc, INT heightSrc, DWORD rop )
1638 X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1639 if (physDevDst != physDevSrc)
1640 X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1642 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1643 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1645 if (physDevDst != physDevSrc)
1646 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1647 X11DRV_UnlockDIBSection( physDevDst, TRUE );