winex11.drv: Add an optimized path for BitBlt(SRCINVERT).
[wine/winequartzdrv.git] / dlls / winex11.drv / bitblt.c
blob6f91413bf3297dfd431cb561d6152f9d5863a8da
1 /*
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
22 #include "config.h"
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "x11drv.h"
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 )
451 int res;
452 switch(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;
471 return res & 1;
474 int main()
476 int rop, i, res, src, dst, pat, tmp, dstUsed;
477 const BYTE *opcode;
479 for (rop = 0; rop < 256; rop++)
481 res = dstUsed = 0;
482 for (i = 0; i < 8; i++)
484 pat = (i >> 2) & 1;
485 src = (i >> 1) & 1;
486 dst = i & 1;
487 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
489 switch(*opcode >> 4)
491 case OP_ARGS(DST,TMP):
492 tmp = do_bitop( dst, tmp, *opcode & 0xf );
493 break;
494 case OP_ARGS(DST,SRC):
495 src = do_bitop( dst, src, *opcode & 0xf );
496 break;
497 case OP_ARGS(SRC,TMP):
498 tmp = do_bitop( src, tmp, *opcode & 0xf );
499 break;
500 case OP_ARGS(SRC,DST):
501 dst = do_bitop( src, dst, *opcode & 0xf );
502 dstUsed = 1;
503 break;
504 case OP_ARGS(PAT,TMP):
505 tmp = do_bitop( pat, tmp, *opcode & 0xf );
506 break;
507 case OP_ARGS(PAT,DST):
508 dst = do_bitop( pat, dst, *opcode & 0xf );
509 dstUsed = 1;
510 break;
511 case OP_ARGS(PAT,SRC):
512 src = do_bitop( pat, src, *opcode & 0xf );
513 break;
514 case OP_ARGS(TMP,DST):
515 dst = do_bitop( tmp, dst, *opcode & 0xf );
516 dstUsed = 1;
517 break;
518 case OP_ARGS(TMP,SRC):
519 src = do_bitop( tmp, src, *opcode & 0xf );
520 break;
521 default:
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 );
531 return 0;
534 #endif /* BITBLT_TEST */
537 static void get_colors(X11DRV_PDEVICE *physDevDst, X11DRV_PDEVICE *physDevSrc,
538 int *fg, int *bg)
540 RGBQUAD rgb[2];
542 *fg = physDevDst->textPixel;
543 *bg = physDevDst->backgroundPixel;
544 if(physDevSrc->depth == 1) {
545 if(GetDIBColorTable(physDevSrc->hdc, 0, 2, rgb) == 2) {
546 DWORD logcolor;
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 /***********************************************************************
556 * BITBLT_StretchRow
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;
565 rowDst += startDst;
566 switch(mode)
568 case STRETCH_ANDSCANS:
569 for(; widthDst > 0; widthDst--, xsrc += xinc)
570 *rowDst++ &= rowSrc[xsrc >> 16];
571 break;
572 case STRETCH_ORSCANS:
573 for(; widthDst > 0; widthDst--, xsrc += xinc)
574 *rowDst++ |= rowSrc[xsrc >> 16];
575 break;
576 case STRETCH_DELETESCANS:
577 for(; widthDst > 0; widthDst--, xsrc += xinc)
578 *rowDst++ = rowSrc[xsrc >> 16];
579 break;
584 /***********************************************************************
585 * BITBLT_ShrinkRow
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;
594 rowSrc += startSrc;
595 switch(mode)
597 case STRETCH_ORSCANS:
598 for(; widthSrc > 0; widthSrc--, xdst += xinc)
599 rowDst[xdst >> 16] |= *rowSrc++;
600 break;
601 case STRETCH_ANDSCANS:
602 for(; widthSrc > 0; widthSrc--, xdst += xinc)
603 rowDst[xdst >> 16] &= *rowSrc++;
604 break;
605 case STRETCH_DELETESCANS:
606 for(; widthSrc > 0; widthSrc--, xdst += xinc)
607 rowDst[xdst >> 16] = *rowSrc++;
608 break;
613 /***********************************************************************
614 * BITBLT_GetRow
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)
622 register INT i;
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 )];
635 else
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 );
641 else
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;
679 char *pdata;
680 INT xinc, xoff, yinc, ysrc, ydst;
681 register INT x, y;
682 BOOL hstretch, vstretch, hswap, vswap;
684 hswap = widthSrc * widthDst < 0;
685 vswap = 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);
709 if (hstretch)
711 xinc = (widthSrc << 16) / widthDst;
712 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
714 else
716 xinc = ((int)widthDst << 16) / widthSrc;
717 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
720 wine_tsx11_lock();
721 if (vstretch)
723 yinc = (heightSrc << 16) / heightDst;
724 ydst = visRectDst->top;
725 if (vswap)
727 ysrc = yinc * (heightDst - ydst - 1);
728 yinc = -yinc;
730 else
731 ysrc = yinc * ydst;
733 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
735 if (((ysrc >> 16) < visRectSrc->top) ||
736 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
738 /* Retrieve a source row */
739 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
740 hswap ? widthSrc - visRectSrc->right
741 : visRectSrc->left,
742 visRectSrc->right - visRectSrc->left,
743 dstImage->depth, foreground, background, hswap );
745 /* Stretch or shrink it */
746 if (hstretch)
747 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
748 visRectDst->right - visRectDst->left,
749 xinc, xoff, mode );
750 else BITBLT_ShrinkRow( rowSrc, rowDst,
751 hswap ? widthSrc - visRectSrc->right
752 : visRectSrc->left,
753 visRectSrc->right - visRectSrc->left,
754 xinc, xoff, mode );
756 /* Store the destination row */
757 pixel = rowDst + visRectDst->right - 1;
758 y = ydst - visRectDst->top;
759 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
760 XPutPixel( dstImage, x, y, *pixel-- );
761 if (mode != STRETCH_DELETESCANS)
762 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
763 widthDst*sizeof(int) );
765 /* Make copies of the destination row */
767 pdata = dstImage->data + dstImage->bytes_per_line * y;
768 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
769 (ydst < visRectDst->bottom-1))
771 memcpy( pdata + dstImage->bytes_per_line, pdata,
772 dstImage->bytes_per_line );
773 pdata += dstImage->bytes_per_line;
774 ysrc += yinc;
775 ydst++;
779 else /* Shrinking */
781 yinc = (heightDst << 16) / heightSrc;
782 ysrc = visRectSrc->top;
783 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
784 if (vswap)
786 ydst += yinc * (heightSrc - ysrc - 1);
787 yinc = -yinc;
789 else
790 ydst += yinc * ysrc;
792 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
794 if (((ydst >> 16) < visRectDst->top) ||
795 ((ydst >> 16) >= visRectDst->bottom)) continue;
797 /* Retrieve a source row */
798 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
799 hswap ? widthSrc - visRectSrc->right
800 : visRectSrc->left,
801 visRectSrc->right - visRectSrc->left,
802 dstImage->depth, foreground, background, hswap );
804 /* Stretch or shrink it */
805 if (hstretch)
806 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
807 visRectDst->right - visRectDst->left,
808 xinc, xoff, mode );
809 else BITBLT_ShrinkRow( rowSrc, rowDst,
810 hswap ? widthSrc - visRectSrc->right
811 : visRectSrc->left,
812 visRectSrc->right - visRectSrc->left,
813 xinc, xoff, mode );
815 /* Merge several source rows into the destination */
816 if (mode == STRETCH_DELETESCANS)
818 /* Simply skip the overlapping rows */
819 while (((ydst + yinc) >> 16 == ydst >> 16) &&
820 (ysrc < visRectSrc->bottom-1))
822 ydst += yinc;
823 ysrc++;
826 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
827 (ysrc < visRectSrc->bottom-1))
828 continue; /* Restart loop for next overlapping row */
830 /* Store the destination row */
831 pixel = rowDst + visRectDst->right - 1;
832 y = (ydst >> 16) - visRectDst->top;
833 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
834 XPutPixel( dstImage, x, y, *pixel-- );
835 if (mode != STRETCH_DELETESCANS)
836 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
837 widthDst*sizeof(int) );
840 wine_tsx11_unlock();
841 HeapFree( GetProcessHeap(), 0, rowSrc );
845 /***********************************************************************
846 * BITBLT_GetSrcAreaStretch
848 * Retrieve an area from the source DC, stretching and mapping all the
849 * pixels to Windows colors.
851 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
852 Pixmap pixmap, GC gc,
853 INT xSrc, INT ySrc,
854 INT widthSrc, INT heightSrc,
855 INT xDst, INT yDst,
856 INT widthDst, INT heightDst,
857 RECT *visRectSrc, RECT *visRectDst )
859 XImage *imageSrc, *imageDst;
860 RECT rectSrc = *visRectSrc;
861 RECT rectDst = *visRectDst;
862 int fg, bg;
864 if (widthSrc < 0) xSrc += widthSrc;
865 if (widthDst < 0) xDst += widthDst;
866 if (heightSrc < 0) ySrc += heightSrc;
867 if (heightDst < 0) yDst += heightDst;
868 rectSrc.left -= xSrc;
869 rectSrc.right -= xSrc;
870 rectSrc.top -= ySrc;
871 rectSrc.bottom -= ySrc;
872 rectDst.left -= xDst;
873 rectDst.right -= xDst;
874 rectDst.top -= yDst;
875 rectDst.bottom -= yDst;
877 get_colors(physDevDst, physDevSrc, &fg, &bg);
878 wine_tsx11_lock();
879 /* FIXME: avoid BadMatch errors */
880 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
881 physDevSrc->dc_rect.left + visRectSrc->left,
882 physDevSrc->dc_rect.top + visRectSrc->top,
883 visRectSrc->right - visRectSrc->left,
884 visRectSrc->bottom - visRectSrc->top,
885 AllPlanes, ZPixmap );
886 wine_tsx11_unlock();
888 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
889 rectDst.bottom - rectDst.top, physDevDst->depth );
890 BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
891 widthDst, heightDst, &rectSrc, &rectDst,
892 fg, physDevDst->depth != 1 ?
893 bg : physDevSrc->backgroundPixel,
894 GetStretchBltMode(physDevDst->hdc) );
895 wine_tsx11_lock();
896 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
897 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
898 XDestroyImage( imageSrc );
899 XDestroyImage( imageDst );
900 wine_tsx11_unlock();
901 return 0; /* no exposure events generated */
905 /***********************************************************************
906 * BITBLT_GetSrcArea
908 * Retrieve an area from the source DC, mapping all the
909 * pixels to Windows colors.
911 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
912 Pixmap pixmap, GC gc, INT xSrc, INT ySrc, RECT *visRectSrc )
914 XImage *imageSrc, *imageDst;
915 register INT x, y;
916 int exposures = 0;
917 INT width = visRectSrc->right - visRectSrc->left;
918 INT height = visRectSrc->bottom - visRectSrc->top;
919 int fg, bg;
920 BOOL memdc = (GetObjectType(physDevSrc->hdc) == OBJ_MEMDC);
922 if (physDevSrc->depth == physDevDst->depth)
924 wine_tsx11_lock();
925 if (!X11DRV_PALETTE_XPixelToPalette ||
926 (physDevDst->depth == 1)) /* monochrome -> monochrome */
928 if (physDevDst->depth == 1)
930 /* MSDN says if StretchBlt must convert a bitmap from monochrome
931 to color or vice versa, the foreground and background color of
932 the device context are used. In fact, it also applies to the
933 case when it is converted from mono to mono. */
934 XSetBackground( gdi_display, gc, physDevDst->textPixel );
935 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
936 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
937 physDevSrc->dc_rect.left + visRectSrc->left,
938 physDevSrc->dc_rect.top + visRectSrc->top,
939 width, height, 0, 0, 1);
941 else
942 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
943 physDevSrc->dc_rect.left + visRectSrc->left,
944 physDevSrc->dc_rect.top + visRectSrc->top,
945 width, height, 0, 0);
946 exposures++;
948 else /* color -> color */
950 if (memdc)
951 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
952 physDevSrc->dc_rect.left + visRectSrc->left,
953 physDevSrc->dc_rect.top + visRectSrc->top,
954 width, height, AllPlanes, ZPixmap );
955 else
957 /* Make sure we don't get a BadMatch error */
958 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
959 physDevSrc->dc_rect.left + visRectSrc->left,
960 physDevSrc->dc_rect.top + visRectSrc->top,
961 width, height, 0, 0);
962 exposures++;
963 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
964 AllPlanes, ZPixmap );
966 for (y = 0; y < height; y++)
967 for (x = 0; x < width; x++)
968 XPutPixel(imageSrc, x, y,
969 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
970 XPutImage( gdi_display, pixmap, gc, imageSrc,
971 0, 0, 0, 0, width, height );
972 XDestroyImage( imageSrc );
974 wine_tsx11_unlock();
976 else
978 if (physDevSrc->depth == 1) /* monochrome -> color */
980 get_colors(physDevDst, physDevSrc, &fg, &bg);
982 wine_tsx11_lock();
983 if (X11DRV_PALETTE_XPixelToPalette)
985 XSetBackground( gdi_display, gc,
986 X11DRV_PALETTE_XPixelToPalette[fg] );
987 XSetForeground( gdi_display, gc,
988 X11DRV_PALETTE_XPixelToPalette[bg]);
990 else
992 XSetBackground( gdi_display, gc, fg );
993 XSetForeground( gdi_display, gc, bg );
995 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
996 physDevSrc->dc_rect.left + visRectSrc->left,
997 physDevSrc->dc_rect.top + visRectSrc->top,
998 width, height, 0, 0, 1 );
999 exposures++;
1000 wine_tsx11_unlock();
1002 else /* color -> monochrome */
1004 wine_tsx11_lock();
1005 /* FIXME: avoid BadMatch error */
1006 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1007 physDevSrc->dc_rect.left + visRectSrc->left,
1008 physDevSrc->dc_rect.top + visRectSrc->top,
1009 width, height, AllPlanes, ZPixmap );
1010 if (!imageSrc)
1012 wine_tsx11_unlock();
1013 return exposures;
1015 imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1016 if (!imageDst)
1018 XDestroyImage(imageSrc);
1019 wine_tsx11_unlock();
1020 return exposures;
1022 for (y = 0; y < height; y++)
1023 for (x = 0; x < width; x++)
1024 XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1025 physDevSrc->backgroundPixel) );
1026 XPutImage( gdi_display, pixmap, gc, imageDst,
1027 0, 0, 0, 0, width, height );
1028 XDestroyImage( imageSrc );
1029 XDestroyImage( imageDst );
1030 wine_tsx11_unlock();
1033 return exposures;
1037 /***********************************************************************
1038 * BITBLT_GetDstArea
1040 * Retrieve an area from the destination DC, mapping all the
1041 * pixels to Windows colors.
1043 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1045 int exposures = 0;
1046 INT width = visRectDst->right - visRectDst->left;
1047 INT height = visRectDst->bottom - visRectDst->top;
1048 BOOL memdc = (GetObjectType( physDev->hdc ) == OBJ_MEMDC);
1050 wine_tsx11_lock();
1052 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1053 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1055 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1056 physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
1057 width, height, 0, 0 );
1058 exposures++;
1060 else
1062 register INT x, y;
1063 XImage *image;
1065 if (memdc)
1066 image = XGetImage( gdi_display, physDev->drawable,
1067 physDev->dc_rect.left + visRectDst->left,
1068 physDev->dc_rect.top + visRectDst->top,
1069 width, height, AllPlanes, ZPixmap );
1070 else
1072 /* Make sure we don't get a BadMatch error */
1073 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1074 physDev->dc_rect.left + visRectDst->left,
1075 physDev->dc_rect.top + visRectDst->top,
1076 width, height, 0, 0);
1077 exposures++;
1078 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1079 AllPlanes, ZPixmap );
1081 if (image)
1083 for (y = 0; y < height; y++)
1084 for (x = 0; x < width; x++)
1085 XPutPixel( image, x, y,
1086 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1087 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1088 XDestroyImage( image );
1092 wine_tsx11_unlock();
1093 return exposures;
1097 /***********************************************************************
1098 * BITBLT_PutDstArea
1100 * Put an area back into the destination DC, mapping the pixel
1101 * colors to X pixels.
1103 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1105 int exposures = 0;
1106 INT width = visRectDst->right - visRectDst->left;
1107 INT height = visRectDst->bottom - visRectDst->top;
1109 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1111 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1112 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1114 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1115 physDev->dc_rect.left + visRectDst->left,
1116 physDev->dc_rect.top + visRectDst->top );
1117 exposures++;
1119 else
1121 register INT x, y;
1122 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1123 AllPlanes, ZPixmap );
1124 for (y = 0; y < height; y++)
1125 for (x = 0; x < width; x++)
1127 XPutPixel( image, x, y,
1128 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1130 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1131 physDev->dc_rect.left + visRectDst->left,
1132 physDev->dc_rect.top + visRectDst->top, width, height );
1133 XDestroyImage( image );
1135 return exposures;
1139 /***********************************************************************
1140 * BITBLT_GetVisRectangles
1142 * Get the source and destination visible rectangles for StretchBlt().
1143 * Return FALSE if one of the rectangles is empty.
1145 static BOOL BITBLT_GetVisRectangles( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1146 INT widthDst, INT heightDst,
1147 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1148 INT widthSrc, INT heightSrc,
1149 RECT *visRectSrc, RECT *visRectDst )
1151 RECT rect, clipRect;
1153 /* Get the destination visible rectangle */
1155 rect.left = xDst;
1156 rect.top = yDst;
1157 rect.right = xDst + widthDst;
1158 rect.bottom = yDst + heightDst;
1159 if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1160 if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1161 GetRgnBox( physDevDst->region, &clipRect );
1162 if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1164 /* Get the source visible rectangle */
1166 if (!physDevSrc) return TRUE;
1167 rect.left = xSrc;
1168 rect.top = ySrc;
1169 rect.right = xSrc + widthSrc;
1170 rect.bottom = ySrc + heightSrc;
1171 if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1172 if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1173 /* Apparently the clipping and visible regions are only for output,
1174 so just check against dc extent here to avoid BadMatch errors */
1175 clipRect = physDevSrc->drawable_rect;
1176 OffsetRect( &clipRect, -(physDevSrc->drawable_rect.left + physDevSrc->dc_rect.left),
1177 -(physDevSrc->drawable_rect.top + physDevSrc->dc_rect.top) );
1178 if (!IntersectRect( visRectSrc, &rect, &clipRect ))
1179 return FALSE;
1181 /* Intersect the rectangles */
1183 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1185 visRectSrc->left += xDst - xSrc;
1186 visRectSrc->right += xDst - xSrc;
1187 visRectSrc->top += yDst - ySrc;
1188 visRectSrc->bottom += yDst - ySrc;
1189 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1190 *visRectSrc = *visRectDst = rect;
1191 visRectSrc->left += xSrc - xDst;
1192 visRectSrc->right += xSrc - xDst;
1193 visRectSrc->top += ySrc - yDst;
1194 visRectSrc->bottom += ySrc - yDst;
1196 else /* stretching */
1198 /* Map source rectangle into destination coordinates */
1199 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1200 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1201 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1202 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1203 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1204 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1206 /* Avoid rounding errors */
1207 rect.left--;
1208 rect.top--;
1209 rect.right++;
1210 rect.bottom++;
1211 if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1213 /* Map destination rectangle back to source coordinates */
1214 rect = *visRectDst;
1215 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1216 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1217 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1218 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1219 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1220 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1222 /* Avoid rounding errors */
1223 rect.left--;
1224 rect.top--;
1225 rect.right++;
1226 rect.bottom++;
1227 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1229 return TRUE;
1233 /***********************************************************************
1234 * BITBLT_InternalStretchBlt
1236 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1238 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1239 INT widthDst, INT heightDst,
1240 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1241 INT widthSrc, INT heightSrc,
1242 DWORD rop )
1244 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1245 RECT visRectDst, visRectSrc;
1246 INT width, height;
1247 const BYTE *opcode;
1248 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1249 GC tmpGC = 0;
1250 POINT pts[2];
1252 /* compensate for off-by-one shifting for negative widths and heights */
1253 if (widthDst < 0)
1254 ++xDst;
1255 if (heightDst < 0)
1256 ++yDst;
1257 if (widthSrc < 0)
1258 ++xSrc;
1259 if (heightSrc < 0)
1260 ++ySrc;
1262 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1263 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1264 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1265 if (!physDevSrc && useSrc) return FALSE;
1267 /* Map the coordinates to device coords */
1269 pts[0].x = xDst;
1270 pts[0].y = yDst;
1271 pts[1].x = xDst + widthDst;
1272 pts[1].y = yDst + heightDst;
1273 LPtoDP(physDevDst->hdc, pts, 2);
1274 xDst = pts[0].x;
1275 yDst = pts[0].y;
1276 widthDst = pts[1].x - pts[0].x;
1277 heightDst = pts[1].y - pts[0].y;
1279 TRACE(" rectdst=%d,%d-%d,%d orgdst=%d,%d\n",
1280 xDst, yDst, widthDst, heightDst,
1281 physDevDst->dc_rect.left, physDevDst->dc_rect.top );
1283 if (useSrc)
1285 pts[0].x = xSrc;
1286 pts[0].y = ySrc;
1287 pts[1].x = xSrc + widthSrc;
1288 pts[1].y = ySrc + heightSrc;
1289 LPtoDP(physDevSrc->hdc, pts, 2);
1290 xSrc = pts[0].x;
1291 ySrc = pts[0].y;
1292 widthSrc = pts[1].x - pts[0].x;
1293 heightSrc = pts[1].y - pts[0].y;
1295 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1296 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%d,%d\n",
1297 xSrc, ySrc, widthSrc, heightSrc,
1298 physDevSrc->dc_rect.left, physDevSrc->dc_rect.top );
1299 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1300 physDevSrc, xSrc, ySrc, widthSrc, heightSrc,
1301 &visRectSrc, &visRectDst ))
1302 return TRUE;
1303 TRACE(" vissrc=%d,%d-%d,%d visdst=%d,%d-%d,%d\n",
1304 visRectSrc.left, visRectSrc.top,
1305 visRectSrc.right, visRectSrc.bottom,
1306 visRectDst.left, visRectDst.top,
1307 visRectDst.right, visRectDst.bottom );
1309 else
1311 fStretch = FALSE;
1312 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1313 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1314 return TRUE;
1315 TRACE(" vissrc=none visdst=%d,%d-%d,%d\n",
1316 visRectDst.left, visRectDst.top,
1317 visRectDst.right, visRectDst.bottom );
1320 width = visRectDst.right - visRectDst.left;
1321 height = visRectDst.bottom - visRectDst.top;
1323 if (!fStretch) switch(rop) /* A few optimisations */
1325 case BLACKNESS: /* 0x00 */
1326 wine_tsx11_lock();
1327 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1328 XSetFunction( gdi_display, physDevDst->gc, GXclear );
1329 else
1331 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1332 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
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,
1338 width, height );
1339 wine_tsx11_unlock();
1340 return TRUE;
1342 case DSTINVERT: /* 0x55 */
1343 wine_tsx11_lock();
1344 XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1346 if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1347 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1348 else
1350 /* Xor is much better when we do not have full colormap. */
1351 /* Using white^black ensures that we invert at least black */
1352 /* and white. */
1353 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1354 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1355 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1356 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1357 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1359 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1360 physDevDst->dc_rect.left + visRectDst.left,
1361 physDevDst->dc_rect.top + visRectDst.top,
1362 width, height );
1363 wine_tsx11_unlock();
1364 return TRUE;
1366 case PATINVERT: /* 0x5a */
1367 if (X11DRV_SetupGCForBrush( physDevDst ))
1369 wine_tsx11_lock();
1370 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1371 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1372 physDevDst->dc_rect.left + visRectDst.left,
1373 physDevDst->dc_rect.top + visRectDst.top,
1374 width, height );
1375 wine_tsx11_unlock();
1377 return TRUE;
1379 case 0xa50065:
1380 if (X11DRV_SetupGCForBrush( physDevDst ))
1382 wine_tsx11_lock();
1383 XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1384 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1385 physDevDst->dc_rect.left + visRectDst.left,
1386 physDevDst->dc_rect.top + visRectDst.top,
1387 width, height );
1388 wine_tsx11_unlock();
1390 return TRUE;
1392 case SRCCOPY: /* 0xcc */
1393 case SRCINVERT:
1394 if (physDevSrc->depth == physDevDst->depth)
1396 wine_tsx11_lock();
1397 XSetFunction( gdi_display, physDevDst->gc, rop == SRCCOPY ? GXcopy : GXxor );
1398 XCopyArea( gdi_display, physDevSrc->drawable,
1399 physDevDst->drawable, physDevDst->gc,
1400 physDevSrc->dc_rect.left + visRectSrc.left,
1401 physDevSrc->dc_rect.top + visRectSrc.top,
1402 width, height,
1403 physDevDst->dc_rect.left + visRectDst.left,
1404 physDevDst->dc_rect.top + visRectDst.top );
1405 physDevDst->exposures++;
1406 wine_tsx11_unlock();
1407 return TRUE;
1410 if (physDevSrc->depth == 1)
1412 int fg, bg;
1413 get_colors(physDevDst, physDevSrc, &fg, &bg);
1414 wine_tsx11_lock();
1416 XSetBackground( gdi_display, physDevDst->gc, fg );
1417 XSetForeground( gdi_display, physDevDst->gc, bg );
1418 XSetFunction( gdi_display, physDevDst->gc, rop == SRCCOPY ? GXcopy : GXxor );
1419 XCopyPlane( gdi_display, physDevSrc->drawable,
1420 physDevDst->drawable, physDevDst->gc,
1421 physDevSrc->dc_rect.left + visRectSrc.left,
1422 physDevSrc->dc_rect.top + visRectSrc.top,
1423 width, height,
1424 physDevDst->dc_rect.left + visRectDst.left,
1425 physDevDst->dc_rect.top + visRectDst.top, 1 );
1426 physDevDst->exposures++;
1427 wine_tsx11_unlock();
1428 return TRUE;
1430 break;
1432 case PATCOPY: /* 0xf0 */
1433 if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1434 wine_tsx11_lock();
1435 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1436 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1437 physDevDst->dc_rect.left + visRectDst.left,
1438 physDevDst->dc_rect.top + visRectDst.top,
1439 width, height );
1440 wine_tsx11_unlock();
1441 return TRUE;
1443 case WHITENESS: /* 0xff */
1444 wine_tsx11_lock();
1445 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1446 XSetFunction( gdi_display, physDevDst->gc, GXset );
1447 else
1449 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1450 XSetForeground( gdi_display, physDevDst->gc,
1451 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1452 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1454 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1455 physDevDst->dc_rect.left + visRectDst.left,
1456 physDevDst->dc_rect.top + visRectDst.top,
1457 width, height );
1458 wine_tsx11_unlock();
1459 return TRUE;
1462 wine_tsx11_lock();
1463 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1464 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1465 XSetGraphicsExposures( gdi_display, tmpGC, False );
1466 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1467 physDevDst->depth );
1468 wine_tsx11_unlock();
1470 if (useSrc)
1472 wine_tsx11_lock();
1473 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1474 physDevDst->depth );
1475 wine_tsx11_unlock();
1476 if (fStretch)
1477 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1478 xSrc, ySrc, widthSrc, heightSrc,
1479 xDst, yDst, widthDst, heightDst,
1480 &visRectSrc, &visRectDst );
1481 else
1482 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1483 xSrc, ySrc, &visRectSrc );
1486 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1487 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1488 else fNullBrush = FALSE;
1489 destUsed = FALSE;
1491 wine_tsx11_lock();
1492 for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1494 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1495 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1496 switch(OP_SRCDST(*opcode))
1498 case OP_ARGS(DST,TMP):
1499 case OP_ARGS(SRC,TMP):
1500 if (!pixmaps[TMP])
1501 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1502 width, height, physDevDst->depth );
1503 /* fall through */
1504 case OP_ARGS(DST,SRC):
1505 case OP_ARGS(SRC,DST):
1506 case OP_ARGS(TMP,SRC):
1507 case OP_ARGS(TMP,DST):
1508 if (useSrc)
1509 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1510 pixmaps[OP_DST(*opcode)], tmpGC,
1511 0, 0, width, height, 0, 0 );
1512 break;
1514 case OP_ARGS(PAT,TMP):
1515 if (!pixmaps[TMP] && !fNullBrush)
1516 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1517 width, height, physDevDst->depth );
1518 /* fall through */
1519 case OP_ARGS(PAT,DST):
1520 case OP_ARGS(PAT,SRC):
1521 if (!fNullBrush)
1522 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1523 tmpGC, 0, 0, width, height );
1524 break;
1527 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1528 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1529 &visRectDst );
1530 XFreePixmap( gdi_display, pixmaps[DST] );
1531 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1532 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1533 XFreeGC( gdi_display, tmpGC );
1534 wine_tsx11_unlock();
1535 return TRUE;
1539 /***********************************************************************
1540 * X11DRV_PatBlt
1542 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1544 BOOL result;
1546 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod );
1547 result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1548 X11DRV_UnlockDIBSection( physDev, TRUE );
1549 return result;
1553 /***********************************************************************
1554 * X11DRV_ClientSideDIBCopy
1556 static BOOL X11DRV_ClientSideDIBCopy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1557 X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1558 INT width, INT height )
1560 DIBSECTION srcDib, dstDib;
1561 BYTE *srcPtr, *dstPtr;
1562 INT srcRowOffset, dstRowOffset;
1563 INT bytesPerPixel;
1564 INT bytesToCopy;
1565 INT y;
1566 static RECT unusedRect;
1568 if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib))
1569 return FALSE;
1570 if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib))
1571 return FALSE;
1573 /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */
1574 if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight)
1575 return FALSE;
1576 if (xSrc + width > srcDib.dsBm.bmWidth)
1577 width = srcDib.dsBm.bmWidth - xSrc;
1578 if (ySrc + height > srcDib.dsBm.bmHeight)
1579 height = srcDib.dsBm.bmHeight - ySrc;
1581 if (GetRgnBox(physDevSrc->region, &unusedRect) == COMPLEXREGION ||
1582 GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION)
1584 /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */
1585 FIXME("potential optimization: client-side complex region clipping\n");
1586 return FALSE;
1588 if (dstDib.dsBm.bmBitsPixel <= 8)
1590 FIXME("potential optimization: client-side color-index mode DIB copy\n");
1591 return FALSE;
1593 if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1594 dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1595 !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1596 && !(srcDib.dsBmih.biCompression == BI_RGB &&
1597 dstDib.dsBmih.biCompression == BI_RGB))
1599 FIXME("potential optimization: client-side compressed DIB copy\n");
1600 return FALSE;
1602 if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1604 FIXME("potential optimization: pixel format conversion\n");
1605 return FALSE;
1607 if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1609 FIXME("negative widths not yet implemented\n");
1610 return FALSE;
1613 switch (dstDib.dsBm.bmBitsPixel)
1615 case 15:
1616 case 16:
1617 bytesPerPixel = 2;
1618 break;
1619 case 24:
1620 bytesPerPixel = 3;
1621 break;
1622 case 32:
1623 bytesPerPixel = 4;
1624 break;
1625 default:
1626 FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1627 return FALSE;
1630 bytesToCopy = width * bytesPerPixel;
1632 if (srcDib.dsBmih.biHeight < 0)
1634 srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1635 srcRowOffset = srcDib.dsBm.bmWidthBytes;
1637 else
1639 srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1640 + xSrc*bytesPerPixel];
1641 srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1643 if (dstDib.dsBmih.biHeight < 0)
1645 dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1646 dstRowOffset = dstDib.dsBm.bmWidthBytes;
1648 else
1650 dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1651 + xDst*bytesPerPixel];
1652 dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1655 /* Handle overlapping regions on the same DIB */
1656 if (physDevSrc == physDevDst && ySrc < yDst)
1658 srcPtr += srcRowOffset * (height - 1);
1659 srcRowOffset = -srcRowOffset;
1660 dstPtr += dstRowOffset * (height - 1);
1661 dstRowOffset = -dstRowOffset;
1664 for (y = yDst; y < yDst + height; ++y)
1666 memmove(dstPtr, srcPtr, bytesToCopy);
1667 srcPtr += srcRowOffset;
1668 dstPtr += dstRowOffset;
1671 return TRUE;
1675 /***********************************************************************
1676 * X11DRV_BitBlt
1678 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1679 INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1680 INT xSrc, INT ySrc, DWORD rop )
1682 BOOL result = FALSE;
1683 INT sSrc, sDst;
1684 RECT visRectDst, visRectSrc;
1686 if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1687 /* FIXME: seems the ROP doesn't include destination;
1688 * now if the destination area include the entire dcDst,
1689 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1690 * which may avoid a copy in some situations */
1693 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None );
1694 if (physDevDst != physDevSrc)
1695 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None );
1696 else
1697 sSrc = sDst;
1699 if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1700 (physDevSrc->depth == physDevDst->depth))
1702 POINT pts[2];
1703 /* do everything ourselves; map coordinates */
1705 pts[0].x = xSrc;
1706 pts[0].y = ySrc;
1707 pts[1].x = xSrc + width;
1708 pts[1].y = ySrc + height;
1710 LPtoDP(physDevSrc->hdc, pts, 2);
1711 width = pts[1].x - pts[0].x;
1712 height = pts[1].y - pts[0].y;
1713 xSrc = pts[0].x;
1714 ySrc = pts[0].y;
1716 pts[0].x = xDst;
1717 pts[0].y = yDst;
1718 LPtoDP(physDevDst->hdc, pts, 1);
1720 xDst = pts[0].x;
1721 yDst = pts[0].y;
1723 /* Perform basic clipping */
1724 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, width, height,
1725 physDevSrc, xSrc, ySrc, width, height,
1726 &visRectSrc, &visRectDst ))
1727 goto END;
1729 xSrc = visRectSrc.left;
1730 ySrc = visRectSrc.top;
1731 xDst = visRectDst.left;
1732 yDst = visRectDst.top;
1733 width = visRectDst.right - visRectDst.left;
1734 height = visRectDst.bottom - visRectDst.top;
1736 if (sDst == DIB_Status_AppMod) {
1737 result = X11DRV_ClientSideDIBCopy( physDevSrc, xSrc, ySrc,
1738 physDevDst, xDst, yDst,
1739 width, height );
1740 if (result)
1741 goto END;
1742 /* fall back to X server copying */
1744 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod );
1746 wine_tsx11_lock();
1747 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1748 wine_tsx11_unlock();
1750 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1751 result = TRUE;
1752 goto END;
1755 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod );
1756 if (physDevDst != physDevSrc)
1757 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1759 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1760 physDevSrc, xSrc, ySrc, width, height, rop );
1762 END:
1763 if (physDevDst != physDevSrc)
1764 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1765 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1767 return result;
1771 /***********************************************************************
1772 * X11DRV_StretchBlt
1774 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1775 INT widthDst, INT heightDst,
1776 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1777 INT widthSrc, INT heightSrc, DWORD rop )
1779 BOOL result;
1781 X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod );
1782 if (physDevDst != physDevSrc)
1783 X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod );
1785 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1786 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1788 if (physDevDst != physDevSrc)
1789 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1790 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1791 return result;