Commit | Line | Data |
---|---|---|
401710d7 AJ |
1 | /* |
2 | * GDI bit-blit operations | |
3 | * | |
3a5816f8 | 4 | * Copyright 1993, 1994 Alexandre Julliard |
54fd8b3d | 5 | * Copyright 2006 Damjan Jovanovic |
0799c1a7 AJ |
6 | * |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2.1 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the Free Software | |
360a3f91 | 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
3a5816f8 AJ |
20 | */ |
21 | ||
ab121e78 PS |
22 | #include "config.h" |
23 | ||
b1bac320 | 24 | #include <assert.h> |
e37c6e18 | 25 | #include <stdarg.h> |
401710d7 AJ |
26 | #include <stdio.h> |
27 | #include <stdlib.h> | |
15c64e70 | 28 | |
e37c6e18 | 29 | #include "windef.h" |
8efd4540 AJ |
30 | #include "winbase.h" |
31 | #include "wingdi.h" | |
32 | #include "winuser.h" | |
75d86e1f | 33 | #include "x11drv.h" |
0799c1a7 | 34 | #include "wine/debug.h" |
401710d7 | 35 | |
0799c1a7 | 36 | WINE_DEFAULT_DEBUG_CHANNEL(bitblt); |
b4b9fae6 | 37 | |
3a5816f8 | 38 | |
7cbe6572 AJ |
39 | #define DST 0 /* Destination drawable */ |
40 | #define SRC 1 /* Source drawable */ | |
41 | #define TMP 2 /* Temporary drawable */ | |
3a5816f8 AJ |
42 | #define PAT 3 /* Pattern (brush) in destination DC */ |
43 | ||
7cbe6572 | 44 | #define OP(src,dst,rop) (OP_ARGS(src,dst) << 4 | (rop)) |
3a5816f8 AJ |
45 | #define OP_ARGS(src,dst) (((src) << 2) | (dst)) |
46 | ||
7cbe6572 | 47 | #define OP_SRC(opcode) ((opcode) >> 6) |
9a624916 | 48 | #define OP_DST(opcode) (((opcode) >> 4) & 3) |
7cbe6572 AJ |
49 | #define OP_SRCDST(opcode) ((opcode) >> 4) |
50 | #define OP_ROP(opcode) ((opcode) & 0x0f) | |
3a5816f8 | 51 | |
7cbe6572 | 52 | #define MAX_OP_LEN 6 /* Longest opcode + 1 for the terminating 0 */ |
3a5816f8 | 53 | |
b1bac320 | 54 | #define SWAP_INT32(i1,i2) \ |
a3960292 | 55 | do { INT __t = *(i1); *(i1) = *(i2); *(i2) = __t; } while(0) |
b1bac320 | 56 | |
3a5816f8 AJ |
57 | static const unsigned char BITBLT_Opcodes[256][MAX_OP_LEN] = |
58 | { | |
59 | { OP(PAT,DST,GXclear) }, /* 0x00 0 */ | |
60 | { OP(PAT,SRC,GXor), OP(SRC,DST,GXnor) }, /* 0x01 ~(D|(P|S)) */ | |
61 | { OP(PAT,SRC,GXnor), OP(SRC,DST,GXand) }, /* 0x02 D&~(P|S) */ | |
62 | { OP(PAT,SRC,GXnor) }, /* 0x03 ~(P|S) */ | |
63 | { OP(PAT,DST,GXnor), OP(SRC,DST,GXand) }, /* 0x04 S&~(D|P) */ | |
64 | { OP(PAT,DST,GXnor) }, /* 0x05 ~(D|P) */ | |
65 | { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnor), }, /* 0x06 ~(P|~(D^S)) */ | |
66 | { OP(SRC,DST,GXand), OP(PAT,DST,GXnor) }, /* 0x07 ~(P|(D&S)) */ | |
67 | { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXand) },/* 0x08 S&D&~P */ | |
68 | { OP(SRC,DST,GXxor), OP(PAT,DST,GXnor) }, /* 0x09 ~(P|(D^S)) */ | |
69 | { OP(PAT,DST,GXandInverted) }, /* 0x0a D&~P */ | |
70 | { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXnor) }, /* 0x0b ~(P|(S&~D)) */ | |
71 | { OP(PAT,SRC,GXandInverted) }, /* 0x0c S&~P */ | |
72 | { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXnor) },/* 0x0d ~(P|(D&~S)) */ | |
73 | { OP(SRC,DST,GXnor), OP(PAT,DST,GXnor) }, /* 0x0e ~(P|~(D|S)) */ | |
74 | { OP(PAT,DST,GXcopyInverted) }, /* 0x0f ~P */ | |
75 | { OP(SRC,DST,GXnor), OP(PAT,DST,GXand) }, /* 0x10 P&~(S|D) */ | |
76 | { OP(SRC,DST,GXnor) }, /* 0x11 ~(D|S) */ | |
77 | { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnor) }, /* 0x12 ~(S|~(D^P)) */ | |
78 | { OP(PAT,DST,GXand), OP(SRC,DST,GXnor) }, /* 0x13 ~(S|(D&P)) */ | |
79 | { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnor) }, /* 0x14 ~(D|~(P^S)) */ | |
80 | { OP(PAT,SRC,GXand), OP(SRC,DST,GXnor) }, /* 0x15 ~(D|(P&S)) */ | |
81 | { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand), | |
82 | OP(TMP,DST,GXand), OP(SRC,DST,GXxor), | |
83 | OP(PAT,DST,GXxor) }, /* 0x16 P^S^(D&~(P&S) */ | |
84 | { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor), | |
85 | OP(PAT,SRC,GXxor), OP(SRC,DST,GXand), | |
86 | OP(TMP,DST,GXequiv) }, /* 0x17 ~S^((S^P)&(S^D))*/ | |
87 | { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor), | |
88 | OP(SRC,DST,GXand) }, /* 0x18 (S^P)&(D^P) */ | |
89 | { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXnand), | |
90 | OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x19 ~S^(D&~(P&S)) */ | |
91 | { OP(PAT,SRC,GXand), OP(SRC,DST,GXor), | |
92 | OP(PAT,DST,GXxor) }, /* 0x1a P^(D|(S&P)) */ | |
93 | { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXxor), | |
94 | OP(TMP,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x1b ~S^(D&(P^S)) */ | |
95 | { OP(PAT,DST,GXand), OP(SRC,DST,GXor), | |
96 | OP(PAT,DST,GXxor) }, /* 0x1c P^(S|(D&P)) */ | |
97 | { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor), | |
98 | OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x1d ~D^(S&(D^P)) */ | |
99 | { OP(SRC,DST,GXor), OP(PAT,DST,GXxor) }, /* 0x1e P^(D|S) */ | |
100 | { OP(SRC,DST,GXor), OP(PAT,DST,GXnand) }, /* 0x1f ~(P&(D|S)) */ | |
101 | { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXand) }, /* 0x20 D&(P&~S) */ | |
102 | { OP(PAT,DST,GXxor), OP(SRC,DST,GXnor) }, /* 0x21 ~(S|(D^P)) */ | |
103 | { OP(SRC,DST,GXandInverted) }, /* 0x22 ~S&D */ | |
104 | { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x23 ~(S|(P&~D)) */ | |
105 | { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor), | |
106 | OP(SRC,DST,GXand) }, /* 0x24 (S^P)&(S^D) */ | |
107 | { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand), | |
108 | OP(PAT,DST,GXequiv) }, /* 0x25 ~P^(D&~(S&P)) */ | |
109 | { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand), | |
110 | OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x26 S^(D|(S&P)) */ | |
111 | { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXequiv), | |
112 | OP(TMP,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x27 S^(D|~(P^S)) */ | |
113 | { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand) }, /* 0x28 D&(P^S) */ | |
114 | { OP(SRC,TMP,GXcopy), OP(PAT,TMP,GXand), | |
115 | OP(TMP,DST,GXor), OP(SRC,DST,GXxor), | |
116 | OP(PAT,DST,GXequiv) }, /* 0x29 ~P^S^(D|(P&S)) */ | |
117 | { OP(PAT,SRC,GXnand), OP(SRC,DST,GXand) }, /* 0x2a D&~(P&S) */ | |
118 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor), | |
119 | OP(PAT,DST,GXxor), OP(SRC,DST,GXand), | |
120 | OP(TMP,DST,GXequiv) }, /* 0x2b ~S^((P^S)&(P^D))*/ | |
121 | { OP(SRC,DST,GXor), OP(PAT,DST,GXand), | |
122 | OP(SRC,DST,GXxor) }, /* 0x2c S^(P&(S|D)) */ | |
123 | { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXxor) }, /* 0x2d P^(S|~D) */ | |
124 | { OP(PAT,DST,GXxor), OP(SRC,DST,GXor), | |
125 | OP(PAT,DST,GXxor) }, /* 0x2e P^(S|(D^P)) */ | |
126 | { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXnand) }, /* 0x2f ~(P&(S|~D)) */ | |
127 | { OP(PAT,SRC,GXandReverse) }, /* 0x30 P&~S */ | |
128 | { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXnor) },/* 0x31 ~(S|(D&~P)) */ | |
129 | { OP(SRC,DST,GXor), OP(PAT,DST,GXor), | |
130 | OP(SRC,DST,GXxor) }, /* 0x32 S^(D|P|S) */ | |
131 | { OP(SRC,DST,GXcopyInverted) }, /* 0x33 ~S */ | |
132 | { OP(SRC,DST,GXand), OP(PAT,DST,GXor), | |
133 | OP(SRC,DST,GXxor) }, /* 0x34 S^(P|(D&S)) */ | |
134 | { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor), | |
135 | OP(SRC,DST,GXxor) }, /* 0x35 S^(P|~(D^S)) */ | |
136 | { OP(PAT,DST,GXor), OP(SRC,DST,GXxor) }, /* 0x36 S^(D|P) */ | |
137 | { OP(PAT,DST,GXor), OP(SRC,DST,GXnand) }, /* 0x37 ~(S&(D|P)) */ | |
138 | { OP(PAT,DST,GXor), OP(SRC,DST,GXand), | |
139 | OP(PAT,DST,GXxor) }, /* 0x38 P^(S&(D|P)) */ | |
140 | { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x39 S^(P|~D) */ | |
141 | { OP(SRC,DST,GXxor), OP(PAT,DST,GXor), | |
142 | OP(SRC,DST,GXxor) }, /* 0x3a S^(P|(D^S)) */ | |
143 | { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x3b ~(S&(P|~D)) */ | |
144 | { OP(PAT,SRC,GXxor) }, /* 0x3c P^S */ | |
145 | { OP(SRC,DST,GXnor), OP(PAT,DST,GXor), | |
146 | OP(SRC,DST,GXxor) }, /* 0x3d S^(P|~(D|S)) */ | |
147 | { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor), | |
148 | OP(SRC,DST,GXxor) }, /* 0x3e S^(P|(D&~S)) */ | |
149 | { OP(PAT,SRC,GXnand) }, /* 0x3f ~(P&S) */ | |
150 | { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXand) }, /* 0x40 P&S&~D */ | |
151 | { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnor) }, /* 0x41 ~(D|(P^S)) */ | |
152 | { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor), | |
153 | OP(SRC,DST,GXand) }, /* 0x42 (S^D)&(P^D) */ | |
154 | { OP(SRC,DST,GXnand), OP(PAT,DST,GXand), | |
155 | OP(SRC,DST,GXequiv) }, /* 0x43 ~S^(P&~(D&S)) */ | |
156 | { OP(SRC,DST,GXandReverse) }, /* 0x44 S&~D */ | |
157 | { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXnor) }, /* 0x45 ~(D|(P&~S)) */ | |
158 | { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand), | |
159 | OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x46 D^(S|(P&D)) */ | |
160 | { OP(PAT,DST,GXxor), OP(SRC,DST,GXand), | |
161 | OP(PAT,DST,GXequiv) }, /* 0x47 ~P^(S&(D^P)) */ | |
162 | { OP(PAT,DST,GXxor), OP(SRC,DST,GXand) }, /* 0x48 S&(P^D) */ | |
163 | { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand), | |
164 | OP(SRC,DST,GXor), OP(TMP,DST,GXxor), | |
165 | OP(PAT,DST,GXequiv) }, /* 0x49 ~P^D^(S|(P&D)) */ | |
166 | { OP(DST,SRC,GXor), OP(PAT,SRC,GXand), | |
167 | OP(SRC,DST,GXxor) }, /* 0x4a D^(P&(S|D)) */ | |
168 | { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXxor) }, /* 0x4b P^(D|~S) */ | |
169 | { OP(PAT,DST,GXnand), OP(SRC,DST,GXand) }, /* 0x4c S&~(D&P) */ | |
170 | { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor), | |
171 | OP(PAT,SRC,GXxor), OP(SRC,DST,GXor), | |
172 | OP(TMP,DST,GXequiv) }, /* 0x4d ~S^((S^P)|(S^D))*/ | |
173 | { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor), | |
174 | OP(PAT,DST,GXxor) }, /* 0x4e P^(D|(S^P)) */ | |
175 | { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXnand) },/* 0x4f ~(P&(D|~S)) */ | |
176 | { OP(PAT,DST,GXandReverse) }, /* 0x50 P&~D */ | |
177 | { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXnor) },/* 0x51 ~(D|(S&~P)) */ | |
178 | { OP(DST,SRC,GXand), OP(PAT,SRC,GXor), | |
179 | OP(SRC,DST,GXxor) }, /* 0x52 D^(P|(S&D)) */ | |
180 | { OP(SRC,DST,GXxor), OP(PAT,DST,GXand), | |
181 | OP(SRC,DST,GXequiv) }, /* 0x53 ~S^(P&(D^S)) */ | |
182 | { OP(PAT,SRC,GXnor), OP(SRC,DST,GXnor) }, /* 0x54 ~(D|~(P|S)) */ | |
183 | { OP(PAT,DST,GXinvert) }, /* 0x55 ~D */ | |
184 | { OP(PAT,SRC,GXor), OP(SRC,DST,GXxor) }, /* 0x56 D^(P|S) */ | |
185 | { OP(PAT,SRC,GXor), OP(SRC,DST,GXnand) }, /* 0x57 ~(D&(P|S)) */ | |
186 | { OP(PAT,SRC,GXor), OP(SRC,DST,GXand), | |
187 | OP(PAT,DST,GXxor) }, /* 0x58 P^(D&(P|S)) */ | |
188 | { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXxor) }, /* 0x59 D^(P|~S) */ | |
189 | { OP(PAT,DST,GXxor) }, /* 0x5a D^P */ | |
190 | { OP(DST,SRC,GXnor), OP(PAT,SRC,GXor), | |
191 | OP(SRC,DST,GXxor) }, /* 0x5b D^(P|~(S|D)) */ | |
192 | { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor), | |
193 | OP(SRC,DST,GXxor) }, /* 0x5c D^(P|(S^D)) */ | |
194 | { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXnand) }, /* 0x5d ~(D&(P|~S)) */ | |
195 | { OP(DST,SRC,GXandInverted), OP(PAT,SRC,GXor), | |
196 | OP(SRC,DST,GXxor) }, /* 0x5e D^(P|(S&~D)) */ | |
197 | { OP(PAT,DST,GXnand) }, /* 0x5f ~(D&P) */ | |
198 | { OP(SRC,DST,GXxor), OP(PAT,DST,GXand) }, /* 0x60 P&(D^S) */ | |
199 | { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand), | |
200 | OP(PAT,DST,GXor), OP(SRC,DST,GXxor), | |
201 | OP(TMP,DST,GXequiv) }, /* 0x61 ~D^S^(P|(D&S)) */ | |
202 | { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor), | |
203 | OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x62 D^(S&(P|D)) */ | |
204 | { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x63 S^(D|~P) */ | |
205 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor), | |
206 | OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x64 S^(D&(P|S)) */ | |
207 | { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXxor) }, /* 0x65 D^(S|~P) */ | |
208 | { OP(SRC,DST,GXxor) }, /* 0x66 S^D */ | |
209 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor), | |
210 | OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x67 S^(D|~(S|P) */ | |
211 | { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnor), | |
212 | OP(PAT,DST,GXor), OP(SRC,DST,GXxor), | |
213 | OP(TMP,DST,GXequiv) }, /* 0x68 ~D^S^(P|~(D|S))*/ | |
214 | { OP(SRC,DST,GXxor), OP(PAT,DST,GXequiv) }, /* 0x69 ~P^(D^S) */ | |
215 | { OP(PAT,SRC,GXand), OP(SRC,DST,GXxor) }, /* 0x6a D^(P&S) */ | |
216 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor), | |
217 | OP(SRC,DST,GXand), OP(TMP,DST,GXxor), | |
218 | OP(PAT,DST,GXequiv) }, /* 0x6b ~P^S^(D&(P|S)) */ | |
219 | { OP(PAT,DST,GXand), OP(SRC,DST,GXxor) }, /* 0x6c S^(D&P) */ | |
220 | { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor), | |
221 | OP(SRC,DST,GXand), OP(TMP,DST,GXxor), | |
222 | OP(PAT,DST,GXequiv) }, /* 0x6d ~P^D^(S&(P|D)) */ | |
223 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse), | |
224 | OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0x6e S^(D&(P|~S)) */ | |
225 | { OP(SRC,DST,GXequiv), OP(PAT,DST,GXnand) }, /* 0x6f ~(P&~(S^D)) */ | |
226 | { OP(SRC,DST,GXnand), OP(PAT,DST,GXand) }, /* 0x70 P&~(D&S) */ | |
227 | { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor), | |
228 | OP(PAT,DST,GXxor), OP(SRC,DST,GXand), | |
229 | OP(TMP,DST,GXequiv) }, /* 0x71 ~S^((S^D)&(P^D))*/ | |
230 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor), | |
231 | OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x72 S^(D|(P^S)) */ | |
232 | { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXnand) },/* 0x73 ~(S&(D|~P)) */ | |
233 | { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor), | |
234 | OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x74 D^(S|(P^D)) */ | |
235 | { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXnand) },/* 0x75 ~(D&(S|~P)) */ | |
236 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse), | |
237 | OP(SRC,DST,GXor), OP(TMP,DST,GXxor) }, /* 0x76 S^(D|(P&~S)) */ | |
238 | { OP(SRC,DST,GXnand) }, /* 0x77 ~(S&D) */ | |
239 | { OP(SRC,DST,GXand), OP(PAT,DST,GXxor) }, /* 0x78 P^(D&S) */ | |
240 | { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor), | |
241 | OP(PAT,DST,GXand), OP(SRC,DST,GXxor), | |
242 | OP(TMP,DST,GXequiv) }, /* 0x79 ~D^S^(P&(D|S)) */ | |
243 | { OP(DST,SRC,GXorInverted), OP(PAT,SRC,GXand), | |
244 | OP(SRC,DST,GXxor) }, /* 0x7a D^(P&(S|~D)) */ | |
245 | { OP(PAT,DST,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7b ~(S&~(D^P)) */ | |
246 | { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand), | |
247 | OP(SRC,DST,GXxor) }, /* 0x7c S^(P&(D|~S)) */ | |
248 | { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXnand) }, /* 0x7d ~(D&~(P^S)) */ | |
249 | { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor), | |
250 | OP(SRC,DST,GXor) }, /* 0x7e (S^P)|(S^D) */ | |
251 | { OP(PAT,SRC,GXand), OP(SRC,DST,GXnand) }, /* 0x7f ~(D&P&S) */ | |
252 | { OP(PAT,SRC,GXand), OP(SRC,DST,GXand) }, /* 0x80 D&P&S */ | |
253 | { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor), | |
254 | OP(SRC,DST,GXnor) }, /* 0x81 ~((S^P)|(S^D)) */ | |
255 | { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXand) }, /* 0x82 D&~(P^S) */ | |
256 | { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand), | |
257 | OP(SRC,DST,GXequiv) }, /* 0x83 ~S^(P&(D|~S)) */ | |
258 | { OP(PAT,DST,GXequiv), OP(SRC,DST,GXand) }, /* 0x84 S&~(D^P) */ | |
259 | { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand), | |
260 | OP(PAT,DST,GXequiv) }, /* 0x85 ~P^(D&(S|~P)) */ | |
261 | { OP(DST,TMP,GXcopy), OP(SRC,DST,GXor), | |
262 | OP(PAT,DST,GXand), OP(SRC,DST,GXxor), | |
263 | OP(TMP,DST,GXxor) }, /* 0x86 D^S^(P&(D|S)) */ | |
264 | { OP(SRC,DST,GXand), OP(PAT,DST,GXequiv) }, /* 0x87 ~P^(D&S) */ | |
265 | { OP(SRC,DST,GXand) }, /* 0x88 S&D */ | |
266 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXandReverse), | |
267 | OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x89 ~S^(D|(P&~S)) */ | |
268 | { OP(PAT,SRC,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8a D&(S|~P) */ | |
269 | { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor), | |
270 | OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8b ~D^(S|(P^D)) */ | |
271 | { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXand) }, /* 0x8c S&(D|~P) */ | |
272 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor), | |
273 | OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x8d ~S^(D|(P^S)) */ | |
274 | { OP(SRC,TMP,GXcopy), OP(DST,SRC,GXxor), | |
275 | OP(PAT,DST,GXxor), OP(SRC,DST,GXand), | |
276 | OP(TMP,DST,GXxor) }, /* 0x8e S^((S^D)&(P^D))*/ | |
277 | { OP(SRC,DST,GXnand), OP(PAT,DST,GXnand) }, /* 0x8f ~(P&~(D&S)) */ | |
278 | { OP(SRC,DST,GXequiv), OP(PAT,DST,GXand) }, /* 0x90 P&~(D^S) */ | |
279 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXorReverse), | |
280 | OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x91 ~S^(D&(P|~S)) */ | |
281 | { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor), | |
282 | OP(SRC,DST,GXand), OP(PAT,DST,GXxor), | |
283 | OP(TMP,DST,GXxor) }, /* 0x92 D^P^(S&(D|P)) */ | |
284 | { OP(PAT,DST,GXand), OP(SRC,DST,GXequiv) }, /* 0x93 ~S^(P&D) */ | |
285 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor), | |
286 | OP(SRC,DST,GXand), OP(PAT,DST,GXxor), | |
287 | OP(TMP,DST,GXxor) }, /* 0x94 S^P^(D&(P|S)) */ | |
288 | { OP(PAT,SRC,GXand), OP(SRC,DST,GXequiv) }, /* 0x95 ~D^(P&S) */ | |
289 | { OP(PAT,SRC,GXxor), OP(SRC,DST,GXxor) }, /* 0x96 D^P^S */ | |
290 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor), | |
291 | OP(SRC,DST,GXor), OP(PAT,DST,GXxor), | |
292 | OP(TMP,DST,GXxor) }, /* 0x97 S^P^(D|~(P|S)) */ | |
293 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnor), | |
294 | OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0x98 ~S^(D|~(P|S)) */ | |
295 | { OP(SRC,DST,GXequiv) }, /* 0x99 ~S^D */ | |
296 | { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9a D^(P&~S) */ | |
297 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXor), | |
298 | OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9b ~S^(D&(P|S)) */ | |
299 | { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXxor) }, /* 0x9c S^(P&~D) */ | |
300 | { OP(DST,TMP,GXcopy), OP(PAT,DST,GXor), | |
301 | OP(SRC,DST,GXand), OP(TMP,DST,GXequiv) }, /* 0x9d ~D^(S&(P|D)) */ | |
302 | { OP(DST,TMP,GXcopy), OP(SRC,DST,GXand), | |
303 | OP(PAT,DST,GXor), OP(SRC,DST,GXxor), | |
304 | OP(TMP,DST,GXxor) }, /* 0x9e D^S^(P|(D&S)) */ | |
305 | { OP(SRC,DST,GXxor), OP(PAT,DST,GXnand) }, /* 0x9f ~(P&(D^S)) */ | |
306 | { OP(PAT,DST,GXand) }, /* 0xa0 D&P */ | |
307 | { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor), | |
308 | OP(PAT,DST,GXequiv) }, /* 0xa1 ~P^(D|(S&~P)) */ | |
309 | { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXand) }, /* 0xa2 D&(P|~S) */ | |
310 | { OP(DST,SRC,GXxor), OP(PAT,SRC,GXor), | |
311 | OP(SRC,DST,GXequiv) }, /* 0xa3 ~D^(P|(S^D)) */ | |
312 | { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor), | |
313 | OP(PAT,DST,GXequiv) }, /* 0xa4 ~P^(D|~(S|P)) */ | |
314 | { OP(PAT,DST,GXequiv) }, /* 0xa5 ~P^D */ | |
315 | { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXxor) },/* 0xa6 D^(S&~P) */ | |
316 | { OP(PAT,SRC,GXor), OP(SRC,DST,GXand), | |
317 | OP(PAT,DST,GXequiv) }, /* 0xa7 ~P^(D&(S|P)) */ | |
318 | { OP(PAT,SRC,GXor), OP(SRC,DST,GXand) }, /* 0xa8 D&(P|S) */ | |
319 | { OP(PAT,SRC,GXor), OP(SRC,DST,GXequiv) }, /* 0xa9 ~D^(P|S) */ | |
23afe2e9 | 320 | { OP(PAT,DST,GXnoop) }, /* 0xaa D */ |
3a5816f8 AJ |
321 | { OP(PAT,SRC,GXnor), OP(SRC,DST,GXor) }, /* 0xab D|~(P|S) */ |
322 | { OP(SRC,DST,GXxor), OP(PAT,DST,GXand), | |
323 | OP(SRC,DST,GXxor) }, /* 0xac S^(P&(D^S)) */ | |
324 | { OP(DST,SRC,GXand), OP(PAT,SRC,GXor), | |
325 | OP(SRC,DST,GXequiv) }, /* 0xad ~D^(P|(S&D)) */ | |
326 | { OP(PAT,SRC,GXandInverted), OP(SRC,DST,GXor) }, /* 0xae D|(S&~P) */ | |
327 | { OP(PAT,DST,GXorInverted) }, /* 0xaf D|~P */ | |
328 | { OP(SRC,DST,GXorInverted), OP(PAT,DST,GXand) }, /* 0xb0 P&(D|~S) */ | |
329 | { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor), | |
330 | OP(PAT,DST,GXequiv) }, /* 0xb1 ~P^(D|(S^P)) */ | |
331 | { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor), | |
332 | OP(PAT,SRC,GXxor), OP(SRC,DST,GXor), | |
333 | OP(TMP,DST,GXxor) }, /* 0xb2 S^((S^P)|(S^D))*/ | |
334 | { OP(PAT,DST,GXnand), OP(SRC,DST,GXnand) }, /* 0xb3 ~(S&~(D&P)) */ | |
335 | { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXxor) }, /* 0xb4 P^(S&~D) */ | |
336 | { OP(DST,SRC,GXor), OP(PAT,SRC,GXand), | |
337 | OP(SRC,DST,GXequiv) }, /* 0xb5 ~D^(P&(S|D)) */ | |
338 | { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand), | |
339 | OP(SRC,DST,GXor), OP(PAT,DST,GXxor), | |
340 | OP(TMP,DST,GXxor) }, /* 0xb6 D^P^(S|(D&P)) */ | |
341 | { OP(PAT,DST,GXxor), OP(SRC,DST,GXnand) }, /* 0xb7 ~(S&(D^P)) */ | |
342 | { OP(PAT,DST,GXxor), OP(SRC,DST,GXand), | |
343 | OP(PAT,DST,GXxor) }, /* 0xb8 P^(S&(D^P)) */ | |
344 | { OP(DST,TMP,GXcopy), OP(PAT,DST,GXand), | |
345 | OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xb9 ~D^(S|(P&D)) */ | |
346 | { OP(PAT,SRC,GXandReverse), OP(SRC,DST,GXor) }, /* 0xba D|(P&~S) */ | |
347 | { OP(SRC,DST,GXorInverted) }, /* 0xbb ~S|D */ | |
348 | { OP(SRC,DST,GXnand), OP(PAT,DST,GXand), | |
349 | OP(SRC,DST,GXxor) }, /* 0xbc S^(P&~(D&S)) */ | |
350 | { OP(DST,SRC,GXxor), OP(PAT,DST,GXxor), | |
351 | OP(SRC,DST,GXnand) }, /* 0xbd ~((S^D)&(P^D)) */ | |
352 | { OP(PAT,SRC,GXxor), OP(SRC,DST,GXor) }, /* 0xbe D|(P^S) */ | |
353 | { OP(PAT,SRC,GXnand), OP(SRC,DST,GXor) }, /* 0xbf D|~(P&S) */ | |
354 | { OP(PAT,SRC,GXand) }, /* 0xc0 P&S */ | |
355 | { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor), | |
356 | OP(SRC,DST,GXequiv) }, /* 0xc1 ~S^(P|(D&~S)) */ | |
357 | { OP(SRC,DST,GXnor), OP(PAT,DST,GXor), | |
358 | OP(SRC,DST,GXequiv) }, /* 0xc2 ~S^(P|~(D|S)) */ | |
359 | { OP(PAT,SRC,GXequiv) }, /* 0xc3 ~P^S */ | |
360 | { OP(PAT,DST,GXorReverse), OP(SRC,DST,GXand) }, /* 0xc4 S&(P|~D) */ | |
361 | { OP(SRC,DST,GXxor), OP(PAT,DST,GXor), | |
362 | OP(SRC,DST,GXequiv) }, /* 0xc5 ~S^(P|(D^S)) */ | |
363 | { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXxor) },/* 0xc6 S^(D&~P) */ | |
364 | { OP(PAT,DST,GXor), OP(SRC,DST,GXand), | |
365 | OP(PAT,DST,GXequiv) }, /* 0xc7 ~P^(S&(D|P)) */ | |
366 | { OP(PAT,DST,GXor), OP(SRC,DST,GXand) }, /* 0xc8 S&(D|P) */ | |
367 | { OP(PAT,DST,GXor), OP(SRC,DST,GXequiv) }, /* 0xc9 ~S^(P|D) */ | |
368 | { OP(DST,SRC,GXxor), OP(PAT,SRC,GXand), | |
369 | OP(SRC,DST,GXxor) }, /* 0xca D^(P&(S^D)) */ | |
370 | { OP(SRC,DST,GXand), OP(PAT,DST,GXor), | |
371 | OP(SRC,DST,GXequiv) }, /* 0xcb ~S^(P|(D&S)) */ | |
372 | { OP(SRC,DST,GXcopy) }, /* 0xcc S */ | |
373 | { OP(PAT,DST,GXnor), OP(SRC,DST,GXor) }, /* 0xcd S|~(D|P) */ | |
374 | { OP(PAT,DST,GXandInverted), OP(SRC,DST,GXor) }, /* 0xce S|(D&~P) */ | |
375 | { OP(PAT,SRC,GXorInverted) }, /* 0xcf S|~P */ | |
376 | { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXand) }, /* 0xd0 P&(S|~D) */ | |
377 | { OP(PAT,DST,GXxor), OP(SRC,DST,GXor), | |
378 | OP(PAT,DST,GXequiv) }, /* 0xd1 ~P^(S|(D^P)) */ | |
379 | { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXxor) },/* 0xd2 P^(D&~S) */ | |
380 | { OP(SRC,DST,GXor), OP(PAT,DST,GXand), | |
381 | OP(SRC,DST,GXequiv) }, /* 0xd3 ~S^(P&(D|S)) */ | |
382 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor), | |
383 | OP(PAT,DST,GXxor), OP(SRC,DST,GXand), | |
384 | OP(TMP,DST,GXxor) }, /* 0xd4 S^((S^P)&(D^P))*/ | |
385 | { OP(PAT,SRC,GXnand), OP(SRC,DST,GXnand) }, /* 0xd5 ~(D&~(P&S)) */ | |
386 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand), | |
387 | OP(SRC,DST,GXor), OP(PAT,DST,GXxor), | |
388 | OP(TMP,DST,GXxor) }, /* 0xd6 S^P^(D|(P&S)) */ | |
389 | { OP(PAT,SRC,GXxor), OP(SRC,DST,GXnand) }, /* 0xd7 ~(D&(P^S)) */ | |
390 | { OP(PAT,SRC,GXxor), OP(SRC,DST,GXand), | |
391 | OP(PAT,DST,GXxor) }, /* 0xd8 P^(D&(S^P)) */ | |
392 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXand), | |
393 | OP(SRC,DST,GXor), OP(TMP,DST,GXequiv) }, /* 0xd9 ~S^(D|(P&S)) */ | |
394 | { OP(DST,SRC,GXnand), OP(PAT,SRC,GXand), | |
395 | OP(SRC,DST,GXxor) }, /* 0xda D^(P&~(S&D)) */ | |
396 | { OP(SRC,DST,GXxor), OP(PAT,SRC,GXxor), | |
397 | OP(SRC,DST,GXnand) }, /* 0xdb ~((S^P)&(S^D)) */ | |
398 | { OP(PAT,DST,GXandReverse), OP(SRC,DST,GXor) }, /* 0xdc S|(P&~D) */ | |
399 | { OP(SRC,DST,GXorReverse) }, /* 0xdd S|~D */ | |
400 | { OP(PAT,DST,GXxor), OP(SRC,DST,GXor) }, /* 0xde S|(D^P) */ | |
401 | { OP(PAT,DST,GXnand), OP(SRC,DST,GXor) }, /* 0xdf S|~(D&P) */ | |
402 | { OP(SRC,DST,GXor), OP(PAT,DST,GXand) }, /* 0xe0 P&(D|S) */ | |
403 | { OP(SRC,DST,GXor), OP(PAT,DST,GXequiv) }, /* 0xe1 ~P^(D|S) */ | |
404 | { OP(DST,TMP,GXcopy), OP(PAT,DST,GXxor), | |
405 | OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe2 D^(S&(P^D)) */ | |
406 | { OP(PAT,DST,GXand), OP(SRC,DST,GXor), | |
407 | OP(PAT,DST,GXequiv) }, /* 0xe3 ~P^(S|(D&P)) */ | |
408 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXxor), | |
409 | OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe4 S^(D&(P^S)) */ | |
410 | { OP(PAT,SRC,GXand), OP(SRC,DST,GXor), | |
411 | OP(PAT,DST,GXequiv) }, /* 0xe5 ~P^(D|(S&P)) */ | |
412 | { OP(SRC,TMP,GXcopy), OP(PAT,SRC,GXnand), | |
413 | OP(SRC,DST,GXand), OP(TMP,DST,GXxor) }, /* 0xe6 S^(D&~(P&S)) */ | |
414 | { OP(PAT,SRC,GXxor), OP(PAT,DST,GXxor), | |
415 | OP(SRC,DST,GXnand) }, /* 0xe7 ~((S^P)&(D^P)) */ | |
416 | { OP(SRC,TMP,GXcopy), OP(SRC,DST,GXxor), | |
417 | OP(PAT,SRC,GXxor), OP(SRC,DST,GXand), | |
418 | OP(TMP,DST,GXxor) }, /* 0xe8 S^((S^P)&(S^D))*/ | |
419 | { OP(DST,TMP,GXcopy), OP(SRC,DST,GXnand), | |
420 | OP(PAT,DST,GXand), OP(SRC,DST,GXxor), | |
421 | OP(TMP,DST,GXequiv) }, /* 0xe9 ~D^S^(P&~(S&D))*/ | |
422 | { OP(PAT,SRC,GXand), OP(SRC,DST,GXor) }, /* 0xea D|(P&S) */ | |
423 | { OP(PAT,SRC,GXequiv), OP(SRC,DST,GXor) }, /* 0xeb D|~(P^S) */ | |
424 | { OP(PAT,DST,GXand), OP(SRC,DST,GXor) }, /* 0xec S|(D&P) */ | |
425 | { OP(PAT,DST,GXequiv), OP(SRC,DST,GXor) }, /* 0xed S|~(D^P) */ | |
426 | { OP(SRC,DST,GXor) }, /* 0xee S|D */ | |
427 | { OP(PAT,DST,GXorInverted), OP(SRC,DST,GXor) }, /* 0xef S|D|~P */ | |
428 | { OP(PAT,DST,GXcopy) }, /* 0xf0 P */ | |
429 | { OP(SRC,DST,GXnor), OP(PAT,DST,GXor) }, /* 0xf1 P|~(D|S) */ | |
430 | { OP(SRC,DST,GXandInverted), OP(PAT,DST,GXor) }, /* 0xf2 P|(D&~S) */ | |
431 | { OP(PAT,SRC,GXorReverse) }, /* 0xf3 P|~S */ | |
432 | { OP(SRC,DST,GXandReverse), OP(PAT,DST,GXor) }, /* 0xf4 P|(S&~D) */ | |
433 | { OP(PAT,DST,GXorReverse) }, /* 0xf5 P|~D */ | |
434 | { OP(SRC,DST,GXxor), OP(PAT,DST,GXor) }, /* 0xf6 P|(D^S) */ | |
435 | { OP(SRC,DST,GXnand), OP(PAT,DST,GXor) }, /* 0xf7 P|~(S&D) */ | |
436 | { OP(SRC,DST,GXand), OP(PAT,DST,GXor) }, /* 0xf8 P|(D&S) */ | |
437 | { OP(SRC,DST,GXequiv), OP(PAT,DST,GXor) }, /* 0xf9 P|~(D^S) */ | |
438 | { OP(PAT,DST,GXor) }, /* 0xfa D|P */ | |
439 | { OP(PAT,SRC,GXorReverse), OP(SRC,DST,GXor) }, /* 0xfb D|P|~S */ | |
440 | { OP(PAT,SRC,GXor) }, /* 0xfc P|S */ | |
441 | { OP(SRC,DST,GXorReverse), OP(PAT,DST,GXor) }, /* 0xfd P|S|~D */ | |
442 | { OP(SRC,DST,GXor), OP(PAT,DST,GXor) }, /* 0xfe P|D|S */ | |
443 | { OP(PAT,DST,GXset) } /* 0xff 1 */ | |
444 | }; | |
445 | ||
446 | ||
447 | #ifdef BITBLT_TEST /* Opcodes test */ | |
448 | ||
449 | static int do_bitop( int s, int d, int rop ) | |
450 | { | |
451 | int res; | |
452 | switch(rop) | |
453 | { | |
454 | case GXclear: res = 0; break; | |
455 | case GXand: res = s & d; break; | |
456 | case GXandReverse: res = s & ~d; break; | |
457 | case GXcopy: res = s; break; | |
458 | case GXandInverted: res = ~s & d; break; | |
459 | case GXnoop: res = d; break; | |
460 | case GXxor: res = s ^ d; break; | |
461 | case GXor: res = s | d; break; | |
462 | case GXnor: res = ~(s | d); break; | |
463 | case GXequiv: res = ~s ^ d; break; | |
464 | case GXinvert: res = ~d; break; | |
465 | case GXorReverse: res = s | ~d; break; | |
466 | case GXcopyInverted: res = ~s; break; | |
467 | case GXorInverted: res = ~s | d; break; | |
468 | case GXnand: res = ~(s & d); break; | |
469 | case GXset: res = 1; break; | |
470 | } | |
471 | return res & 1; | |
472 | } | |
473 | ||
3c0211f9 | 474 | int main() |
3a5816f8 AJ |
475 | { |
476 | int rop, i, res, src, dst, pat, tmp, dstUsed; | |
477 | const BYTE *opcode; | |
478 | ||
479 | for (rop = 0; rop < 256; rop++) | |
480 | { | |
481 | res = dstUsed = 0; | |
482 | for (i = 0; i < 8; i++) | |
483 | { | |
484 | pat = (i >> 2) & 1; | |
485 | src = (i >> 1) & 1; | |
486 | dst = i & 1; | |
487 | for (opcode = BITBLT_Opcodes[rop]; *opcode; opcode++) | |
488 | { | |
489 | switch(*opcode >> 4) | |
490 | { | |
491 | case OP_ARGS(DST,TMP): | |
492 | tmp = do_bitop( dst, tmp, *opcode & 0xf ); | |
493 | break; | |
494 | case OP_ARGS(DST,SRC): | |
495 | src = do_bitop( dst, src, *opcode & 0xf ); | |
496 | break; | |
497 | case OP_ARGS(SRC,TMP): | |
498 | tmp = do_bitop( src, tmp, *opcode & 0xf ); | |
499 | break; | |
500 | case OP_ARGS(SRC,DST): | |
501 | dst = do_bitop( src, dst, *opcode & 0xf ); | |
502 | dstUsed = 1; | |
503 | break; | |
504 | case OP_ARGS(PAT,TMP): | |
505 | tmp = do_bitop( pat, tmp, *opcode & 0xf ); | |
506 | break; | |
507 | case OP_ARGS(PAT,DST): | |
508 | dst = do_bitop( pat, dst, *opcode & 0xf ); | |
509 | dstUsed = 1; | |
510 | break; | |
511 | case OP_ARGS(PAT,SRC): | |
512 | src = do_bitop( pat, src, *opcode & 0xf ); | |
513 | break; | |
514 | case OP_ARGS(TMP,DST): | |
515 | dst = do_bitop( tmp, dst, *opcode & 0xf ); | |
516 | dstUsed = 1; | |
517 | break; | |
518 | case OP_ARGS(TMP,SRC): | |
519 | src = do_bitop( tmp, src, *opcode & 0xf ); | |
520 | break; | |
521 | default: | |
522 | printf( "Invalid opcode %x\n", *opcode ); | |
523 | } | |
524 | } | |
525 | if (!dstUsed) dst = src; | |
526 | if (dst) res |= 1 << i; | |
527 | } | |
528 | if (res != rop) printf( "%02x: ERROR, res=%02x\n", rop, res ); | |
529 | } | |
3c0211f9 PS |
530 | |
531 | return 0; | |
3a5816f8 AJ |
532 | } |
533 | ||
534 | #endif /* BITBLT_TEST */ | |
535 | ||
401710d7 | 536 | |
daf776fd HD |
537 | static void get_colors(X11DRV_PDEVICE *physDevDst, X11DRV_PDEVICE *physDevSrc, |
538 | int *fg, int *bg) | |
539 | { | |
540 | RGBQUAD rgb[2]; | |
541 | ||
542 | *fg = physDevDst->textPixel; | |
543 | *bg = physDevDst->backgroundPixel; | |
544 | if(physDevSrc->depth == 1) { | |
545 | if(GetDIBColorTable(physDevSrc->hdc, 0, 2, rgb) == 2) { | |
546 | DWORD logcolor; | |
547 | logcolor = RGB(rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue); | |
548 | *fg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor ); | |
549 | logcolor = RGB(rgb[1].rgbRed, rgb[1].rgbGreen,rgb[1].rgbBlue); | |
550 | *bg = X11DRV_PALETTE_ToPhysical( physDevDst, logcolor ); | |
551 | } | |
552 | } | |
553 | } | |
554 | ||
da57adf2 AJ |
555 | /* return a mask for meaningful bits when doing an XGetPixel on an image */ |
556 | static unsigned long image_pixel_mask( X11DRV_PDEVICE *physDev ) | |
557 | { | |
558 | unsigned long ret; | |
559 | ColorShifts *shifts = physDev->color_shifts; | |
560 | ||
561 | if (!shifts) shifts = &X11DRV_PALETTE_default_shifts; | |
562 | ret = (shifts->physicalRed.max << shifts->physicalRed.shift) | | |
563 | (shifts->physicalGreen.max << shifts->physicalGreen.shift) | | |
564 | (shifts->physicalBlue.max << shifts->physicalBlue.shift); | |
565 | if (!ret) ret = (1 << physDev->depth) - 1; | |
566 | return ret; | |
567 | } | |
568 | ||
569 | ||
ecc3712d | 570 | /*********************************************************************** |
7cbe6572 AJ |
571 | * BITBLT_StretchRow |
572 | * | |
573 | * Stretch a row of pixels. Helper function for BITBLT_StretchImage. | |
ecc3712d | 574 | */ |
7cbe6572 | 575 | static void BITBLT_StretchRow( int *rowSrc, int *rowDst, |
a3960292 AJ |
576 | INT startDst, INT widthDst, |
577 | INT xinc, INT xoff, WORD mode ) | |
ecc3712d | 578 | { |
a3960292 | 579 | register INT xsrc = xinc * startDst + xoff; |
7cbe6572 AJ |
580 | rowDst += startDst; |
581 | switch(mode) | |
ecc3712d | 582 | { |
7cbe6572 AJ |
583 | case STRETCH_ANDSCANS: |
584 | for(; widthDst > 0; widthDst--, xsrc += xinc) | |
585 | *rowDst++ &= rowSrc[xsrc >> 16]; | |
586 | break; | |
587 | case STRETCH_ORSCANS: | |
588 | for(; widthDst > 0; widthDst--, xsrc += xinc) | |
589 | *rowDst++ |= rowSrc[xsrc >> 16]; | |
590 | break; | |
591 | case STRETCH_DELETESCANS: | |
592 | for(; widthDst > 0; widthDst--, xsrc += xinc) | |
593 | *rowDst++ = rowSrc[xsrc >> 16]; | |
594 | break; | |
ecc3712d | 595 | } |
7cbe6572 AJ |
596 | } |
597 | ||
598 | ||
599 | /*********************************************************************** | |
600 | * BITBLT_ShrinkRow | |
601 | * | |
602 | * Shrink a row of pixels. Helper function for BITBLT_StretchImage. | |
603 | */ | |
604 | static void BITBLT_ShrinkRow( int *rowSrc, int *rowDst, | |
a3960292 AJ |
605 | INT startSrc, INT widthSrc, |
606 | INT xinc, INT xoff, WORD mode ) | |
7cbe6572 | 607 | { |
a3960292 | 608 | register INT xdst = xinc * startSrc + xoff; |
7cbe6572 AJ |
609 | rowSrc += startSrc; |
610 | switch(mode) | |
ecc3712d | 611 | { |
7cbe6572 AJ |
612 | case STRETCH_ORSCANS: |
613 | for(; widthSrc > 0; widthSrc--, xdst += xinc) | |
614 | rowDst[xdst >> 16] |= *rowSrc++; | |
615 | break; | |
616 | case STRETCH_ANDSCANS: | |
617 | for(; widthSrc > 0; widthSrc--, xdst += xinc) | |
618 | rowDst[xdst >> 16] &= *rowSrc++; | |
619 | break; | |
620 | case STRETCH_DELETESCANS: | |
621 | for(; widthSrc > 0; widthSrc--, xdst += xinc) | |
622 | rowDst[xdst >> 16] = *rowSrc++; | |
623 | break; | |
ecc3712d | 624 | } |
ecc3712d AJ |
625 | } |
626 | ||
627 | ||
3a5816f8 | 628 | /*********************************************************************** |
7cbe6572 | 629 | * BITBLT_GetRow |
3a5816f8 | 630 | * |
7cbe6572 | 631 | * Retrieve a row from an image. Helper function for BITBLT_StretchImage. |
3a5816f8 | 632 | */ |
a3960292 AJ |
633 | static void BITBLT_GetRow( XImage *image, int *pdata, INT row, |
634 | INT start, INT width, INT depthDst, | |
da57adf2 | 635 | int fg, int bg, unsigned long pixel_mask, BOOL swap) |
3a5816f8 | 636 | { |
a3960292 | 637 | register INT i; |
3a5816f8 | 638 | |
b1bac320 AJ |
639 | assert( (row >= 0) && (row < image->height) ); |
640 | assert( (start >= 0) && (width <= image->width) ); | |
641 | ||
7cbe6572 | 642 | pdata += swap ? start+width-1 : start; |
a2f2e019 | 643 | if (image->depth == depthDst) /* color -> color */ |
3a5816f8 | 644 | { |
b87fe2e9 | 645 | if (X11DRV_PALETTE_XPixelToPalette && (depthDst != 1)) |
7cbe6572 | 646 | if (swap) for (i = 0; i < width; i++) |
b87fe2e9 | 647 | *pdata-- = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )]; |
7cbe6572 | 648 | else for (i = 0; i < width; i++) |
b87fe2e9 | 649 | *pdata++ = X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, i, row )]; |
7cbe6572 AJ |
650 | else |
651 | if (swap) for (i = 0; i < width; i++) | |
03468f7d | 652 | *pdata-- = XGetPixel( image, i, row ); |
7cbe6572 | 653 | else for (i = 0; i < width; i++) |
03468f7d | 654 | *pdata++ = XGetPixel( image, i, row ); |
3a5816f8 | 655 | } |
7cbe6572 | 656 | else |
3a5816f8 | 657 | { |
a2f2e019 AJ |
658 | if (image->depth == 1) /* monochrome -> color */ |
659 | { | |
b87fe2e9 | 660 | if (X11DRV_PALETTE_XPixelToPalette) |
a2f2e019 | 661 | { |
b87fe2e9 PS |
662 | fg = X11DRV_PALETTE_XPixelToPalette[fg]; |
663 | bg = X11DRV_PALETTE_XPixelToPalette[bg]; | |
a2f2e019 | 664 | } |
7cbe6572 | 665 | if (swap) for (i = 0; i < width; i++) |
03468f7d | 666 | *pdata-- = XGetPixel( image, i, row ) ? bg : fg; |
7cbe6572 | 667 | else for (i = 0; i < width; i++) |
03468f7d | 668 | *pdata++ = XGetPixel( image, i, row ) ? bg : fg; |
a2f2e019 AJ |
669 | } |
670 | else /* color -> monochrome */ | |
671 | { | |
7cbe6572 | 672 | if (swap) for (i = 0; i < width; i++) |
da57adf2 | 673 | *pdata-- = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0; |
7cbe6572 | 674 | else for (i = 0; i < width; i++) |
da57adf2 | 675 | *pdata++ = ((XGetPixel( image, i, row ) & pixel_mask) == bg) ? 1 : 0; |
a2f2e019 | 676 | } |
3a5816f8 | 677 | } |
7cbe6572 AJ |
678 | } |
679 | ||
680 | ||
681 | /*********************************************************************** | |
682 | * BITBLT_StretchImage | |
683 | * | |
684 | * Stretch an X image. | |
75d86e1f | 685 | * FIXME: does not work for full 32-bit coordinates. |
7cbe6572 AJ |
686 | */ |
687 | static void BITBLT_StretchImage( XImage *srcImage, XImage *dstImage, | |
a3960292 AJ |
688 | INT widthSrc, INT heightSrc, |
689 | INT widthDst, INT heightDst, | |
690 | RECT *visRectSrc, RECT *visRectDst, | |
da57adf2 AJ |
691 | int foreground, int background, |
692 | unsigned long pixel_mask, WORD mode ) | |
7cbe6572 AJ |
693 | { |
694 | int *rowSrc, *rowDst, *pixel; | |
b1bac320 | 695 | char *pdata; |
a3960292 AJ |
696 | INT xinc, xoff, yinc, ysrc, ydst; |
697 | register INT x, y; | |
698 | BOOL hstretch, vstretch, hswap, vswap; | |
7cbe6572 | 699 | |
68feed7e AT |
700 | hswap = widthSrc * widthDst < 0; |
701 | vswap = heightSrc * heightDst < 0; | |
7cbe6572 AJ |
702 | widthSrc = abs(widthSrc); |
703 | heightSrc = abs(heightSrc); | |
704 | widthDst = abs(widthDst); | |
705 | heightDst = abs(heightDst); | |
7cbe6572 | 706 | |
9ed61de9 JE |
707 | if (!(rowSrc = HeapAlloc( GetProcessHeap(), 0, |
708 | (widthSrc+widthDst)*sizeof(int) ))) return; | |
7cbe6572 | 709 | rowDst = rowSrc + widthSrc; |
3a5816f8 | 710 | |
7cbe6572 AJ |
711 | /* When stretching, all modes are the same, and DELETESCANS is faster */ |
712 | if ((widthSrc < widthDst) && (heightSrc < heightDst)) | |
713 | mode = STRETCH_DELETESCANS; | |
714 | ||
0f55bdd4 HD |
715 | if (mode == STRETCH_HALFTONE) /* FIXME */ |
716 | mode = STRETCH_DELETESCANS; | |
717 | ||
18506558 AJ |
718 | if (mode != STRETCH_DELETESCANS) |
719 | memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00, | |
720 | widthDst*sizeof(int) ); | |
721 | ||
8cc3a5e4 AJ |
722 | hstretch = (widthSrc < widthDst); |
723 | vstretch = (heightSrc < heightDst); | |
724 | ||
b1bac320 AJ |
725 | if (hstretch) |
726 | { | |
68feed7e | 727 | xinc = (widthSrc << 16) / widthDst; |
b1bac320 AJ |
728 | xoff = ((widthSrc << 16) - (xinc * widthDst)) / 2; |
729 | } | |
730 | else | |
731 | { | |
732 | xinc = ((int)widthDst << 16) / widthSrc; | |
733 | xoff = ((widthDst << 16) - (xinc * widthSrc)) / 2; | |
734 | } | |
7cbe6572 | 735 | |
809af590 | 736 | wine_tsx11_lock(); |
7cbe6572 | 737 | if (vstretch) |
3a5816f8 | 738 | { |
68feed7e | 739 | yinc = (heightSrc << 16) / heightDst; |
7cbe6572 | 740 | ydst = visRectDst->top; |
b1bac320 AJ |
741 | if (vswap) |
742 | { | |
743 | ysrc = yinc * (heightDst - ydst - 1); | |
744 | yinc = -yinc; | |
745 | } | |
746 | else | |
747 | ysrc = yinc * ydst; | |
748 | ||
749 | for ( ; (ydst < visRectDst->bottom); ysrc += yinc, ydst++) | |
750 | { | |
751 | if (((ysrc >> 16) < visRectSrc->top) || | |
752 | ((ysrc >> 16) >= visRectSrc->bottom)) continue; | |
753 | ||
754 | /* Retrieve a source row */ | |
755 | BITBLT_GetRow( srcImage, rowSrc, (ysrc >> 16) - visRectSrc->top, | |
756 | hswap ? widthSrc - visRectSrc->right | |
757 | : visRectSrc->left, | |
758 | visRectSrc->right - visRectSrc->left, | |
da57adf2 | 759 | dstImage->depth, foreground, background, pixel_mask, hswap ); |
b1bac320 AJ |
760 | |
761 | /* Stretch or shrink it */ | |
762 | if (hstretch) | |
763 | BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left, | |
764 | visRectDst->right - visRectDst->left, | |
765 | xinc, xoff, mode ); | |
766 | else BITBLT_ShrinkRow( rowSrc, rowDst, | |
767 | hswap ? widthSrc - visRectSrc->right | |
768 | : visRectSrc->left, | |
769 | visRectSrc->right - visRectSrc->left, | |
770 | xinc, xoff, mode ); | |
771 | ||
772 | /* Store the destination row */ | |
773 | pixel = rowDst + visRectDst->right - 1; | |
774 | y = ydst - visRectDst->top; | |
775 | for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--) | |
03468f7d | 776 | XPutPixel( dstImage, x, y, *pixel-- ); |
b1bac320 AJ |
777 | if (mode != STRETCH_DELETESCANS) |
778 | memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00, | |
779 | widthDst*sizeof(int) ); | |
780 | ||
781 | /* Make copies of the destination row */ | |
782 | ||
783 | pdata = dstImage->data + dstImage->bytes_per_line * y; | |
784 | while (((ysrc + yinc) >> 16 == ysrc >> 16) && | |
785 | (ydst < visRectDst->bottom-1)) | |
786 | { | |
787 | memcpy( pdata + dstImage->bytes_per_line, pdata, | |
788 | dstImage->bytes_per_line ); | |
789 | pdata += dstImage->bytes_per_line; | |
790 | ysrc += yinc; | |
791 | ydst++; | |
792 | } | |
9a624916 | 793 | } |
3a5816f8 | 794 | } |
b1bac320 | 795 | else /* Shrinking */ |
3a5816f8 | 796 | { |
68feed7e | 797 | yinc = (heightDst << 16) / heightSrc; |
7cbe6572 | 798 | ysrc = visRectSrc->top; |
b1bac320 AJ |
799 | ydst = ((heightDst << 16) - (yinc * heightSrc)) / 2; |
800 | if (vswap) | |
801 | { | |
802 | ydst += yinc * (heightSrc - ysrc - 1); | |
803 | yinc = -yinc; | |
804 | } | |
805 | else | |
806 | ydst += yinc * ysrc; | |
7cbe6572 | 807 | |
b1bac320 | 808 | for( ; (ysrc < visRectSrc->bottom); ydst += yinc, ysrc++) |
7cbe6572 | 809 | { |
b1bac320 AJ |
810 | if (((ydst >> 16) < visRectDst->top) || |
811 | ((ydst >> 16) >= visRectDst->bottom)) continue; | |
812 | ||
813 | /* Retrieve a source row */ | |
814 | BITBLT_GetRow( srcImage, rowSrc, ysrc - visRectSrc->top, | |
815 | hswap ? widthSrc - visRectSrc->right | |
816 | : visRectSrc->left, | |
817 | visRectSrc->right - visRectSrc->left, | |
da57adf2 | 818 | dstImage->depth, foreground, background, pixel_mask, hswap ); |
b1bac320 AJ |
819 | |
820 | /* Stretch or shrink it */ | |
821 | if (hstretch) | |
822 | BITBLT_StretchRow( rowSrc, rowDst, visRectDst->left, | |
823 | visRectDst->right - visRectDst->left, | |
824 | xinc, xoff, mode ); | |
825 | else BITBLT_ShrinkRow( rowSrc, rowDst, | |
826 | hswap ? widthSrc - visRectSrc->right | |
827 | : visRectSrc->left, | |
828 | visRectSrc->right - visRectSrc->left, | |
829 | xinc, xoff, mode ); | |
830 | ||
831 | /* Merge several source rows into the destination */ | |
7cbe6572 | 832 | if (mode == STRETCH_DELETESCANS) |
3a5816f8 | 833 | { |
b1bac320 | 834 | /* Simply skip the overlapping rows */ |
7cbe6572 AJ |
835 | while (((ydst + yinc) >> 16 == ydst >> 16) && |
836 | (ysrc < visRectSrc->bottom-1)) | |
837 | { | |
838 | ydst += yinc; | |
839 | ysrc++; | |
840 | } | |
3a5816f8 | 841 | } |
7cbe6572 AJ |
842 | else if (((ydst + yinc) >> 16 == ydst >> 16) && |
843 | (ysrc < visRectSrc->bottom-1)) | |
7cbe6572 | 844 | continue; /* Restart loop for next overlapping row */ |
9a624916 | 845 | |
b1bac320 AJ |
846 | /* Store the destination row */ |
847 | pixel = rowDst + visRectDst->right - 1; | |
848 | y = (ydst >> 16) - visRectDst->top; | |
849 | for (x = visRectDst->right-visRectDst->left-1; x >= 0; x--) | |
03468f7d | 850 | XPutPixel( dstImage, x, y, *pixel-- ); |
b1bac320 AJ |
851 | if (mode != STRETCH_DELETESCANS) |
852 | memset( rowDst, (mode == STRETCH_ANDSCANS) ? 0xff : 0x00, | |
853 | widthDst*sizeof(int) ); | |
7cbe6572 | 854 | } |
9a624916 | 855 | } |
809af590 | 856 | wine_tsx11_unlock(); |
491502b9 | 857 | HeapFree( GetProcessHeap(), 0, rowSrc ); |
3a5816f8 AJ |
858 | } |
859 | ||
860 | ||
861 | /*********************************************************************** | |
7cbe6572 | 862 | * BITBLT_GetSrcAreaStretch |
3a5816f8 | 863 | * |
7cbe6572 AJ |
864 | * Retrieve an area from the source DC, stretching and mapping all the |
865 | * pixels to Windows colors. | |
3a5816f8 | 866 | */ |
e21c15e3 | 867 | static int BITBLT_GetSrcAreaStretch( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst, |
39493b06 AJ |
868 | Pixmap pixmap, GC gc, |
869 | const struct bitblt_coords *src, const struct bitblt_coords *dst ) | |
3a5816f8 | 870 | { |
7cbe6572 | 871 | XImage *imageSrc, *imageDst; |
39493b06 AJ |
872 | RECT rectSrc = src->visrect; |
873 | RECT rectDst = dst->visrect; | |
daf776fd | 874 | int fg, bg; |
b1bac320 | 875 | |
39493b06 AJ |
876 | rectSrc.left -= src->x; |
877 | rectSrc.right -= src->x; | |
878 | rectSrc.top -= src->y; | |
879 | rectSrc.bottom -= src->y; | |
880 | rectDst.left -= dst->x; | |
881 | rectDst.right -= dst->x; | |
882 | rectDst.top -= dst->y; | |
883 | rectDst.bottom -= dst->y; | |
884 | if (src->width < 0) | |
885 | { | |
886 | rectSrc.left -= src->width; | |
887 | rectSrc.right -= src->width; | |
888 | } | |
889 | if (dst->width < 0) | |
890 | { | |
891 | rectDst.left -= dst->width; | |
892 | rectDst.right -= dst->width; | |
893 | } | |
894 | if (src->height < 0) | |
895 | { | |
896 | rectSrc.top -= src->height; | |
897 | rectSrc.bottom -= src->height; | |
898 | } | |
899 | if (dst->height < 0) | |
900 | { | |
901 | rectDst.top -= dst->height; | |
902 | rectDst.bottom -= dst->height; | |
903 | } | |
b1bac320 | 904 | |
daf776fd | 905 | get_colors(physDevDst, physDevSrc, &fg, &bg); |
809af590 | 906 | wine_tsx11_lock(); |
1e37a181 | 907 | /* FIXME: avoid BadMatch errors */ |
c559735b | 908 | imageSrc = XGetImage( gdi_display, physDevSrc->drawable, |
39493b06 AJ |
909 | physDevSrc->dc_rect.left + src->visrect.left, |
910 | physDevSrc->dc_rect.top + src->visrect.top, | |
911 | src->visrect.right - src->visrect.left, | |
912 | src->visrect.bottom - src->visrect.top, | |
7cbe6572 | 913 | AllPlanes, ZPixmap ); |
809af590 AJ |
914 | wine_tsx11_unlock(); |
915 | ||
c559735b | 916 | imageDst = X11DRV_DIB_CreateXImage( rectDst.right - rectDst.left, |
b89525fb | 917 | rectDst.bottom - rectDst.top, physDevDst->depth ); |
39493b06 AJ |
918 | BITBLT_StretchImage( imageSrc, imageDst, src->width, src->height, |
919 | dst->width, dst->height, &rectSrc, &rectDst, | |
da57adf2 AJ |
920 | fg, physDevDst->depth != 1 ? bg : physDevSrc->backgroundPixel, |
921 | image_pixel_mask( physDevSrc ), GetStretchBltMode(physDevDst->hdc) ); | |
809af590 | 922 | wine_tsx11_lock(); |
c559735b | 923 | XPutImage( gdi_display, pixmap, gc, imageDst, 0, 0, 0, 0, |
7cbe6572 | 924 | rectDst.right - rectDst.left, rectDst.bottom - rectDst.top ); |
03468f7d | 925 | XDestroyImage( imageSrc ); |
90ef43ab | 926 | X11DRV_DIB_DestroyXImage( imageDst ); |
809af590 | 927 | wine_tsx11_unlock(); |
6d027e1f | 928 | return 0; /* no exposure events generated */ |
7cbe6572 | 929 | } |
3a5816f8 | 930 | |
7cbe6572 AJ |
931 | |
932 | /*********************************************************************** | |
933 | * BITBLT_GetSrcArea | |
934 | * | |
935 | * Retrieve an area from the source DC, mapping all the | |
936 | * pixels to Windows colors. | |
937 | */ | |
e21c15e3 | 938 | static int BITBLT_GetSrcArea( X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst, |
773d53d8 | 939 | Pixmap pixmap, GC gc, RECT *visRectSrc ) |
7cbe6572 AJ |
940 | { |
941 | XImage *imageSrc, *imageDst; | |
a3960292 | 942 | register INT x, y; |
6d027e1f | 943 | int exposures = 0; |
a3960292 AJ |
944 | INT width = visRectSrc->right - visRectSrc->left; |
945 | INT height = visRectSrc->bottom - visRectSrc->top; | |
daf776fd | 946 | int fg, bg; |
809af590 | 947 | BOOL memdc = (GetObjectType(physDevSrc->hdc) == OBJ_MEMDC); |
7cbe6572 | 948 | |
b89525fb | 949 | if (physDevSrc->depth == physDevDst->depth) |
3a5816f8 | 950 | { |
809af590 | 951 | wine_tsx11_lock(); |
b87fe2e9 | 952 | if (!X11DRV_PALETTE_XPixelToPalette || |
b89525fb | 953 | (physDevDst->depth == 1)) /* monochrome -> monochrome */ |
7cbe6572 | 954 | { |
b89525fb | 955 | if (physDevDst->depth == 1) |
960dc908 AJ |
956 | { |
957 | /* MSDN says if StretchBlt must convert a bitmap from monochrome | |
0e4adae9 | 958 | to color or vice versa, the foreground and background color of |
960dc908 | 959 | the device context are used. In fact, it also applies to the |
9a624916 | 960 | case when it is converted from mono to mono. */ |
c559735b AJ |
961 | XSetBackground( gdi_display, gc, physDevDst->textPixel ); |
962 | XSetForeground( gdi_display, gc, physDevDst->backgroundPixel ); | |
963 | XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc, | |
4bdf4345 UC |
964 | physDevSrc->dc_rect.left + visRectSrc->left, |
965 | physDevSrc->dc_rect.top + visRectSrc->top, | |
960dc908 AJ |
966 | width, height, 0, 0, 1); |
967 | } | |
968 | else | |
c559735b | 969 | XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, |
4bdf4345 UC |
970 | physDevSrc->dc_rect.left + visRectSrc->left, |
971 | physDevSrc->dc_rect.top + visRectSrc->top, | |
d3cab185 | 972 | width, height, 0, 0); |
6d027e1f | 973 | exposures++; |
7cbe6572 AJ |
974 | } |
975 | else /* color -> color */ | |
976 | { | |
809af590 | 977 | if (memdc) |
c559735b | 978 | imageSrc = XGetImage( gdi_display, physDevSrc->drawable, |
4bdf4345 UC |
979 | physDevSrc->dc_rect.left + visRectSrc->left, |
980 | physDevSrc->dc_rect.top + visRectSrc->top, | |
1e37a181 AJ |
981 | width, height, AllPlanes, ZPixmap ); |
982 | else | |
983 | { | |
984 | /* Make sure we don't get a BadMatch error */ | |
c559735b | 985 | XCopyArea( gdi_display, physDevSrc->drawable, pixmap, gc, |
4bdf4345 UC |
986 | physDevSrc->dc_rect.left + visRectSrc->left, |
987 | physDevSrc->dc_rect.top + visRectSrc->top, | |
1e37a181 | 988 | width, height, 0, 0); |
6d027e1f | 989 | exposures++; |
c559735b | 990 | imageSrc = XGetImage( gdi_display, pixmap, 0, 0, width, height, |
1e37a181 AJ |
991 | AllPlanes, ZPixmap ); |
992 | } | |
7cbe6572 AJ |
993 | for (y = 0; y < height; y++) |
994 | for (x = 0; x < width; x++) | |
03468f7d | 995 | XPutPixel(imageSrc, x, y, |
b87fe2e9 | 996 | X11DRV_PALETTE_XPixelToPalette[XGetPixel(imageSrc, x, y)]); |
c559735b | 997 | XPutImage( gdi_display, pixmap, gc, imageSrc, |
7cbe6572 | 998 | 0, 0, 0, 0, width, height ); |
03468f7d | 999 | XDestroyImage( imageSrc ); |
7cbe6572 | 1000 | } |
809af590 | 1001 | wine_tsx11_unlock(); |
3a5816f8 AJ |
1002 | } |
1003 | else | |
1004 | { | |
b89525fb | 1005 | if (physDevSrc->depth == 1) /* monochrome -> color */ |
7cbe6572 | 1006 | { |
daf776fd HD |
1007 | get_colors(physDevDst, physDevSrc, &fg, &bg); |
1008 | ||
809af590 | 1009 | wine_tsx11_lock(); |
b87fe2e9 | 1010 | if (X11DRV_PALETTE_XPixelToPalette) |
3a5816f8 | 1011 | { |
c559735b | 1012 | XSetBackground( gdi_display, gc, |
daf776fd | 1013 | X11DRV_PALETTE_XPixelToPalette[fg] ); |
c559735b | 1014 | XSetForeground( gdi_display, gc, |
daf776fd | 1015 | X11DRV_PALETTE_XPixelToPalette[bg]); |
3a5816f8 | 1016 | } |
7cbe6572 AJ |
1017 | else |
1018 | { | |
daf776fd HD |
1019 | XSetBackground( gdi_display, gc, fg ); |
1020 | XSetForeground( gdi_display, gc, bg ); | |
7cbe6572 | 1021 | } |
c559735b | 1022 | XCopyPlane( gdi_display, physDevSrc->drawable, pixmap, gc, |
4bdf4345 UC |
1023 | physDevSrc->dc_rect.left + visRectSrc->left, |
1024 | physDevSrc->dc_rect.top + visRectSrc->top, | |
7cbe6572 | 1025 | width, height, 0, 0, 1 ); |
6d027e1f | 1026 | exposures++; |
809af590 | 1027 | wine_tsx11_unlock(); |
7cbe6572 AJ |
1028 | } |
1029 | else /* color -> monochrome */ | |
1030 | { | |
da57adf2 | 1031 | unsigned long pixel_mask; |
809af590 | 1032 | wine_tsx11_lock(); |
1e37a181 | 1033 | /* FIXME: avoid BadMatch error */ |
c559735b | 1034 | imageSrc = XGetImage( gdi_display, physDevSrc->drawable, |
4bdf4345 UC |
1035 | physDevSrc->dc_rect.left + visRectSrc->left, |
1036 | physDevSrc->dc_rect.top + visRectSrc->top, | |
7cbe6572 | 1037 | width, height, AllPlanes, ZPixmap ); |
e845fd9c WB |
1038 | if (!imageSrc) |
1039 | { | |
809af590 | 1040 | wine_tsx11_unlock(); |
e845fd9c WB |
1041 | return exposures; |
1042 | } | |
b89525fb | 1043 | imageDst = X11DRV_DIB_CreateXImage( width, height, physDevDst->depth ); |
809af590 | 1044 | if (!imageDst) |
e845fd9c WB |
1045 | { |
1046 | XDestroyImage(imageSrc); | |
809af590 | 1047 | wine_tsx11_unlock(); |
e845fd9c WB |
1048 | return exposures; |
1049 | } | |
da57adf2 | 1050 | pixel_mask = image_pixel_mask( physDevSrc ); |
7cbe6572 AJ |
1051 | for (y = 0; y < height; y++) |
1052 | for (x = 0; x < width; x++) | |
da57adf2 AJ |
1053 | XPutPixel(imageDst, x, y, |
1054 | !((XGetPixel(imageSrc,x,y) ^ physDevSrc->backgroundPixel) & pixel_mask)); | |
c559735b | 1055 | XPutImage( gdi_display, pixmap, gc, imageDst, |
7cbe6572 | 1056 | 0, 0, 0, 0, width, height ); |
03468f7d | 1057 | XDestroyImage( imageSrc ); |
90ef43ab | 1058 | X11DRV_DIB_DestroyXImage( imageDst ); |
809af590 | 1059 | wine_tsx11_unlock(); |
7cbe6572 | 1060 | } |
3a5816f8 | 1061 | } |
6d027e1f | 1062 | return exposures; |
3a5816f8 AJ |
1063 | } |
1064 | ||
1065 | ||
1066 | /*********************************************************************** | |
7cbe6572 | 1067 | * BITBLT_GetDstArea |
3a5816f8 | 1068 | * |
7cbe6572 AJ |
1069 | * Retrieve an area from the destination DC, mapping all the |
1070 | * pixels to Windows colors. | |
3a5816f8 | 1071 | */ |
e21c15e3 | 1072 | static int BITBLT_GetDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, GC gc, RECT *visRectDst) |
3a5816f8 | 1073 | { |
6d027e1f | 1074 | int exposures = 0; |
a3960292 AJ |
1075 | INT width = visRectDst->right - visRectDst->left; |
1076 | INT height = visRectDst->bottom - visRectDst->top; | |
809af590 AJ |
1077 | BOOL memdc = (GetObjectType( physDev->hdc ) == OBJ_MEMDC); |
1078 | ||
1079 | wine_tsx11_lock(); | |
7cbe6572 | 1080 | |
b89525fb | 1081 | if (!X11DRV_PALETTE_XPixelToPalette || (physDev->depth == 1) || |
b87fe2e9 | 1082 | (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) ) |
3a5816f8 | 1083 | { |
c559735b | 1084 | XCopyArea( gdi_display, physDev->drawable, pixmap, gc, |
4bdf4345 | 1085 | physDev->dc_rect.left + visRectDst->left, physDev->dc_rect.top + visRectDst->top, |
d3cab185 | 1086 | width, height, 0, 0 ); |
6d027e1f | 1087 | exposures++; |
3a5816f8 AJ |
1088 | } |
1089 | else | |
1090 | { | |
a3960292 | 1091 | register INT x, y; |
1e37a181 AJ |
1092 | XImage *image; |
1093 | ||
809af590 | 1094 | if (memdc) |
c559735b | 1095 | image = XGetImage( gdi_display, physDev->drawable, |
4bdf4345 UC |
1096 | physDev->dc_rect.left + visRectDst->left, |
1097 | physDev->dc_rect.top + visRectDst->top, | |
1e37a181 AJ |
1098 | width, height, AllPlanes, ZPixmap ); |
1099 | else | |
1100 | { | |
1101 | /* Make sure we don't get a BadMatch error */ | |
c559735b | 1102 | XCopyArea( gdi_display, physDev->drawable, pixmap, gc, |
4bdf4345 UC |
1103 | physDev->dc_rect.left + visRectDst->left, |
1104 | physDev->dc_rect.top + visRectDst->top, | |
d3cab185 | 1105 | width, height, 0, 0); |
6d027e1f | 1106 | exposures++; |
c559735b | 1107 | image = XGetImage( gdi_display, pixmap, 0, 0, width, height, |
1e37a181 AJ |
1108 | AllPlanes, ZPixmap ); |
1109 | } | |
809af590 AJ |
1110 | if (image) |
1111 | { | |
1112 | for (y = 0; y < height; y++) | |
1113 | for (x = 0; x < width; x++) | |
1114 | XPutPixel( image, x, y, | |
1115 | X11DRV_PALETTE_XPixelToPalette[XGetPixel( image, x, y )]); | |
1116 | XPutImage( gdi_display, pixmap, gc, image, 0, 0, 0, 0, width, height ); | |
1117 | XDestroyImage( image ); | |
1118 | } | |
3a5816f8 | 1119 | } |
809af590 AJ |
1120 | |
1121 | wine_tsx11_unlock(); | |
6d027e1f | 1122 | return exposures; |
7cbe6572 AJ |
1123 | } |
1124 | ||
1125 | ||
1126 | /*********************************************************************** | |
1127 | * BITBLT_PutDstArea | |
1128 | * | |
1129 | * Put an area back into the destination DC, mapping the pixel | |
1130 | * colors to X pixels. | |
1131 | */ | |
e21c15e3 | 1132 | static int BITBLT_PutDstArea(X11DRV_PDEVICE *physDev, Pixmap pixmap, RECT *visRectDst) |
7cbe6572 | 1133 | { |
6d027e1f | 1134 | int exposures = 0; |
a3960292 AJ |
1135 | INT width = visRectDst->right - visRectDst->left; |
1136 | INT height = visRectDst->bottom - visRectDst->top; | |
7cbe6572 | 1137 | |
b87fe2e9 | 1138 | /* !X11DRV_PALETTE_PaletteToXPixel is _NOT_ enough */ |
ac9c9b07 | 1139 | |
b89525fb | 1140 | if (!X11DRV_PALETTE_PaletteToXPixel || (physDev->depth == 1) || |
b87fe2e9 | 1141 | (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_VIRTUAL) ) |
3a5816f8 | 1142 | { |
d3cab185 | 1143 | XCopyArea( gdi_display, pixmap, physDev->drawable, physDev->gc, 0, 0, width, height, |
4bdf4345 UC |
1144 | physDev->dc_rect.left + visRectDst->left, |
1145 | physDev->dc_rect.top + visRectDst->top ); | |
6d027e1f | 1146 | exposures++; |
3a5816f8 | 1147 | } |
7cbe6572 | 1148 | else |
3a5816f8 | 1149 | { |
a3960292 | 1150 | register INT x, y; |
c559735b | 1151 | XImage *image = XGetImage( gdi_display, pixmap, 0, 0, width, height, |
7cbe6572 AJ |
1152 | AllPlanes, ZPixmap ); |
1153 | for (y = 0; y < height; y++) | |
1154 | for (x = 0; x < width; x++) | |
1155 | { | |
03468f7d | 1156 | XPutPixel( image, x, y, |
b87fe2e9 | 1157 | X11DRV_PALETTE_PaletteToXPixel[XGetPixel( image, x, y )]); |
7cbe6572 | 1158 | } |
e21c15e3 | 1159 | XPutImage( gdi_display, physDev->drawable, physDev->gc, image, 0, 0, |
4bdf4345 UC |
1160 | physDev->dc_rect.left + visRectDst->left, |
1161 | physDev->dc_rect.top + visRectDst->top, width, height ); | |
03468f7d | 1162 | XDestroyImage( image ); |
3a5816f8 | 1163 | } |
6d027e1f | 1164 | return exposures; |
3a5816f8 AJ |
1165 | } |
1166 | ||
1167 | ||
401710d7 | 1168 | /*********************************************************************** |
7cbe6572 AJ |
1169 | * BITBLT_GetVisRectangles |
1170 | * | |
1171 | * Get the source and destination visible rectangles for StretchBlt(). | |
1172 | * Return FALSE if one of the rectangles is empty. | |
401710d7 | 1173 | */ |
39493b06 AJ |
1174 | static BOOL BITBLT_GetVisRectangles( X11DRV_PDEVICE *physDevDst, X11DRV_PDEVICE *physDevSrc, |
1175 | struct bitblt_coords *dst, struct bitblt_coords *src ) | |
401710d7 | 1176 | { |
a3960292 | 1177 | RECT rect, clipRect; |
401710d7 | 1178 | |
7cbe6572 | 1179 | /* Get the destination visible rectangle */ |
aca05783 | 1180 | |
39493b06 AJ |
1181 | rect.left = dst->x; |
1182 | rect.top = dst->y; | |
1183 | rect.right = dst->x + dst->width; | |
1184 | rect.bottom = dst->y + dst->height; | |
439223d4 AJ |
1185 | LPtoDP( physDevDst->hdc, (POINT *)&rect, 2 ); |
1186 | dst->x = rect.left; | |
1187 | dst->y = rect.top; | |
1188 | dst->width = rect.right - rect.left; | |
1189 | dst->height = rect.bottom - rect.top; | |
ebcd07a9 AJ |
1190 | if (dst->layout & LAYOUT_RTL && dst->layout & LAYOUT_BITMAPORIENTATIONPRESERVED) |
1191 | { | |
1192 | SWAP_INT32( &rect.left, &rect.right ); | |
1193 | dst->x = rect.left; | |
1194 | dst->width = rect.right - rect.left; | |
1195 | } | |
1196 | if (rect.left > rect.right) { SWAP_INT32( &rect.left, &rect.right ); rect.left++; rect.right++; } | |
1197 | if (rect.top > rect.bottom) { SWAP_INT32( &rect.top, &rect.bottom ); rect.top++; rect.bottom++; } | |
439223d4 | 1198 | |
e04fe7da | 1199 | GetRgnBox( physDevDst->region, &clipRect ); |
39493b06 | 1200 | if (!IntersectRect( &dst->visrect, &rect, &clipRect )) return FALSE; |
7cbe6572 AJ |
1201 | |
1202 | /* Get the source visible rectangle */ | |
aca05783 | 1203 | |
50a783f7 | 1204 | if (!physDevSrc) return TRUE; |
439223d4 | 1205 | |
39493b06 AJ |
1206 | rect.left = src->x; |
1207 | rect.top = src->y; | |
1208 | rect.right = src->x + src->width; | |
1209 | rect.bottom = src->y + src->height; | |
439223d4 AJ |
1210 | LPtoDP( physDevSrc->hdc, (POINT *)&rect, 2 ); |
1211 | src->x = rect.left; | |
1212 | src->y = rect.top; | |
1213 | src->width = rect.right - rect.left; | |
1214 | src->height = rect.bottom - rect.top; | |
ebcd07a9 AJ |
1215 | if (src->layout & LAYOUT_RTL && src->layout & LAYOUT_BITMAPORIENTATIONPRESERVED) |
1216 | { | |
1217 | SWAP_INT32( &rect.left, &rect.right ); | |
1218 | src->x = rect.left; | |
1219 | src->width = rect.right - rect.left; | |
1220 | } | |
1221 | if (rect.left > rect.right) { SWAP_INT32( &rect.left, &rect.right ); rect.left++; rect.right++; } | |
1222 | if (rect.top > rect.bottom) { SWAP_INT32( &rect.top, &rect.bottom ); rect.top++; rect.bottom++; } | |
439223d4 | 1223 | |
9a624916 | 1224 | /* Apparently the clipping and visible regions are only for output, |
da6214a3 | 1225 | so just check against dc extent here to avoid BadMatch errors */ |
d302db41 AJ |
1226 | clipRect = physDevSrc->drawable_rect; |
1227 | OffsetRect( &clipRect, -(physDevSrc->drawable_rect.left + physDevSrc->dc_rect.left), | |
1228 | -(physDevSrc->drawable_rect.top + physDevSrc->dc_rect.top) ); | |
39493b06 | 1229 | if (!IntersectRect( &src->visrect, &rect, &clipRect )) |
27bb362f | 1230 | return FALSE; |
aca05783 | 1231 | |
7cbe6572 | 1232 | /* Intersect the rectangles */ |
aca05783 | 1233 | |
39493b06 | 1234 | if ((src->width == dst->width) && (src->height == dst->height)) /* no stretching */ |
aca05783 | 1235 | { |
39493b06 AJ |
1236 | OffsetRect( &src->visrect, dst->x - src->x, dst->y - src->y ); |
1237 | if (!IntersectRect( &rect, &src->visrect, &dst->visrect )) return FALSE; | |
1238 | src->visrect = dst->visrect = rect; | |
1239 | OffsetRect( &src->visrect, src->x - dst->x, src->y - dst->y ); | |
aca05783 | 1240 | } |
7cbe6572 | 1241 | else /* stretching */ |
aca05783 | 1242 | { |
b1bac320 | 1243 | /* Map source rectangle into destination coordinates */ |
39493b06 AJ |
1244 | rect.left = dst->x + (src->visrect.left - src->x)*dst->width/src->width; |
1245 | rect.top = dst->y + (src->visrect.top - src->y)*dst->height/src->height; | |
1246 | rect.right = dst->x + (src->visrect.right - src->x)*dst->width/src->width; | |
1247 | rect.bottom = dst->y + (src->visrect.bottom - src->y)*dst->height/src->height; | |
b1bac320 AJ |
1248 | if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right ); |
1249 | if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom ); | |
62f824f7 AJ |
1250 | |
1251 | /* Avoid rounding errors */ | |
1252 | rect.left--; | |
1253 | rect.top--; | |
1254 | rect.right++; | |
1255 | rect.bottom++; | |
39493b06 | 1256 | if (!IntersectRect( &dst->visrect, &rect, &dst->visrect )) return FALSE; |
b1bac320 AJ |
1257 | |
1258 | /* Map destination rectangle back to source coordinates */ | |
39493b06 AJ |
1259 | rect = dst->visrect; |
1260 | rect.left = src->x + (dst->visrect.left - dst->x)*src->width/dst->width; | |
1261 | rect.top = src->y + (dst->visrect.top - dst->y)*src->height/dst->height; | |
1262 | rect.right = src->x + (dst->visrect.right - dst->x)*src->width/dst->width; | |
1263 | rect.bottom = src->y + (dst->visrect.bottom - dst->y)*src->height/dst->height; | |
b1bac320 AJ |
1264 | if (rect.left > rect.right) SWAP_INT32( &rect.left, &rect.right ); |
1265 | if (rect.top > rect.bottom) SWAP_INT32( &rect.top, &rect.bottom ); | |
62f824f7 AJ |
1266 | |
1267 | /* Avoid rounding errors */ | |
1268 | rect.left--; | |
1269 | rect.top--; | |
1270 | rect.right++; | |
1271 | rect.bottom++; | |
39493b06 | 1272 | if (!IntersectRect( &src->visrect, &rect, &src->visrect )) return FALSE; |
aca05783 | 1273 | } |
401710d7 AJ |
1274 | return TRUE; |
1275 | } | |
1276 | ||
1277 | ||
7bc4b074 AJ |
1278 | /*********************************************************************** |
1279 | * client_side_dib_copy | |
1280 | */ | |
1281 | static BOOL client_side_dib_copy( X11DRV_PDEVICE *physDevSrc, INT xSrc, INT ySrc, | |
1282 | X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst, | |
1283 | INT width, INT height ) | |
1284 | { | |
1285 | DIBSECTION srcDib, dstDib; | |
1286 | BYTE *srcPtr, *dstPtr; | |
1287 | INT srcRowOffset, dstRowOffset; | |
1288 | INT bytesPerPixel; | |
1289 | INT bytesToCopy; | |
1290 | INT y; | |
1291 | static RECT unusedRect; | |
1292 | ||
1293 | if (GetObjectW(physDevSrc->bitmap->hbitmap, sizeof(srcDib), &srcDib) != sizeof(srcDib)) | |
1294 | return FALSE; | |
1295 | if (GetObjectW(physDevDst->bitmap->hbitmap, sizeof(dstDib), &dstDib) != sizeof(dstDib)) | |
1296 | return FALSE; | |
1297 | ||
1298 | /* check for oversized values, just like X11DRV_DIB_CopyDIBSection() */ | |
1299 | if (xSrc > srcDib.dsBm.bmWidth || ySrc > srcDib.dsBm.bmHeight) | |
1300 | return FALSE; | |
1301 | if (xSrc + width > srcDib.dsBm.bmWidth) | |
1302 | width = srcDib.dsBm.bmWidth - xSrc; | |
1303 | if (ySrc + height > srcDib.dsBm.bmHeight) | |
1304 | height = srcDib.dsBm.bmHeight - ySrc; | |
1305 | ||
1306 | if (GetRgnBox(physDevDst->region, &unusedRect) == COMPLEXREGION) | |
1307 | { | |
1308 | /* for simple regions, the clipping was already done by BITBLT_GetVisRectangles */ | |
1309 | FIXME("potential optimization: client-side complex region clipping\n"); | |
1310 | return FALSE; | |
1311 | } | |
1312 | if (dstDib.dsBm.bmBitsPixel <= 8) | |
1313 | { | |
c7089361 AH |
1314 | static BOOL fixme_once; |
1315 | if(!fixme_once++) FIXME("potential optimization: client-side color-index mode DIB copy\n"); | |
7bc4b074 AJ |
1316 | return FALSE; |
1317 | } | |
1318 | if (!(srcDib.dsBmih.biCompression == BI_BITFIELDS && | |
1319 | dstDib.dsBmih.biCompression == BI_BITFIELDS && | |
1320 | !memcmp(srcDib.dsBitfields, dstDib.dsBitfields, 3*sizeof(DWORD))) | |
1321 | && !(srcDib.dsBmih.biCompression == BI_RGB && | |
1322 | dstDib.dsBmih.biCompression == BI_RGB)) | |
1323 | { | |
1324 | FIXME("potential optimization: client-side compressed DIB copy\n"); | |
1325 | return FALSE; | |
1326 | } | |
1327 | if (srcDib.dsBm.bmBitsPixel != dstDib.dsBm.bmBitsPixel) | |
1328 | { | |
1329 | FIXME("potential optimization: pixel format conversion\n"); | |
1330 | return FALSE; | |
1331 | } | |
1332 | if (srcDib.dsBmih.biWidth < 0 || dstDib.dsBmih.biWidth < 0) | |
1333 | { | |
1334 | FIXME("negative widths not yet implemented\n"); | |
1335 | return FALSE; | |
1336 | } | |
1337 | ||
1338 | switch (dstDib.dsBm.bmBitsPixel) | |
1339 | { | |
1340 | case 15: | |
1341 | case 16: | |
1342 | bytesPerPixel = 2; | |
1343 | break; | |
1344 | case 24: | |
1345 | bytesPerPixel = 3; | |
1346 | break; | |
1347 | case 32: | |
1348 | bytesPerPixel = 4; | |
1349 | break; | |
1350 | default: | |
1351 | FIXME("don't know how to work with a depth of %d\n", physDevSrc->depth); | |
1352 | return FALSE; | |
1353 | } | |
1354 | ||
1355 | bytesToCopy = width * bytesPerPixel; | |
1356 | ||
f331fe4c | 1357 | if (physDevSrc->bitmap->topdown) |
7bc4b074 AJ |
1358 | { |
1359 | srcPtr = &physDevSrc->bitmap->base[ySrc*srcDib.dsBm.bmWidthBytes + xSrc*bytesPerPixel]; | |
1360 | srcRowOffset = srcDib.dsBm.bmWidthBytes; | |
1361 | } | |
1362 | else | |
1363 | { | |
1364 | srcPtr = &physDevSrc->bitmap->base[(srcDib.dsBm.bmHeight-ySrc-1)*srcDib.dsBm.bmWidthBytes | |
1365 | + xSrc*bytesPerPixel]; | |
1366 | srcRowOffset = -srcDib.dsBm.bmWidthBytes; | |
1367 | } | |
f331fe4c | 1368 | if (physDevDst->bitmap->topdown) |
7bc4b074 AJ |
1369 | { |
1370 | dstPtr = &physDevDst->bitmap->base[yDst*dstDib.dsBm.bmWidthBytes + xDst*bytesPerPixel]; | |
1371 | dstRowOffset = dstDib.dsBm.bmWidthBytes; | |
1372 | } | |
1373 | else | |
1374 | { | |
1375 | dstPtr = &physDevDst->bitmap->base[(dstDib.dsBm.bmHeight-yDst-1)*dstDib.dsBm.bmWidthBytes | |
1376 | + xDst*bytesPerPixel]; | |
1377 | dstRowOffset = -dstDib.dsBm.bmWidthBytes; | |
1378 | } | |
1379 | ||
1380 | /* Handle overlapping regions on the same DIB */ | |
1381 | if (physDevSrc == physDevDst && ySrc < yDst) | |
1382 | { | |
1383 | srcPtr += srcRowOffset * (height - 1); | |
1384 | srcRowOffset = -srcRowOffset; | |
1385 | dstPtr += dstRowOffset * (height - 1); | |
1386 | dstRowOffset = -dstRowOffset; | |
1387 | } | |
1388 | ||
1389 | for (y = yDst; y < yDst + height; ++y) | |
1390 | { | |
1391 | memmove(dstPtr, srcPtr, bytesToCopy); | |
1392 | srcPtr += srcRowOffset; | |
1393 | dstPtr += dstRowOffset; | |
1394 | } | |
1395 | ||
1396 | return TRUE; | |
1397 | } | |
1398 | ||
61633b62 RC |
1399 | static BOOL same_format(X11DRV_PDEVICE *physDevSrc, X11DRV_PDEVICE *physDevDst) |
1400 | { | |
1401 | if (physDevSrc->depth != physDevDst->depth) return FALSE; | |
1402 | if (!physDevSrc->color_shifts && !physDevDst->color_shifts) return TRUE; | |
1403 | if (physDevSrc->color_shifts && physDevDst->color_shifts) | |
1404 | return !memcmp(physDevSrc->color_shifts, physDevDst->color_shifts, sizeof(ColorShifts)); | |
1405 | return FALSE; | |
1406 | } | |
7bc4b074 | 1407 | |
8e396a94 AJ |
1408 | /*********************************************************************** |
1409 | * X11DRV_PatBlt | |
1410 | */ | |
1411 | BOOL CDECL X11DRV_PatBlt( X11DRV_PDEVICE *physDev, INT x, INT y, INT width, INT height, DWORD rop ) | |
1412 | { | |
1413 | BOOL usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000)); | |
1414 | const BYTE *opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; | |
1415 | struct bitblt_coords dst; | |
1416 | ||
1417 | dst.x = x; | |
1418 | dst.y = y; | |
1419 | dst.width = width; | |
1420 | dst.height = height; | |
1421 | dst.layout = GetLayout( physDev->hdc ); | |
1422 | ||
1423 | if (rop & NOMIRRORBITMAP) | |
1424 | { | |
1425 | dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED; | |
1426 | rop &= ~NOMIRRORBITMAP; | |
1427 | } | |
1428 | ||
1429 | if (!BITBLT_GetVisRectangles( physDev, NULL, &dst, NULL )) return TRUE; | |
1430 | if (usePat && !X11DRV_SetupGCForBrush( physDev )) return TRUE; | |
1431 | ||
1432 | TRACE( "rect=%d,%d %dx%d org=%d,%d vis=%s\n", | |
1433 | dst.x, dst.y, dst.width, dst.height, | |
1434 | physDev->dc_rect.left, physDev->dc_rect.top, wine_dbgstr_rect( &dst.visrect ) ); | |
1435 | ||
1436 | width = dst.visrect.right - dst.visrect.left; | |
1437 | height = dst.visrect.bottom - dst.visrect.top; | |
1438 | ||
1439 | X11DRV_LockDIBSection( physDev, DIB_Status_GdiMod ); | |
1440 | ||
1441 | wine_tsx11_lock(); | |
1442 | XSetFunction( gdi_display, physDev->gc, OP_ROP(*opcode) ); | |
1443 | ||
1444 | switch(rop) /* a few special cases */ | |
1445 | { | |
1446 | case BLACKNESS: /* 0x00 */ | |
1447 | case WHITENESS: /* 0xff */ | |
1448 | if ((physDev->depth != 1) && X11DRV_PALETTE_PaletteToXPixel) | |
1449 | { | |
1450 | XSetFunction( gdi_display, physDev->gc, GXcopy ); | |
1451 | if (rop == BLACKNESS) | |
1452 | XSetForeground( gdi_display, physDev->gc, X11DRV_PALETTE_PaletteToXPixel[0] ); | |
1453 | else | |
1454 | XSetForeground( gdi_display, physDev->gc, | |
1455 | WhitePixel( gdi_display, DefaultScreen(gdi_display) )); | |
1456 | XSetFillStyle( gdi_display, physDev->gc, FillSolid ); | |
1457 | } | |
1458 | break; | |
1459 | case DSTINVERT: /* 0x55 */ | |
1460 | if (!(X11DRV_PALETTE_PaletteFlags & (X11DRV_PALETTE_PRIVATE | X11DRV_PALETTE_VIRTUAL))) | |
1461 | { | |
1462 | /* Xor is much better when we do not have full colormap. */ | |
1463 | /* Using white^black ensures that we invert at least black */ | |
1464 | /* and white. */ | |
1465 | unsigned long xor_pix = (WhitePixel( gdi_display, DefaultScreen(gdi_display) ) ^ | |
1466 | BlackPixel( gdi_display, DefaultScreen(gdi_display) )); | |
1467 | XSetFunction( gdi_display, physDev->gc, GXxor ); | |
1468 | XSetForeground( gdi_display, physDev->gc, xor_pix); | |
1469 | XSetFillStyle( gdi_display, physDev->gc, FillSolid ); | |
1470 | } | |
1471 | break; | |
1472 | } | |
1473 | XFillRectangle( gdi_display, physDev->drawable, physDev->gc, | |
1474 | physDev->dc_rect.left + dst.visrect.left, | |
1475 | physDev->dc_rect.top + dst.visrect.top, | |
1476 | dst.visrect.right - dst.visrect.left, | |
1477 | dst.visrect.bottom - dst.visrect.top ); | |
1478 | wine_tsx11_unlock(); | |
1479 | ||
1480 | X11DRV_UnlockDIBSection( physDev, TRUE ); | |
1481 | return TRUE; | |
1482 | } | |
1483 | ||
1484 | ||
401710d7 | 1485 | /*********************************************************************** |
89c91ac0 | 1486 | * X11DRV_StretchBlt |
401710d7 | 1487 | */ |
89c91ac0 | 1488 | BOOL CDECL X11DRV_StretchBlt( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst, |
3d34f01f | 1489 | PHYSDEV src_dev, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, |
89c91ac0 | 1490 | DWORD rop ) |
401710d7 | 1491 | { |
3d34f01f | 1492 | X11DRV_PDEVICE *physDevSrc = (X11DRV_PDEVICE *)src_dev; /* FIXME: check that it's really an x11 dev */ |
8e396a94 | 1493 | BOOL usePat, useDst, destUsed, fStretch, fNullBrush; |
39493b06 | 1494 | struct bitblt_coords src, dst; |
a3960292 | 1495 | INT width, height; |
77b9b8a3 | 1496 | INT sDst, sSrc = DIB_Status_None; |
3a5816f8 | 1497 | const BYTE *opcode; |
7cbe6572 | 1498 | Pixmap pixmaps[3] = { 0, 0, 0 }; /* pixmaps for DST, SRC, TMP */ |
3a5816f8 | 1499 | GC tmpGC = 0; |
401710d7 | 1500 | |
3a5816f8 | 1501 | usePat = (((rop >> 4) & 0x0f0000) != (rop & 0x0f0000)); |
3a5816f8 | 1502 | useDst = (((rop >> 1) & 0x550000) != (rop & 0x550000)); |
aca05783 | 1503 | |
439223d4 AJ |
1504 | src.x = xSrc; |
1505 | src.y = ySrc; | |
1506 | src.width = widthSrc; | |
1507 | src.height = heightSrc; | |
3d34f01f | 1508 | src.layout = GetLayout( physDevSrc->hdc ); |
439223d4 AJ |
1509 | dst.x = xDst; |
1510 | dst.y = yDst; | |
1511 | dst.width = widthDst; | |
1512 | dst.height = heightDst; | |
ebcd07a9 AJ |
1513 | dst.layout = GetLayout( physDevDst->hdc ); |
1514 | ||
1515 | if (rop & NOMIRRORBITMAP) | |
1516 | { | |
1517 | src.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED; | |
1518 | dst.layout |= LAYOUT_BITMAPORIENTATIONPRESERVED; | |
1519 | rop &= ~NOMIRRORBITMAP; | |
1520 | } | |
ded3038c | 1521 | |
8e396a94 AJ |
1522 | if (!BITBLT_GetVisRectangles( physDevDst, physDevSrc, &dst, &src )) |
1523 | return TRUE; | |
1524 | fStretch = (src.width != dst.width) || (src.height != dst.height); | |
439223d4 | 1525 | |
8e396a94 AJ |
1526 | if (physDevDst != physDevSrc) |
1527 | sSrc = X11DRV_LockDIBSection( physDevSrc, DIB_Status_None ); | |
3a5816f8 | 1528 | |
439223d4 AJ |
1529 | TRACE(" rectdst=%d,%d %dx%d orgdst=%d,%d visdst=%s\n", |
1530 | dst.x, dst.y, dst.width, dst.height, | |
1531 | physDevDst->dc_rect.left, physDevDst->dc_rect.top, wine_dbgstr_rect( &dst.visrect ) ); | |
8e396a94 AJ |
1532 | TRACE(" rectsrc=%d,%d %dx%d orgsrc=%d,%d vissrc=%s\n", |
1533 | src.x, src.y, src.width, src.height, | |
1534 | physDevSrc->dc_rect.left, physDevSrc->dc_rect.top, wine_dbgstr_rect( &src.visrect ) ); | |
439223d4 | 1535 | |
39493b06 AJ |
1536 | width = dst.visrect.right - dst.visrect.left; |
1537 | height = dst.visrect.bottom - dst.visrect.top; | |
3a5816f8 | 1538 | |
77b9b8a3 AJ |
1539 | sDst = X11DRV_LockDIBSection( physDevDst, DIB_Status_None ); |
1540 | if (physDevDst == physDevSrc) sSrc = sDst; | |
1541 | ||
1542 | /* try client-side DIB copy */ | |
1543 | if (!fStretch && rop == SRCCOPY && | |
1544 | sSrc == DIB_Status_AppMod && sDst == DIB_Status_AppMod && | |
61633b62 | 1545 | same_format(physDevSrc, physDevDst)) |
77b9b8a3 | 1546 | { |
39493b06 AJ |
1547 | if (client_side_dib_copy( physDevSrc, src.visrect.left, src.visrect.top, |
1548 | physDevDst, dst.visrect.left, dst.visrect.top, width, height )) | |
77b9b8a3 AJ |
1549 | goto done; |
1550 | } | |
1551 | ||
1552 | X11DRV_CoerceDIBSection( physDevDst, DIB_Status_GdiMod ); | |
1553 | ||
23afe2e9 | 1554 | opcode = BITBLT_Opcodes[(rop >> 16) & 0xff]; |
daf776fd | 1555 | |
6e59cd2c | 1556 | /* a few optimizations for single-op ROPs */ |
8e396a94 | 1557 | if (!fStretch && !opcode[1] && OP_SRCDST(opcode[0]) == OP_ARGS(SRC,DST)) |
23afe2e9 | 1558 | { |
8e396a94 | 1559 | if (same_format(physDevSrc, physDevDst)) |
3a5816f8 | 1560 | { |
8e396a94 AJ |
1561 | wine_tsx11_lock(); |
1562 | XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) ); | |
1563 | wine_tsx11_unlock(); | |
1564 | ||
1565 | if (physDevSrc != physDevDst) | |
23afe2e9 | 1566 | { |
8e396a94 | 1567 | if (sSrc == DIB_Status_AppMod) |
23afe2e9 | 1568 | { |
8e396a94 AJ |
1569 | X11DRV_DIB_CopyDIBSection( physDevSrc, physDevDst, src.visrect.left, src.visrect.top, |
1570 | dst.visrect.left, dst.visrect.top, width, height ); | |
77b9b8a3 | 1571 | goto done; |
23afe2e9 | 1572 | } |
8e396a94 | 1573 | X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod ); |
23afe2e9 | 1574 | } |
8e396a94 AJ |
1575 | wine_tsx11_lock(); |
1576 | XCopyArea( gdi_display, physDevSrc->drawable, | |
1577 | physDevDst->drawable, physDevDst->gc, | |
1578 | physDevSrc->dc_rect.left + src.visrect.left, | |
1579 | physDevSrc->dc_rect.top + src.visrect.top, | |
1580 | width, height, | |
1581 | physDevDst->dc_rect.left + dst.visrect.left, | |
1582 | physDevDst->dc_rect.top + dst.visrect.top ); | |
1583 | physDevDst->exposures++; | |
1584 | wine_tsx11_unlock(); | |
77b9b8a3 | 1585 | goto done; |
3a5816f8 | 1586 | } |
8e396a94 | 1587 | if (physDevSrc->depth == 1) |
7cbe6572 | 1588 | { |
8e396a94 | 1589 | int fg, bg; |
77b9b8a3 | 1590 | |
8e396a94 AJ |
1591 | X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod ); |
1592 | get_colors(physDevDst, physDevSrc, &fg, &bg); | |
1593 | wine_tsx11_lock(); | |
1594 | XSetBackground( gdi_display, physDevDst->gc, fg ); | |
1595 | XSetForeground( gdi_display, physDevDst->gc, bg ); | |
1596 | XSetFunction( gdi_display, physDevDst->gc, OP_ROP(*opcode) ); | |
1597 | XCopyPlane( gdi_display, physDevSrc->drawable, | |
1598 | physDevDst->drawable, physDevDst->gc, | |
1599 | physDevSrc->dc_rect.left + src.visrect.left, | |
1600 | physDevSrc->dc_rect.top + src.visrect.top, | |
1601 | width, height, | |
1602 | physDevDst->dc_rect.left + dst.visrect.left, | |
1603 | physDevDst->dc_rect.top + dst.visrect.top, 1 ); | |
1604 | physDevDst->exposures++; | |
1605 | wine_tsx11_unlock(); | |
1606 | goto done; | |
7cbe6572 | 1607 | } |
988ca977 | 1608 | } |
401710d7 | 1609 | |
704d0353 | 1610 | wine_tsx11_lock(); |
c559735b | 1611 | tmpGC = XCreateGC( gdi_display, physDevDst->drawable, 0, NULL ); |
dc4fe773 | 1612 | XSetSubwindowMode( gdi_display, tmpGC, IncludeInferiors ); |
c559735b AJ |
1613 | XSetGraphicsExposures( gdi_display, tmpGC, False ); |
1614 | pixmaps[DST] = XCreatePixmap( gdi_display, root_window, width, height, | |
b89525fb | 1615 | physDevDst->depth ); |
8e396a94 AJ |
1616 | pixmaps[SRC] = XCreatePixmap( gdi_display, root_window, width, height, |
1617 | physDevDst->depth ); | |
809af590 AJ |
1618 | wine_tsx11_unlock(); |
1619 | ||
8e396a94 | 1620 | if (physDevDst != physDevSrc) X11DRV_CoerceDIBSection( physDevSrc, DIB_Status_GdiMod ); |
004eabfb | 1621 | |
8e396a94 AJ |
1622 | if(!X11DRV_XRender_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, &src, &dst )) |
1623 | { | |
1624 | if (fStretch) | |
1625 | BITBLT_GetSrcAreaStretch( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, &src, &dst ); | |
1626 | else | |
1627 | BITBLT_GetSrcArea( physDevSrc, physDevDst, pixmaps[SRC], tmpGC, &src.visrect ); | |
7cbe6572 | 1628 | } |
704d0353 | 1629 | |
39493b06 | 1630 | if (useDst) BITBLT_GetDstArea( physDevDst, pixmaps[DST], tmpGC, &dst.visrect ); |
e21c15e3 | 1631 | if (usePat) fNullBrush = !X11DRV_SetupGCForPatBlt( physDevDst, tmpGC, TRUE ); |
7cbe6572 | 1632 | else fNullBrush = FALSE; |
3a5816f8 AJ |
1633 | destUsed = FALSE; |
1634 | ||
809af590 | 1635 | wine_tsx11_lock(); |
23afe2e9 | 1636 | for ( ; *opcode; opcode++) |
3a5816f8 | 1637 | { |
7cbe6572 | 1638 | if (OP_DST(*opcode) == DST) destUsed = TRUE; |
c559735b | 1639 | XSetFunction( gdi_display, tmpGC, OP_ROP(*opcode) ); |
7cbe6572 | 1640 | switch(OP_SRCDST(*opcode)) |
3a5816f8 AJ |
1641 | { |
1642 | case OP_ARGS(DST,TMP): | |
3a5816f8 | 1643 | case OP_ARGS(SRC,TMP): |
7cbe6572 | 1644 | if (!pixmaps[TMP]) |
c559735b | 1645 | pixmaps[TMP] = XCreatePixmap( gdi_display, root_window, |
b89525fb | 1646 | width, height, physDevDst->depth ); |
7cbe6572 AJ |
1647 | /* fall through */ |
1648 | case OP_ARGS(DST,SRC): | |
3a5816f8 | 1649 | case OP_ARGS(SRC,DST): |
7cbe6572 AJ |
1650 | case OP_ARGS(TMP,SRC): |
1651 | case OP_ARGS(TMP,DST): | |
8e396a94 AJ |
1652 | XCopyArea( gdi_display, pixmaps[OP_SRC(*opcode)], |
1653 | pixmaps[OP_DST(*opcode)], tmpGC, | |
1654 | 0, 0, width, height, 0, 0 ); | |
3a5816f8 AJ |
1655 | break; |
1656 | ||
1657 | case OP_ARGS(PAT,TMP): | |
7cbe6572 | 1658 | if (!pixmaps[TMP] && !fNullBrush) |
c559735b | 1659 | pixmaps[TMP] = XCreatePixmap( gdi_display, root_window, |
b89525fb | 1660 | width, height, physDevDst->depth ); |
7cbe6572 | 1661 | /* fall through */ |
3a5816f8 | 1662 | case OP_ARGS(PAT,DST): |
3a5816f8 | 1663 | case OP_ARGS(PAT,SRC): |
7cbe6572 | 1664 | if (!fNullBrush) |
c559735b | 1665 | XFillRectangle( gdi_display, pixmaps[OP_DST(*opcode)], |
7cbe6572 | 1666 | tmpGC, 0, 0, width, height ); |
3a5816f8 AJ |
1667 | break; |
1668 | } | |
1669 | } | |
c559735b | 1670 | XSetFunction( gdi_display, physDevDst->gc, GXcopy ); |
39493b06 | 1671 | physDevDst->exposures += BITBLT_PutDstArea( physDevDst, pixmaps[destUsed ? DST : SRC], &dst.visrect ); |
c559735b AJ |
1672 | XFreePixmap( gdi_display, pixmaps[DST] ); |
1673 | if (pixmaps[SRC]) XFreePixmap( gdi_display, pixmaps[SRC] ); | |
1674 | if (pixmaps[TMP]) XFreePixmap( gdi_display, pixmaps[TMP] ); | |
1675 | XFreeGC( gdi_display, tmpGC ); | |
704d0353 | 1676 | wine_tsx11_unlock(); |
77b9b8a3 AJ |
1677 | |
1678 | done: | |
8e396a94 | 1679 | if (physDevDst != physDevSrc) X11DRV_UnlockDIBSection( physDevSrc, FALSE ); |
77b9b8a3 | 1680 | X11DRV_UnlockDIBSection( physDevDst, TRUE ); |
3a5816f8 | 1681 | return TRUE; |
401710d7 | 1682 | } |
246e3732 AJ |
1683 | |
1684 | ||
1685 | /*********************************************************************** | |
1686 | * X11DRV_AlphaBlend | |
1687 | */ | |
1688 | BOOL CDECL X11DRV_AlphaBlend( X11DRV_PDEVICE *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst, | |
3d34f01f | 1689 | PHYSDEV src_dev, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc, |
246e3732 AJ |
1690 | BLENDFUNCTION blendfn ) |
1691 | { | |
3d34f01f | 1692 | X11DRV_PDEVICE *physDevSrc = (X11DRV_PDEVICE *)src_dev; /* FIXME: check that it's really an x11 dev */ |
246e3732 AJ |
1693 | struct bitblt_coords src, dst; |
1694 | ||
1695 | src.x = xSrc; | |
1696 | src.y = ySrc; | |
1697 | src.width = widthSrc; | |
1698 | src.height = heightSrc; | |
ebcd07a9 | 1699 | src.layout = GetLayout( physDevSrc->hdc ); |
246e3732 AJ |
1700 | dst.x = xDst; |
1701 | dst.y = yDst; | |
1702 | dst.width = widthDst; | |
1703 | dst.height = heightDst; | |
ebcd07a9 | 1704 | dst.layout = GetLayout( physDevDst->hdc ); |
246e3732 AJ |
1705 | |
1706 | if (!BITBLT_GetVisRectangles( physDevDst, physDevSrc, &dst, &src )) return TRUE; | |
1707 | ||
f0460e3c AJ |
1708 | TRACE( "format %x alpha %u rectdst=%d,%d %dx%d orgdst=%d,%d visdst=%s rectsrc=%d,%d %dx%d orgsrc=%d,%d vissrc=%s\n", |
1709 | blendfn.AlphaFormat, blendfn.SourceConstantAlpha, dst.x, dst.y, dst.width, dst.height, | |
1710 | physDevDst->dc_rect.left, physDevDst->dc_rect.top, wine_dbgstr_rect( &dst.visrect ), | |
1711 | src.x, src.y, src.width, src.height, | |
1712 | physDevSrc->dc_rect.left, physDevSrc->dc_rect.top, wine_dbgstr_rect( &src.visrect ) ); | |
1713 | ||
246e3732 AJ |
1714 | if (src.x < 0 || src.y < 0 || src.width < 0 || src.height < 0 || |
1715 | src.width > physDevSrc->drawable_rect.right - physDevSrc->drawable_rect.left - src.x || | |
1716 | src.height > physDevSrc->drawable_rect.bottom - physDevSrc->drawable_rect.top - src.y) | |
1717 | { | |
1718 | WARN( "Invalid src coords: (%d,%d), size %dx%d\n", src.x, src.y, src.width, src.height ); | |
1719 | SetLastError( ERROR_INVALID_PARAMETER ); | |
1720 | return FALSE; | |
1721 | } | |
1722 | ||
1723 | return XRender_AlphaBlend( physDevDst, physDevSrc, &dst, &src, blendfn ); | |
1724 | } |