Moved a bunch of definitions from gdi.h into a new gdi_private.h to
[wine/multimedia.git] / dlls / x11drv / bitblt.c
blob5daf99d42848878b03d5e53ed7a0d640c5e6a390
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 "gdi.h"
35 #include "x11drv.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
41 #define DST 0 /* Destination drawable */
42 #define SRC 1 /* Source drawable */
43 #define TMP 2 /* Temporary drawable */
44 #define PAT 3 /* Pattern (brush) in destination DC */
46 #define OP(src,dst,rop) (OP_ARGS(src,dst) << 4 | (rop))
47 #define OP_ARGS(src,dst) (((src) << 2) | (dst))
49 #define OP_SRC(opcode) ((opcode) >> 6)
50 #define OP_DST(opcode) (((opcode) >> 4) & 3)
51 #define OP_SRCDST(opcode) ((opcode) >> 4)
52 #define OP_ROP(opcode) ((opcode) & 0x0f)
54 #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */
56 #define SWAP_INT32(i1,i2) \
57 do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0)
59 static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] =
61 { OP(PAT,DST,GXclear) }, /* 0x00 0 */
62 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */
63 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */
64 { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */
65 { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */
66 { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */
67 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */
68 { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */
69 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */
70 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */
71 { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */
72 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */
73 { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */
74 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */
75 { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */
76 { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */
77 { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */
78 { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */
79 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */
80 { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */
81 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */
82 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */
83 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
84 OP(TMP,DST,GXand), OP(SRC,DST,GXxor),
85 OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */
86 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
87 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
88 OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/
89 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
90 OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */
91 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand),
92 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */
93 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
94 OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */
95 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXxor),
96 OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */
97 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
98 OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */
99 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
100 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */
101 { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */
102 { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */
103 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */
104 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */
105 { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */
106 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */
107 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
108 OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */
109 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand),
110 OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */
111 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
112 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */
113 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXequiv),
114 OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */
115 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */
116 { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand),
117 OP(TMP,DST,GXor), OP(SRC,DST,GXxor),
118 OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */
119 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */
120 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
121 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
122 OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/
123 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
124 OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */
125 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */
126 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
127 OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */
128 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */
129 { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */
130 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */
131 { OP(SRC,DST,GXor), OP(PAT,DST,GXor),
132 OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */
133 { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */
134 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
135 OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */
136 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor),
137 OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */
138 { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */
139 { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */
140 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
141 OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */
142 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */
143 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
144 OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */
145 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */
146 { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */
147 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
148 OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */
149 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
150 OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */
151 { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */
152 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */
153 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */
154 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
155 OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */
156 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
157 OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */
158 { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */
159 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */
160 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
161 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */
162 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
163 OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */
164 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */
165 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
166 OP(SRC,DST,GXor), OP(TMP,DST,GXxor),
167 OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */
168 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
169 OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */
170 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */
171 { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */
172 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
173 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
174 OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/
175 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
176 OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */
177 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */
178 { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */
179 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */
180 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
181 OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */
182 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
183 OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */
184 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */
185 { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */
186 { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */
187 { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */
188 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
189 OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */
190 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */
191 { OP(PAT,DST,GXxor) }, /* 0x5a D^P */
192 { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor),
193 OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */
194 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
195 OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */
196 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */
197 { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor),
198 OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */
199 { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */
200 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */
201 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
202 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
203 OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */
204 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
205 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */
206 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */
207 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
208 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */
209 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */
210 { OP(SRC,DST,GXxor) }, /* 0x66 S^D */
211 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
212 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */
213 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor),
214 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
215 OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/
216 { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */
217 { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */
218 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
219 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
220 OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */
221 { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */
222 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
223 OP(SRC,DST,GXand), OP(TMP,DST,GXxor),
224 OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */
225 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
226 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */
227 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */
228 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */
229 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
230 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
231 OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/
232 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
233 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */
234 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */
235 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
236 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */
237 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */
238 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
239 OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */
240 { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */
241 { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */
242 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
243 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
244 OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */
245 { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand),
246 OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */
247 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */
248 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
249 OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */
250 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */
251 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
252 OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */
253 { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */
254 { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */
255 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
256 OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */
257 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */
258 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand),
259 OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */
260 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */
261 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand),
262 OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */
263 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor),
264 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
265 OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */
266 { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */
267 { OP(SRC,DST,GXand) }, /* 0x88 S&D */
268 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse),
269 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */
270 { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */
271 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
272 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */
273 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */
274 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
275 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */
276 { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor),
277 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
278 OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/
279 { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */
280 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */
281 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse),
282 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */
283 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
284 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
285 OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */
286 { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */
287 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
288 OP(SRC,DST,GXand), OP(PAT,DST,GXxor),
289 OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */
290 { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */
291 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */
292 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
293 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
294 OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */
295 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor),
296 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */
297 { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */
298 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */
299 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor),
300 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */
301 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */
302 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor),
303 OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */
304 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand),
305 OP(PAT,DST,GXor), OP(SRC,DST,GXxor),
306 OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */
307 { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */
308 { OP(PAT,DST,GXand) }, /* 0xa0 D&P */
309 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor),
310 OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */
311 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */
312 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor),
313 OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */
314 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor),
315 OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */
316 { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */
317 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */
318 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand),
319 OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */
320 { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */
321 { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */
322 { OP(SRC,DST,GXnoop) }, /* 0xaa D */
323 { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */
324 { OP(SRC,DST,GXxor), OP(PAT,DST,GXand),
325 OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */
326 { OP(DST,SRC,GXand), OP(PAT,SRC,GXor),
327 OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */
328 { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */
329 { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */
330 { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */
331 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
332 OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */
333 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
334 OP(PAT,SRC,GXxor), OP(SRC,DST,GXor),
335 OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/
336 { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */
337 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */
338 { OP(DST,SRC,GXor), OP(PAT,SRC,GXand),
339 OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */
340 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
341 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
342 OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */
343 { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */
344 { OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
345 OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */
346 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand),
347 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */
348 { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */
349 { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */
350 { OP(SRC,DST,GXnand), OP(PAT,DST,GXand),
351 OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */
352 { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor),
353 OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */
354 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */
355 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */
356 { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */
357 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor),
358 OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */
359 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor),
360 OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */
361 { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */
362 { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */
363 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor),
364 OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */
365 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */
366 { OP(PAT,DST,GXor), OP(SRC,DST,GXand),
367 OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */
368 { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */
369 { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */
370 { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand),
371 OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */
372 { OP(SRC,DST,GXand), OP(PAT,DST,GXor),
373 OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */
374 { OP(SRC,DST,GXcopy) }, /* 0xcc S */
375 { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */
376 { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */
377 { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */
378 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */
379 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor),
380 OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */
381 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */
382 { OP(SRC,DST,GXor), OP(PAT,DST,GXand),
383 OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */
384 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
385 OP(PAT,DST,GXxor), OP(SRC,DST,GXand),
386 OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/
387 { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */
388 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
389 OP(SRC,DST,GXor), OP(PAT,DST,GXxor),
390 OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */
391 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */
392 { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
393 OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */
394 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand),
395 OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */
396 { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand),
397 OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */
398 { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor),
399 OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */
400 { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */
401 { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */
402 { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */
403 { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */
404 { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */
405 { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */
406 { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor),
407 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */
408 { OP(PAT,DST,GXand), OP(SRC,DST,GXor),
409 OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */
410 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor),
411 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */
412 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor),
413 OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */
414 { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand),
415 OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */
416 { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor),
417 OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */
418 { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor),
419 OP(PAT,SRC,GXxor), OP(SRC,DST,GXand),
420 OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/
421 { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand),
422 OP(PAT,DST,GXand), OP(SRC,DST,GXxor),
423 OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/
424 { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */
425 { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */
426 { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */
427 { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */
428 { OP(SRC,DST,GXor) }, /* 0xee S|D */
429 { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */
430 { OP(PAT,DST,GXcopy) }, /* 0xf0 P */
431 { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */
432 { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */
433 { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */
434 { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */
435 { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */
436 { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */
437 { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */
438 { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */
439 { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */
440 { OP(PAT,DST,GXor) }, /* 0xfa D|P */
441 { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */
442 { OP(PAT,SRC,GXor) }, /* 0xfc P|S */
443 { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */
444 { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */
445 { OP(PAT,DST,GXset) } /* 0xff 1 */
449 #ifdef BITBLT_TEST /* Opcodes test */
451 static int do_bitop( int s, int d, int rop )
453 int res;
454 switch(rop)
456 case GXclear: res = 0; break;
457 case GXand: res = s & d; break;
458 case GXandReverse: res = s & ~d; break;
459 case GXcopy: res = s; break;
460 case GXandInverted: res = ~s & d; break;
461 case GXnoop: res = d; break;
462 case GXxor: res = s ^ d; break;
463 case GXor: res = s | d; break;
464 case GXnor: res = ~(s | d); break;
465 case GXequiv: res = ~s ^ d; break;
466 case GXinvert: res = ~d; break;
467 case GXorReverse: res = s | ~d; break;
468 case GXcopyInverted: res = ~s; break;
469 case GXorInverted: res = ~s | d; break;
470 case GXnand: res = ~(s & d); break;
471 case GXset: res = 1; break;
473 return res & 1;
476 int main()
478 int rop, i, res, src, dst, pat, tmp, dstUsed;
479 const BYTE *opcode;
481 for (rop = 0; rop < 256; rop++)
483 res = dstUsed = 0;
484 for (i = 0; i < 8; i++)
486 pat = (i >> 2) & 1;
487 src = (i >> 1) & 1;
488 dst = i & 1;
489 for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++)
491 switch(*opcode >> 4)
493 case OP_ARGS(DST,TMP):
494 tmp = do_bitop( dst, tmp, *opcode & 0xf );
495 break;
496 case OP_ARGS(DST,SRC):
497 src = do_bitop( dst, src, *opcode & 0xf );
498 break;
499 case OP_ARGS(SRC,TMP):
500 tmp = do_bitop( src, tmp, *opcode & 0xf );
501 break;
502 case OP_ARGS(SRC,DST):
503 dst = do_bitop( src, dst, *opcode & 0xf );
504 dstUsed = 1;
505 break;
506 case OP_ARGS(PAT,TMP):
507 tmp = do_bitop( pat, tmp, *opcode & 0xf );
508 break;
509 case OP_ARGS(PAT,DST):
510 dst = do_bitop( pat, dst, *opcode & 0xf );
511 dstUsed = 1;
512 break;
513 case OP_ARGS(PAT,SRC):
514 src = do_bitop( pat, src, *opcode & 0xf );
515 break;
516 case OP_ARGS(TMP,DST):
517 dst = do_bitop( tmp, dst, *opcode & 0xf );
518 dstUsed = 1;
519 break;
520 case OP_ARGS(TMP,SRC):
521 src = do_bitop( tmp, src, *opcode & 0xf );
522 break;
523 default:
524 printf( "Invalid opcode %x\n", *opcode );
527 if (!dstUsed) dst = src;
528 if (dst) res |= 1 << i;
530 if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res );
533 return 0;
536 #endif /* BITBLT_TEST */
539 /***********************************************************************
540 * perfect_graphics
542 * Favor correctness or speed?
544 static int perfect_graphics(void)
546 static int perfect = -1;
547 if (perfect == -1)
549 HKEY hkey;
550 char buffer[20];
551 /* default value */
552 perfect = 0;
553 if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", &hkey))
555 DWORD type, count = sizeof(buffer);
556 if(!RegQueryValueExA(hkey, "PerfectGraphics", 0, &type, buffer, &count))
558 char ch = buffer[0];
559 perfect = (ch == 'y' || ch == 'Y' || ch == 't' || ch == 'T' || ch == '1');
561 RegCloseKey(hkey);
564 return perfect;
567 /***********************************************************************
568 * BITBLT_StretchRow
570 * Stretch a row of pixels. Helper function for BITBLT_StretchImage.
572 static void BITBLT_StretchRow( int *rowSrc, int *rowDst,
573 INT startDst, INT widthDst,
574 INT xinc, INT xoff, WORD mode )
576 register INT xsrc = xinc * startDst + xoff;
577 rowDst += startDst;
578 switch(mode)
580 case STRETCH_ANDSCANS:
581 for(; widthDst > 0; widthDst--, xsrc += xinc)
582 *rowDst++ &= rowSrc[xsrc >> 16];
583 break;
584 case STRETCH_ORSCANS:
585 for(; widthDst > 0; widthDst--, xsrc += xinc)
586 *rowDst++ |= rowSrc[xsrc >> 16];
587 break;
588 case STRETCH_DELETESCANS:
589 for(; widthDst > 0; widthDst--, xsrc += xinc)
590 *rowDst++ = rowSrc[xsrc >> 16];
591 break;
596 /***********************************************************************
597 * BITBLT_ShrinkRow
599 * Shrink a row of pixels. Helper function for BITBLT_StretchImage.
601 static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst,
602 INT startSrc, INT widthSrc,
603 INT xinc, INT xoff, WORD mode )
605 register INT xdst = xinc * startSrc + xoff;
606 rowSrc += startSrc;
607 switch(mode)
609 case STRETCH_ORSCANS:
610 for(; widthSrc > 0; widthSrc--, xdst += xinc)
611 rowDst[xdst >> 16] |= *rowSrc++;
612 break;
613 case STRETCH_ANDSCANS:
614 for(; widthSrc > 0; widthSrc--, xdst += xinc)
615 rowDst[xdst >> 16] &= *rowSrc++;
616 break;
617 case STRETCH_DELETESCANS:
618 for(; widthSrc > 0; widthSrc--, xdst += xinc)
619 rowDst[xdst >> 16] = *rowSrc++;
620 break;
625 /***********************************************************************
626 * BITBLT_GetRow
628 * Retrieve a row from an image. Helper function for BITBLT_StretchImage.
630 static void BITBLT_GetRow( XImage *image, int *pdata, INT row,
631 INT start, INT width, INT depthDst,
632 int fg, int bg, BOOL swap)
634 register INT i;
636 assert( (row >= 0) && (row < image->height) );
637 assert( (start >= 0) && (width <= image->width) );
639 pdata += swap ? start+width-1 : start;
640 if (image->depth == depthDst) /* color -> color */
642 if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1))
643 if (swap) for (i = 0; i < width; i++)
644 *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
645 else for (i = 0; i < width; i++)
646 *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )];
647 else
648 if (swap) for (i = 0; i < width; i++)
649 *pdata-- = XGetPixel( image, i, row );
650 else for (i = 0; i < width; i++)
651 *pdata++ = XGetPixel( image, i, row );
653 else
655 if (image->depth == 1) /* monochrome -> color */
657 if (X11DRV_PALETTE_XPixelToPalette)
659 fg = X11DRV_PALETTE_XPixelToPalette[fg];
660 bg = X11DRV_PALETTE_XPixelToPalette[bg];
662 if (swap) for (i = 0; i < width; i++)
663 *pdata-- = XGetPixel( image, i, row ) ? bg : fg;
664 else for (i = 0; i < width; i++)
665 *pdata++ = XGetPixel( image, i, row ) ? bg : fg;
667 else /* color -> monochrome */
669 if (swap) for (i = 0; i < width; i++)
670 *pdata-- = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
671 else for (i = 0; i < width; i++)
672 *pdata++ = (XGetPixel( image, i, row ) == bg) ? 1 : 0;
678 /***********************************************************************
679 * BITBLT_StretchImage
681 * Stretch an X image.
682 * FIXME: does not work for full 32-bit coordinates.
684 static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage,
685 INT widthSrc, INT heightSrc,
686 INT widthDst, INT heightDst,
687 RECT *visRectSrc, RECT *visRectDst,
688 int foreground, int background, WORD mode )
690 int *rowSrc, *rowDst, *pixel;
691 char *pdata;
692 INT xinc, xoff, yinc, ysrc, ydst;
693 register INT x, y;
694 BOOL hstretch, vstretch, hswap, vswap;
696 hswap = ((int)widthSrc * widthDst) < 0;
697 vswap = ((int)heightSrc * heightDst) < 0;
698 widthSrc = abs(widthSrc);
699 heightSrc = abs(heightSrc);
700 widthDst = abs(widthDst);
701 heightDst = abs(heightDst);
703 if (!(rowSrc = (int *)HeapAlloc( GetProcessHeap(), 0,
704 (widthSrc+widthDst)*sizeof(int) ))) return;
705 rowDst = rowSrc + widthSrc;
707 /* When stretching, all modes are the same, and DELETESCANS is faster */
708 if ((widthSrc < widthDst) && (heightSrc < heightDst))
709 mode = STRETCH_DELETESCANS;
711 if (mode == STRETCH_HALFTONE) /* FIXME */
712 mode = STRETCH_DELETESCANS;
714 if (mode != STRETCH_DELETESCANS)
715 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
716 widthDst*sizeof(int) );
718 hstretch = (widthSrc < widthDst);
719 vstretch = (heightSrc < heightDst);
721 if (hstretch)
723 xinc = ((int)widthSrc << 16) / widthDst;
724 xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2;
726 else
728 xinc = ((int)widthDst << 16) / widthSrc;
729 xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2;
732 if (vstretch)
734 yinc = ((int)heightSrc << 16) / heightDst;
735 ydst = visRectDst->top;
736 if (vswap)
738 ysrc = yinc * (heightDst - ydst - 1);
739 yinc = -yinc;
741 else
742 ysrc = yinc * ydst;
744 for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++)
746 if (((ysrc >> 16) < visRectSrc->top) ||
747 ((ysrc >> 16) >= visRectSrc->bottom)) continue;
749 /* Retrieve a source row */
750 BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top,
751 hswap ? widthSrc - visRectSrc->right
752 : visRectSrc->left,
753 visRectSrc->right - visRectSrc->left,
754 dstImage->depth, foreground, background, hswap );
756 /* Stretch or shrink it */
757 if (hstretch)
758 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
759 visRectDst->right - visRectDst->left,
760 xinc, xoff, mode );
761 else BITBLT_ShrinkRow( rowSrc, rowDst,
762 hswap ? widthSrc - visRectSrc->right
763 : visRectSrc->left,
764 visRectSrc->right - visRectSrc->left,
765 xinc, xoff, mode );
767 /* Store the destination row */
768 pixel = rowDst + visRectDst->right - 1;
769 y = ydst - visRectDst->top;
770 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
771 XPutPixel( dstImage, x, y, *pixel-- );
772 if (mode != STRETCH_DELETESCANS)
773 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
774 widthDst*sizeof(int) );
776 /* Make copies of the destination row */
778 pdata = dstImage->data + dstImage->bytes_per_line * y;
779 while (((ysrc + yinc) >> 16 == ysrc >> 16) &&
780 (ydst < visRectDst->bottom-1))
782 memcpy( pdata + dstImage->bytes_per_line, pdata,
783 dstImage->bytes_per_line );
784 pdata += dstImage->bytes_per_line;
785 ysrc += yinc;
786 ydst++;
790 else /* Shrinking */
792 yinc = ((int)heightDst << 16) / heightSrc;
793 ysrc = visRectSrc->top;
794 ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2;
795 if (vswap)
797 ydst += yinc * (heightSrc - ysrc - 1);
798 yinc = -yinc;
800 else
801 ydst += yinc * ysrc;
803 for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++)
805 if (((ydst >> 16) < visRectDst->top) ||
806 ((ydst >> 16) >= visRectDst->bottom)) continue;
808 /* Retrieve a source row */
809 BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top,
810 hswap ? widthSrc - visRectSrc->right
811 : visRectSrc->left,
812 visRectSrc->right - visRectSrc->left,
813 dstImage->depth, foreground, background, hswap );
815 /* Stretch or shrink it */
816 if (hstretch)
817 BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left,
818 visRectDst->right - visRectDst->left,
819 xinc, xoff, mode );
820 else BITBLT_ShrinkRow( rowSrc, rowDst,
821 hswap ? widthSrc - visRectSrc->right
822 : visRectSrc->left,
823 visRectSrc->right - visRectSrc->left,
824 xinc, xoff, mode );
826 /* Merge several source rows into the destination */
827 if (mode == STRETCH_DELETESCANS)
829 /* Simply skip the overlapping rows */
830 while (((ydst + yinc) >> 16 == ydst >> 16) &&
831 (ysrc < visRectSrc->bottom-1))
833 ydst += yinc;
834 ysrc++;
837 else if (((ydst + yinc) >> 16 == ydst >> 16) &&
838 (ysrc < visRectSrc->bottom-1))
839 continue; /* Restart loop for next overlapping row */
841 /* Store the destination row */
842 pixel = rowDst + visRectDst->right - 1;
843 y = (ydst >> 16) - visRectDst->top;
844 for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--)
845 XPutPixel( dstImage, x, y, *pixel-- );
846 if (mode != STRETCH_DELETESCANS)
847 memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00,
848 widthDst*sizeof(int) );
851 HeapFree( GetProcessHeap(), 0, rowSrc );
855 /***********************************************************************
856 * BITBLT_GetSrcAreaStretch
858 * Retrieve an area from the source DC, stretching and mapping all the
859 * pixels to Windows colors.
861 static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
862 Pixmap pixmap, GC gc,
863 INT xSrc, INT ySrc,
864 INT widthSrc, INT heightSrc,
865 INT xDst, INT yDst,
866 INT widthDst, INT heightDst,
867 RECT *visRectSrc, RECT *visRectDst )
869 XImage *imageSrc, *imageDst;
870 DC *dcDst = physDevDst->dc;
872 RECT rectSrc = *visRectSrc;
873 RECT rectDst = *visRectDst;
875 if (widthSrc < 0) xSrc += widthSrc;
876 if (widthDst < 0) xDst += widthDst;
877 if (heightSrc < 0) ySrc += heightSrc;
878 if (heightDst < 0) yDst += heightDst;
879 rectSrc.left -= xSrc;
880 rectSrc.right -= xSrc;
881 rectSrc.top -= ySrc;
882 rectSrc.bottom -= ySrc;
883 rectDst.left -= xDst;
884 rectDst.right -= xDst;
885 rectDst.top -= yDst;
886 rectDst.bottom -= yDst;
888 /* FIXME: avoid BadMatch errors */
889 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
890 physDevSrc->org.x + visRectSrc->left,
891 physDevSrc->org.y + visRectSrc->top,
892 visRectSrc->right - visRectSrc->left,
893 visRectSrc->bottom - visRectSrc->top,
894 AllPlanes, ZPixmap );
895 imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left,
896 rectDst.bottom - rectDst.top, dcDst->bitsPerPixel );
897 BITBLT_StretchImage( imageSrc, imageDst, widthSrc, heightSrc,
898 widthDst, heightDst, &rectSrc, &rectDst,
899 physDevDst->textPixel, dcDst->bitsPerPixel != 1 ?
900 physDevDst->backgroundPixel :
901 physDevSrc->backgroundPixel,
902 dcDst->stretchBltMode );
903 XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0,
904 rectDst.right - rectDst.left, rectDst.bottom - rectDst.top );
905 XDestroyImage( imageSrc );
906 XDestroyImage( imageDst );
907 return 0; /* no exposure events generated */
911 /***********************************************************************
912 * BITBLT_GetSrcArea
914 * Retrieve an area from the source DC, mapping all the
915 * pixels to Windows colors.
917 static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst,
918 Pixmap pixmap, GC gc, INT xSrc, INT ySrc, RECT *visRectSrc )
920 XImage *imageSrc, *imageDst;
921 register INT x, y;
922 int exposures = 0;
923 INT width = visRectSrc->right - visRectSrc->left;
924 INT height = visRectSrc->bottom - visRectSrc->top;
925 DC *dcSrc = physDevSrc->dc;
926 DC *dcDst = physDevDst->dc;
928 if (dcSrc->bitsPerPixel == dcDst->bitsPerPixel)
930 if (!X11DRV_PALETTE_XPixelToPalette ||
931 (dcDst->bitsPerPixel == 1)) /* monochrome -> monochrome */
933 if (dcDst->bitsPerPixel == 1)
935 /* MSDN says if StretchBlt must convert a bitmap from monochrome
936 to color or vice versa, the forground and background color of
937 the device context are used. In fact, it also applies to the
938 case when it is converted from mono to mono. */
939 XSetBackground( gdi_display, gc, physDevDst->textPixel );
940 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
941 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
942 physDevSrc->org.x + visRectSrc->left,
943 physDevSrc->org.y + visRectSrc->top,
944 width, height, 0, 0, 1);
946 else
947 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
948 physDevSrc->org.x + visRectSrc->left,
949 physDevSrc->org.y + visRectSrc->top,
950 width, height, 0, 0);
951 exposures++;
953 else /* color -> color */
955 if (GetObjectType(physDevSrc->hdc) == OBJ_MEMDC)
956 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
957 physDevSrc->org.x + visRectSrc->left,
958 physDevSrc->org.y + visRectSrc->top,
959 width, height, AllPlanes, ZPixmap );
960 else
962 /* Make sure we don't get a BadMatch error */
963 XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc,
964 physDevSrc->org.x + visRectSrc->left,
965 physDevSrc->org.y + visRectSrc->top,
966 width, height, 0, 0);
967 exposures++;
968 imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height,
969 AllPlanes, ZPixmap );
971 for (y = 0; y < height; y++)
972 for (x = 0; x < width; x++)
973 XPutPixel(imageSrc, x, y,
974 X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]);
975 XPutImage( gdi_display, pixmap, gc, imageSrc,
976 0, 0, 0, 0, width, height );
977 XDestroyImage( imageSrc );
980 else
982 if (dcSrc->bitsPerPixel == 1) /* monochrome -> color */
984 if (X11DRV_PALETTE_XPixelToPalette)
986 XSetBackground( gdi_display, gc,
987 X11DRV_PALETTE_XPixelToPalette[physDevDst->textPixel] );
988 XSetForeground( gdi_display, gc,
989 X11DRV_PALETTE_XPixelToPalette[physDevDst->backgroundPixel]);
991 else
993 XSetBackground( gdi_display, gc, physDevDst->textPixel );
994 XSetForeground( gdi_display, gc, physDevDst->backgroundPixel );
996 XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc,
997 physDevSrc->org.x + visRectSrc->left,
998 physDevSrc->org.y + visRectSrc->top,
999 width, height, 0, 0, 1 );
1000 exposures++;
1002 else /* color -> monochrome */
1004 /* FIXME: avoid BadMatch error */
1005 imageSrc = XGetImage( gdi_display, physDevSrc->drawable,
1006 physDevSrc->org.x + visRectSrc->left,
1007 physDevSrc->org.y + visRectSrc->top,
1008 width, height, AllPlanes, ZPixmap );
1009 if (!imageSrc)
1011 return exposures;
1013 imageDst = X11DRV_DIB_CreateXImage( width, height, dcDst->bitsPerPixel );
1014 if (!imageDst)
1016 XDestroyImage(imageSrc);
1017 return exposures;
1019 for (y = 0; y < height; y++)
1020 for (x = 0; x < width; x++)
1021 XPutPixel(imageDst, x, y, (XGetPixel(imageSrc,x,y) ==
1022 physDevSrc->backgroundPixel) );
1023 XPutImage( gdi_display, pixmap, gc, imageDst,
1024 0, 0, 0, 0, width, height );
1025 XDestroyImage( imageSrc );
1026 XDestroyImage( imageDst );
1029 return exposures;
1033 /***********************************************************************
1034 * BITBLT_GetDstArea
1036 * Retrieve an area from the destination DC, mapping all the
1037 * pixels to Windows colors.
1039 static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst)
1041 int exposures = 0;
1042 INT width = visRectDst->right - visRectDst->left;
1043 INT height = visRectDst->bottom - visRectDst->top;
1045 if (!X11DRV_PALETTE_XPixelToPalette || (physDev->dc->bitsPerPixel == 1) ||
1046 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1048 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1049 physDev->org.x + visRectDst->left, physDev->org.y + visRectDst->top,
1050 width, height, 0, 0 );
1051 exposures++;
1053 else
1055 register INT x, y;
1056 XImage *image;
1058 if (GetObjectType( physDev->hdc ) == OBJ_MEMDC)
1059 image = XGetImage( gdi_display, physDev->drawable,
1060 physDev->org.x + visRectDst->left,
1061 physDev->org.y + visRectDst->top,
1062 width, height, AllPlanes, ZPixmap );
1063 else
1065 /* Make sure we don't get a BadMatch error */
1066 XCopyArea( gdi_display, physDev->drawable, pixmap, gc,
1067 physDev->org.x + visRectDst->left,
1068 physDev->org.y + visRectDst->top,
1069 width, height, 0, 0);
1070 exposures++;
1071 image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1072 AllPlanes, ZPixmap );
1074 for (y = 0; y < height; y++)
1075 for (x = 0; x < width; x++)
1076 XPutPixel( image, x, y,
1077 X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]);
1078 XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height );
1079 XDestroyImage( image );
1081 return exposures;
1085 /***********************************************************************
1086 * BITBLT_PutDstArea
1088 * Put an area back into the destination DC, mapping the pixel
1089 * colors to X pixels.
1091 static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst)
1093 int exposures = 0;
1094 INT width = visRectDst->right - visRectDst->left;
1095 INT height = visRectDst->bottom - visRectDst->top;
1097 /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */
1099 if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->dc->bitsPerPixel == 1) ||
1100 (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) )
1102 XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height,
1103 physDev->org.x + visRectDst->left,
1104 physDev->org.y + visRectDst->top );
1105 exposures++;
1107 else
1109 register INT x, y;
1110 XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height,
1111 AllPlanes, ZPixmap );
1112 for (y = 0; y < height; y++)
1113 for (x = 0; x < width; x++)
1115 XPutPixel( image, x, y,
1116 X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]);
1118 XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0,
1119 physDev->org.x + visRectDst->left,
1120 physDev->org.y + visRectDst->top, width, height );
1121 XDestroyImage( image );
1123 return exposures;
1127 /***********************************************************************
1128 * BITBLT_GetVisRectangles
1130 * Get the source and destination visible rectangles for StretchBlt().
1131 * Return FALSE if one of the rectangles is empty.
1133 static BOOL BITBLT_GetVisRectangles( DC *dcDst, INT xDst, INT yDst,
1134 INT widthDst, INT heightDst,
1135 DC *dcSrc, INT xSrc, INT ySrc,
1136 INT widthSrc, INT heightSrc,
1137 RECT *visRectSrc, RECT *visRectDst )
1139 RECT rect, clipRect;
1141 /* Get the destination visible rectangle */
1143 rect.left = xDst;
1144 rect.top = yDst;
1145 rect.right = xDst + widthDst;
1146 rect.bottom = yDst + heightDst;
1147 if (widthDst < 0) SWAP_INT32( &rect.left, &rect.right );
1148 if (heightDst < 0) SWAP_INT32( &rect.top, &rect.bottom );
1149 GetRgnBox( dcDst->hGCClipRgn, &clipRect );
1150 if (!IntersectRect( visRectDst, &rect, &clipRect )) return FALSE;
1152 /* Get the source visible rectangle */
1154 if (!dcSrc) return TRUE;
1155 rect.left = xSrc;
1156 rect.top = ySrc;
1157 rect.right = xSrc + widthSrc;
1158 rect.bottom = ySrc + heightSrc;
1159 if (widthSrc < 0) SWAP_INT32( &rect.left, &rect.right );
1160 if (heightSrc < 0) SWAP_INT32( &rect.top, &rect.bottom );
1161 /* Apparently the clipping and visible regions are only for output,
1162 so just check against totalExtent here to avoid BadMatch errors */
1163 if (!IntersectRect( visRectSrc, &rect, &dcSrc->totalExtent ))
1164 return FALSE;
1166 /* Intersect the rectangles */
1168 if ((widthSrc == widthDst) && (heightSrc == heightDst)) /* no stretching */
1170 visRectSrc->left += xDst - xSrc;
1171 visRectSrc->right += xDst - xSrc;
1172 visRectSrc->top += yDst - ySrc;
1173 visRectSrc->bottom += yDst - ySrc;
1174 if (!IntersectRect( &rect, visRectSrc, visRectDst )) return FALSE;
1175 *visRectSrc = *visRectDst = rect;
1176 visRectSrc->left += xSrc - xDst;
1177 visRectSrc->right += xSrc - xDst;
1178 visRectSrc->top += ySrc - yDst;
1179 visRectSrc->bottom += ySrc - yDst;
1181 else /* stretching */
1183 /* Map source rectangle into destination coordinates */
1184 rect.left = xDst + (visRectSrc->left - xSrc)*widthDst/widthSrc;
1185 rect.top = yDst + (visRectSrc->top - ySrc)*heightDst/heightSrc;
1186 rect.right = xDst + ((visRectSrc->right - xSrc)*widthDst)/widthSrc;
1187 rect.bottom = yDst + ((visRectSrc->bottom - ySrc)*heightDst)/heightSrc;
1188 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1189 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1191 /* Avoid rounding errors */
1192 rect.left--;
1193 rect.top--;
1194 rect.right++;
1195 rect.bottom++;
1196 if (!IntersectRect( visRectDst, &rect, visRectDst )) return FALSE;
1198 /* Map destination rectangle back to source coordinates */
1199 rect = *visRectDst;
1200 rect.left = xSrc + (visRectDst->left - xDst)*widthSrc/widthDst;
1201 rect.top = ySrc + (visRectDst->top - yDst)*heightSrc/heightDst;
1202 rect.right = xSrc + ((visRectDst->right - xDst)*widthSrc)/widthDst;
1203 rect.bottom = ySrc + ((visRectDst->bottom - yDst)*heightSrc)/heightDst;
1204 if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right );
1205 if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom );
1207 /* Avoid rounding errors */
1208 rect.left--;
1209 rect.top--;
1210 rect.right++;
1211 rect.bottom++;
1212 if (!IntersectRect( visRectSrc, &rect, visRectSrc )) return FALSE;
1214 return TRUE;
1218 /***********************************************************************
1219 * BITBLT_InternalStretchBlt
1221 * Implementation of PatBlt(), BitBlt() and StretchBlt().
1223 static BOOL BITBLT_InternalStretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1224 INT widthDst, INT heightDst,
1225 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1226 INT widthSrc, INT heightSrc,
1227 DWORD rop )
1229 BOOL usePat, useSrc, useDst, destUsed, fStretch, fNullBrush;
1230 RECT visRectDst, visRectSrc;
1231 INT width, height;
1232 const BYTE *opcode;
1233 Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */
1234 GC tmpGC = 0;
1235 POINT pts[2];
1236 DC *dcSrc = physDevSrc ? physDevSrc->dc : NULL;
1237 DC *dcDst = physDevDst->dc;
1239 /* compensate for off-by-one shifting for negative widths and heights */
1240 if (widthDst < 0)
1241 ++xDst;
1242 if (heightDst < 0)
1243 ++yDst;
1244 if (widthSrc < 0)
1245 ++xSrc;
1246 if (heightSrc < 0)
1247 ++ySrc;
1249 usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000));
1250 useSrc = (((rop >> 2) & 0x330000) != (rop & 0x330000));
1251 useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000));
1252 if (!dcSrc && useSrc) return FALSE;
1254 /* Map the coordinates to device coords */
1256 pts[0].x = xDst;
1257 pts[0].y = yDst;
1258 pts[1].x = xDst + widthDst;
1259 pts[1].y = yDst + heightDst;
1260 LPtoDP(physDevDst->hdc, pts, 2);
1261 xDst = pts[0].x;
1262 yDst = pts[0].y;
1263 widthDst = pts[1].x - pts[0].x;
1264 heightDst = pts[1].y - pts[0].y;
1266 TRACE(" vportdst=%d,%d-%d,%d wnddst=%d,%d-%d,%d\n",
1267 dcDst->vportOrgX, dcDst->vportOrgY,
1268 dcDst->vportExtX, dcDst->vportExtY,
1269 dcDst->wndOrgX, dcDst->wndOrgY,
1270 dcDst->wndExtX, dcDst->wndExtY );
1271 TRACE(" rectdst=%d,%d-%d,%d orgdst=%ld,%ld\n",
1272 xDst, yDst, widthDst, heightDst,
1273 physDevDst->org.x, physDevDst->org.y );
1275 if (useSrc)
1277 pts[0].x = xSrc;
1278 pts[0].y = ySrc;
1279 pts[1].x = xSrc + widthSrc;
1280 pts[1].y = ySrc + heightSrc;
1281 LPtoDP(physDevSrc->hdc, pts, 2);
1282 xSrc = pts[0].x;
1283 ySrc = pts[0].y;
1284 widthSrc = pts[1].x - pts[0].x;
1285 heightSrc = pts[1].y - pts[0].y;
1287 fStretch = (widthSrc != widthDst) || (heightSrc != heightDst);
1288 TRACE(" vportsrc=%d,%d-%d,%d wndsrc=%d,%d-%d,%d\n",
1289 dcSrc->vportOrgX, dcSrc->vportOrgY,
1290 dcSrc->vportExtX, dcSrc->vportExtY,
1291 dcSrc->wndOrgX, dcSrc->wndOrgY,
1292 dcSrc->wndExtX, dcSrc->wndExtY );
1293 TRACE(" rectsrc=%d,%d-%d,%d orgsrc=%ld,%ld\n",
1294 xSrc, ySrc, widthSrc, heightSrc,
1295 physDevSrc->org.x, physDevSrc->org.y );
1296 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1297 dcSrc, xSrc, ySrc, widthSrc, heightSrc,
1298 &visRectSrc, &visRectDst ))
1299 return TRUE;
1300 TRACE(" vissrc=%ld,%ld-%ld,%ld visdst=%ld,%ld-%ld,%ld\n",
1301 visRectSrc.left, visRectSrc.top,
1302 visRectSrc.right, visRectSrc.bottom,
1303 visRectDst.left, visRectDst.top,
1304 visRectDst.right, visRectDst.bottom );
1306 else
1308 fStretch = FALSE;
1309 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, widthDst, heightDst,
1310 NULL, 0, 0, 0, 0, NULL, &visRectDst ))
1311 return TRUE;
1312 TRACE(" vissrc=none visdst=%ld,%ld-%ld,%ld\n",
1313 visRectDst.left, visRectDst.top,
1314 visRectDst.right, visRectDst.bottom );
1317 width = visRectDst.right - visRectDst.left;
1318 height = visRectDst.bottom - visRectDst.top;
1320 if (!fStretch) switch(rop) /* A few optimisations */
1322 case BLACKNESS: /* 0x00 */
1323 wine_tsx11_lock();
1324 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1325 XSetFunction( gdi_display, physDevDst->gc, GXclear );
1326 else
1328 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1329 XSetForeground( gdi_display, physDevDst->gc, X11DRV_PALETTE_PaletteToXPixel[0] );
1330 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1332 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1333 physDevDst->org.x + visRectDst.left,
1334 physDevDst->org.y + visRectDst.top,
1335 width, height );
1336 wine_tsx11_unlock();
1337 return TRUE;
1339 case DSTINVERT: /* 0x55 */
1340 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel ||
1341 !perfect_graphics())
1343 wine_tsx11_lock();
1344 XSetFunction( gdi_display, physDevDst->gc, GXinvert );
1346 if( X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL) )
1347 XSetFunction( gdi_display, physDevDst->gc, GXinvert);
1348 else
1350 /* Xor is much better when we do not have full colormap. */
1351 /* Using white^black ensures that we invert at least black */
1352 /* and white. */
1353 Pixel xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^
1354 BlackPixel( gdi_display, DefaultScreen(gdi_display) ));
1355 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1356 XSetForeground( gdi_display, physDevDst->gc, xor_pix);
1357 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1359 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1360 physDevDst->org.x + visRectDst.left,
1361 physDevDst->org.y + visRectDst.top,
1362 width, height );
1363 wine_tsx11_unlock();
1364 return TRUE;
1366 break;
1368 case PATINVERT: /* 0x5a */
1369 if (perfect_graphics()) break;
1370 if (X11DRV_SetupGCForBrush( physDevDst ))
1372 wine_tsx11_lock();
1373 XSetFunction( gdi_display, physDevDst->gc, GXxor );
1374 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1375 physDevDst->org.x + visRectDst.left,
1376 physDevDst->org.y + visRectDst.top,
1377 width, height );
1378 wine_tsx11_unlock();
1380 return TRUE;
1382 case 0xa50065:
1383 if (perfect_graphics()) break;
1384 if (X11DRV_SetupGCForBrush( physDevDst ))
1386 wine_tsx11_lock();
1387 XSetFunction( gdi_display, physDevDst->gc, GXequiv );
1388 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1389 physDevDst->org.x + visRectDst.left,
1390 physDevDst->org.y + visRectDst.top,
1391 width, height );
1392 wine_tsx11_unlock();
1394 return TRUE;
1396 case SRCCOPY: /* 0xcc */
1397 if (dcSrc->bitsPerPixel == dcDst->bitsPerPixel)
1399 wine_tsx11_lock();
1400 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1401 XCopyArea( gdi_display, physDevSrc->drawable,
1402 physDevDst->drawable, physDevDst->gc,
1403 physDevSrc->org.x + visRectSrc.left,
1404 physDevSrc->org.y + visRectSrc.top,
1405 width, height,
1406 physDevDst->org.x + visRectDst.left,
1407 physDevDst->org.y + visRectDst.top );
1408 physDevDst->exposures++;
1409 wine_tsx11_unlock();
1410 return TRUE;
1412 if (dcSrc->bitsPerPixel == 1)
1414 wine_tsx11_lock();
1415 XSetBackground( gdi_display, physDevDst->gc, physDevDst->textPixel );
1416 XSetForeground( gdi_display, physDevDst->gc, physDevDst->backgroundPixel );
1417 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1418 XCopyPlane( gdi_display, physDevSrc->drawable,
1419 physDevDst->drawable, physDevDst->gc,
1420 physDevSrc->org.x + visRectSrc.left,
1421 physDevSrc->org.y + visRectSrc.top,
1422 width, height,
1423 physDevDst->org.x + visRectDst.left,
1424 physDevDst->org.y + visRectDst.top, 1 );
1425 physDevDst->exposures++;
1426 wine_tsx11_unlock();
1427 return TRUE;
1429 break;
1431 case PATCOPY: /* 0xf0 */
1432 if (!X11DRV_SetupGCForBrush( physDevDst )) return TRUE;
1433 wine_tsx11_lock();
1434 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1435 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1436 physDevDst->org.x + visRectDst.left,
1437 physDevDst->org.y + visRectDst.top,
1438 width, height );
1439 wine_tsx11_unlock();
1440 return TRUE;
1442 case WHITENESS: /* 0xff */
1443 wine_tsx11_lock();
1444 if ((dcDst->bitsPerPixel == 1) || !X11DRV_PALETTE_PaletteToXPixel)
1445 XSetFunction( gdi_display, physDevDst->gc, GXset );
1446 else
1448 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1449 XSetForeground( gdi_display, physDevDst->gc,
1450 WhitePixel( gdi_display, DefaultScreen(gdi_display) ));
1451 XSetFillStyle( gdi_display, physDevDst->gc, FillSolid );
1453 XFillRectangle( gdi_display, physDevDst->drawable, physDevDst->gc,
1454 physDevDst->org.x + visRectDst.left,
1455 physDevDst->org.y + visRectDst.top,
1456 width, height );
1457 wine_tsx11_unlock();
1458 return TRUE;
1461 wine_tsx11_lock();
1463 tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL );
1464 XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors );
1465 XSetGraphicsExposures( gdi_display, tmpGC, False );
1466 pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height,
1467 dcDst->bitsPerPixel );
1468 if (useSrc)
1470 pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height,
1471 dcDst->bitsPerPixel );
1472 if (fStretch)
1473 BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1474 xSrc, ySrc, widthSrc, heightSrc,
1475 xDst, yDst, widthDst, heightDst,
1476 &visRectSrc, &visRectDst );
1477 else
1478 BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC,
1479 xSrc, ySrc, &visRectSrc );
1482 if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &visRectDst );
1483 if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE );
1484 else fNullBrush = FALSE;
1485 destUsed = FALSE;
1487 for (opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; *opcode; opcode++)
1489 if (OP_DST(*opcode) == DST) destUsed = TRUE;
1490 XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) );
1491 switch(OP_SRCDST(*opcode))
1493 case OP_ARGS(DST,TMP):
1494 case OP_ARGS(SRC,TMP):
1495 if (!pixmaps[TMP])
1496 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1497 width, height,
1498 dcDst->bitsPerPixel );
1499 /* fall through */
1500 case OP_ARGS(DST,SRC):
1501 case OP_ARGS(SRC,DST):
1502 case OP_ARGS(TMP,SRC):
1503 case OP_ARGS(TMP,DST):
1504 if (useSrc)
1505 XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)],
1506 pixmaps[OP_DST(*opcode)], tmpGC,
1507 0, 0, width, height, 0, 0 );
1508 break;
1510 case OP_ARGS(PAT,TMP):
1511 if (!pixmaps[TMP] && !fNullBrush)
1512 pixmaps[TMP] = XCreatePixmap( gdi_display, root_window,
1513 width, height,
1514 dcDst->bitsPerPixel );
1515 /* fall through */
1516 case OP_ARGS(PAT,DST):
1517 case OP_ARGS(PAT,SRC):
1518 if (!fNullBrush)
1519 XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)],
1520 tmpGC, 0, 0, width, height );
1521 break;
1524 XSetFunction( gdi_display, physDevDst->gc, GXcopy );
1525 physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC],
1526 &visRectDst );
1527 XFreePixmap( gdi_display, pixmaps[DST] );
1528 if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] );
1529 if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] );
1530 XFreeGC( gdi_display, tmpGC );
1531 wine_tsx11_unlock();
1532 return TRUE;
1536 /***********************************************************************
1537 * X11DRV_PatBlt
1539 BOOL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT left, INT top, INT width, INT height, DWORD rop )
1541 BOOL result;
1543 X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod, FALSE );
1544 result = BITBLT_InternalStretchBlt( physDev, left, top, width, height, NULL, 0, 0, 0, 0, rop );
1545 X11DRV_UnlockDIBSection( physDev, TRUE );
1546 return result;
1550 /***********************************************************************
1551 * X11DRV_BitBlt
1553 BOOL X11DRV_BitBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1554 INT width, INT height, X11DRV_PDEVICE *physDevSrc,
1555 INT xSrc, INT ySrc, DWORD rop )
1557 BOOL result = FALSE;
1558 INT sSrc, sDst;
1559 RECT visRectDst, visRectSrc;
1560 DC *dcSrc = physDevSrc ? physDevSrc->dc : NULL;
1561 DC *dcDst = physDevDst->dc;
1563 if (((rop >> 16) & 0x55) == ((rop >> 17) & 0x55)) {
1564 /* FIXME: seems the ROP doesn't include destination;
1565 * now if the destination area include the entire dcDst,
1566 * we can pass TRUE instead of FALSE to CoerceDIBSection(dcDst...),
1567 * which may avoid a copy in some situations */
1569 sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None, FALSE );
1570 sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None, FALSE );
1572 if ((sSrc == DIB_Status_AppMod) && (rop == SRCCOPY) &&
1573 (dcSrc->bitsPerPixel == dcDst->bitsPerPixel))
1575 POINT pts[2];
1576 /* do everything ourselves; map coordinates */
1578 pts[0].x = xSrc;
1579 pts[0].y = ySrc;
1580 pts[1].x = xSrc + width;
1581 pts[1].y = ySrc + height;
1583 LPtoDP(physDevSrc->hdc, pts, 2);
1584 width = pts[1].x - pts[0].x;
1585 height = pts[1].y - pts[0].y;
1586 xSrc = pts[0].x;
1587 ySrc = pts[0].y;
1589 pts[0].x = xDst;
1590 pts[0].y = yDst;
1591 LPtoDP(physDevDst->hdc, pts, 1);
1593 xDst = pts[0].x;
1594 yDst = pts[0].y;
1596 /* Perform basic clipping */
1597 if (!BITBLT_GetVisRectangles( dcDst, xDst, yDst, width, height,
1598 dcSrc, xSrc, ySrc, width, height,
1599 &visRectSrc, &visRectDst ))
1600 goto END;
1602 xSrc = visRectSrc.left;
1603 ySrc = visRectSrc.top;
1604 xDst = visRectDst.left;
1605 yDst = visRectDst.top;
1606 width = visRectDst.right - visRectDst.left;
1607 height = visRectDst.bottom - visRectDst.top;
1609 if (sDst == DIB_Status_AppMod) {
1610 FIXME("potential optimization - client-side DIB copy\n");
1612 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1614 X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, xSrc, ySrc, xDst, yDst, width, height );
1615 result = TRUE;
1616 goto END;
1619 X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1620 if (physDevDst != physDevSrc)
1621 X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1623 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, width, height,
1624 physDevSrc, xSrc, ySrc, width, height, rop );
1626 END:
1627 if (physDevDst != physDevSrc)
1628 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1629 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1631 return result;
1635 /***********************************************************************
1636 * X11DRV_StretchBlt
1638 BOOL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst,
1639 INT widthDst, INT heightDst,
1640 X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc,
1641 INT widthSrc, INT heightSrc, DWORD rop )
1643 BOOL result;
1645 X11DRV_LockDIBSection( physDevDst, DIB_Status_GdiMod, FALSE );
1646 if (physDevDst != physDevSrc)
1647 X11DRV_LockDIBSection( physDevSrc, DIB_Status_GdiMod, FALSE );
1649 result = BITBLT_InternalStretchBlt( physDevDst, xDst, yDst, widthDst, heightDst,
1650 physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop );
1652 if (physDevDst != physDevSrc)
1653 X11DRV_UnlockDIBSection( physDevSrc, FALSE );
1654 X11DRV_UnlockDIBSection( physDevDst, TRUE );
1655 return result;