2 * GDI bit-blit operations
4 * Copyright 1993, 1994 Alexandre Julliard
5 * Copyright 2006 Damjan Jovanovic
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
39 #define DST 0 /* Destination drawable */
40 #define SRC 1 /* Source drawable */
41 #define TMP 2 /* Temporary drawable */
42 #define PAT 3 /* Pattern (brush) in destination DC */
44 #define OP(src,dst,rop) (OP_ARGS(src,dst) << 4 | (rop))
45 #define OP_ARGS(src,dst) (((src) << 2) | (dst))
47 #define OP_SRC(opcode) ((opcode) >> 6)
48 #define OP_DST(opcode) (((opcode) >> 4) & 3)
49 #define OP_SRCDST(opcode) ((opcode) >> 4)
50 #define OP_ROP(opcode) ((opcode) & 0x0f)
52 #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */
54 #define SWAP_INT32(i1,i2) \
55 do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
57 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
59 { OP(PAT,DST,GXclear) }, /* 0x00 0 */
60 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */
61 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */
62 { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */
63 { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */
64 { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */
65 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */
66 { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */
67 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */
68 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */
69 { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */
70 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */
71 { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */
72 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */
73 { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */
74 { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */
75 { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */
76 { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */
77 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */
78 { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */
79 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */
80 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */
81 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
82 OP(TMP,DST,GXand), OP(SRC,DST,GXxor),
83 OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */
84 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
85 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
86 OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/
87 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
88 OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */
89 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
90 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */
91 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
92 OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */
93 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXxor),
94 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */
95 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
96 OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */
97 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
98 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */
99 { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */
100 { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */
101 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */
102 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */
103 { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */
104 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */
105 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
106 OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */
107 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
108 OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */
109 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
110 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
111 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXequiv),
112 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */
113 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */
114 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
115 OP(TMP,DST,GXor), OP(SRC,DST,GXxor),
116 OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */
117 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */
118 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
119 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
120 OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/
121 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
122 OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */
123 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */
124 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
125 OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */
126 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */
127 { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */
128 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */
129 { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
130 OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */
131 { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */
132 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
133 OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */
134 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
135 OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */
136 { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */
137 { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */
138 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
139 OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */
140 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */
141 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
142 OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */
143 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */
144 { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */
145 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
146 OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */
147 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
148 OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */
149 { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */
150 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */
151 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */
152 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
153 OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */
154 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
155 OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */
156 { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */
157 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */
158 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
159 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */
160 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
161 OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */
162 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */
163 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
164 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
165 OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */
166 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
167 OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */
168 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */
169 { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */
170 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
171 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
172 OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/
173 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
174 OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */
175 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */
176 { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */
177 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */
178 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
179 OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */
180 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
181 OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */
182 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */
183 { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */
184 { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */
185 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */
186 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
187 OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */
188 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */
189 { OP(PAT,DST,GXxor) }, /* 0x5a D^P */
190 { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
191 OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */
192 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
193 OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */
194 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */
195 { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
196 OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */
197 { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */
198 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */
199 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
200 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
201 OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */
202 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
203 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */
204 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */
205 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
206 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */
207 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */
208 { OP(SRC,DST,GXxor) }, /* 0x66 S^D */
209 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
210 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */
211 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
212 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
213 OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/
214 { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */
215 { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */
216 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
217 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
218 OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */
219 { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */
220 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
221 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
222 OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */
223 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
224 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */
225 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */
226 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */
227 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
228 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
229 OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/
230 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
231 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */
232 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */
233 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
234 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */
235 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */
236 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
237 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */
238 { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */
239 { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */
240 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
241 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
242 OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */
243 { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
244 OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */
245 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */
246 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
247 OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */
248 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */
249 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
250 OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */
251 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */
252 { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */
253 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
254 OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */
255 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */
256 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
257 OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */
258 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */
259 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
260 OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */
261 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
262 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
263 OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */
264 { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */
265 { OP(SRC,DST,GXand) }, /* 0x88 S&D */
266 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
267 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */
268 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */
269 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
270 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */
271 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */
272 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
273 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */
274 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
275 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
276 OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/
277 { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */
278 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */
279 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
280 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */
281 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
282 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
283 OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */
284 { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */
285 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
286 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
287 OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */
288 { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */
289 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */
290 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
291 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
292 OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */
293 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
294 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */
295 { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */
296 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */
297 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
298 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */
299 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */
300 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
301 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */
302 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
303 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
304 OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */
305 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */
306 { OP(PAT,DST,GXand) }, /* 0xa0 D&P */
307 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
308 OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */
309 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */
310 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
311 OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */
312 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
313 OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */
314 { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */
315 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */
316 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
317 OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */
318 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */
319 { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */
320 { OP(SRC,DST,GXnoop) }, /* 0xaa D */
321 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */
322 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
323 OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */
324 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
325 OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */
326 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */
327 { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */
328 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */
329 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
330 OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */
331 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
332 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
333 OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/
334 { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */
335 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */
336 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
337 OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */
338 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
339 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
340 OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */
341 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */
342 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
343 OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */
344 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
345 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */
346 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */
347 { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */
348 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
349 OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */
350 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
351 OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */
352 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */
353 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */
354 { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */
355 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
356 OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */
357 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
358 OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */
359 { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */
360 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */
361 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
362 OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */
363 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */
364 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
365 OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */
366 { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */
367 { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */
368 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
369 OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */
370 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
371 OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */
372 { OP(SRC,DST,GXcopy) }, /* 0xcc S */
373 { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */
374 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */
375 { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */
376 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */
377 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
378 OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */
379 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */
380 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
381 OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */
382 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
383 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
384 OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/
385 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */
386 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
387 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
388 OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */
389 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */
390 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
391 OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */
392 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
393 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */
394 { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
395 OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */
396 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
397 OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */
398 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */
399 { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */
400 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */
401 { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */
402 { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */
403 { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */
404 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
405 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */
406 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
407 OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */
408 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
409 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */
410 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
411 OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */
412 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
413 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */
414 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
415 OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */
416 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
417 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
418 OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/
419 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
420 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
421 OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/
422 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */
423 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */
424 { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */
425 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */
426 { OP(SRC,DST,GXor) }, /* 0xee S|D */
427 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */
428 { OP(PAT,DST,GXcopy) }, /* 0xf0 P */
429 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */
430 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */
431 { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */
432 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */
433 { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */
434 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */
435 { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */
436 { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */
437 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */
438 { OP(PAT,DST,GXor) }, /* 0xfa D|P */
439 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */
440 { OP(PAT,SRC,GXor) }, /* 0xfc P|S */
441 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */
442 { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */
443 { OP(PAT,DST,GXset) } /* 0xff 1 */
447 #ifdef BITBLT_TEST /* Opcodes test */
449 static int do_bitop( int s, int d, int rop )
454 case GXclear: res = 0; break;
455 case GXand: res = s & d; break;
456 case GXandReverse: res = s & ~d; break;
457 case GXcopy: res = s; break;
458 case GXandInverted: res = ~s & d; break;
459 case GXnoop: res = d; break;
460 case GXxor: res = s ^ d; break;
461 case GXor: res = s | d; break;
462 case GXnor: res = ~(s | d); break;
463 case GXequiv: res = ~s ^ d; break;
464 case GXinvert: res = ~d; break;
465 case GXorReverse: res = s | ~d; break;
466 case GXcopyInverted: res = ~s; break;
467 case GXorInverted: res = ~s | d; break;
468 case GXnand: res = ~(s & d); break;
469 case GXset: res = 1; break;
476 int rop, i, res, src, dst, pat, tmp, dstUsed;
479 for (rop = 0; rop < 256; rop++)
482 for (i = 0; i < 8; i++)
487 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
491 case OP_ARGS(DST,TMP):
492 tmp = do_bitop( dst, tmp, *opcode & 0xf );
494 case OP_ARGS(DST,SRC):
495 src = do_bitop( dst, src, *opcode & 0xf );
497 case OP_ARGS(SRC,TMP):
498 tmp = do_bitop( src, tmp, *opcode & 0xf );
500 case OP_ARGS(SRC,DST):
501 dst = do_bitop( src, dst, *opcode & 0xf );
504 case OP_ARGS(PAT,TMP):
505 tmp = do_bitop( pat, tmp, *opcode & 0xf );
507 case OP_ARGS(PAT,DST):
508 dst = do_bitop( pat, dst, *opcode & 0xf );
511 case OP_ARGS(PAT,SRC):
512 src = do_bitop( pat, src, *opcode & 0xf );
514 case OP_ARGS(TMP,DST):
515 dst = do_bitop( tmp, dst, *opcode & 0xf );
518 case OP_ARGS(TMP,SRC):
519 src = do_bitop( tmp, src, *opcode & 0xf );
522 printf( "Invalid opcode %x\n", *opcode );
525 if (!dstUsed) dst = src;
526 if (dst) res |= 1 << i;
528 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
534 #endif /* BITBLT_TEST */
537 static void get_colors(X11DRV_PDEVICE *physDevDst, X11DRV_PDEVICE *physDevSrc,
542 *fg = physDevDst->textPixel;
543 *bg = physDevDst->backgroundPixel;
544 if(physDevSrc->depth == 1) {
545 if(GetDIBColorTable(physDevSrc->hdc, 0, 2, rgb) == 2) {
547 logcolor = RGB(rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue);
548 *fg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
549 logcolor = RGB(rgb[1].rgbRed, rgb[1].rgbGreen,rgb[1].rgbBlue);
550 *bg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
555 /***********************************************************************
558 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
560 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
561 INT startDst, INT widthDst,
562 INT xinc, INT xoff, WORD mode )
564 register INT xsrc = xinc * startDst + xoff;
568 case STRETCH_ANDSCANS:
569 for(; widthDst > 0; widthDst--, xsrc += xinc)
570 *rowDst++ &= rowSrc[xsrc >> 16];
572 case STRETCH_ORSCANS:
573 for(; widthDst > 0; widthDst--, xsrc += xinc)
574 *rowDst++ |= rowSrc[xsrc >> 16];
576 case STRETCH_DELETESCANS:
577 for(; widthDst > 0; widthDst--, xsrc += xinc)
578 *rowDst++ = rowSrc[xsrc >> 16];
584 /***********************************************************************
587 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
589 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
590 INT startSrc, INT widthSrc,
591 INT xinc, INT xoff, WORD mode )
593 register INT xdst = xinc * startSrc + xoff;
597 case STRETCH_ORSCANS:
598 for(; widthSrc > 0; widthSrc--, xdst += xinc)
599 rowDst[xdst >> 16] |= *rowSrc++;
601 case STRETCH_ANDSCANS:
602 for(; widthSrc > 0; widthSrc--, xdst += xinc)
603 rowDst[xdst >> 16] &= *rowSrc++;
605 case STRETCH_DELETESCANS:
606 for(; widthSrc > 0; widthSrc--, xdst += xinc)
607 rowDst[xdst >> 16] = *rowSrc++;
613 /***********************************************************************
616 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
618 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
619 INT start, INT width, INT depthDst,
620 int fg, int bg, BOOL swap)
624 assert( (row >= 0) && (row < image->height) );
625 assert( (start >= 0) && (width <= image->width) );
627 pdata += swap ? start+width-1 : start;
628 if (image->depth == depthDst) /* color -> color */
630 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
631 if (swap) for (i = 0; i < width; i++)
632 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
633 else for (i = 0; i < width; i++)
634 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
636 if (swap) for (i = 0; i < width; i++)
637 *pdata-- = XGetPixel( image, i, row );
638 else for (i = 0; i < width; i++)
639 *pdata++ = XGetPixel( image, i, row );
643 if (image->depth == 1) /* monochrome -> color */
645 if (X11DRV_PALETTE_XPixelToPalette)
647 fg = X11DRV_PALETTE_XPixelToPalette[fg];
648 bg = X11DRV_PALETTE_XPixelToPalette[bg];
650 if (swap) for (i = 0; i < width; i++)
651 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
652 else for (i = 0; i < width; i++)
653 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
655 else /* color -> monochrome */
657 if (swap) for (i = 0; i < width; i++)
658 *pdata-- = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
659 else for (i = 0; i < width; i++)
660 *pdata++ = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
666 /***********************************************************************
667 * BITBLT_StretchImage
669 * Stretch an X image.
670 * FIXME: does not work for full 32-bit coordinates.
672 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
673 INT widthSrc, INT heightSrc,
674 INT widthDst, INT heightDst,
675 RECT *visRectSrc, RECT *visRectDst,
676 int foreground, int background, WORD mode )
678 int *rowSrc, *rowDst, *pixel;
680 INT xinc, xoff, yinc, ysrc, ydst;
682 BOOL hstretch, vstretch, hswap, vswap;
684 hswap = ((int)widthSrc * widthDst) < 0;
685 vswap = ((int)heightSrc * heightDst) < 0;
686 widthSrc = abs(widthSrc);
687 heightSrc = abs(heightSrc);
688 widthDst = abs(widthDst);
689 heightDst = abs(heightDst);
691 if (!(rowSrc = HeapAlloc( GetProcessHeap(), 0,
692 (widthSrc+widthDst)*sizeof(int) ))) return;
693 rowDst = rowSrc + widthSrc;
695 /* When stretching, all modes are the same, and DELETESCANS is faster */
696 if ((widthSrc < widthDst) && (heightSrc < heightDst))
697 mode = STRETCH_DELETESCANS;
699 if (mode == STRETCH_HALFTONE) /* FIXME */
700 mode = STRETCH_DELETESCANS;
702 if (mode != STRETCH_DELETESCANS)
703 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
704 widthDst*sizeof(int) );
706 hstretch = (widthSrc < widthDst);
707 vstretch = (heightSrc < heightDst);
711 xinc = ((int)widthSrc << 16) / widthDst;
712 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
716 xinc = ((int)widthDst << 16) / widthSrc;
717 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
722 yinc = ((int)heightSrc << 16) / heightDst;
723 ydst = visRectDst->top;
726 ysrc = yinc * (heightDst - ydst - 1);
732 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
734 if (((ysrc >> 16) < visRectSrc->top) ||
735 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
737 /* Retrieve a source row */
738 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
739 hswap ? widthSrc - visRectSrc->right
741 visRectSrc->right - visRectSrc->left,
742 dstImage->depth, foreground, background, hswap );
744 /* Stretch or shrink it */
746 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
747 visRectDst->right - visRectDst->left,
749 else BITBLT_ShrinkRow( rowSrc, rowDst,
750 hswap ? widthSrc - visRectSrc->right
752 visRectSrc->right - visRectSrc->left,
755 /* Store the destination row */
756 pixel = rowDst + visRectDst->right - 1;
757 y = ydst - visRectDst->top;
758 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
759 XPutPixel( dstImage, x, y, *pixel-- );
760 if (mode != STRETCH_DELETESCANS)
761 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
762 widthDst*sizeof(int) );
764 /* Make copies of the destination row */
766 pdata = dstImage->data + dstImage->bytes_per_line * y;
767 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
768 (ydst < visRectDst->bottom-1))
770 memcpy( pdata + dstImage->bytes_per_line, pdata,
771 dstImage->bytes_per_line );
772 pdata += dstImage->bytes_per_line;
780 yinc = ((int)heightDst << 16) / heightSrc;
781 ysrc = visRectSrc->top;
782 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
785 ydst += yinc * (heightSrc - ysrc - 1);
791 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
793 if (((ydst >> 16) < visRectDst->top) ||
794 ((ydst >> 16) >= visRectDst->bottom)) continue;
796 /* Retrieve a source row */
797 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
798 hswap ? widthSrc - visRectSrc->right
800 visRectSrc->right - visRectSrc->left,
801 dstImage->depth, foreground, background, hswap );
803 /* Stretch or shrink it */
805 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
806 visRectDst->right - visRectDst->left,
808 else BITBLT_ShrinkRow( rowSrc, rowDst,
809 hswap ? widthSrc - visRectSrc->right
811 visRectSrc->right - visRectSrc->left,
814 /* Merge several source rows into the destination */
815 if (mode == STRETCH_DELETESCANS)
817 /* Simply skip the overlapping rows */
818 while (((ydst + yinc) >> 16 == ydst >> 16) &&
819 (ysrc < visRectSrc->bottom-1))
825 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
826 (ysrc < visRectSrc->bottom-1))
827 continue; /* Restart loop for next overlapping row */
829 /* Store the destination row */
830 pixel = rowDst + visRectDst->right - 1;
831 y = (ydst >> 16) - visRectDst->top;
832 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
833 XPutPixel( dstImage, x, y, *pixel-- );
834 if (mode != STRETCH_DELETESCANS)
835 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
836 widthDst*sizeof(int) );
839 HeapFree( GetProcessHeap(), 0, rowSrc );
843 /***********************************************************************
844 * BITBLT_GetSrcAreaStretch
846 * Retrieve an area from the source DC, stretching and mapping all the
847 * pixels to Windows colors.
849 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
850 Pixmap pixmap, GC gc,
852 INT widthSrc, INT heightSrc,
854 INT widthDst, INT heightDst,
855 RECT *visRectSrc, RECT *visRectDst )
857 XImage *imageSrc, *imageDst;
858 RECT rectSrc = *visRectSrc;
859 RECT rectDst = *visRectDst;
862 if (widthSrc < 0) xSrc += widthSrc;
863 if (widthDst < 0) xDst += widthDst;
864 if (heightSrc < 0) ySrc += heightSrc;
865 if (heightDst < 0) yDst += heightDst;
866 rectSrc.left -= xSrc;
867 rectSrc.right -= xSrc;
869 rectSrc.bottom -= ySrc;
870 rectDst.left -= xDst;
871 rectDst.right -= xDst;
873 rectDst.bottom -= yDst;
875 get_colors(physDevDst, physDevSrc, &fg, &bg);
876 /* FIXME: avoid BadMatch errors */
877 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
878 physDevSrc->dc_rect.left + visRectSrc->left,
879 physDevSrc->dc_rect.top + visRectSrc->top,
880 visRectSrc->right - visRectSrc->left,
881 visRectSrc->bottom - visRectSrc->top,
882 AllPlanes, ZPixmap );
883 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
884 rectDst.bottom - rectDst.top, physDevDst->depth );
885 BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
886 widthDst, heightDst, &rectSrc, &rectDst,
887 fg, physDevDst->depth != 1 ?
888 bg : physDevSrc->backgroundPixel,
889 GetStretchBltMode(physDevDst->hdc) );
890 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
891 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
892 XDestroyImage( imageSrc );
893 XDestroyImage( imageDst );
894 return 0; /* no exposure events generated */
898 /***********************************************************************
901 * Retrieve an area from the source DC, mapping all the
902 * pixels to Windows colors.
904 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
905 Pixmap pixmap, GC gc, INT xSrc, INT ySrc, RECT *visRectSrc )
907 XImage *imageSrc, *imageDst;
910 INT width = visRectSrc->right - visRectSrc->left;
911 INT height = visRectSrc->bottom - visRectSrc->top;
914 if (physDevSrc->depth == physDevDst->depth)
916 if (!X11DRV_PALETTE_XPixelToPalette ||
917 (physDevDst->depth == 1)) /* monochrome -> monochrome */
919 if (physDevDst->depth == 1)
921 /* MSDN says if StretchBlt must convert a bitmap from monochrome
922 to color or vice versa, the forground and background color of
923 the device context are used. In fact, it also applies to the
924 case when it is converted from mono to mono. */
925 XSetBackground( gdi_display, gc, physDevDst->textPixel );
926 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
927 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
928 physDevSrc->dc_rect.left + visRectSrc->left,
929 physDevSrc->dc_rect.top + visRectSrc->top,
930 width, height, 0, 0, 1);
933 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
934 physDevSrc->dc_rect.left + visRectSrc->left,
935 physDevSrc->dc_rect.top + visRectSrc->top,
936 width, height, 0, 0);
939 else /* color -> color */
941 if (GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
942 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
943 physDevSrc->dc_rect.left + visRectSrc->left,
944 physDevSrc->dc_rect.top + visRectSrc->top,
945 width, height, AllPlanes, ZPixmap );
948 /* Make sure we don't get a BadMatch error */
949 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
950 physDevSrc->dc_rect.left + visRectSrc->left,
951 physDevSrc->dc_rect.top + visRectSrc->top,
952 width, height, 0, 0);
954 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
955 AllPlanes, ZPixmap );
957 for (y = 0; y < height; y++)
958 for (x = 0; x < width; x++)
959 XPutPixel(imageSrc, x, y,
960 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
961 XPutImage( gdi_display, pixmap, gc, imageSrc,
962 0, 0, 0, 0, width, height );
963 XDestroyImage( imageSrc );
968 if (physDevSrc->depth == 1) /* monochrome -> color */
970 get_colors(physDevDst, physDevSrc, &fg, &bg);
972 if (X11DRV_PALETTE_XPixelToPalette)
974 XSetBackground( gdi_display, gc,
975 X11DRV_PALETTE_XPixelToPalette[fg] );
976 XSetForeground( gdi_display, gc,
977 X11DRV_PALETTE_XPixelToPalette[bg]);
981 XSetBackground( gdi_display, gc, fg );
982 XSetForeground( gdi_display, gc, bg );
984 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
985 physDevSrc->dc_rect.left + visRectSrc->left,
986 physDevSrc->dc_rect.top + visRectSrc->top,
987 width, height, 0, 0, 1 );
990 else /* color -> monochrome */
992 /* FIXME: avoid BadMatch error */
993 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
994 physDevSrc->dc_rect.left + visRectSrc->left,
995 physDevSrc->dc_rect.top + visRectSrc->top,
996 width, height, AllPlanes, ZPixmap );
1001 imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1004 XDestroyImage(imageSrc);
1007 for (y = 0; y < height; y++)
1008 for (x = 0; x < width; x++)
1009 XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1010 physDevSrc->backgroundPixel) );
1011 XPutImage( gdi_display, pixmap, gc, imageDst,
1012 0, 0, 0, 0, width, height );
1013 XDestroyImage( imageSrc );
1014 XDestroyImage( imageDst );
1021 /***********************************************************************
1024 * Retrieve an area from the destination DC, mapping all the
1025 * pixels to Windows colors.
1027 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1030 INT width = visRectDst->right - visRectDst->left;
1031 INT height = visRectDst->bottom - visRectDst->top;
1033 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1034 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1036 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1037 physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
1038 width, height, 0, 0 );
1046 if (GetObjectType( physDev->hdc ) == OBJ_MEMDC)
1047 image = XGetImage( gdi_display, physDev->drawable,
1048 physDev->dc_rect.left + visRectDst->left,
1049 physDev->dc_rect.top + visRectDst->top,
1050 width, height, AllPlanes, ZPixmap );
1053 /* Make sure we don't get a BadMatch error */
1054 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1055 physDev->dc_rect.left + visRectDst->left,
1056 physDev->dc_rect.top + visRectDst->top,
1057 width, height, 0, 0);
1059 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1060 AllPlanes, ZPixmap );
1062 for (y = 0; y < height; y++)
1063 for (x = 0; x < width; x++)
1064 XPutPixel( image, x, y,
1065 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1066 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1067 XDestroyImage( image );
1073 /***********************************************************************
1076 * Put an area back into the destination DC, mapping the pixel
1077 * colors to X pixels.
1079 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1082 INT width = visRectDst->right - visRectDst->left;
1083 INT height = visRectDst->bottom - visRectDst->top;
1085 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1087 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1088 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1090 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1091 physDev->dc_rect.left + visRectDst->left,
1092 physDev->dc_rect.top + visRectDst->top );
1098 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1099 AllPlanes, ZPixmap );
1100 for (y = 0; y < height; y++)
1101 for (x = 0; x < width; x++)
1103 XPutPixel( image, x, y,
1104 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1106 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1107 physDev->dc_rect.left + visRectDst->left,
1108 physDev->dc_rect.top + visRectDst->top, width, height );
1109 XDestroyImage( image );
1115 /***********************************************************************
1116 * BITBLT_GetVisRectangles
1118 * Get the source and destination visible rectangles for StretchBlt().
1119 * Return FALSE if one of the rectangles is empty.
1121 static BOOL BITBLT_GetVisRectangles( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1122 INT widthDst, INT heightDst,
1123 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1124 INT widthSrc, INT heightSrc,
1125 RECT *visRectSrc, RECT *visRectDst )
1127 RECT rect, clipRect;
1129 /* Get the destination visible rectangle */
1133 rect.right = xDst + widthDst;
1134 rect.bottom = yDst + heightDst;
1135 if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1136 if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1137 GetRgnBox( physDevDst->region, &clipRect );
1138 if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1140 /* Get the source visible rectangle */
1142 if (!physDevSrc) return TRUE;
1145 rect.right = xSrc + widthSrc;
1146 rect.bottom = ySrc + heightSrc;
1147 if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1148 if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1149 /* Apparently the clipping and visible regions are only for output,
1150 so just check against dc extent here to avoid BadMatch errors */
1151 clipRect = physDevSrc->drawable_rect;
1152 OffsetRect( &clipRect, -(physDevSrc->drawable_rect.left + physDevSrc->dc_rect.left),
1153 -(physDevSrc->drawable_rect.top + physDevSrc->dc_rect.top) );
1154 if (!IntersectRect( visRectSrc, &rect, &clipRect ))
1157 /* Intersect the rectangles */
1159 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1161 visRectSrc->left += xDst - xSrc;
1162 visRectSrc->right += xDst - xSrc;
1163 visRectSrc->top += yDst - ySrc;
1164 visRectSrc->bottom += yDst - ySrc;
1165 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1166 *visRectSrc = *visRectDst = rect;
1167 visRectSrc->left += xSrc - xDst;
1168 visRectSrc->right += xSrc - xDst;
1169 visRectSrc->top += ySrc - yDst;
1170 visRectSrc->bottom += ySrc - yDst;
1172 else /* stretching */
1174 /* Map source rectangle into destination coordinates */
1175 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1176 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1177 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1178 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1179 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1180 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1182 /* Avoid rounding errors */
1187 if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1189 /* Map destination rectangle back to source coordinates */
1191 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1192 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1193 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1194 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1195 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1196 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1198 /* Avoid rounding errors */
1203 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1209 /***********************************************************************
1210 * BITBLT_InternalStretchBlt
1212 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1214 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1215 INT widthDst, INT heightDst,
1216 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1217 INT widthSrc, INT heightSrc,
1220 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1221 RECT visRectDst, visRectSrc;
1224 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1228 /* compensate for off-by-one shifting for negative widths and heights */
1238 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1239 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1240 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1241 if (!physDevSrc && useSrc) return FALSE;
1243 /* Map the coordinates to device coords */
1247 pts[1].x = xDst + widthDst;
1248 pts[1].y = yDst + heightDst;
1249 LPtoDP(physDevDst->hdc, pts, 2);
1252 widthDst = pts[1].x - pts[0].x;
1253 heightDst = pts[1].y - pts[0].y;
1255 TRACE(" rectdst=%d,%d-%d,%d orgdst=%d,%d\n",
1256 xDst, yDst, widthDst, heightDst,
1257 physDevDst->dc_rect.left, physDevDst->dc_rect.top );
1263 pts[1].x = xSrc + widthSrc;
1264 pts[1].y = ySrc + heightSrc;
1265 LPtoDP(physDevSrc->hdc, pts, 2);
1268 widthSrc = pts[1].x - pts[0].x;
1269 heightSrc = pts[1].y - pts[0].y;
1271 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1272 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%d,%d\n",
1273 xSrc, ySrc, widthSrc, heightSrc,
1274 physDevSrc->dc_rect.left, physDevSrc->dc_rect.top );
1275 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1276 physDevSrc, xSrc, ySrc, widthSrc, heightSrc,
1277 &visRectSrc, &visRectDst ))
1279 TRACE(" vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1280 visRectSrc.left, visRectSrc.top,
1281 visRectSrc.right, visRectSrc.bottom,
1282 visRectDst.left, visRectDst.top,
1283 visRectDst.right, visRectDst.bottom );
1288 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1289 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1291 TRACE(" vissrc=none visdst=%d,%d-%d,%d\n",
1292 visRectDst.left, visRectDst.top,
1293 visRectDst.right, visRectDst.bottom );
1296 width = visRectDst.right - visRectDst.left;
1297 height = visRectDst.bottom - visRectDst.top;
1299 if (!fStretch) switch(rop) /* A few optimisations */
1301 case BLACKNESS: /* 0x00 */
1303 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1304 XSetFunction( gdi_display, physDevDst->gc, GXclear );
1307 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1308 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1309 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1311 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1312 physDevDst->dc_rect.left + visRectDst.left,
1313 physDevDst->dc_rect.top + visRectDst.top,
1315 wine_tsx11_unlock();
1318 case DSTINVERT: /* 0x55 */
1320 XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1322 if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1323 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1326 /* Xor is much better when we do not have full colormap. */
1327 /* Using white^black ensures that we invert at least black */
1329 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1330 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1331 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1332 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1333 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1335 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1336 physDevDst->dc_rect.left + visRectDst.left,
1337 physDevDst->dc_rect.top + visRectDst.top,
1339 wine_tsx11_unlock();
1342 case PATINVERT: /* 0x5a */
1343 if (X11DRV_SetupGCForBrush( physDevDst ))
1346 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1347 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1348 physDevDst->dc_rect.left + visRectDst.left,
1349 physDevDst->dc_rect.top + visRectDst.top,
1351 wine_tsx11_unlock();
1356 if (X11DRV_SetupGCForBrush( physDevDst ))
1359 XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1360 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1361 physDevDst->dc_rect.left + visRectDst.left,
1362 physDevDst->dc_rect.top + visRectDst.top,
1364 wine_tsx11_unlock();
1368 case SRCCOPY: /* 0xcc */
1369 if (physDevSrc->depth == physDevDst->depth)
1372 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1373 XCopyArea( gdi_display, physDevSrc->drawable,
1374 physDevDst->drawable, physDevDst->gc,
1375 physDevSrc->dc_rect.left + visRectSrc.left,
1376 physDevSrc->dc_rect.top + visRectSrc.top,
1378 physDevDst->dc_rect.left + visRectDst.left,
1379 physDevDst->dc_rect.top + visRectDst.top );
1380 physDevDst->exposures++;
1381 wine_tsx11_unlock();
1385 if (physDevSrc->depth == 1)
1388 get_colors(physDevDst, physDevSrc, &fg, &bg);
1391 XSetBackground( gdi_display, physDevDst->gc, fg );
1392 XSetForeground( gdi_display, physDevDst->gc, bg );
1393 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1394 XCopyPlane( gdi_display, physDevSrc->drawable,
1395 physDevDst->drawable, physDevDst->gc,
1396 physDevSrc->dc_rect.left + visRectSrc.left,
1397 physDevSrc->dc_rect.top + visRectSrc.top,
1399 physDevDst->dc_rect.left + visRectDst.left,
1400 physDevDst->dc_rect.top + visRectDst.top, 1 );
1401 physDevDst->exposures++;
1402 wine_tsx11_unlock();
1407 case PATCOPY: /* 0xf0 */
1408 if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1410 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1411 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1412 physDevDst->dc_rect.left + visRectDst.left,
1413 physDevDst->dc_rect.top + visRectDst.top,
1415 wine_tsx11_unlock();
1418 case WHITENESS: /* 0xff */
1420 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1421 XSetFunction( gdi_display, physDevDst->gc, GXset );
1424 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1425 XSetForeground( gdi_display, physDevDst->gc,
1426 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1427 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1429 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1430 physDevDst->dc_rect.left + visRectDst.left,
1431 physDevDst->dc_rect.top + visRectDst.top,
1433 wine_tsx11_unlock();
1439 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1440 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1441 XSetGraphicsExposures( gdi_display, tmpGC, False );
1442 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1443 physDevDst->depth );
1446 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1447 physDevDst->depth );
1449 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1450 xSrc, ySrc, widthSrc, heightSrc,
1451 xDst, yDst, widthDst, heightDst,
1452 &visRectSrc, &visRectDst );
1454 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1455 xSrc, ySrc, &visRectSrc );
1458 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1459 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1460 else fNullBrush = FALSE;
1463 for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1465 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1466 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1467 switch(OP_SRCDST(*opcode))
1469 case OP_ARGS(DST,TMP):
1470 case OP_ARGS(SRC,TMP):
1472 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1473 width, height, physDevDst->depth );
1475 case OP_ARGS(DST,SRC):
1476 case OP_ARGS(SRC,DST):
1477 case OP_ARGS(TMP,SRC):
1478 case OP_ARGS(TMP,DST):
1480 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1481 pixmaps[OP_DST(*opcode)], tmpGC,
1482 0, 0, width, height, 0, 0 );
1485 case OP_ARGS(PAT,TMP):
1486 if (!pixmaps[TMP] && !fNullBrush)
1487 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1488 width, height, physDevDst->depth );
1490 case OP_ARGS(PAT,DST):
1491 case OP_ARGS(PAT,SRC):
1493 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1494 tmpGC, 0, 0, width, height );
1498 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1499 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1501 XFreePixmap( gdi_display, pixmaps[DST] );
1502 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1503 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1504 XFreeGC( gdi_display, tmpGC );
1505 wine_tsx11_unlock();
1510 /***********************************************************************
1513 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1517 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1518 result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1519 X11DRV_UnlockDIBSection( physDev, TRUE );
1524 /***********************************************************************
1525 * X11DRV_ClientSideDIBCopy
1527 static BOOL X11DRV_ClientSideDIBCopy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1528 X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1529 INT width, INT height )
1531 DIBSECTION srcDib, dstDib;
1532 BYTE *srcPtr, *dstPtr;
1533 INT srcRowOffset, dstRowOffset;
1537 static RECT unusedRect;
1539 if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib))
1541 if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib))
1544 /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */
1545 if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight)
1547 if (xSrc + width > srcDib.dsBm.bmWidth)
1548 width = srcDib.dsBm.bmWidth - xSrc;
1549 if (ySrc + height > srcDib.dsBm.bmHeight)
1550 height = srcDib.dsBm.bmHeight - ySrc;
1552 if (GetRgnBox(physDevSrc->region, &unusedRect) == COMPLEXREGION ||
1553 GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION)
1555 /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */
1556 FIXME("potential optimization: client-side complex region clipping\n");
1559 if (dstDib.dsBm.bmBitsPixel <= 8)
1561 FIXME("potential optimization: client-side color-index mode DIB copy\n");
1564 if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1565 dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1566 !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1567 && !(srcDib.dsBmih.biCompression == BI_RGB &&
1568 dstDib.dsBmih.biCompression == BI_RGB))
1570 FIXME("potential optimization: client-side compressed DIB copy\n");
1573 if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1575 FIXME("potential optimization: pixel format conversion\n");
1578 if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1580 FIXME("negative widths not yet implemented\n");
1584 switch (dstDib.dsBm.bmBitsPixel)
1597 FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1601 bytesToCopy = width * bytesPerPixel;
1603 if (srcDib.dsBmih.biHeight < 0)
1605 srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1606 srcRowOffset = srcDib.dsBm.bmWidthBytes;
1610 srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1611 + xSrc*bytesPerPixel];
1612 srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1614 if (dstDib.dsBmih.biHeight < 0)
1616 dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1617 dstRowOffset = dstDib.dsBm.bmWidthBytes;
1621 dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1622 + xDst*bytesPerPixel];
1623 dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1626 /* Handle overlapping regions on the same DIB */
1627 if (physDevSrc == physDevDst && ySrc < yDst)
1629 srcPtr += srcRowOffset * (height - 1);
1630 srcRowOffset = -srcRowOffset;
1631 dstPtr += dstRowOffset * (height - 1);
1632 dstRowOffset = -dstRowOffset;
1635 for (y = yDst; y < yDst + height; ++y)
1637 memmove(dstPtr, srcPtr, bytesToCopy);
1638 srcPtr += srcRowOffset;
1639 dstPtr += dstRowOffset;
1646 /***********************************************************************
1649 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1650 INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1651 INT xSrc, INT ySrc, DWORD rop )
1653 BOOL result = FALSE;
1655 RECT visRectDst, visRectSrc;
1657 if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1658 /* FIXME: seems the ROP doesn't include destination;
1659 * now if the destination area include the entire dcDst,
1660 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1661 * which may avoid a copy in some situations */
1664 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1665 if (physDevDst != physDevSrc)
1666 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1670 if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1671 (physDevSrc->depth == physDevDst->depth))
1674 /* do everything ourselves; map coordinates */
1678 pts[1].x = xSrc + width;
1679 pts[1].y = ySrc + height;
1681 LPtoDP(physDevSrc->hdc, pts, 2);
1682 width = pts[1].x - pts[0].x;
1683 height = pts[1].y - pts[0].y;
1689 LPtoDP(physDevDst->hdc, pts, 1);
1694 /* Perform basic clipping */
1695 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, width, height,
1696 physDevSrc, xSrc, ySrc, width, height,
1697 &visRectSrc, &visRectDst ))
1700 xSrc = visRectSrc.left;
1701 ySrc = visRectSrc.top;
1702 xDst = visRectDst.left;
1703 yDst = visRectDst.top;
1704 width = visRectDst.right - visRectDst.left;
1705 height = visRectDst.bottom - visRectDst.top;
1707 if (sDst == DIB_Status_AppMod) {
1708 result = X11DRV_ClientSideDIBCopy( physDevSrc, xSrc, ySrc,
1709 physDevDst, xDst, yDst,
1713 /* fall back to X server copying */
1715 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1718 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1719 wine_tsx11_unlock();
1721 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1726 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1727 if (physDevDst != physDevSrc)
1728 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1730 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1731 physDevSrc, xSrc, ySrc, width, height, rop );
1734 if (physDevDst != physDevSrc)
1735 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1736 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1742 /***********************************************************************
1745 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1746 INT widthDst, INT heightDst,
1747 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1748 INT widthSrc, INT heightSrc, DWORD rop )
1752 X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1753 if (physDevDst != physDevSrc)
1754 X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1756 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1757 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1759 if (physDevDst != physDevSrc)
1760 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1761 X11DRV_UnlockDIBSection( physDevDst, TRUE );