kernel32: Update Italian translation.
[wine/testsucceed.git] / dlls / winex11.drv / bitblt.c
blob653e4189eb99d4604e539778f51c902f8cb90dcf
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(PAT,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 /* return a mask for meaningful bits when doing an XGetPixel on an image */
556 static unsigned long image_pixel_mask( X11DRV_PDEVICE *physDev )
558 unsigned long ret;
559 ColorShifts *shifts = physDev->color_shifts;
561 if (!shifts) shifts = &X11DRV_PALETTE_default_shifts;
562 ret = (shifts->physicalRed.max << shifts->physicalRed.shift) |
563 (shifts->physicalGreen.max << shifts->physicalGreen.shift) |
564 (shifts->physicalBlue.max << shifts->physicalBlue.shift);
565 if (!ret) ret = (1 << physDev->depth) - 1;
566 return ret;
570 /***********************************************************************
571 * BITBLT_StretchRow
573 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
575 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
576 INT startDst, INT widthDst,
577 INT xinc, INT xoff, WORD mode )
579 register INT xsrc = xinc * startDst + xoff;
580 rowDst += startDst;
581 switch(mode)
583 case STRETCH_ANDSCANS:
584 for(; widthDst > 0; widthDst--, xsrc += xinc)
585 *rowDst++ &= rowSrc[xsrc >> 16];
586 break;
587 case STRETCH_ORSCANS:
588 for(; widthDst > 0; widthDst--, xsrc += xinc)
589 *rowDst++ |= rowSrc[xsrc >> 16];
590 break;
591 case STRETCH_DELETESCANS:
592 for(; widthDst > 0; widthDst--, xsrc += xinc)
593 *rowDst++ = rowSrc[xsrc >> 16];
594 break;
599 /***********************************************************************
600 * BITBLT_ShrinkRow
602 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
604 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
605 INT startSrc, INT widthSrc,
606 INT xinc, INT xoff, WORD mode )
608 register INT xdst = xinc * startSrc + xoff;
609 rowSrc += startSrc;
610 switch(mode)
612 case STRETCH_ORSCANS:
613 for(; widthSrc > 0; widthSrc--, xdst += xinc)
614 rowDst[xdst >> 16] |= *rowSrc++;
615 break;
616 case STRETCH_ANDSCANS:
617 for(; widthSrc > 0; widthSrc--, xdst += xinc)
618 rowDst[xdst >> 16] &= *rowSrc++;
619 break;
620 case STRETCH_DELETESCANS:
621 for(; widthSrc > 0; widthSrc--, xdst += xinc)
622 rowDst[xdst >> 16] = *rowSrc++;
623 break;
628 /***********************************************************************
629 * BITBLT_GetRow
631 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
633 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
634 INT start, INT width, INT depthDst,
635 int fg, int bg, unsigned long pixel_mask, BOOL swap)
637 register INT i;
639 assert( (row >= 0) && (row < image->height) );
640 assert( (start >= 0) && (width <= image->width) );
642 pdata += swap ? start+width-1 : start;
643 if (image->depth == depthDst) /* color -> color */
645 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
646 if (swap) for (i = 0; i < width; i++)
647 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
648 else for (i = 0; i < width; i++)
649 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
650 else
651 if (swap) for (i = 0; i < width; i++)
652 *pdata-- = XGetPixel( image, i, row );
653 else for (i = 0; i < width; i++)
654 *pdata++ = XGetPixel( image, i, row );
656 else
658 if (image->depth == 1) /* monochrome -> color */
660 if (X11DRV_PALETTE_XPixelToPalette)
662 fg = X11DRV_PALETTE_XPixelToPalette[fg];
663 bg = X11DRV_PALETTE_XPixelToPalette[bg];
665 if (swap) for (i = 0; i < width; i++)
666 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
667 else for (i = 0; i < width; i++)
668 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
670 else /* color -> monochrome */
672 if (swap) for (i = 0; i < width; i++)
673 *pdata-- = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0;
674 else for (i = 0; i < width; i++)
675 *pdata++ = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0;
681 /***********************************************************************
682 * BITBLT_StretchImage
684 * Stretch an X image.
685 * FIXME: does not work for full 32-bit coordinates.
687 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
688 INT widthSrc, INT heightSrc,
689 INT widthDst, INT heightDst,
690 RECT *visRectSrc, RECT *visRectDst,
691 int foreground, int background,
692 unsigned long pixel_mask, WORD mode )
694 int *rowSrc, *rowDst, *pixel;
695 char *pdata;
696 INT xinc, xoff, yinc, ysrc, ydst;
697 register INT x, y;
698 BOOL hstretch, vstretch, hswap, vswap;
700 hswap = widthSrc * widthDst < 0;
701 vswap = heightSrc * heightDst < 0;
702 widthSrc = abs(widthSrc);
703 heightSrc = abs(heightSrc);
704 widthDst = abs(widthDst);
705 heightDst = abs(heightDst);
707 if (!(rowSrc = HeapAlloc( GetProcessHeap(), 0,
708 (widthSrc+widthDst)*sizeof(int) ))) return;
709 rowDst = rowSrc + widthSrc;
711 /* When stretching, all modes are the same, and DELETESCANS is faster */
712 if ((widthSrc < widthDst) && (heightSrc < heightDst))
713 mode = STRETCH_DELETESCANS;
715 if (mode == STRETCH_HALFTONE) /* FIXME */
716 mode = STRETCH_DELETESCANS;
718 if (mode != STRETCH_DELETESCANS)
719 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
720 widthDst*sizeof(int) );
722 hstretch = (widthSrc < widthDst);
723 vstretch = (heightSrc < heightDst);
725 if (hstretch)
727 xinc = (widthSrc << 16) / widthDst;
728 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
730 else
732 xinc = ((int)widthDst << 16) / widthSrc;
733 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
736 wine_tsx11_lock();
737 if (vstretch)
739 yinc = (heightSrc << 16) / heightDst;
740 ydst = visRectDst->top;
741 if (vswap)
743 ysrc = yinc * (heightDst - ydst - 1);
744 yinc = -yinc;
746 else
747 ysrc = yinc * ydst;
749 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
751 if (((ysrc >> 16) < visRectSrc->top) ||
752 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
754 /* Retrieve a source row */
755 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
756 hswap ? widthSrc - visRectSrc->right
757 : visRectSrc->left,
758 visRectSrc->right - visRectSrc->left,
759 dstImage->depth, foreground, background, pixel_mask, hswap );
761 /* Stretch or shrink it */
762 if (hstretch)
763 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
764 visRectDst->right - visRectDst->left,
765 xinc, xoff, mode );
766 else BITBLT_ShrinkRow( rowSrc, rowDst,
767 hswap ? widthSrc - visRectSrc->right
768 : visRectSrc->left,
769 visRectSrc->right - visRectSrc->left,
770 xinc, xoff, mode );
772 /* Store the destination row */
773 pixel = rowDst + visRectDst->right - 1;
774 y = ydst - visRectDst->top;
775 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
776 XPutPixel( dstImage, x, y, *pixel-- );
777 if (mode != STRETCH_DELETESCANS)
778 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
779 widthDst*sizeof(int) );
781 /* Make copies of the destination row */
783 pdata = dstImage->data + dstImage->bytes_per_line * y;
784 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
785 (ydst < visRectDst->bottom-1))
787 memcpy( pdata + dstImage->bytes_per_line, pdata,
788 dstImage->bytes_per_line );
789 pdata += dstImage->bytes_per_line;
790 ysrc += yinc;
791 ydst++;
795 else /* Shrinking */
797 yinc = (heightDst << 16) / heightSrc;
798 ysrc = visRectSrc->top;
799 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
800 if (vswap)
802 ydst += yinc * (heightSrc - ysrc - 1);
803 yinc = -yinc;
805 else
806 ydst += yinc * ysrc;
808 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
810 if (((ydst >> 16) < visRectDst->top) ||
811 ((ydst >> 16) >= visRectDst->bottom)) continue;
813 /* Retrieve a source row */
814 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
815 hswap ? widthSrc - visRectSrc->right
816 : visRectSrc->left,
817 visRectSrc->right - visRectSrc->left,
818 dstImage->depth, foreground, background, pixel_mask, hswap );
820 /* Stretch or shrink it */
821 if (hstretch)
822 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
823 visRectDst->right - visRectDst->left,
824 xinc, xoff, mode );
825 else BITBLT_ShrinkRow( rowSrc, rowDst,
826 hswap ? widthSrc - visRectSrc->right
827 : visRectSrc->left,
828 visRectSrc->right - visRectSrc->left,
829 xinc, xoff, mode );
831 /* Merge several source rows into the destination */
832 if (mode == STRETCH_DELETESCANS)
834 /* Simply skip the overlapping rows */
835 while (((ydst + yinc) >> 16 == ydst >> 16) &&
836 (ysrc < visRectSrc->bottom-1))
838 ydst += yinc;
839 ysrc++;
842 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
843 (ysrc < visRectSrc->bottom-1))
844 continue; /* Restart loop for next overlapping row */
846 /* Store the destination row */
847 pixel = rowDst + visRectDst->right - 1;
848 y = (ydst >> 16) - visRectDst->top;
849 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
850 XPutPixel( dstImage, x, y, *pixel-- );
851 if (mode != STRETCH_DELETESCANS)
852 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
853 widthDst*sizeof(int) );
856 wine_tsx11_unlock();
857 HeapFree( GetProcessHeap(), 0, rowSrc );
861 /***********************************************************************
862 * BITBLT_GetSrcAreaStretch
864 * Retrieve an area from the source DC, stretching and mapping all the
865 * pixels to Windows colors.
867 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
868 Pixmap pixmap, GC gc,
869 const struct bitblt_coords *src, const struct bitblt_coords *dst )
871 XImage *imageSrc, *imageDst;
872 RECT rectSrc = src->visrect;
873 RECT rectDst = dst->visrect;
874 int fg, bg;
876 rectSrc.left -= src->x;
877 rectSrc.right -= src->x;
878 rectSrc.top -= src->y;
879 rectSrc.bottom -= src->y;
880 rectDst.left -= dst->x;
881 rectDst.right -= dst->x;
882 rectDst.top -= dst->y;
883 rectDst.bottom -= dst->y;
884 if (src->width < 0)
886 rectSrc.left -= src->width;
887 rectSrc.right -= src->width;
889 if (dst->width < 0)
891 rectDst.left -= dst->width;
892 rectDst.right -= dst->width;
894 if (src->height < 0)
896 rectSrc.top -= src->height;
897 rectSrc.bottom -= src->height;
899 if (dst->height < 0)
901 rectDst.top -= dst->height;
902 rectDst.bottom -= dst->height;
905 get_colors(physDevDst, physDevSrc, &fg, &bg);
906 wine_tsx11_lock();
907 /* FIXME: avoid BadMatch errors */
908 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
909 physDevSrc->dc_rect.left + src->visrect.left,
910 physDevSrc->dc_rect.top + src->visrect.top,
911 src->visrect.right - src->visrect.left,
912 src->visrect.bottom - src->visrect.top,
913 AllPlanes, ZPixmap );
914 wine_tsx11_unlock();
916 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
917 rectDst.bottom - rectDst.top, physDevDst->depth );
918 BITBLT_StretchImage( imageSrc, imageDst, src->width, src->height,
919 dst->width, dst->height, &rectSrc, &rectDst,
920 fg, physDevDst->depth != 1 ? bg : physDevSrc->backgroundPixel,
921 image_pixel_mask( physDevSrc ), GetStretchBltMode(physDevDst->hdc) );
922 wine_tsx11_lock();
923 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
924 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
925 XDestroyImage( imageSrc );
926 X11DRV_DIB_DestroyXImage( imageDst );
927 wine_tsx11_unlock();
928 return 0; /* no exposure events generated */
932 /***********************************************************************
933 * BITBLT_GetSrcArea
935 * Retrieve an area from the source DC, mapping all the
936 * pixels to Windows colors.
938 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
939 Pixmap pixmap, GC gc, RECT *visRectSrc )
941 XImage *imageSrc, *imageDst;
942 register INT x, y;
943 int exposures = 0;
944 INT width = visRectSrc->right - visRectSrc->left;
945 INT height = visRectSrc->bottom - visRectSrc->top;
946 int fg, bg;
947 BOOL memdc = (GetObjectType(physDevSrc->hdc) == OBJ_MEMDC);
949 if (physDevSrc->depth == physDevDst->depth)
951 wine_tsx11_lock();
952 if (!X11DRV_PALETTE_XPixelToPalette ||
953 (physDevDst->depth == 1)) /* monochrome -> monochrome */
955 if (physDevDst->depth == 1)
957 /* MSDN says if StretchBlt must convert a bitmap from monochrome
958 to color or vice versa, the foreground and background color of
959 the device context are used. In fact, it also applies to the
960 case when it is converted from mono to mono. */
961 XSetBackground( gdi_display, gc, physDevDst->textPixel );
962 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
963 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
964 physDevSrc->dc_rect.left + visRectSrc->left,
965 physDevSrc->dc_rect.top + visRectSrc->top,
966 width, height, 0, 0, 1);
968 else
969 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
970 physDevSrc->dc_rect.left + visRectSrc->left,
971 physDevSrc->dc_rect.top + visRectSrc->top,
972 width, height, 0, 0);
973 exposures++;
975 else /* color -> color */
977 if (memdc)
978 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
979 physDevSrc->dc_rect.left + visRectSrc->left,
980 physDevSrc->dc_rect.top + visRectSrc->top,
981 width, height, AllPlanes, ZPixmap );
982 else
984 /* Make sure we don't get a BadMatch error */
985 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
986 physDevSrc->dc_rect.left + visRectSrc->left,
987 physDevSrc->dc_rect.top + visRectSrc->top,
988 width, height, 0, 0);
989 exposures++;
990 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
991 AllPlanes, ZPixmap );
993 for (y = 0; y < height; y++)
994 for (x = 0; x < width; x++)
995 XPutPixel(imageSrc, x, y,
996 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
997 XPutImage( gdi_display, pixmap, gc, imageSrc,
998 0, 0, 0, 0, width, height );
999 XDestroyImage( imageSrc );
1001 wine_tsx11_unlock();
1003 else
1005 if (physDevSrc->depth == 1) /* monochrome -> color */
1007 get_colors(physDevDst, physDevSrc, &fg, &bg);
1009 wine_tsx11_lock();
1010 if (X11DRV_PALETTE_XPixelToPalette)
1012 XSetBackground( gdi_display, gc,
1013 X11DRV_PALETTE_XPixelToPalette[fg] );
1014 XSetForeground( gdi_display, gc,
1015 X11DRV_PALETTE_XPixelToPalette[bg]);
1017 else
1019 XSetBackground( gdi_display, gc, fg );
1020 XSetForeground( gdi_display, gc, bg );
1022 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
1023 physDevSrc->dc_rect.left + visRectSrc->left,
1024 physDevSrc->dc_rect.top + visRectSrc->top,
1025 width, height, 0, 0, 1 );
1026 exposures++;
1027 wine_tsx11_unlock();
1029 else /* color -> monochrome */
1031 unsigned long pixel_mask;
1032 wine_tsx11_lock();
1033 /* FIXME: avoid BadMatch error */
1034 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1035 physDevSrc->dc_rect.left + visRectSrc->left,
1036 physDevSrc->dc_rect.top + visRectSrc->top,
1037 width, height, AllPlanes, ZPixmap );
1038 if (!imageSrc)
1040 wine_tsx11_unlock();
1041 return exposures;
1043 imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1044 if (!imageDst)
1046 XDestroyImage(imageSrc);
1047 wine_tsx11_unlock();
1048 return exposures;
1050 pixel_mask = image_pixel_mask( physDevSrc );
1051 for (y = 0; y < height; y++)
1052 for (x = 0; x < width; x++)
1053 XPutPixel(imageDst, x, y,
1054 !((XGetPixel(imageSrc,x,y) ^ physDevSrc->backgroundPixel) & pixel_mask));
1055 XPutImage( gdi_display, pixmap, gc, imageDst,
1056 0, 0, 0, 0, width, height );
1057 XDestroyImage( imageSrc );
1058 X11DRV_DIB_DestroyXImage( imageDst );
1059 wine_tsx11_unlock();
1062 return exposures;
1066 /***********************************************************************
1067 * BITBLT_GetDstArea
1069 * Retrieve an area from the destination DC, mapping all the
1070 * pixels to Windows colors.
1072 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1074 int exposures = 0;
1075 INT width = visRectDst->right - visRectDst->left;
1076 INT height = visRectDst->bottom - visRectDst->top;
1077 BOOL memdc = (GetObjectType( physDev->hdc ) == OBJ_MEMDC);
1079 wine_tsx11_lock();
1081 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1082 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1084 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1085 physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top,
1086 width, height, 0, 0 );
1087 exposures++;
1089 else
1091 register INT x, y;
1092 XImage *image;
1094 if (memdc)
1095 image = XGetImage( gdi_display, physDev->drawable,
1096 physDev->dc_rect.left + visRectDst->left,
1097 physDev->dc_rect.top + visRectDst->top,
1098 width, height, AllPlanes, ZPixmap );
1099 else
1101 /* Make sure we don't get a BadMatch error */
1102 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1103 physDev->dc_rect.left + visRectDst->left,
1104 physDev->dc_rect.top + visRectDst->top,
1105 width, height, 0, 0);
1106 exposures++;
1107 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1108 AllPlanes, ZPixmap );
1110 if (image)
1112 for (y = 0; y < height; y++)
1113 for (x = 0; x < width; x++)
1114 XPutPixel( image, x, y,
1115 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1116 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1117 XDestroyImage( image );
1121 wine_tsx11_unlock();
1122 return exposures;
1126 /***********************************************************************
1127 * BITBLT_PutDstArea
1129 * Put an area back into the destination DC, mapping the pixel
1130 * colors to X pixels.
1132 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1134 int exposures = 0;
1135 INT width = visRectDst->right - visRectDst->left;
1136 INT height = visRectDst->bottom - visRectDst->top;
1138 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1140 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1141 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1143 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1144 physDev->dc_rect.left + visRectDst->left,
1145 physDev->dc_rect.top + visRectDst->top );
1146 exposures++;
1148 else
1150 register INT x, y;
1151 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1152 AllPlanes, ZPixmap );
1153 for (y = 0; y < height; y++)
1154 for (x = 0; x < width; x++)
1156 XPutPixel( image, x, y,
1157 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1159 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1160 physDev->dc_rect.left + visRectDst->left,
1161 physDev->dc_rect.top + visRectDst->top, width, height );
1162 XDestroyImage( image );
1164 return exposures;
1168 /***********************************************************************
1169 * BITBLT_GetVisRectangles
1171 * Get the source and destination visible rectangles for StretchBlt().
1172 * Return FALSE if one of the rectangles is empty.
1174 static BOOL BITBLT_GetVisRectangles( X11DRV_PDEVICE *physDevDst, X11DRV_PDEVICE *physDevSrc,
1175 struct bitblt_coords *dst, struct bitblt_coords *src )
1177 RECT rect, clipRect;
1179 /* Get the destination visible rectangle */
1181 rect.left = dst->x;
1182 rect.top = dst->y;
1183 rect.right = dst->x + dst->width;
1184 rect.bottom = dst->y + dst->height;
1185 LPtoDP( physDevDst->hdc, (POINT *)&rect, 2 );
1186 dst->x = rect.left;
1187 dst->y = rect.top;
1188 dst->width = rect.right - rect.left;
1189 dst->height = rect.bottom - rect.top;
1190 if (dst->width < 0) SWAP_INT32( &rect.left, &rect.right );
1191 if (dst->height < 0) SWAP_INT32( &rect.top, &rect.bottom );
1193 GetRgnBox( physDevDst->region, &clipRect );
1194 if (!IntersectRect( &dst->visrect, &rect, &clipRect )) return FALSE;
1196 /* Get the source visible rectangle */
1198 if (!physDevSrc) return TRUE;
1200 rect.left = src->x;
1201 rect.top = src->y;
1202 rect.right = src->x + src->width;
1203 rect.bottom = src->y + src->height;
1204 LPtoDP( physDevSrc->hdc, (POINT *)&rect, 2 );
1205 src->x = rect.left;
1206 src->y = rect.top;
1207 src->width = rect.right - rect.left;
1208 src->height = rect.bottom - rect.top;
1209 if (src->width < 0) SWAP_INT32( &rect.left, &rect.right );
1210 if (src->height < 0) SWAP_INT32( &rect.top, &rect.bottom );
1212 /* Apparently the clipping and visible regions are only for output,
1213 so just check against dc extent here to avoid BadMatch errors */
1214 clipRect = physDevSrc->drawable_rect;
1215 OffsetRect( &clipRect, -(physDevSrc->drawable_rect.left + physDevSrc->dc_rect.left),
1216 -(physDevSrc->drawable_rect.top + physDevSrc->dc_rect.top) );
1217 if (!IntersectRect( &src->visrect, &rect, &clipRect ))
1218 return FALSE;
1220 /* Intersect the rectangles */
1222 if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */
1224 OffsetRect( &src->visrect, dst->x - src->x, dst->y - src->y );
1225 if (!IntersectRect( &rect, &src->visrect, &dst->visrect )) return FALSE;
1226 src->visrect = dst->visrect = rect;
1227 OffsetRect( &src->visrect, src->x - dst->x, src->y - dst->y );
1229 else /* stretching */
1231 /* Map source rectangle into destination coordinates */
1232 rect.left = dst->x + (src->visrect.left - src->x)*dst->width/src->width;
1233 rect.top = dst->y + (src->visrect.top - src->y)*dst->height/src->height;
1234 rect.right = dst->x + (src->visrect.right - src->x)*dst->width/src->width;
1235 rect.bottom = dst->y + (src->visrect.bottom - src->y)*dst->height/src->height;
1236 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1237 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1239 /* Avoid rounding errors */
1240 rect.left--;
1241 rect.top--;
1242 rect.right++;
1243 rect.bottom++;
1244 if (!IntersectRect( &dst->visrect, &rect, &dst->visrect )) return FALSE;
1246 /* Map destination rectangle back to source coordinates */
1247 rect = dst->visrect;
1248 rect.left = src->x + (dst->visrect.left - dst->x)*src->width/dst->width;
1249 rect.top = src->y + (dst->visrect.top - dst->y)*src->height/dst->height;
1250 rect.right = src->x + (dst->visrect.right - dst->x)*src->width/dst->width;
1251 rect.bottom = src->y + (dst->visrect.bottom - dst->y)*src->height/dst->height;
1252 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1253 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1255 /* Avoid rounding errors */
1256 rect.left--;
1257 rect.top--;
1258 rect.right++;
1259 rect.bottom++;
1260 if (!IntersectRect( &src->visrect, &rect, &src->visrect )) return FALSE;
1262 return TRUE;
1266 /***********************************************************************
1267 * client_side_dib_copy
1269 static BOOL client_side_dib_copy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1270 X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1271 INT width, INT height )
1273 DIBSECTION srcDib, dstDib;
1274 BYTE *srcPtr, *dstPtr;
1275 INT srcRowOffset, dstRowOffset;
1276 INT bytesPerPixel;
1277 INT bytesToCopy;
1278 INT y;
1279 static RECT unusedRect;
1281 if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib))
1282 return FALSE;
1283 if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib))
1284 return FALSE;
1286 /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */
1287 if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight)
1288 return FALSE;
1289 if (xSrc + width > srcDib.dsBm.bmWidth)
1290 width = srcDib.dsBm.bmWidth - xSrc;
1291 if (ySrc + height > srcDib.dsBm.bmHeight)
1292 height = srcDib.dsBm.bmHeight - ySrc;
1294 if (GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION)
1296 /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */
1297 FIXME("potential optimization: client-side complex region clipping\n");
1298 return FALSE;
1300 if (dstDib.dsBm.bmBitsPixel <= 8)
1302 FIXME("potential optimization: client-side color-index mode DIB copy\n");
1303 return FALSE;
1305 if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS &&
1306 dstDib.dsBmih.biCompression == BI_BITFIELDS &&
1307 !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD)))
1308 && !(srcDib.dsBmih.biCompression == BI_RGB &&
1309 dstDib.dsBmih.biCompression == BI_RGB))
1311 FIXME("potential optimization: client-side compressed DIB copy\n");
1312 return FALSE;
1314 if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel)
1316 FIXME("potential optimization: pixel format conversion\n");
1317 return FALSE;
1319 if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0)
1321 FIXME("negative widths not yet implemented\n");
1322 return FALSE;
1325 switch (dstDib.dsBm.bmBitsPixel)
1327 case 15:
1328 case 16:
1329 bytesPerPixel = 2;
1330 break;
1331 case 24:
1332 bytesPerPixel = 3;
1333 break;
1334 case 32:
1335 bytesPerPixel = 4;
1336 break;
1337 default:
1338 FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth);
1339 return FALSE;
1342 bytesToCopy = width * bytesPerPixel;
1344 if (physDevSrc->bitmap->topdown)
1346 srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel];
1347 srcRowOffset = srcDib.dsBm.bmWidthBytes;
1349 else
1351 srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes
1352 + xSrc*bytesPerPixel];
1353 srcRowOffset = -srcDib.dsBm.bmWidthBytes;
1355 if (physDevDst->bitmap->topdown)
1357 dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel];
1358 dstRowOffset = dstDib.dsBm.bmWidthBytes;
1360 else
1362 dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes
1363 + xDst*bytesPerPixel];
1364 dstRowOffset = -dstDib.dsBm.bmWidthBytes;
1367 /* Handle overlapping regions on the same DIB */
1368 if (physDevSrc == physDevDst && ySrc < yDst)
1370 srcPtr += srcRowOffset * (height - 1);
1371 srcRowOffset = -srcRowOffset;
1372 dstPtr += dstRowOffset * (height - 1);
1373 dstRowOffset = -dstRowOffset;
1376 for (y = yDst; y < yDst + height; ++y)
1378 memmove(dstPtr, srcPtr, bytesToCopy);
1379 srcPtr += srcRowOffset;
1380 dstPtr += dstRowOffset;
1383 return TRUE;
1386 static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst)
1388 if (physDevSrc->depth != physDevDst->depth) return FALSE;
1389 if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE;
1390 if (physDevSrc->color_shifts && physDevDst->color_shifts)
1391 return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts));
1392 return FALSE;
1395 /***********************************************************************
1396 * X11DRV_StretchBlt
1398 BOOL CDECL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1399 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1400 DWORD rop )
1402 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1403 struct bitblt_coords src, dst;
1404 INT width, height;
1405 INT sDst, sSrc = DIB_Status_None;
1406 const BYTE *opcode;
1407 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1408 GC tmpGC = 0;
1410 /* compensate for off-by-one shifting for negative widths and heights */
1411 if (widthDst < 0)
1412 ++xDst;
1413 if (heightDst < 0)
1414 ++yDst;
1415 if (widthSrc < 0)
1416 ++xSrc;
1417 if (heightSrc < 0)
1418 ++ySrc;
1420 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1421 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1422 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1423 if (!physDevSrc && useSrc) return FALSE;
1425 src.x = xSrc;
1426 src.y = ySrc;
1427 src.width = widthSrc;
1428 src.height = heightSrc;
1429 dst.x = xDst;
1430 dst.y = yDst;
1431 dst.width = widthDst;
1432 dst.height = heightDst;
1434 if (useSrc)
1436 if (!BITBLT_GetVisRectangles( physDevDst, physDevSrc, &dst, &src ))
1437 return TRUE;
1438 fStretch = (src.width != dst.width) || (src.height != dst.height);
1440 if (physDevDst != physDevSrc)
1441 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None );
1443 else
1445 fStretch = FALSE;
1446 if (!BITBLT_GetVisRectangles( physDevDst, NULL, &dst, NULL ))
1447 return TRUE;
1450 TRACE(" rectdst=%d,%d %dx%d orgdst=%d,%d visdst=%s\n",
1451 dst.x, dst.y, dst.width, dst.height,
1452 physDevDst->dc_rect.left, physDevDst->dc_rect.top, wine_dbgstr_rect( &dst.visrect ) );
1453 if (useSrc)
1454 TRACE(" rectsrc=%d,%d %dx%d orgsrc=%d,%d vissrc=%s\n",
1455 src.x, src.y, src.width, src.height,
1456 physDevSrc->dc_rect.left, physDevSrc->dc_rect.top, wine_dbgstr_rect( &src.visrect ) );
1458 width = dst.visrect.right - dst.visrect.left;
1459 height = dst.visrect.bottom - dst.visrect.top;
1461 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None );
1462 if (physDevDst == physDevSrc) sSrc = sDst;
1464 /* try client-side DIB copy */
1465 if (!fStretch && rop == SRCCOPY &&
1466 sSrc == DIB_Status_AppMod && sDst == DIB_Status_AppMod &&
1467 same_format(physDevSrc, physDevDst))
1469 if (client_side_dib_copy( physDevSrc, src.visrect.left, src.visrect.top,
1470 physDevDst, dst.visrect.left, dst.visrect.top, width, height ))
1471 goto done;
1474 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod );
1476 opcode = BITBLT_Opcodes[(rop >> 16) & 0xff];
1478 /* a few optimizations for single-op ROPs */
1479 if (!fStretch && !opcode[1])
1481 if (OP_SRCDST(*opcode) == OP_ARGS(PAT,DST))
1483 switch(rop) /* a few special cases */
1485 case BLACKNESS: /* 0x00 */
1486 case WHITENESS: /* 0xff */
1487 if ((physDevDst->depth != 1) && X11DRV_PALETTE_PaletteToXPixel)
1489 wine_tsx11_lock();
1490 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1491 if (rop == BLACKNESS)
1492 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1493 else
1494 XSetForeground( gdi_display, physDevDst->gc,
1495 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1496 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1497 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1498 physDevDst->dc_rect.left + dst.visrect.left,
1499 physDevDst->dc_rect.top + dst.visrect.top,
1500 width, height );
1501 wine_tsx11_unlock();
1502 goto done;
1504 break;
1505 case DSTINVERT: /* 0x55 */
1506 if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL)))
1508 /* Xor is much better when we do not have full colormap. */
1509 /* Using white^black ensures that we invert at least black */
1510 /* and white. */
1511 unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1512 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1513 wine_tsx11_lock();
1514 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1515 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1516 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1517 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1518 physDevDst->dc_rect.left + dst.visrect.left,
1519 physDevDst->dc_rect.top + dst.visrect.top,
1520 width, height );
1521 wine_tsx11_unlock();
1522 goto done;
1524 break;
1526 if (!usePat || X11DRV_SetupGCForBrush( physDevDst ))
1528 wine_tsx11_lock();
1529 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1530 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1531 physDevDst->dc_rect.left + dst.visrect.left,
1532 physDevDst->dc_rect.top + dst.visrect.top,
1533 width, height );
1534 wine_tsx11_unlock();
1536 goto done;
1538 else if (OP_SRCDST(*opcode) == OP_ARGS(SRC,DST))
1540 if (same_format(physDevSrc, physDevDst))
1542 wine_tsx11_lock();
1543 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1544 wine_tsx11_unlock();
1546 if (physDevSrc != physDevDst)
1548 if (sSrc == DIB_Status_AppMod)
1550 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, src.visrect.left, src.visrect.top,
1551 dst.visrect.left, dst.visrect.top, width, height );
1552 goto done;
1554 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1556 wine_tsx11_lock();
1557 XCopyArea( gdi_display, physDevSrc->drawable,
1558 physDevDst->drawable, physDevDst->gc,
1559 physDevSrc->dc_rect.left + src.visrect.left,
1560 physDevSrc->dc_rect.top + src.visrect.top,
1561 width, height,
1562 physDevDst->dc_rect.left + dst.visrect.left,
1563 physDevDst->dc_rect.top + dst.visrect.top );
1564 physDevDst->exposures++;
1565 wine_tsx11_unlock();
1566 goto done;
1568 if (physDevSrc->depth == 1)
1570 int fg, bg;
1572 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1573 get_colors(physDevDst, physDevSrc, &fg, &bg);
1574 wine_tsx11_lock();
1575 XSetBackground( gdi_display, physDevDst->gc, fg );
1576 XSetForeground( gdi_display, physDevDst->gc, bg );
1577 XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) );
1578 XCopyPlane( gdi_display, physDevSrc->drawable,
1579 physDevDst->drawable, physDevDst->gc,
1580 physDevSrc->dc_rect.left + src.visrect.left,
1581 physDevSrc->dc_rect.top + src.visrect.top,
1582 width, height,
1583 physDevDst->dc_rect.left + dst.visrect.left,
1584 physDevDst->dc_rect.top + dst.visrect.top, 1 );
1585 physDevDst->exposures++;
1586 wine_tsx11_unlock();
1587 goto done;
1592 wine_tsx11_lock();
1593 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1594 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1595 XSetGraphicsExposures( gdi_display, tmpGC, False );
1596 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1597 physDevDst->depth );
1598 wine_tsx11_unlock();
1600 if (useSrc)
1602 wine_tsx11_lock();
1603 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1604 physDevDst->depth );
1605 wine_tsx11_unlock();
1607 if (physDevDst != physDevSrc) X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod );
1609 if(!X11DRV_XRender_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, &src, &dst ))
1611 if (fStretch)
1612 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, &src, &dst );
1613 else
1614 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, &src.visrect );
1618 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &dst.visrect );
1619 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1620 else fNullBrush = FALSE;
1621 destUsed = FALSE;
1623 wine_tsx11_lock();
1624 for ( ; *opcode; opcode++)
1626 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1627 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1628 switch(OP_SRCDST(*opcode))
1630 case OP_ARGS(DST,TMP):
1631 case OP_ARGS(SRC,TMP):
1632 if (!pixmaps[TMP])
1633 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1634 width, height, physDevDst->depth );
1635 /* fall through */
1636 case OP_ARGS(DST,SRC):
1637 case OP_ARGS(SRC,DST):
1638 case OP_ARGS(TMP,SRC):
1639 case OP_ARGS(TMP,DST):
1640 if (useSrc)
1641 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1642 pixmaps[OP_DST(*opcode)], tmpGC,
1643 0, 0, width, height, 0, 0 );
1644 break;
1646 case OP_ARGS(PAT,TMP):
1647 if (!pixmaps[TMP] && !fNullBrush)
1648 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1649 width, height, physDevDst->depth );
1650 /* fall through */
1651 case OP_ARGS(PAT,DST):
1652 case OP_ARGS(PAT,SRC):
1653 if (!fNullBrush)
1654 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1655 tmpGC, 0, 0, width, height );
1656 break;
1659 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1660 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC], &dst.visrect );
1661 XFreePixmap( gdi_display, pixmaps[DST] );
1662 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1663 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1664 XFreeGC( gdi_display, tmpGC );
1665 wine_tsx11_unlock();
1667 done:
1668 if (useSrc && physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1669 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1670 return TRUE;
1674 /***********************************************************************
1675 * X11DRV_AlphaBlend
1677 BOOL CDECL X11DRV_AlphaBlend( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
1678 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
1679 BLENDFUNCTION blendfn )
1681 struct bitblt_coords src, dst;
1683 src.x = xSrc;
1684 src.y = ySrc;
1685 src.width = widthSrc;
1686 src.height = heightSrc;
1687 dst.x = xDst;
1688 dst.y = yDst;
1689 dst.width = widthDst;
1690 dst.height = heightDst;
1692 if (!BITBLT_GetVisRectangles( physDevDst, physDevSrc, &dst, &src )) return TRUE;
1694 TRACE( "format %x alpha %u rectdst=%d,%d %dx%d orgdst=%d,%d visdst=%s rectsrc=%d,%d %dx%d orgsrc=%d,%d vissrc=%s\n",
1695 blendfn.AlphaFormat, blendfn.SourceConstantAlpha, dst.x, dst.y, dst.width, dst.height,
1696 physDevDst->dc_rect.left, physDevDst->dc_rect.top, wine_dbgstr_rect( &dst.visrect ),
1697 src.x, src.y, src.width, src.height,
1698 physDevSrc->dc_rect.left, physDevSrc->dc_rect.top, wine_dbgstr_rect( &src.visrect ) );
1700 if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 ||
1701 src.width > physDevSrc->drawable_rect.right - physDevSrc->drawable_rect.left - src.x ||
1702 src.height > physDevSrc->drawable_rect.bottom - physDevSrc->drawable_rect.top - src.y)
1704 WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height );
1705 SetLastError( ERROR_INVALID_PARAMETER );
1706 return FALSE;
1709 return XRender_AlphaBlend( physDevDst, physDevSrc, &dst, &src, blendfn );