2 * GDI bit-blit operations
4 * Copyright 1993, 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <X11/Intrinsic.h>
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
41 #define DST 0 /* Destination drawable */
42 #define SRC 1 /* Source drawable */
43 #define TMP 2 /* Temporary drawable */
44 #define PAT 3 /* Pattern (brush) in destination DC */
46 #define OP(src,dst,rop) (OP_ARGS(src,dst) << 4 | (rop))
47 #define OP_ARGS(src,dst) (((src) << 2) | (dst))
49 #define OP_SRC(opcode) ((opcode) >> 6)
50 #define OP_DST(opcode) (((opcode) >> 4) & 3)
51 #define OP_SRCDST(opcode) ((opcode) >> 4)
52 #define OP_ROP(opcode) ((opcode) & 0x0f)
54 #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */
56 #define SWAP_INT32(i1,i2) \
57 do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
59 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
61 { OP(PAT,DST,GXclear) }, /* 0x00 0 */
62 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */
63 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */
64 { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */
65 { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */
66 { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */
67 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */
68 { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */
69 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */
70 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */
71 { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */
72 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */
73 { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */
74 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */
75 { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */
76 { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */
77 { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */
78 { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */
79 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */
80 { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */
81 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */
82 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */
83 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
84 OP(TMP,DST,GXand), OP(SRC,DST,GXxor),
85 OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */
86 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
87 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
88 OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/
89 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
90 OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */
91 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
92 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */
93 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
94 OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */
95 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXxor),
96 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */
97 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
98 OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */
99 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
100 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */
101 { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */
102 { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */
103 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */
104 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */
105 { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */
106 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */
107 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
108 OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */
109 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
110 OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */
111 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
112 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
113 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXequiv),
114 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */
115 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */
116 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
117 OP(TMP,DST,GXor), OP(SRC,DST,GXxor),
118 OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */
119 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */
120 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
121 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
122 OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/
123 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
124 OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */
125 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */
126 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
127 OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */
128 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */
129 { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */
130 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */
131 { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
132 OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */
133 { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */
134 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
135 OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */
136 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
137 OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */
138 { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */
139 { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */
140 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
141 OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */
142 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */
143 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
144 OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */
145 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */
146 { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */
147 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
148 OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */
149 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
150 OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */
151 { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */
152 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */
153 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */
154 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
155 OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */
156 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
157 OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */
158 { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */
159 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */
160 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
161 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */
162 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
163 OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */
164 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */
165 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
166 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
167 OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */
168 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
169 OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */
170 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */
171 { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */
172 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
173 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
174 OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/
175 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
176 OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */
177 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */
178 { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */
179 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */
180 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
181 OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */
182 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
183 OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */
184 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */
185 { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */
186 { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */
187 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */
188 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
189 OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */
190 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */
191 { OP(PAT,DST,GXxor) }, /* 0x5a D^P */
192 { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
193 OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */
194 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
195 OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */
196 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */
197 { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
198 OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */
199 { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */
200 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */
201 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
202 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
203 OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */
204 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
205 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */
206 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */
207 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
208 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */
209 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */
210 { OP(SRC,DST,GXxor) }, /* 0x66 S^D */
211 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
212 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */
213 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
214 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
215 OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/
216 { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */
217 { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */
218 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
219 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
220 OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */
221 { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */
222 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
223 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
224 OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */
225 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
226 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */
227 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */
228 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */
229 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
230 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
231 OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/
232 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
233 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */
234 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */
235 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
236 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */
237 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */
238 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
239 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */
240 { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */
241 { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */
242 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
243 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
244 OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */
245 { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
246 OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */
247 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */
248 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
249 OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */
250 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */
251 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
252 OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */
253 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */
254 { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */
255 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
256 OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */
257 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */
258 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
259 OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */
260 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */
261 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
262 OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */
263 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
264 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
265 OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */
266 { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */
267 { OP(SRC,DST,GXand) }, /* 0x88 S&D */
268 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
269 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */
270 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */
271 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
272 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */
273 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */
274 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
275 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */
276 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
277 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
278 OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/
279 { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */
280 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */
281 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
282 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */
283 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
284 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
285 OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */
286 { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */
287 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
288 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
289 OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */
290 { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */
291 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */
292 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
293 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
294 OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */
295 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
296 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */
297 { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */
298 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */
299 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
300 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */
301 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */
302 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
303 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */
304 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
305 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
306 OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */
307 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */
308 { OP(PAT,DST,GXand) }, /* 0xa0 D&P */
309 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
310 OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */
311 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */
312 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
313 OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */
314 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
315 OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */
316 { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */
317 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */
318 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
319 OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */
320 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */
321 { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */
322 { OP(SRC,DST,GXnoop) }, /* 0xaa D */
323 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */
324 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
325 OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */
326 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
327 OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */
328 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */
329 { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */
330 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */
331 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
332 OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */
333 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
334 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
335 OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/
336 { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */
337 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */
338 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
339 OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */
340 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
341 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
342 OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */
343 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */
344 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
345 OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */
346 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
347 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */
348 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */
349 { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */
350 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
351 OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */
352 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
353 OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */
354 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */
355 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */
356 { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */
357 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
358 OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */
359 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
360 OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */
361 { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */
362 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */
363 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
364 OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */
365 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */
366 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
367 OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */
368 { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */
369 { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */
370 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
371 OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */
372 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
373 OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */
374 { OP(SRC,DST,GXcopy) }, /* 0xcc S */
375 { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */
376 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */
377 { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */
378 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */
379 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
380 OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */
381 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */
382 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
383 OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */
384 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
385 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
386 OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/
387 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */
388 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
389 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
390 OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */
391 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */
392 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
393 OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */
394 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
395 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */
396 { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
397 OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */
398 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
399 OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */
400 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */
401 { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */
402 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */
403 { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */
404 { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */
405 { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */
406 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
407 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */
408 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
409 OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */
410 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
411 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */
412 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
413 OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */
414 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
415 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */
416 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
417 OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */
418 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
419 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
420 OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/
421 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
422 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
423 OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/
424 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */
425 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */
426 { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */
427 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */
428 { OP(SRC,DST,GXor) }, /* 0xee S|D */
429 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */
430 { OP(PAT,DST,GXcopy) }, /* 0xf0 P */
431 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */
432 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */
433 { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */
434 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */
435 { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */
436 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */
437 { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */
438 { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */
439 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */
440 { OP(PAT,DST,GXor) }, /* 0xfa D|P */
441 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */
442 { OP(PAT,SRC,GXor) }, /* 0xfc P|S */
443 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */
444 { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */
445 { OP(PAT,DST,GXset) } /* 0xff 1 */
449 #ifdef BITBLT_TEST /* Opcodes test */
451 static int do_bitop( int s, int d, int rop )
456 case GXclear: res = 0; break;
457 case GXand: res = s & d; break;
458 case GXandReverse: res = s & ~d; break;
459 case GXcopy: res = s; break;
460 case GXandInverted: res = ~s & d; break;
461 case GXnoop: res = d; break;
462 case GXxor: res = s ^ d; break;
463 case GXor: res = s | d; break;
464 case GXnor: res = ~(s | d); break;
465 case GXequiv: res = ~s ^ d; break;
466 case GXinvert: res = ~d; break;
467 case GXorReverse: res = s | ~d; break;
468 case GXcopyInverted: res = ~s; break;
469 case GXorInverted: res = ~s | d; break;
470 case GXnand: res = ~(s & d); break;
471 case GXset: res = 1; break;
478 int rop, i, res, src, dst, pat, tmp, dstUsed;
481 for (rop = 0; rop < 256; rop++)
484 for (i = 0; i < 8; i++)
489 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
493 case OP_ARGS(DST,TMP):
494 tmp = do_bitop( dst, tmp, *opcode & 0xf );
496 case OP_ARGS(DST,SRC):
497 src = do_bitop( dst, src, *opcode & 0xf );
499 case OP_ARGS(SRC,TMP):
500 tmp = do_bitop( src, tmp, *opcode & 0xf );
502 case OP_ARGS(SRC,DST):
503 dst = do_bitop( src, dst, *opcode & 0xf );
506 case OP_ARGS(PAT,TMP):
507 tmp = do_bitop( pat, tmp, *opcode & 0xf );
509 case OP_ARGS(PAT,DST):
510 dst = do_bitop( pat, dst, *opcode & 0xf );
513 case OP_ARGS(PAT,SRC):
514 src = do_bitop( pat, src, *opcode & 0xf );
516 case OP_ARGS(TMP,DST):
517 dst = do_bitop( tmp, dst, *opcode & 0xf );
520 case OP_ARGS(TMP,SRC):
521 src = do_bitop( tmp, src, *opcode & 0xf );
524 printf( "Invalid opcode %x\n", *opcode );
527 if (!dstUsed) dst = src;
528 if (dst) res |= 1 << i;
530 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
536 #endif /* BITBLT_TEST */
539 /***********************************************************************
542 * Favor correctness or speed?
544 static int perfect_graphics(void)
546 static int perfect = -1;
553 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
555 DWORD type, count = sizeof(buffer);
556 if(!RegQueryValueExA(hkey, "PerfectGraphics", 0, &type, buffer, &count))
559 perfect = (ch == 'y' || ch == 'Y' || ch == 't' || ch == 'T' || ch == '1');
567 /***********************************************************************
570 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
572 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
573 INT startDst, INT widthDst,
574 INT xinc, INT xoff, WORD mode )
576 register INT xsrc = xinc * startDst + xoff;
580 case STRETCH_ANDSCANS:
581 for(; widthDst > 0; widthDst--, xsrc += xinc)
582 *rowDst++ &= rowSrc[xsrc >> 16];
584 case STRETCH_ORSCANS:
585 for(; widthDst > 0; widthDst--, xsrc += xinc)
586 *rowDst++ |= rowSrc[xsrc >> 16];
588 case STRETCH_DELETESCANS:
589 for(; widthDst > 0; widthDst--, xsrc += xinc)
590 *rowDst++ = rowSrc[xsrc >> 16];
596 /***********************************************************************
599 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
601 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
602 INT startSrc, INT widthSrc,
603 INT xinc, INT xoff, WORD mode )
605 register INT xdst = xinc * startSrc + xoff;
609 case STRETCH_ORSCANS:
610 for(; widthSrc > 0; widthSrc--, xdst += xinc)
611 rowDst[xdst >> 16] |= *rowSrc++;
613 case STRETCH_ANDSCANS:
614 for(; widthSrc > 0; widthSrc--, xdst += xinc)
615 rowDst[xdst >> 16] &= *rowSrc++;
617 case STRETCH_DELETESCANS:
618 for(; widthSrc > 0; widthSrc--, xdst += xinc)
619 rowDst[xdst >> 16] = *rowSrc++;
625 /***********************************************************************
628 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
630 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
631 INT start, INT width, INT depthDst,
632 int fg, int bg, BOOL swap)
636 assert( (row >= 0) && (row < image->height) );
637 assert( (start >= 0) && (width <= image->width) );
639 pdata += swap ? start+width-1 : start;
640 if (image->depth == depthDst) /* color -> color */
642 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
643 if (swap) for (i = 0; i < width; i++)
644 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
645 else for (i = 0; i < width; i++)
646 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
648 if (swap) for (i = 0; i < width; i++)
649 *pdata-- = XGetPixel( image, i, row );
650 else for (i = 0; i < width; i++)
651 *pdata++ = XGetPixel( image, i, row );
655 if (image->depth == 1) /* monochrome -> color */
657 if (X11DRV_PALETTE_XPixelToPalette)
659 fg = X11DRV_PALETTE_XPixelToPalette[fg];
660 bg = X11DRV_PALETTE_XPixelToPalette[bg];
662 if (swap) for (i = 0; i < width; i++)
663 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
664 else for (i = 0; i < width; i++)
665 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
667 else /* color -> monochrome */
669 if (swap) for (i = 0; i < width; i++)
670 *pdata-- = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
671 else for (i = 0; i < width; i++)
672 *pdata++ = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
678 /***********************************************************************
679 * BITBLT_StretchImage
681 * Stretch an X image.
682 * FIXME: does not work for full 32-bit coordinates.
684 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
685 INT widthSrc, INT heightSrc,
686 INT widthDst, INT heightDst,
687 RECT *visRectSrc, RECT *visRectDst,
688 int foreground, int background, WORD mode )
690 int *rowSrc, *rowDst, *pixel;
692 INT xinc, xoff, yinc, ysrc, ydst;
694 BOOL hstretch, vstretch, hswap, vswap;
696 hswap = ((int)widthSrc * widthDst) < 0;
697 vswap = ((int)heightSrc * heightDst) < 0;
698 widthSrc = abs(widthSrc);
699 heightSrc = abs(heightSrc);
700 widthDst = abs(widthDst);
701 heightDst = abs(heightDst);
703 if (!(rowSrc = (int *)HeapAlloc( GetProcessHeap(), 0,
704 (widthSrc+widthDst)*sizeof(int) ))) return;
705 rowDst = rowSrc + widthSrc;
707 /* When stretching, all modes are the same, and DELETESCANS is faster */
708 if ((widthSrc < widthDst) && (heightSrc < heightDst))
709 mode = STRETCH_DELETESCANS;
711 if (mode == STRETCH_HALFTONE) /* FIXME */
712 mode = STRETCH_DELETESCANS;
714 if (mode != STRETCH_DELETESCANS)
715 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
716 widthDst*sizeof(int) );
718 hstretch = (widthSrc < widthDst);
719 vstretch = (heightSrc < heightDst);
723 xinc = ((int)widthSrc << 16) / widthDst;
724 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
728 xinc = ((int)widthDst << 16) / widthSrc;
729 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
734 yinc = ((int)heightSrc << 16) / heightDst;
735 ydst = visRectDst->top;
738 ysrc = yinc * (heightDst - ydst - 1);
744 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
746 if (((ysrc >> 16) < visRectSrc->top) ||
747 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
749 /* Retrieve a source row */
750 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
751 hswap ? widthSrc - visRectSrc->right
753 visRectSrc->right - visRectSrc->left,
754 dstImage->depth, foreground, background, hswap );
756 /* Stretch or shrink it */
758 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
759 visRectDst->right - visRectDst->left,
761 else BITBLT_ShrinkRow( rowSrc, rowDst,
762 hswap ? widthSrc - visRectSrc->right
764 visRectSrc->right - visRectSrc->left,
767 /* Store the destination row */
768 pixel = rowDst + visRectDst->right - 1;
769 y = ydst - visRectDst->top;
770 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
771 XPutPixel( dstImage, x, y, *pixel-- );
772 if (mode != STRETCH_DELETESCANS)
773 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
774 widthDst*sizeof(int) );
776 /* Make copies of the destination row */
778 pdata = dstImage->data + dstImage->bytes_per_line * y;
779 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
780 (ydst < visRectDst->bottom-1))
782 memcpy( pdata + dstImage->bytes_per_line, pdata,
783 dstImage->bytes_per_line );
784 pdata += dstImage->bytes_per_line;
792 yinc = ((int)heightDst << 16) / heightSrc;
793 ysrc = visRectSrc->top;
794 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
797 ydst += yinc * (heightSrc - ysrc - 1);
803 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
805 if (((ydst >> 16) < visRectDst->top) ||
806 ((ydst >> 16) >= visRectDst->bottom)) continue;
808 /* Retrieve a source row */
809 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
810 hswap ? widthSrc - visRectSrc->right
812 visRectSrc->right - visRectSrc->left,
813 dstImage->depth, foreground, background, hswap );
815 /* Stretch or shrink it */
817 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
818 visRectDst->right - visRectDst->left,
820 else BITBLT_ShrinkRow( rowSrc, rowDst,
821 hswap ? widthSrc - visRectSrc->right
823 visRectSrc->right - visRectSrc->left,
826 /* Merge several source rows into the destination */
827 if (mode == STRETCH_DELETESCANS)
829 /* Simply skip the overlapping rows */
830 while (((ydst + yinc) >> 16 == ydst >> 16) &&
831 (ysrc < visRectSrc->bottom-1))
837 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
838 (ysrc < visRectSrc->bottom-1))
839 continue; /* Restart loop for next overlapping row */
841 /* Store the destination row */
842 pixel = rowDst + visRectDst->right - 1;
843 y = (ydst >> 16) - visRectDst->top;
844 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
845 XPutPixel( dstImage, x, y, *pixel-- );
846 if (mode != STRETCH_DELETESCANS)
847 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
848 widthDst*sizeof(int) );
851 HeapFree( GetProcessHeap(), 0, rowSrc );
855 /***********************************************************************
856 * BITBLT_GetSrcAreaStretch
858 * Retrieve an area from the source DC, stretching and mapping all the
859 * pixels to Windows colors.
861 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
862 Pixmap pixmap, GC gc,
864 INT widthSrc, INT heightSrc,
866 INT widthDst, INT heightDst,
867 RECT *visRectSrc, RECT *visRectDst )
869 XImage *imageSrc, *imageDst;
870 RECT rectSrc = *visRectSrc;
871 RECT rectDst = *visRectDst;
873 if (widthSrc < 0) xSrc += widthSrc;
874 if (widthDst < 0) xDst += widthDst;
875 if (heightSrc < 0) ySrc += heightSrc;
876 if (heightDst < 0) yDst += heightDst;
877 rectSrc.left -= xSrc;
878 rectSrc.right -= xSrc;
880 rectSrc.bottom -= ySrc;
881 rectDst.left -= xDst;
882 rectDst.right -= xDst;
884 rectDst.bottom -= yDst;
886 /* FIXME: avoid BadMatch errors */
887 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
888 physDevSrc->org.x + visRectSrc->left,
889 physDevSrc->org.y + visRectSrc->top,
890 visRectSrc->right - visRectSrc->left,
891 visRectSrc->bottom - visRectSrc->top,
892 AllPlanes, ZPixmap );
893 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
894 rectDst.bottom - rectDst.top, physDevDst->depth );
895 BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
896 widthDst, heightDst, &rectSrc, &rectDst,
897 physDevDst->textPixel, physDevDst->depth != 1 ?
898 physDevDst->backgroundPixel :
899 physDevSrc->backgroundPixel,
900 GetStretchBltMode(physDevDst->hdc) );
901 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
902 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
903 XDestroyImage( imageSrc );
904 XDestroyImage( imageDst );
905 return 0; /* no exposure events generated */
909 /***********************************************************************
912 * Retrieve an area from the source DC, mapping all the
913 * pixels to Windows colors.
915 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
916 Pixmap pixmap, GC gc, INT xSrc, INT ySrc, RECT *visRectSrc )
918 XImage *imageSrc, *imageDst;
921 INT width = visRectSrc->right - visRectSrc->left;
922 INT height = visRectSrc->bottom - visRectSrc->top;
924 if (physDevSrc->depth == physDevDst->depth)
926 if (!X11DRV_PALETTE_XPixelToPalette ||
927 (physDevDst->depth == 1)) /* monochrome -> monochrome */
929 if (physDevDst->depth == 1)
931 /* MSDN says if StretchBlt must convert a bitmap from monochrome
932 to color or vice versa, the forground and background color of
933 the device context are used. In fact, it also applies to the
934 case when it is converted from mono to mono. */
935 XSetBackground( gdi_display, gc, physDevDst->textPixel );
936 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
937 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
938 physDevSrc->org.x + visRectSrc->left,
939 physDevSrc->org.y + visRectSrc->top,
940 width, height, 0, 0, 1);
943 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
944 physDevSrc->org.x + visRectSrc->left,
945 physDevSrc->org.y + visRectSrc->top,
946 width, height, 0, 0);
949 else /* color -> color */
951 if (GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
952 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
953 physDevSrc->org.x + visRectSrc->left,
954 physDevSrc->org.y + visRectSrc->top,
955 width, height, AllPlanes, ZPixmap );
958 /* Make sure we don't get a BadMatch error */
959 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
960 physDevSrc->org.x + visRectSrc->left,
961 physDevSrc->org.y + visRectSrc->top,
962 width, height, 0, 0);
964 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
965 AllPlanes, ZPixmap );
967 for (y = 0; y < height; y++)
968 for (x = 0; x < width; x++)
969 XPutPixel(imageSrc, x, y,
970 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
971 XPutImage( gdi_display, pixmap, gc, imageSrc,
972 0, 0, 0, 0, width, height );
973 XDestroyImage( imageSrc );
978 if (physDevSrc->depth == 1) /* monochrome -> color */
980 if (X11DRV_PALETTE_XPixelToPalette)
982 XSetBackground( gdi_display, gc,
983 X11DRV_PALETTE_XPixelToPalette[physDevDst->textPixel] );
984 XSetForeground( gdi_display, gc,
985 X11DRV_PALETTE_XPixelToPalette[physDevDst->backgroundPixel]);
989 XSetBackground( gdi_display, gc, physDevDst->textPixel );
990 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
992 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
993 physDevSrc->org.x + visRectSrc->left,
994 physDevSrc->org.y + visRectSrc->top,
995 width, height, 0, 0, 1 );
998 else /* color -> monochrome */
1000 /* FIXME: avoid BadMatch error */
1001 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1002 physDevSrc->org.x + visRectSrc->left,
1003 physDevSrc->org.y + visRectSrc->top,
1004 width, height, AllPlanes, ZPixmap );
1009 imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1012 XDestroyImage(imageSrc);
1015 for (y = 0; y < height; y++)
1016 for (x = 0; x < width; x++)
1017 XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1018 physDevSrc->backgroundPixel) );
1019 XPutImage( gdi_display, pixmap, gc, imageDst,
1020 0, 0, 0, 0, width, height );
1021 XDestroyImage( imageSrc );
1022 XDestroyImage( imageDst );
1029 /***********************************************************************
1032 * Retrieve an area from the destination DC, mapping all the
1033 * pixels to Windows colors.
1035 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1038 INT width = visRectDst->right - visRectDst->left;
1039 INT height = visRectDst->bottom - visRectDst->top;
1041 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1042 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1044 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1045 physDev->org.x + visRectDst->left, physDev->org.y + visRectDst->top,
1046 width, height, 0, 0 );
1054 if (GetObjectType( physDev->hdc ) == OBJ_MEMDC)
1055 image = XGetImage( gdi_display, physDev->drawable,
1056 physDev->org.x + visRectDst->left,
1057 physDev->org.y + visRectDst->top,
1058 width, height, AllPlanes, ZPixmap );
1061 /* Make sure we don't get a BadMatch error */
1062 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1063 physDev->org.x + visRectDst->left,
1064 physDev->org.y + visRectDst->top,
1065 width, height, 0, 0);
1067 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1068 AllPlanes, ZPixmap );
1070 for (y = 0; y < height; y++)
1071 for (x = 0; x < width; x++)
1072 XPutPixel( image, x, y,
1073 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1074 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1075 XDestroyImage( image );
1081 /***********************************************************************
1084 * Put an area back into the destination DC, mapping the pixel
1085 * colors to X pixels.
1087 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1090 INT width = visRectDst->right - visRectDst->left;
1091 INT height = visRectDst->bottom - visRectDst->top;
1093 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1095 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1096 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1098 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1099 physDev->org.x + visRectDst->left,
1100 physDev->org.y + visRectDst->top );
1106 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1107 AllPlanes, ZPixmap );
1108 for (y = 0; y < height; y++)
1109 for (x = 0; x < width; x++)
1111 XPutPixel( image, x, y,
1112 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1114 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1115 physDev->org.x + visRectDst->left,
1116 physDev->org.y + visRectDst->top, width, height );
1117 XDestroyImage( image );
1123 /***********************************************************************
1124 * BITBLT_GetVisRectangles
1126 * Get the source and destination visible rectangles for StretchBlt().
1127 * Return FALSE if one of the rectangles is empty.
1129 static BOOL BITBLT_GetVisRectangles( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1130 INT widthDst, INT heightDst,
1131 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1132 INT widthSrc, INT heightSrc,
1133 RECT *visRectSrc, RECT *visRectDst )
1135 RECT rect, clipRect;
1136 DC *dcSrc = physDevSrc ? physDevSrc->dc : NULL;
1137 DC *dcDst = physDevDst->dc;
1139 /* Get the destination visible rectangle */
1143 rect.right = xDst + widthDst;
1144 rect.bottom = yDst + heightDst;
1145 if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1146 if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1147 GetRgnBox( dcDst->hGCClipRgn, &clipRect );
1148 if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1150 /* Get the source visible rectangle */
1152 if (!physDevSrc) return TRUE;
1155 rect.right = xSrc + widthSrc;
1156 rect.bottom = ySrc + heightSrc;
1157 if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1158 if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1159 /* Apparently the clipping and visible regions are only for output,
1160 so just check against totalExtent here to avoid BadMatch errors */
1161 if (!IntersectRect( visRectSrc, &rect, &dcSrc->totalExtent ))
1164 /* Intersect the rectangles */
1166 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1168 visRectSrc->left += xDst - xSrc;
1169 visRectSrc->right += xDst - xSrc;
1170 visRectSrc->top += yDst - ySrc;
1171 visRectSrc->bottom += yDst - ySrc;
1172 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1173 *visRectSrc = *visRectDst = rect;
1174 visRectSrc->left += xSrc - xDst;
1175 visRectSrc->right += xSrc - xDst;
1176 visRectSrc->top += ySrc - yDst;
1177 visRectSrc->bottom += ySrc - yDst;
1179 else /* stretching */
1181 /* Map source rectangle into destination coordinates */
1182 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1183 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1184 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1185 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1186 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1187 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1189 /* Avoid rounding errors */
1194 if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1196 /* Map destination rectangle back to source coordinates */
1198 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1199 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1200 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1201 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1202 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1203 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1205 /* Avoid rounding errors */
1210 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1216 /***********************************************************************
1217 * BITBLT_InternalStretchBlt
1219 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1221 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1222 INT widthDst, INT heightDst,
1223 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1224 INT widthSrc, INT heightSrc,
1227 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1228 RECT visRectDst, visRectSrc;
1231 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1235 /* compensate for off-by-one shifting for negative widths and heights */
1245 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1246 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1247 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1248 if (!physDevSrc && useSrc) return FALSE;
1250 /* Map the coordinates to device coords */
1254 pts[1].x = xDst + widthDst;
1255 pts[1].y = yDst + heightDst;
1256 LPtoDP(physDevDst->hdc, pts, 2);
1259 widthDst = pts[1].x - pts[0].x;
1260 heightDst = pts[1].y - pts[0].y;
1262 TRACE(" rectdst=%d,%d-%d,%d orgdst=%ld,%ld\n",
1263 xDst, yDst, widthDst, heightDst,
1264 physDevDst->org.x, physDevDst->org.y );
1270 pts[1].x = xSrc + widthSrc;
1271 pts[1].y = ySrc + heightSrc;
1272 LPtoDP(physDevSrc->hdc, pts, 2);
1275 widthSrc = pts[1].x - pts[0].x;
1276 heightSrc = pts[1].y - pts[0].y;
1278 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1279 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%ld,%ld\n",
1280 xSrc, ySrc, widthSrc, heightSrc,
1281 physDevSrc->org.x, physDevSrc->org.y );
1282 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1283 physDevSrc, xSrc, ySrc, widthSrc, heightSrc,
1284 &visRectSrc, &visRectDst ))
1286 TRACE(" vissrc=%ld,%ld-%ld,%ld visdst=%ld,%ld-%ld,%ld\n",
1287 visRectSrc.left, visRectSrc.top,
1288 visRectSrc.right, visRectSrc.bottom,
1289 visRectDst.left, visRectDst.top,
1290 visRectDst.right, visRectDst.bottom );
1295 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1296 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1298 TRACE(" vissrc=none visdst=%ld,%ld-%ld,%ld\n",
1299 visRectDst.left, visRectDst.top,
1300 visRectDst.right, visRectDst.bottom );
1303 width = visRectDst.right - visRectDst.left;
1304 height = visRectDst.bottom - visRectDst.top;
1306 if (!fStretch) switch(rop) /* A few optimisations */
1308 case BLACKNESS: /* 0x00 */
1310 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1311 XSetFunction( gdi_display, physDevDst->gc, GXclear );
1314 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1315 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1316 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1318 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1319 physDevDst->org.x + visRectDst.left,
1320 physDevDst->org.y + visRectDst.top,
1322 wine_tsx11_unlock();
1325 case DSTINVERT: /* 0x55 */
1326 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel ||
1327 !perfect_graphics())
1330 XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1332 if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1333 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1336 /* Xor is much better when we do not have full colormap. */
1337 /* Using white^black ensures that we invert at least black */
1339 Pixel xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1340 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1341 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1342 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1343 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1345 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1346 physDevDst->org.x + visRectDst.left,
1347 physDevDst->org.y + visRectDst.top,
1349 wine_tsx11_unlock();
1354 case PATINVERT: /* 0x5a */
1355 if (perfect_graphics()) break;
1356 if (X11DRV_SetupGCForBrush( physDevDst ))
1359 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1360 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1361 physDevDst->org.x + visRectDst.left,
1362 physDevDst->org.y + visRectDst.top,
1364 wine_tsx11_unlock();
1369 if (perfect_graphics()) break;
1370 if (X11DRV_SetupGCForBrush( physDevDst ))
1373 XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1374 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1375 physDevDst->org.x + visRectDst.left,
1376 physDevDst->org.y + visRectDst.top,
1378 wine_tsx11_unlock();
1382 case SRCCOPY: /* 0xcc */
1383 if (physDevSrc->depth == physDevDst->depth)
1386 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1387 XCopyArea( gdi_display, physDevSrc->drawable,
1388 physDevDst->drawable, physDevDst->gc,
1389 physDevSrc->org.x + visRectSrc.left,
1390 physDevSrc->org.y + visRectSrc.top,
1392 physDevDst->org.x + visRectDst.left,
1393 physDevDst->org.y + visRectDst.top );
1394 physDevDst->exposures++;
1395 wine_tsx11_unlock();
1398 if (physDevSrc->depth == 1)
1401 XSetBackground( gdi_display, physDevDst->gc, physDevDst->textPixel );
1402 XSetForeground( gdi_display, physDevDst->gc, physDevDst->backgroundPixel );
1403 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1404 XCopyPlane( gdi_display, physDevSrc->drawable,
1405 physDevDst->drawable, physDevDst->gc,
1406 physDevSrc->org.x + visRectSrc.left,
1407 physDevSrc->org.y + visRectSrc.top,
1409 physDevDst->org.x + visRectDst.left,
1410 physDevDst->org.y + visRectDst.top, 1 );
1411 physDevDst->exposures++;
1412 wine_tsx11_unlock();
1417 case PATCOPY: /* 0xf0 */
1418 if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1420 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1421 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1422 physDevDst->org.x + visRectDst.left,
1423 physDevDst->org.y + visRectDst.top,
1425 wine_tsx11_unlock();
1428 case WHITENESS: /* 0xff */
1430 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1431 XSetFunction( gdi_display, physDevDst->gc, GXset );
1434 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1435 XSetForeground( gdi_display, physDevDst->gc,
1436 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1437 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1439 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1440 physDevDst->org.x + visRectDst.left,
1441 physDevDst->org.y + visRectDst.top,
1443 wine_tsx11_unlock();
1449 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1450 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1451 XSetGraphicsExposures( gdi_display, tmpGC, False );
1452 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1453 physDevDst->depth );
1456 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1457 physDevDst->depth );
1459 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1460 xSrc, ySrc, widthSrc, heightSrc,
1461 xDst, yDst, widthDst, heightDst,
1462 &visRectSrc, &visRectDst );
1464 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1465 xSrc, ySrc, &visRectSrc );
1468 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1469 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1470 else fNullBrush = FALSE;
1473 for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1475 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1476 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1477 switch(OP_SRCDST(*opcode))
1479 case OP_ARGS(DST,TMP):
1480 case OP_ARGS(SRC,TMP):
1482 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1483 width, height, physDevDst->depth );
1485 case OP_ARGS(DST,SRC):
1486 case OP_ARGS(SRC,DST):
1487 case OP_ARGS(TMP,SRC):
1488 case OP_ARGS(TMP,DST):
1490 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1491 pixmaps[OP_DST(*opcode)], tmpGC,
1492 0, 0, width, height, 0, 0 );
1495 case OP_ARGS(PAT,TMP):
1496 if (!pixmaps[TMP] && !fNullBrush)
1497 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1498 width, height, physDevDst->depth );
1500 case OP_ARGS(PAT,DST):
1501 case OP_ARGS(PAT,SRC):
1503 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1504 tmpGC, 0, 0, width, height );
1508 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1509 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1511 XFreePixmap( gdi_display, pixmaps[DST] );
1512 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1513 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1514 XFreeGC( gdi_display, tmpGC );
1515 wine_tsx11_unlock();
1520 /***********************************************************************
1523 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1527 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1528 result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1529 X11DRV_UnlockDIBSection( physDev, TRUE );
1534 /***********************************************************************
1537 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1538 INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1539 INT xSrc, INT ySrc, DWORD rop )
1541 BOOL result = FALSE;
1543 RECT visRectDst, visRectSrc;
1545 if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1546 /* FIXME: seems the ROP doesn't include destination;
1547 * now if the destination area include the entire dcDst,
1548 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1549 * which may avoid a copy in some situations */
1551 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1552 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1554 if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1555 (physDevSrc->depth == physDevDst->depth))
1558 /* do everything ourselves; map coordinates */
1562 pts[1].x = xSrc + width;
1563 pts[1].y = ySrc + height;
1565 LPtoDP(physDevSrc->hdc, pts, 2);
1566 width = pts[1].x - pts[0].x;
1567 height = pts[1].y - pts[0].y;
1573 LPtoDP(physDevDst->hdc, pts, 1);
1578 /* Perform basic clipping */
1579 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, width, height,
1580 physDevSrc, xSrc, ySrc, width, height,
1581 &visRectSrc, &visRectDst ))
1584 xSrc = visRectSrc.left;
1585 ySrc = visRectSrc.top;
1586 xDst = visRectDst.left;
1587 yDst = visRectDst.top;
1588 width = visRectDst.right - visRectDst.left;
1589 height = visRectDst.bottom - visRectDst.top;
1591 if (sDst == DIB_Status_AppMod) {
1592 FIXME("potential optimization - client-side DIB copy\n");
1594 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1596 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1601 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1602 if (physDevDst != physDevSrc)
1603 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1605 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1606 physDevSrc, xSrc, ySrc, width, height, rop );
1609 if (physDevDst != physDevSrc)
1610 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1611 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1617 /***********************************************************************
1620 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1621 INT widthDst, INT heightDst,
1622 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1623 INT widthSrc, INT heightSrc, DWORD rop )
1627 X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1628 if (physDevDst != physDevSrc)
1629 X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1631 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1632 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1634 if (physDevDst != physDevSrc)
1635 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1636 X11DRV_UnlockDIBSection( physDevDst, TRUE );