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