Fix -Wwrite-strings warnings.
[wine/wine64.git] / dlls / x11drv / bitblt.c
blobe71c0bbbbf1ae2bd48ee719cf7383dede34b98c2
1 /*
2 * GDI bit-blit operations
4 * Copyright 1993, 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
23 #include <assert.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <X11/Intrinsic.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winreg.h"
33 #include "winuser.h"
34 #include "x11drv.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
40 #define DST 0 /* Destination drawable */
41 #define SRC 1 /* Source drawable */
42 #define TMP 2 /* Temporary drawable */
43 #define PAT 3 /* Pattern (brush) in destination DC */
45 #define OP(src,dst,rop) (OP_ARGS(src,dst) << 4 | (rop))
46 #define OP_ARGS(src,dst) (((src) << 2) | (dst))
48 #define OP_SRC(opcode) ((opcode) >> 6)
49 #define OP_DST(opcode) (((opcode) >> 4) & 3)
50 #define OP_SRCDST(opcode) ((opcode) >> 4)
51 #define OP_ROP(opcode) ((opcode) & 0x0f)
53 #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */
55 #define SWAP_INT32(i1,i2) \
56 do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
58 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
60 { OP(PAT,DST,GXclear) }, /* 0x00 0 */
61 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */
62 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */
63 { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */
64 { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */
65 { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */
66 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */
67 { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */
68 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */
69 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */
70 { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */
71 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */
72 { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */
73 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */
74 { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */
75 { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */
76 { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */
77 { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */
78 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */
79 { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */
80 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */
81 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */
82 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
83 OP(TMP,DST,GXand), OP(SRC,DST,GXxor),
84 OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */
85 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
86 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
87 OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/
88 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
89 OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */
90 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
91 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */
92 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
93 OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */
94 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXxor),
95 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */
96 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
97 OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */
98 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
99 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */
100 { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */
101 { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */
102 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */
103 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */
104 { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */
105 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */
106 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
107 OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */
108 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
109 OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */
110 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
111 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
112 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXequiv),
113 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */
114 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */
115 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
116 OP(TMP,DST,GXor), OP(SRC,DST,GXxor),
117 OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */
118 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */
119 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
120 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
121 OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/
122 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
123 OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */
124 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */
125 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
126 OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */
127 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */
128 { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */
129 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */
130 { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
131 OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */
132 { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */
133 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
134 OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */
135 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
136 OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */
137 { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */
138 { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */
139 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
140 OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */
141 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */
142 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
143 OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */
144 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */
145 { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */
146 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
147 OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */
148 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
149 OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */
150 { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */
151 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */
152 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */
153 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
154 OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */
155 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
156 OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */
157 { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */
158 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */
159 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
160 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */
161 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
162 OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */
163 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */
164 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
165 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
166 OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */
167 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
168 OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */
169 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */
170 { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */
171 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
172 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
173 OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/
174 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
175 OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */
176 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */
177 { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */
178 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */
179 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
180 OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */
181 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
182 OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */
183 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */
184 { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */
185 { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */
186 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */
187 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
188 OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */
189 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */
190 { OP(PAT,DST,GXxor) }, /* 0x5a D^P */
191 { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
192 OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */
193 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
194 OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */
195 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */
196 { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
197 OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */
198 { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */
199 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */
200 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
201 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
202 OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */
203 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
204 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */
205 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */
206 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
207 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */
208 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */
209 { OP(SRC,DST,GXxor) }, /* 0x66 S^D */
210 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
211 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */
212 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
213 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
214 OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/
215 { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */
216 { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */
217 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
218 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
219 OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */
220 { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */
221 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
222 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
223 OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */
224 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
225 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */
226 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */
227 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */
228 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
229 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
230 OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/
231 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
232 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */
233 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */
234 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
235 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */
236 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */
237 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
238 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */
239 { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */
240 { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */
241 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
242 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
243 OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */
244 { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
245 OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */
246 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */
247 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
248 OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */
249 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */
250 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
251 OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */
252 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */
253 { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */
254 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
255 OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */
256 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */
257 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
258 OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */
259 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */
260 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
261 OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */
262 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
263 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
264 OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */
265 { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */
266 { OP(SRC,DST,GXand) }, /* 0x88 S&D */
267 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
268 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */
269 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */
270 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
271 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */
272 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */
273 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
274 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */
275 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
276 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
277 OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/
278 { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */
279 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */
280 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
281 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */
282 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
283 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
284 OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */
285 { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */
286 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
287 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
288 OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */
289 { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */
290 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */
291 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
292 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
293 OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */
294 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
295 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */
296 { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */
297 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */
298 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
299 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */
300 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */
301 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
302 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */
303 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
304 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
305 OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */
306 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */
307 { OP(PAT,DST,GXand) }, /* 0xa0 D&P */
308 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
309 OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */
310 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */
311 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
312 OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */
313 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
314 OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */
315 { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */
316 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */
317 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
318 OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */
319 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */
320 { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */
321 { OP(SRC,DST,GXnoop) }, /* 0xaa D */
322 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */
323 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
324 OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */
325 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
326 OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */
327 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */
328 { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */
329 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */
330 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
331 OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */
332 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
333 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
334 OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/
335 { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */
336 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */
337 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
338 OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */
339 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
340 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
341 OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */
342 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */
343 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
344 OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */
345 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
346 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */
347 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */
348 { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */
349 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
350 OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */
351 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
352 OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */
353 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */
354 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */
355 { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */
356 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
357 OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */
358 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
359 OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */
360 { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */
361 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */
362 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
363 OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */
364 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */
365 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
366 OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */
367 { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */
368 { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */
369 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
370 OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */
371 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
372 OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */
373 { OP(SRC,DST,GXcopy) }, /* 0xcc S */
374 { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */
375 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */
376 { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */
377 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */
378 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
379 OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */
380 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */
381 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
382 OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */
383 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
384 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
385 OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/
386 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */
387 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
388 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
389 OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */
390 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */
391 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
392 OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */
393 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
394 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */
395 { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
396 OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */
397 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
398 OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */
399 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */
400 { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */
401 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */
402 { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */
403 { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */
404 { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */
405 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
406 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */
407 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
408 OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */
409 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
410 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */
411 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
412 OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */
413 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
414 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */
415 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
416 OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */
417 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
418 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
419 OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/
420 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
421 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
422 OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/
423 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */
424 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */
425 { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */
426 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */
427 { OP(SRC,DST,GXor) }, /* 0xee S|D */
428 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */
429 { OP(PAT,DST,GXcopy) }, /* 0xf0 P */
430 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */
431 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */
432 { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */
433 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */
434 { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */
435 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */
436 { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */
437 { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */
438 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */
439 { OP(PAT,DST,GXor) }, /* 0xfa D|P */
440 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */
441 { OP(PAT,SRC,GXor) }, /* 0xfc P|S */
442 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */
443 { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */
444 { OP(PAT,DST,GXset) } /* 0xff 1 */
448 #ifdef BITBLT_TEST /* Opcodes test */
450 static int do_bitop( int s, int d, int rop )
452 int res;
453 switch(rop)
455 case GXclear: res = 0; break;
456 case GXand: res = s & d; break;
457 case GXandReverse: res = s & ~d; break;
458 case GXcopy: res = s; break;
459 case GXandInverted: res = ~s & d; break;
460 case GXnoop: res = d; break;
461 case GXxor: res = s ^ d; break;
462 case GXor: res = s | d; break;
463 case GXnor: res = ~(s | d); break;
464 case GXequiv: res = ~s ^ d; break;
465 case GXinvert: res = ~d; break;
466 case GXorReverse: res = s | ~d; break;
467 case GXcopyInverted: res = ~s; break;
468 case GXorInverted: res = ~s | d; break;
469 case GXnand: res = ~(s & d); break;
470 case GXset: res = 1; break;
472 return res & 1;
475 int main()
477 int rop, i, res, src, dst, pat, tmp, dstUsed;
478 const BYTE *opcode;
480 for (rop = 0; rop < 256; rop++)
482 res = dstUsed = 0;
483 for (i = 0; i < 8; i++)
485 pat = (i >> 2) & 1;
486 src = (i >> 1) & 1;
487 dst = i & 1;
488 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
490 switch(*opcode >> 4)
492 case OP_ARGS(DST,TMP):
493 tmp = do_bitop( dst, tmp, *opcode & 0xf );
494 break;
495 case OP_ARGS(DST,SRC):
496 src = do_bitop( dst, src, *opcode & 0xf );
497 break;
498 case OP_ARGS(SRC,TMP):
499 tmp = do_bitop( src, tmp, *opcode & 0xf );
500 break;
501 case OP_ARGS(SRC,DST):
502 dst = do_bitop( src, dst, *opcode & 0xf );
503 dstUsed = 1;
504 break;
505 case OP_ARGS(PAT,TMP):
506 tmp = do_bitop( pat, tmp, *opcode & 0xf );
507 break;
508 case OP_ARGS(PAT,DST):
509 dst = do_bitop( pat, dst, *opcode & 0xf );
510 dstUsed = 1;
511 break;
512 case OP_ARGS(PAT,SRC):
513 src = do_bitop( pat, src, *opcode & 0xf );
514 break;
515 case OP_ARGS(TMP,DST):
516 dst = do_bitop( tmp, dst, *opcode & 0xf );
517 dstUsed = 1;
518 break;
519 case OP_ARGS(TMP,SRC):
520 src = do_bitop( tmp, src, *opcode & 0xf );
521 break;
522 default:
523 printf( "Invalid opcode %x\n", *opcode );
526 if (!dstUsed) dst = src;
527 if (dst) res |= 1 << i;
529 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
532 return 0;
535 #endif /* BITBLT_TEST */
538 /***********************************************************************
539 * perfect_graphics
541 * Favor correctness or speed?
543 static int perfect_graphics(void)
545 static int perfect = -1;
546 if (perfect == -1)
548 HKEY hkey;
549 char buffer[20];
550 /* default value */
551 perfect = 0;
552 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
554 DWORD type, count = sizeof(buffer);
555 if(!RegQueryValueExA(hkey, "PerfectGraphics", 0, &type, buffer, &count))
557 char ch = buffer[0];
558 perfect = (ch == 'y' || ch == 'Y' || ch == 't' || ch == 'T' || ch == '1');
560 RegCloseKey(hkey);
563 return perfect;
566 static void get_colors(X11DRV_PDEVICE *physDevDst, X11DRV_PDEVICE *physDevSrc,
567 int *fg, int *bg)
569 RGBQUAD rgb[2];
571 *fg = physDevDst->textPixel;
572 *bg = physDevDst->backgroundPixel;
573 if(physDevSrc->depth == 1) {
574 if(GetDIBColorTable(physDevSrc->hdc, 0, 2, rgb) == 2) {
575 DWORD logcolor;
576 logcolor = RGB(rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue);
577 *fg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
578 logcolor = RGB(rgb[1].rgbRed, rgb[1].rgbGreen,rgb[1].rgbBlue);
579 *bg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor );
584 /***********************************************************************
585 * BITBLT_StretchRow
587 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
589 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
590 INT startDst, INT widthDst,
591 INT xinc, INT xoff, WORD mode )
593 register INT xsrc = xinc * startDst + xoff;
594 rowDst += startDst;
595 switch(mode)
597 case STRETCH_ANDSCANS:
598 for(; widthDst > 0; widthDst--, xsrc += xinc)
599 *rowDst++ &= rowSrc[xsrc >> 16];
600 break;
601 case STRETCH_ORSCANS:
602 for(; widthDst > 0; widthDst--, xsrc += xinc)
603 *rowDst++ |= rowSrc[xsrc >> 16];
604 break;
605 case STRETCH_DELETESCANS:
606 for(; widthDst > 0; widthDst--, xsrc += xinc)
607 *rowDst++ = rowSrc[xsrc >> 16];
608 break;
613 /***********************************************************************
614 * BITBLT_ShrinkRow
616 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
618 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
619 INT startSrc, INT widthSrc,
620 INT xinc, INT xoff, WORD mode )
622 register INT xdst = xinc * startSrc + xoff;
623 rowSrc += startSrc;
624 switch(mode)
626 case STRETCH_ORSCANS:
627 for(; widthSrc > 0; widthSrc--, xdst += xinc)
628 rowDst[xdst >> 16] |= *rowSrc++;
629 break;
630 case STRETCH_ANDSCANS:
631 for(; widthSrc > 0; widthSrc--, xdst += xinc)
632 rowDst[xdst >> 16] &= *rowSrc++;
633 break;
634 case STRETCH_DELETESCANS:
635 for(; widthSrc > 0; widthSrc--, xdst += xinc)
636 rowDst[xdst >> 16] = *rowSrc++;
637 break;
642 /***********************************************************************
643 * BITBLT_GetRow
645 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
647 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
648 INT start, INT width, INT depthDst,
649 int fg, int bg, BOOL swap)
651 register INT i;
653 assert( (row >= 0) && (row < image->height) );
654 assert( (start >= 0) && (width <= image->width) );
656 pdata += swap ? start+width-1 : start;
657 if (image->depth == depthDst) /* color -> color */
659 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
660 if (swap) for (i = 0; i < width; i++)
661 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
662 else for (i = 0; i < width; i++)
663 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
664 else
665 if (swap) for (i = 0; i < width; i++)
666 *pdata-- = XGetPixel( image, i, row );
667 else for (i = 0; i < width; i++)
668 *pdata++ = XGetPixel( image, i, row );
670 else
672 if (image->depth == 1) /* monochrome -> color */
674 if (X11DRV_PALETTE_XPixelToPalette)
676 fg = X11DRV_PALETTE_XPixelToPalette[fg];
677 bg = X11DRV_PALETTE_XPixelToPalette[bg];
679 if (swap) for (i = 0; i < width; i++)
680 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
681 else for (i = 0; i < width; i++)
682 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
684 else /* color -> monochrome */
686 if (swap) for (i = 0; i < width; i++)
687 *pdata-- = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
688 else for (i = 0; i < width; i++)
689 *pdata++ = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
695 /***********************************************************************
696 * BITBLT_StretchImage
698 * Stretch an X image.
699 * FIXME: does not work for full 32-bit coordinates.
701 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
702 INT widthSrc, INT heightSrc,
703 INT widthDst, INT heightDst,
704 RECT *visRectSrc, RECT *visRectDst,
705 int foreground, int background, WORD mode )
707 int *rowSrc, *rowDst, *pixel;
708 char *pdata;
709 INT xinc, xoff, yinc, ysrc, ydst;
710 register INT x, y;
711 BOOL hstretch, vstretch, hswap, vswap;
713 hswap = ((int)widthSrc * widthDst) < 0;
714 vswap = ((int)heightSrc * heightDst) < 0;
715 widthSrc = abs(widthSrc);
716 heightSrc = abs(heightSrc);
717 widthDst = abs(widthDst);
718 heightDst = abs(heightDst);
720 if (!(rowSrc = HeapAlloc( GetProcessHeap(), 0,
721 (widthSrc+widthDst)*sizeof(int) ))) return;
722 rowDst = rowSrc + widthSrc;
724 /* When stretching, all modes are the same, and DELETESCANS is faster */
725 if ((widthSrc < widthDst) && (heightSrc < heightDst))
726 mode = STRETCH_DELETESCANS;
728 if (mode == STRETCH_HALFTONE) /* FIXME */
729 mode = STRETCH_DELETESCANS;
731 if (mode != STRETCH_DELETESCANS)
732 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
733 widthDst*sizeof(int) );
735 hstretch = (widthSrc < widthDst);
736 vstretch = (heightSrc < heightDst);
738 if (hstretch)
740 xinc = ((int)widthSrc << 16) / widthDst;
741 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
743 else
745 xinc = ((int)widthDst << 16) / widthSrc;
746 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
749 if (vstretch)
751 yinc = ((int)heightSrc << 16) / heightDst;
752 ydst = visRectDst->top;
753 if (vswap)
755 ysrc = yinc * (heightDst - ydst - 1);
756 yinc = -yinc;
758 else
759 ysrc = yinc * ydst;
761 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
763 if (((ysrc >> 16) < visRectSrc->top) ||
764 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
766 /* Retrieve a source row */
767 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
768 hswap ? widthSrc - visRectSrc->right
769 : visRectSrc->left,
770 visRectSrc->right - visRectSrc->left,
771 dstImage->depth, foreground, background, hswap );
773 /* Stretch or shrink it */
774 if (hstretch)
775 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
776 visRectDst->right - visRectDst->left,
777 xinc, xoff, mode );
778 else BITBLT_ShrinkRow( rowSrc, rowDst,
779 hswap ? widthSrc - visRectSrc->right
780 : visRectSrc->left,
781 visRectSrc->right - visRectSrc->left,
782 xinc, xoff, mode );
784 /* Store the destination row */
785 pixel = rowDst + visRectDst->right - 1;
786 y = ydst - visRectDst->top;
787 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
788 XPutPixel( dstImage, x, y, *pixel-- );
789 if (mode != STRETCH_DELETESCANS)
790 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
791 widthDst*sizeof(int) );
793 /* Make copies of the destination row */
795 pdata = dstImage->data + dstImage->bytes_per_line * y;
796 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
797 (ydst < visRectDst->bottom-1))
799 memcpy( pdata + dstImage->bytes_per_line, pdata,
800 dstImage->bytes_per_line );
801 pdata += dstImage->bytes_per_line;
802 ysrc += yinc;
803 ydst++;
807 else /* Shrinking */
809 yinc = ((int)heightDst << 16) / heightSrc;
810 ysrc = visRectSrc->top;
811 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
812 if (vswap)
814 ydst += yinc * (heightSrc - ysrc - 1);
815 yinc = -yinc;
817 else
818 ydst += yinc * ysrc;
820 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
822 if (((ydst >> 16) < visRectDst->top) ||
823 ((ydst >> 16) >= visRectDst->bottom)) continue;
825 /* Retrieve a source row */
826 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
827 hswap ? widthSrc - visRectSrc->right
828 : visRectSrc->left,
829 visRectSrc->right - visRectSrc->left,
830 dstImage->depth, foreground, background, hswap );
832 /* Stretch or shrink it */
833 if (hstretch)
834 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
835 visRectDst->right - visRectDst->left,
836 xinc, xoff, mode );
837 else BITBLT_ShrinkRow( rowSrc, rowDst,
838 hswap ? widthSrc - visRectSrc->right
839 : visRectSrc->left,
840 visRectSrc->right - visRectSrc->left,
841 xinc, xoff, mode );
843 /* Merge several source rows into the destination */
844 if (mode == STRETCH_DELETESCANS)
846 /* Simply skip the overlapping rows */
847 while (((ydst + yinc) >> 16 == ydst >> 16) &&
848 (ysrc < visRectSrc->bottom-1))
850 ydst += yinc;
851 ysrc++;
854 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
855 (ysrc < visRectSrc->bottom-1))
856 continue; /* Restart loop for next overlapping row */
858 /* Store the destination row */
859 pixel = rowDst + visRectDst->right - 1;
860 y = (ydst >> 16) - visRectDst->top;
861 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
862 XPutPixel( dstImage, x, y, *pixel-- );
863 if (mode != STRETCH_DELETESCANS)
864 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
865 widthDst*sizeof(int) );
868 HeapFree( GetProcessHeap(), 0, rowSrc );
872 /***********************************************************************
873 * BITBLT_GetSrcAreaStretch
875 * Retrieve an area from the source DC, stretching and mapping all the
876 * pixels to Windows colors.
878 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
879 Pixmap pixmap, GC gc,
880 INT xSrc, INT ySrc,
881 INT widthSrc, INT heightSrc,
882 INT xDst, INT yDst,
883 INT widthDst, INT heightDst,
884 RECT *visRectSrc, RECT *visRectDst )
886 XImage *imageSrc, *imageDst;
887 RECT rectSrc = *visRectSrc;
888 RECT rectDst = *visRectDst;
889 int fg, bg;
891 if (widthSrc < 0) xSrc += widthSrc;
892 if (widthDst < 0) xDst += widthDst;
893 if (heightSrc < 0) ySrc += heightSrc;
894 if (heightDst < 0) yDst += heightDst;
895 rectSrc.left -= xSrc;
896 rectSrc.right -= xSrc;
897 rectSrc.top -= ySrc;
898 rectSrc.bottom -= ySrc;
899 rectDst.left -= xDst;
900 rectDst.right -= xDst;
901 rectDst.top -= yDst;
902 rectDst.bottom -= yDst;
904 get_colors(physDevDst, physDevSrc, &fg, &bg);
905 /* FIXME: avoid BadMatch errors */
906 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
907 physDevSrc->org.x + visRectSrc->left,
908 physDevSrc->org.y + visRectSrc->top,
909 visRectSrc->right - visRectSrc->left,
910 visRectSrc->bottom - visRectSrc->top,
911 AllPlanes, ZPixmap );
912 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
913 rectDst.bottom - rectDst.top, physDevDst->depth );
914 BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
915 widthDst, heightDst, &rectSrc, &rectDst,
916 fg, physDevDst->depth != 1 ?
917 bg : physDevSrc->backgroundPixel,
918 GetStretchBltMode(physDevDst->hdc) );
919 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
920 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
921 XDestroyImage( imageSrc );
922 XDestroyImage( imageDst );
923 return 0; /* no exposure events generated */
927 /***********************************************************************
928 * BITBLT_GetSrcArea
930 * Retrieve an area from the source DC, mapping all the
931 * pixels to Windows colors.
933 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
934 Pixmap pixmap, GC gc, INT xSrc, INT ySrc, RECT *visRectSrc )
936 XImage *imageSrc, *imageDst;
937 register INT x, y;
938 int exposures = 0;
939 INT width = visRectSrc->right - visRectSrc->left;
940 INT height = visRectSrc->bottom - visRectSrc->top;
941 int fg, bg;
943 if (physDevSrc->depth == physDevDst->depth)
945 if (!X11DRV_PALETTE_XPixelToPalette ||
946 (physDevDst->depth == 1)) /* monochrome -> monochrome */
948 if (physDevDst->depth == 1)
950 /* MSDN says if StretchBlt must convert a bitmap from monochrome
951 to color or vice versa, the forground and background color of
952 the device context are used. In fact, it also applies to the
953 case when it is converted from mono to mono. */
954 XSetBackground( gdi_display, gc, physDevDst->textPixel );
955 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
956 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
957 physDevSrc->org.x + visRectSrc->left,
958 physDevSrc->org.y + visRectSrc->top,
959 width, height, 0, 0, 1);
961 else
962 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
963 physDevSrc->org.x + visRectSrc->left,
964 physDevSrc->org.y + visRectSrc->top,
965 width, height, 0, 0);
966 exposures++;
968 else /* color -> color */
970 if (GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
971 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
972 physDevSrc->org.x + visRectSrc->left,
973 physDevSrc->org.y + visRectSrc->top,
974 width, height, AllPlanes, ZPixmap );
975 else
977 /* Make sure we don't get a BadMatch error */
978 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
979 physDevSrc->org.x + visRectSrc->left,
980 physDevSrc->org.y + visRectSrc->top,
981 width, height, 0, 0);
982 exposures++;
983 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
984 AllPlanes, ZPixmap );
986 for (y = 0; y < height; y++)
987 for (x = 0; x < width; x++)
988 XPutPixel(imageSrc, x, y,
989 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
990 XPutImage( gdi_display, pixmap, gc, imageSrc,
991 0, 0, 0, 0, width, height );
992 XDestroyImage( imageSrc );
995 else
997 if (physDevSrc->depth == 1) /* monochrome -> color */
999 get_colors(physDevDst, physDevSrc, &fg, &bg);
1001 if (X11DRV_PALETTE_XPixelToPalette)
1003 XSetBackground( gdi_display, gc,
1004 X11DRV_PALETTE_XPixelToPalette[fg] );
1005 XSetForeground( gdi_display, gc,
1006 X11DRV_PALETTE_XPixelToPalette[bg]);
1008 else
1010 XSetBackground( gdi_display, gc, fg );
1011 XSetForeground( gdi_display, gc, bg );
1013 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
1014 physDevSrc->org.x + visRectSrc->left,
1015 physDevSrc->org.y + visRectSrc->top,
1016 width, height, 0, 0, 1 );
1017 exposures++;
1019 else /* color -> monochrome */
1021 /* FIXME: avoid BadMatch error */
1022 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1023 physDevSrc->org.x + visRectSrc->left,
1024 physDevSrc->org.y + visRectSrc->top,
1025 width, height, AllPlanes, ZPixmap );
1026 if (!imageSrc)
1028 return exposures;
1030 imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth );
1031 if (!imageDst)
1033 XDestroyImage(imageSrc);
1034 return exposures;
1036 for (y = 0; y < height; y++)
1037 for (x = 0; x < width; x++)
1038 XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1039 physDevSrc->backgroundPixel) );
1040 XPutImage( gdi_display, pixmap, gc, imageDst,
1041 0, 0, 0, 0, width, height );
1042 XDestroyImage( imageSrc );
1043 XDestroyImage( imageDst );
1046 return exposures;
1050 /***********************************************************************
1051 * BITBLT_GetDstArea
1053 * Retrieve an area from the destination DC, mapping all the
1054 * pixels to Windows colors.
1056 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1058 int exposures = 0;
1059 INT width = visRectDst->right - visRectDst->left;
1060 INT height = visRectDst->bottom - visRectDst->top;
1062 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) ||
1063 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1065 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1066 physDev->org.x + visRectDst->left, physDev->org.y + visRectDst->top,
1067 width, height, 0, 0 );
1068 exposures++;
1070 else
1072 register INT x, y;
1073 XImage *image;
1075 if (GetObjectType( physDev->hdc ) == OBJ_MEMDC)
1076 image = XGetImage( gdi_display, physDev->drawable,
1077 physDev->org.x + visRectDst->left,
1078 physDev->org.y + visRectDst->top,
1079 width, height, AllPlanes, ZPixmap );
1080 else
1082 /* Make sure we don't get a BadMatch error */
1083 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1084 physDev->org.x + visRectDst->left,
1085 physDev->org.y + visRectDst->top,
1086 width, height, 0, 0);
1087 exposures++;
1088 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1089 AllPlanes, ZPixmap );
1091 for (y = 0; y < height; y++)
1092 for (x = 0; x < width; x++)
1093 XPutPixel( image, x, y,
1094 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1095 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1096 XDestroyImage( image );
1098 return exposures;
1102 /***********************************************************************
1103 * BITBLT_PutDstArea
1105 * Put an area back into the destination DC, mapping the pixel
1106 * colors to X pixels.
1108 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1110 int exposures = 0;
1111 INT width = visRectDst->right - visRectDst->left;
1112 INT height = visRectDst->bottom - visRectDst->top;
1114 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1116 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) ||
1117 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1119 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1120 physDev->org.x + visRectDst->left,
1121 physDev->org.y + visRectDst->top );
1122 exposures++;
1124 else
1126 register INT x, y;
1127 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1128 AllPlanes, ZPixmap );
1129 for (y = 0; y < height; y++)
1130 for (x = 0; x < width; x++)
1132 XPutPixel( image, x, y,
1133 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1135 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1136 physDev->org.x + visRectDst->left,
1137 physDev->org.y + visRectDst->top, width, height );
1138 XDestroyImage( image );
1140 return exposures;
1144 /***********************************************************************
1145 * BITBLT_GetVisRectangles
1147 * Get the source and destination visible rectangles for StretchBlt().
1148 * Return FALSE if one of the rectangles is empty.
1150 static BOOL BITBLT_GetVisRectangles( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1151 INT widthDst, INT heightDst,
1152 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1153 INT widthSrc, INT heightSrc,
1154 RECT *visRectSrc, RECT *visRectDst )
1156 RECT rect, clipRect;
1158 /* Get the destination visible rectangle */
1160 rect.left = xDst;
1161 rect.top = yDst;
1162 rect.right = xDst + widthDst;
1163 rect.bottom = yDst + heightDst;
1164 if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1165 if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1166 GetRgnBox( physDevDst->region, &clipRect );
1167 if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1169 /* Get the source visible rectangle */
1171 if (!physDevSrc) return TRUE;
1172 rect.left = xSrc;
1173 rect.top = ySrc;
1174 rect.right = xSrc + widthSrc;
1175 rect.bottom = ySrc + heightSrc;
1176 if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1177 if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1178 /* Apparently the clipping and visible regions are only for output,
1179 so just check against dc extent here to avoid BadMatch errors */
1180 if (physDevSrc->bitmap)
1182 BITMAP bm;
1183 GetObjectW( physDevSrc->bitmap->hbitmap, sizeof(bm), &bm );
1184 SetRect( &clipRect, 0, 0, bm.bmWidth, bm.bmHeight );
1186 else SetRect( &clipRect, 0, 0, screen_width, screen_height );
1187 if (!IntersectRect( visRectSrc, &rect, &clipRect ))
1188 return FALSE;
1190 /* Intersect the rectangles */
1192 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1194 visRectSrc->left += xDst - xSrc;
1195 visRectSrc->right += xDst - xSrc;
1196 visRectSrc->top += yDst - ySrc;
1197 visRectSrc->bottom += yDst - ySrc;
1198 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1199 *visRectSrc = *visRectDst = rect;
1200 visRectSrc->left += xSrc - xDst;
1201 visRectSrc->right += xSrc - xDst;
1202 visRectSrc->top += ySrc - yDst;
1203 visRectSrc->bottom += ySrc - yDst;
1205 else /* stretching */
1207 /* Map source rectangle into destination coordinates */
1208 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1209 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1210 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1211 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1212 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1213 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1215 /* Avoid rounding errors */
1216 rect.left--;
1217 rect.top--;
1218 rect.right++;
1219 rect.bottom++;
1220 if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1222 /* Map destination rectangle back to source coordinates */
1223 rect = *visRectDst;
1224 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1225 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1226 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1227 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1228 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1229 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1231 /* Avoid rounding errors */
1232 rect.left--;
1233 rect.top--;
1234 rect.right++;
1235 rect.bottom++;
1236 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1238 return TRUE;
1242 /***********************************************************************
1243 * BITBLT_InternalStretchBlt
1245 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1247 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1248 INT widthDst, INT heightDst,
1249 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1250 INT widthSrc, INT heightSrc,
1251 DWORD rop )
1253 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1254 RECT visRectDst, visRectSrc;
1255 INT width, height;
1256 const BYTE *opcode;
1257 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1258 GC tmpGC = 0;
1259 POINT pts[2];
1261 /* compensate for off-by-one shifting for negative widths and heights */
1262 if (widthDst < 0)
1263 ++xDst;
1264 if (heightDst < 0)
1265 ++yDst;
1266 if (widthSrc < 0)
1267 ++xSrc;
1268 if (heightSrc < 0)
1269 ++ySrc;
1271 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1272 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1273 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1274 if (!physDevSrc && useSrc) return FALSE;
1276 /* Map the coordinates to device coords */
1278 pts[0].x = xDst;
1279 pts[0].y = yDst;
1280 pts[1].x = xDst + widthDst;
1281 pts[1].y = yDst + heightDst;
1282 LPtoDP(physDevDst->hdc, pts, 2);
1283 xDst = pts[0].x;
1284 yDst = pts[0].y;
1285 widthDst = pts[1].x - pts[0].x;
1286 heightDst = pts[1].y - pts[0].y;
1288 TRACE(" rectdst=%d,%d-%d,%d orgdst=%ld,%ld\n",
1289 xDst, yDst, widthDst, heightDst,
1290 physDevDst->org.x, physDevDst->org.y );
1292 if (useSrc)
1294 pts[0].x = xSrc;
1295 pts[0].y = ySrc;
1296 pts[1].x = xSrc + widthSrc;
1297 pts[1].y = ySrc + heightSrc;
1298 LPtoDP(physDevSrc->hdc, pts, 2);
1299 xSrc = pts[0].x;
1300 ySrc = pts[0].y;
1301 widthSrc = pts[1].x - pts[0].x;
1302 heightSrc = pts[1].y - pts[0].y;
1304 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1305 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%ld,%ld\n",
1306 xSrc, ySrc, widthSrc, heightSrc,
1307 physDevSrc->org.x, physDevSrc->org.y );
1308 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1309 physDevSrc, xSrc, ySrc, widthSrc, heightSrc,
1310 &visRectSrc, &visRectDst ))
1311 return TRUE;
1312 TRACE(" vissrc=%ld,%ld-%ld,%ld visdst=%ld,%ld-%ld,%ld\n",
1313 visRectSrc.left, visRectSrc.top,
1314 visRectSrc.right, visRectSrc.bottom,
1315 visRectDst.left, visRectDst.top,
1316 visRectDst.right, visRectDst.bottom );
1318 else
1320 fStretch = FALSE;
1321 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, widthDst, heightDst,
1322 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1323 return TRUE;
1324 TRACE(" vissrc=none visdst=%ld,%ld-%ld,%ld\n",
1325 visRectDst.left, visRectDst.top,
1326 visRectDst.right, visRectDst.bottom );
1329 width = visRectDst.right - visRectDst.left;
1330 height = visRectDst.bottom - visRectDst.top;
1332 if (!fStretch) switch(rop) /* A few optimisations */
1334 case BLACKNESS: /* 0x00 */
1335 wine_tsx11_lock();
1336 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1337 XSetFunction( gdi_display, physDevDst->gc, GXclear );
1338 else
1340 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1341 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1342 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1344 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1345 physDevDst->org.x + visRectDst.left,
1346 physDevDst->org.y + visRectDst.top,
1347 width, height );
1348 wine_tsx11_unlock();
1349 return TRUE;
1351 case DSTINVERT: /* 0x55 */
1352 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel ||
1353 !perfect_graphics())
1355 wine_tsx11_lock();
1356 XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1358 if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1359 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1360 else
1362 /* Xor is much better when we do not have full colormap. */
1363 /* Using white^black ensures that we invert at least black */
1364 /* and white. */
1365 Pixel xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1366 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1367 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1368 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1369 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1371 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1372 physDevDst->org.x + visRectDst.left,
1373 physDevDst->org.y + visRectDst.top,
1374 width, height );
1375 wine_tsx11_unlock();
1376 return TRUE;
1378 break;
1380 case PATINVERT: /* 0x5a */
1381 if (perfect_graphics()) break;
1382 if (X11DRV_SetupGCForBrush( physDevDst ))
1384 wine_tsx11_lock();
1385 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1386 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1387 physDevDst->org.x + visRectDst.left,
1388 physDevDst->org.y + visRectDst.top,
1389 width, height );
1390 wine_tsx11_unlock();
1392 return TRUE;
1394 case 0xa50065:
1395 if (perfect_graphics()) break;
1396 if (X11DRV_SetupGCForBrush( physDevDst ))
1398 wine_tsx11_lock();
1399 XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1400 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1401 physDevDst->org.x + visRectDst.left,
1402 physDevDst->org.y + visRectDst.top,
1403 width, height );
1404 wine_tsx11_unlock();
1406 return TRUE;
1408 case SRCCOPY: /* 0xcc */
1409 if (physDevSrc->depth == physDevDst->depth)
1411 wine_tsx11_lock();
1412 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1413 XCopyArea( gdi_display, physDevSrc->drawable,
1414 physDevDst->drawable, physDevDst->gc,
1415 physDevSrc->org.x + visRectSrc.left,
1416 physDevSrc->org.y + visRectSrc.top,
1417 width, height,
1418 physDevDst->org.x + visRectDst.left,
1419 physDevDst->org.y + visRectDst.top );
1420 physDevDst->exposures++;
1421 wine_tsx11_unlock();
1422 return TRUE;
1425 if (physDevSrc->depth == 1)
1427 int fg, bg;
1428 get_colors(physDevDst, physDevSrc, &fg, &bg);
1429 wine_tsx11_lock();
1431 XSetBackground( gdi_display, physDevDst->gc, fg );
1432 XSetForeground( gdi_display, physDevDst->gc, bg );
1433 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1434 XCopyPlane( gdi_display, physDevSrc->drawable,
1435 physDevDst->drawable, physDevDst->gc,
1436 physDevSrc->org.x + visRectSrc.left,
1437 physDevSrc->org.y + visRectSrc.top,
1438 width, height,
1439 physDevDst->org.x + visRectDst.left,
1440 physDevDst->org.y + visRectDst.top, 1 );
1441 physDevDst->exposures++;
1442 wine_tsx11_unlock();
1443 return TRUE;
1445 break;
1447 case PATCOPY: /* 0xf0 */
1448 if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1449 wine_tsx11_lock();
1450 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1451 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1452 physDevDst->org.x + visRectDst.left,
1453 physDevDst->org.y + visRectDst.top,
1454 width, height );
1455 wine_tsx11_unlock();
1456 return TRUE;
1458 case WHITENESS: /* 0xff */
1459 wine_tsx11_lock();
1460 if ((physDevDst->depth == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1461 XSetFunction( gdi_display, physDevDst->gc, GXset );
1462 else
1464 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1465 XSetForeground( gdi_display, physDevDst->gc,
1466 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1467 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1469 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1470 physDevDst->org.x + visRectDst.left,
1471 physDevDst->org.y + visRectDst.top,
1472 width, height );
1473 wine_tsx11_unlock();
1474 return TRUE;
1477 wine_tsx11_lock();
1479 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1480 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1481 XSetGraphicsExposures( gdi_display, tmpGC, False );
1482 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1483 physDevDst->depth );
1484 if (useSrc)
1486 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1487 physDevDst->depth );
1488 if (fStretch)
1489 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1490 xSrc, ySrc, widthSrc, heightSrc,
1491 xDst, yDst, widthDst, heightDst,
1492 &visRectSrc, &visRectDst );
1493 else
1494 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1495 xSrc, ySrc, &visRectSrc );
1498 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1499 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1500 else fNullBrush = FALSE;
1501 destUsed = FALSE;
1503 for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1505 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1506 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1507 switch(OP_SRCDST(*opcode))
1509 case OP_ARGS(DST,TMP):
1510 case OP_ARGS(SRC,TMP):
1511 if (!pixmaps[TMP])
1512 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1513 width, height, physDevDst->depth );
1514 /* fall through */
1515 case OP_ARGS(DST,SRC):
1516 case OP_ARGS(SRC,DST):
1517 case OP_ARGS(TMP,SRC):
1518 case OP_ARGS(TMP,DST):
1519 if (useSrc)
1520 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1521 pixmaps[OP_DST(*opcode)], tmpGC,
1522 0, 0, width, height, 0, 0 );
1523 break;
1525 case OP_ARGS(PAT,TMP):
1526 if (!pixmaps[TMP] && !fNullBrush)
1527 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1528 width, height, physDevDst->depth );
1529 /* fall through */
1530 case OP_ARGS(PAT,DST):
1531 case OP_ARGS(PAT,SRC):
1532 if (!fNullBrush)
1533 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1534 tmpGC, 0, 0, width, height );
1535 break;
1538 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1539 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1540 &visRectDst );
1541 XFreePixmap( gdi_display, pixmaps[DST] );
1542 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1543 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1544 XFreeGC( gdi_display, tmpGC );
1545 wine_tsx11_unlock();
1546 return TRUE;
1550 /***********************************************************************
1551 * X11DRV_PatBlt
1553 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1555 BOOL result;
1557 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1558 result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1559 X11DRV_UnlockDIBSection( physDev, TRUE );
1560 return result;
1564 /***********************************************************************
1565 * X11DRV_BitBlt
1567 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1568 INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1569 INT xSrc, INT ySrc, DWORD rop )
1571 BOOL result = FALSE;
1572 INT sSrc, sDst;
1573 RECT visRectDst, visRectSrc;
1575 if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1576 /* FIXME: seems the ROP doesn't include destination;
1577 * now if the destination area include the entire dcDst,
1578 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1579 * which may avoid a copy in some situations */
1582 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1583 if (physDevDst != physDevSrc)
1584 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1585 else
1586 sSrc = sDst;
1588 if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1589 (physDevSrc->depth == physDevDst->depth))
1591 POINT pts[2];
1592 /* do everything ourselves; map coordinates */
1594 pts[0].x = xSrc;
1595 pts[0].y = ySrc;
1596 pts[1].x = xSrc + width;
1597 pts[1].y = ySrc + height;
1599 LPtoDP(physDevSrc->hdc, pts, 2);
1600 width = pts[1].x - pts[0].x;
1601 height = pts[1].y - pts[0].y;
1602 xSrc = pts[0].x;
1603 ySrc = pts[0].y;
1605 pts[0].x = xDst;
1606 pts[0].y = yDst;
1607 LPtoDP(physDevDst->hdc, pts, 1);
1609 xDst = pts[0].x;
1610 yDst = pts[0].y;
1612 /* Perform basic clipping */
1613 if (!BITBLT_GetVisRectangles( physDevDst, xDst, yDst, width, height,
1614 physDevSrc, xSrc, ySrc, width, height,
1615 &visRectSrc, &visRectDst ))
1616 goto END;
1618 xSrc = visRectSrc.left;
1619 ySrc = visRectSrc.top;
1620 xDst = visRectDst.left;
1621 yDst = visRectDst.top;
1622 width = visRectDst.right - visRectDst.left;
1623 height = visRectDst.bottom - visRectDst.top;
1625 if (sDst == DIB_Status_AppMod) {
1626 FIXME("potential optimization - client-side DIB copy\n");
1628 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1630 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1631 result = TRUE;
1632 goto END;
1635 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1636 if (physDevDst != physDevSrc)
1637 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1639 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1640 physDevSrc, xSrc, ySrc, width, height, rop );
1642 END:
1643 if (physDevDst != physDevSrc)
1644 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1645 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1647 return result;
1651 /***********************************************************************
1652 * X11DRV_StretchBlt
1654 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1655 INT widthDst, INT heightDst,
1656 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1657 INT widthSrc, INT heightSrc, DWORD rop )
1659 BOOL result;
1661 X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1662 if (physDevDst != physDevSrc)
1663 X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1665 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1666 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1668 if (physDevDst != physDevSrc)
1669 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1670 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1671 return result;