/src/FreeRDP/libfreerdp/gdi/gdi.c
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /**  | 
2  |  |  * FreeRDP: A Remote Desktop Protocol Implementation  | 
3  |  |  * GDI Library  | 
4  |  |  *  | 
5  |  |  * Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>  | 
6  |  |  * Copyright 2016 Armin Novak <armin.novak@thincast.com>  | 
7  |  |  * Copyright 2016 Thincast Technologies GmbH  | 
8  |  |  *  | 
9  |  |  * Licensed under the Apache License, Version 2.0 (the "License");  | 
10  |  |  * you may not use this file except in compliance with the License.  | 
11  |  |  * You may obtain a copy of the License at  | 
12  |  |  *  | 
13  |  |  *   http://www.apache.org/licenses/LICENSE-2.0  | 
14  |  |  *  | 
15  |  |  * Unless required by applicable law or agreed to in writing, software  | 
16  |  |  * distributed under the License is distributed on an "AS IS" BASIS,  | 
17  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  | 
18  |  |  * See the License for the specific language governing permissions and  | 
19  |  |  * limitations under the License.  | 
20  |  |  */  | 
21  |  |  | 
22  |  | #include <freerdp/config.h>  | 
23  |  |  | 
24  |  | #include <stdio.h>  | 
25  |  | #include <stdlib.h>  | 
26  |  |  | 
27  |  | #include <winpr/crt.h>  | 
28  |  | #include <winpr/assert.h>  | 
29  |  |  | 
30  |  | #include <freerdp/api.h>  | 
31  |  | #include <freerdp/log.h>  | 
32  |  | #include <freerdp/freerdp.h>  | 
33  |  |  | 
34  |  | #include <freerdp/gdi/gdi.h>  | 
35  |  | #include <freerdp/gdi/dc.h>  | 
36  |  | #include <freerdp/gdi/pen.h>  | 
37  |  | #include <freerdp/gdi/shape.h>  | 
38  |  | #include <freerdp/gdi/region.h>  | 
39  |  | #include <freerdp/gdi/bitmap.h>  | 
40  |  |  | 
41  |  | #include "drawing.h"  | 
42  |  | #include "clipping.h"  | 
43  |  | #include "brush.h"  | 
44  |  | #include "line.h"  | 
45  |  | #include "gdi.h"  | 
46  |  | #include "../core/graphics.h"  | 
47  |  | #include "../core/update.h"  | 
48  |  | #include "../cache/cache.h"  | 
49  |  |  | 
50  | 0  | #define TAG FREERDP_TAG("gdi") | 
51  |  |  | 
52  |  | /* Ternary Raster Operation Table */  | 
53  |  | typedef struct  | 
54  |  | { | 
55  |  |   DWORD code;  | 
56  |  |   const char* name;  | 
57  |  | } rop_table_entry;  | 
58  |  |  | 
59  |  | static const rop_table_entry rop3_code_table[] = { { GDI_BLACKNESS, "0" }, | 
60  |  |                                                  { GDI_DPSoon, "DPSoon" }, | 
61  |  |                                                  { GDI_DPSona, "DPSona" }, | 
62  |  |                                                  { GDI_PSon, "PSon" }, | 
63  |  |                                                  { GDI_SDPona, "SDPona" }, | 
64  |  |                                                  { GDI_DPon, "DPon" }, | 
65  |  |                                                  { GDI_PDSxnon, "PDSxnon" }, | 
66  |  |                                                  { GDI_PDSaon, "PDSaon" }, | 
67  |  |                                                  { GDI_SDPnaa, "SDPnaa" }, | 
68  |  |                                                  { GDI_PDSxon, "PDSxon" }, | 
69  |  |                                                  { GDI_DPna, "DPna" }, | 
70  |  |                                                  { GDI_PSDnaon, "PSDnaon" }, | 
71  |  |                                                  { GDI_SPna, "SPna" }, | 
72  |  |                                                  { GDI_PDSnaon, "PDSnaon" }, | 
73  |  |                                                  { GDI_PDSonon, "PDSonon" }, | 
74  |  |                                                  { GDI_Pn, "Pn" }, | 
75  |  |                                                  { GDI_PDSona, "PDSona" }, | 
76  |  |                                                  { GDI_NOTSRCERASE, "DSon" }, | 
77  |  |                                                  { GDI_SDPxnon, "SDPxnon" }, | 
78  |  |                                                  { GDI_SDPaon, "SDPaon" }, | 
79  |  |                                                  { GDI_DPSxnon, "DPSxnon" }, | 
80  |  |                                                  { GDI_DPSaon, "DPSaon" }, | 
81  |  |                                                  { GDI_PSDPSanaxx, "PSDPSanaxx" }, | 
82  |  |                                                  { GDI_SSPxDSxaxn, "SSPxDSxaxn" }, | 
83  |  |                                                  { GDI_SPxPDxa, "SPxPDxa" }, | 
84  |  |                                                  { GDI_SDPSanaxn, "SDPSanaxn" }, | 
85  |  |                                                  { GDI_PDSPaox, "PDSPaox" }, | 
86  |  |                                                  { GDI_SDPSxaxn, "SDPSxaxn" }, | 
87  |  |                                                  { GDI_PSDPaox, "PSDPaox" }, | 
88  |  |                                                  { GDI_DSPDxaxn, "DSPDxaxn" }, | 
89  |  |                                                  { GDI_PDSox, "PDSox" }, | 
90  |  |                                                  { GDI_PDSoan, "PDSoan" }, | 
91  |  |                                                  { GDI_DPSnaa, "DPSnaa" }, | 
92  |  |                                                  { GDI_SDPxon, "SDPxon" }, | 
93  |  |                                                  { GDI_DSna, "DSna" }, | 
94  |  |                                                  { GDI_SPDnaon, "SPDnaon" }, | 
95  |  |                                                  { GDI_SPxDSxa, "SPxDSxa" }, | 
96  |  |                                                  { GDI_PDSPanaxn, "PDSPanaxn" }, | 
97  |  |                                                  { GDI_SDPSaox, "SDPSaox" }, | 
98  |  |                                                  { GDI_SDPSxnox, "SDPSxnox" }, | 
99  |  |                                                  { GDI_DPSxa, "DPSxa" }, | 
100  |  |                                                  { GDI_PSDPSaoxxn, "PSDPSaoxxn" }, | 
101  |  |                                                  { GDI_DPSana, "DPSana" }, | 
102  |  |                                                  { GDI_SSPxPDxaxn, "SSPxPDxaxn" }, | 
103  |  |                                                  { GDI_SPDSoax, "SPDSoax" }, | 
104  |  |                                                  { GDI_PSDnox, "PSDnox" }, | 
105  |  |                                                  { GDI_PSDPxox, "PSDPxox" }, | 
106  |  |                                                  { GDI_PSDnoan, "PSDnoan" }, | 
107  |  |                                                  { GDI_PSna, "PSna" }, | 
108  |  |                                                  { GDI_SDPnaon, "SDPnaon" }, | 
109  |  |                                                  { GDI_SDPSoox, "SDPSoox" }, | 
110  |  |                                                  { GDI_NOTSRCCOPY, "Sn" }, | 
111  |  |                                                  { GDI_SPDSaox, "SPDSaox" }, | 
112  |  |                                                  { GDI_SPDSxnox, "SPDSxnox" }, | 
113  |  |                                                  { GDI_SDPox, "SDPox" }, | 
114  |  |                                                  { GDI_SDPoan, "SDPoan" }, | 
115  |  |                                                  { GDI_PSDPoax, "PSDPoax" }, | 
116  |  |                                                  { GDI_SPDnox, "SPDnox" }, | 
117  |  |                                                  { GDI_SPDSxox, "SPDSxox" }, | 
118  |  |                                                  { GDI_SPDnoan, "SPDnoan" }, | 
119  |  |                                                  { GDI_PSx, "PSx" }, | 
120  |  |                                                  { GDI_SPDSonox, "SPDSonox" }, | 
121  |  |                                                  { GDI_SPDSnaox, "SPDSnaox" }, | 
122  |  |                                                  { GDI_PSan, "PSan" }, | 
123  |  |                                                  { GDI_PSDnaa, "PSDnaa" }, | 
124  |  |                                                  { GDI_DPSxon, "DPSxon" }, | 
125  |  |                                                  { GDI_SDxPDxa, "SDxPDxa" }, | 
126  |  |                                                  { GDI_SPDSanaxn, "SPDSanaxn" }, | 
127  |  |                                                  { GDI_SRCERASE, "SDna" }, | 
128  |  |                                                  { GDI_DPSnaon, "DPSnaon" }, | 
129  |  |                                                  { GDI_DSPDaox, "DSPDaox" }, | 
130  |  |                                                  { GDI_PSDPxaxn, "PSDPxaxn" }, | 
131  |  |                                                  { GDI_SDPxa, "SDPxa" }, | 
132  |  |                                                  { GDI_PDSPDaoxxn, "PDSPDaoxxn" }, | 
133  |  |                                                  { GDI_DPSDoax, "DPSDoax" }, | 
134  |  |                                                  { GDI_PDSnox, "PDSnox" }, | 
135  |  |                                                  { GDI_SDPana, "SDPana" }, | 
136  |  |                                                  { GDI_SSPxDSxoxn, "SSPxDSxoxn" }, | 
137  |  |                                                  { GDI_PDSPxox, "PDSPxox" }, | 
138  |  |                                                  { GDI_PDSnoan, "PDSnoan" }, | 
139  |  |                                                  { GDI_PDna, "PDna" }, | 
140  |  |                                                  { GDI_DSPnaon, "DSPnaon" }, | 
141  |  |                                                  { GDI_DPSDaox, "DPSDaox" }, | 
142  |  |                                                  { GDI_SPDSxaxn, "SPDSxaxn" }, | 
143  |  |                                                  { GDI_DPSonon, "DPSonon" }, | 
144  |  |                                                  { GDI_DSTINVERT, "Dn" }, | 
145  |  |                                                  { GDI_DPSox, "DPSox" }, | 
146  |  |                                                  { GDI_DPSoan, "DPSoan" }, | 
147  |  |                                                  { GDI_PDSPoax, "PDSPoax" }, | 
148  |  |                                                  { GDI_DPSnox, "DPSnox" }, | 
149  |  |                                                  { GDI_PATINVERT, "DPx" }, | 
150  |  |                                                  { GDI_DPSDonox, "DPSDonox" }, | 
151  |  |                                                  { GDI_DPSDxox, "DPSDxox" }, | 
152  |  |                                                  { GDI_DPSnoan, "DPSnoan" }, | 
153  |  |                                                  { GDI_DPSDnaox, "DPSDnaox" }, | 
154  |  |                                                  { GDI_DPan, "DPan" }, | 
155  |  |                                                  { GDI_PDSxa, "PDSxa" }, | 
156  |  |                                                  { GDI_DSPDSaoxxn, "DSPDSaoxxn" }, | 
157  |  |                                                  { GDI_DSPDoax, "DSPDoax" }, | 
158  |  |                                                  { GDI_SDPnox, "SDPnox" }, | 
159  |  |                                                  { GDI_SDPSoax, "SDPSoax" }, | 
160  |  |                                                  { GDI_DSPnox, "DSPnox" }, | 
161  |  |                                                  { GDI_SRCINVERT, "DSx" }, | 
162  |  |                                                  { GDI_SDPSonox, "SDPSonox" }, | 
163  |  |                                                  { GDI_DSPDSonoxxn, "DSPDSonoxxn" }, | 
164  |  |                                                  { GDI_PDSxxn, "PDSxxn" }, | 
165  |  |                                                  { GDI_DPSax, "DPSax" }, | 
166  |  |                                                  { GDI_PSDPSoaxxn, "PSDPSoaxxn" }, | 
167  |  |                                                  { GDI_SDPax, "SDPax" }, | 
168  |  |                                                  { GDI_PDSPDoaxxn, "PDSPDoaxxn" }, | 
169  |  |                                                  { GDI_SDPSnoax, "SDPSnoax" }, | 
170  |  |                                                  { GDI_PDSxnan, "PDSxnan" }, | 
171  |  |                                                  { GDI_PDSana, "PDSana" }, | 
172  |  |                                                  { GDI_SSDxPDxaxn, "SSDxPDxaxn" }, | 
173  |  |                                                  { GDI_SDPSxox, "SDPSxox" }, | 
174  |  |                                                  { GDI_SDPnoan, "SDPnoan" }, | 
175  |  |                                                  { GDI_DSPDxox, "DSPDxox" }, | 
176  |  |                                                  { GDI_DSPnoan, "DSPnoan" }, | 
177  |  |                                                  { GDI_SDPSnaox, "SDPSnaox" }, | 
178  |  |                                                  { GDI_DSan, "DSan" }, | 
179  |  |                                                  { GDI_PDSax, "PDSax" }, | 
180  |  |                                                  { GDI_DSPDSoaxxn, "DSPDSoaxxn" }, | 
181  |  |                                                  { GDI_DPSDnoax, "DPSDnoax" }, | 
182  |  |                                                  { GDI_SDPxnan, "SDPxnan" }, | 
183  |  |                                                  { GDI_SPDSnoax, "SPDSnoax" }, | 
184  |  |                                                  { GDI_DPSxnan, "DPSxnan" }, | 
185  |  |                                                  { GDI_SPxDSxo, "SPxDSxo" }, | 
186  |  |                                                  { GDI_DPSaan, "DPSaan" }, | 
187  |  |                                                  { GDI_DPSaa, "DPSaa" }, | 
188  |  |                                                  { GDI_SPxDSxon, "SPxDSxon" }, | 
189  |  |                                                  { GDI_DPSxna, "DPSxna" }, | 
190  |  |                                                  { GDI_SPDSnoaxn, "SPDSnoaxn" }, | 
191  |  |                                                  { GDI_SDPxna, "SDPxna" }, | 
192  |  |                                                  { GDI_PDSPnoaxn, "PDSPnoaxn" }, | 
193  |  |                                                  { GDI_DSPDSoaxx, "DSPDSoaxx" }, | 
194  |  |                                                  { GDI_PDSaxn, "PDSaxn" }, | 
195  |  |                                                  { GDI_SRCAND, "DSa" }, | 
196  |  |                                                  { GDI_SDPSnaoxn, "SDPSnaoxn" }, | 
197  |  |                                                  { GDI_DSPnoa, "DSPnoa" }, | 
198  |  |                                                  { GDI_DSPDxoxn, "DSPDxoxn" }, | 
199  |  |                                                  { GDI_SDPnoa, "SDPnoa" }, | 
200  |  |                                                  { GDI_SDPSxoxn, "SDPSxoxn" }, | 
201  |  |                                                  { GDI_SSDxPDxax, "SSDxPDxax" }, | 
202  |  |                                                  { GDI_PDSanan, "PDSanan" }, | 
203  |  |                                                  { GDI_PDSxna, "PDSxna" }, | 
204  |  |                                                  { GDI_SDPSnoaxn, "SDPSnoaxn" }, | 
205  |  |                                                  { GDI_DPSDPoaxx, "DPSDPoaxx" }, | 
206  |  |                                                  { GDI_SPDaxn, "SPDaxn" }, | 
207  |  |                                                  { GDI_PSDPSoaxx, "PSDPSoaxx" }, | 
208  |  |                                                  { GDI_DPSaxn, "DPSaxn" }, | 
209  |  |                                                  { GDI_DPSxx, "DPSxx" }, | 
210  |  |                                                  { GDI_PSDPSonoxx, "PSDPSonoxx" }, | 
211  |  |                                                  { GDI_SDPSonoxn, "SDPSonoxn" }, | 
212  |  |                                                  { GDI_DSxn, "DSxn" }, | 
213  |  |                                                  { GDI_DPSnax, "DPSnax" }, | 
214  |  |                                                  { GDI_SDPSoaxn, "SDPSoaxn" }, | 
215  |  |                                                  { GDI_SPDnax, "SPDnax" }, | 
216  |  |                                                  { GDI_DSPDoaxn, "DSPDoaxn" }, | 
217  |  |                                                  { GDI_DSPDSaoxx, "DSPDSaoxx" }, | 
218  |  |                                                  { GDI_PDSxan, "PDSxan" }, | 
219  |  |                                                  { GDI_DPa, "DPa" }, | 
220  |  |                                                  { GDI_PDSPnaoxn, "PDSPnaoxn" }, | 
221  |  |                                                  { GDI_DPSnoa, "DPSnoa" }, | 
222  |  |                                                  { GDI_DPSDxoxn, "DPSDxoxn" }, | 
223  |  |                                                  { GDI_PDSPonoxn, "PDSPonoxn" }, | 
224  |  |                                                  { GDI_PDxn, "PDxn" }, | 
225  |  |                                                  { GDI_DSPnax, "DSPnax" }, | 
226  |  |                                                  { GDI_PDSPoaxn, "PDSPoaxn" }, | 
227  |  |                                                  { GDI_DPSoa, "DPSoa" }, | 
228  |  |                                                  { GDI_DPSoxn, "DPSoxn" }, | 
229  |  |                                                  { GDI_DSTCOPY, "D" }, | 
230  |  |                                                  { GDI_DPSono, "DPSono" }, | 
231  |  |                                                  { GDI_SPDSxax, "SPDSxax" }, | 
232  |  |                                                  { GDI_DPSDaoxn, "DPSDaoxn" }, | 
233  |  |                                                  { GDI_DSPnao, "DSPnao" }, | 
234  |  |                                                  { GDI_DPno, "DPno" }, | 
235  |  |                                                  { GDI_PDSnoa, "PDSnoa" }, | 
236  |  |                                                  { GDI_PDSPxoxn, "PDSPxoxn" }, | 
237  |  |                                                  { GDI_SSPxDSxox, "SSPxDSxox" }, | 
238  |  |                                                  { GDI_SDPanan, "SDPanan" }, | 
239  |  |                                                  { GDI_PSDnax, "PSDnax" }, | 
240  |  |                                                  { GDI_DPSDoaxn, "DPSDoaxn" }, | 
241  |  |                                                  { GDI_DPSDPaoxx, "DPSDPaoxx" }, | 
242  |  |                                                  { GDI_SDPxan, "SDPxan" }, | 
243  |  |                                                  { GDI_PSDPxax, "PSDPxax" }, | 
244  |  |                                                  { GDI_DSPDaoxn, "DSPDaoxn" }, | 
245  |  |                                                  { GDI_DPSnao, "DPSnao" }, | 
246  |  |                                                  { GDI_MERGEPAINT, "DSno" }, | 
247  |  |                                                  { GDI_SPDSanax, "SPDSanax" }, | 
248  |  |                                                  { GDI_SDxPDxan, "SDxPDxan" }, | 
249  |  |                                                  { GDI_DPSxo, "DPSxo" }, | 
250  |  |                                                  { GDI_DPSano, "DPSano" }, | 
251  |  |                                                  { GDI_MERGECOPY, "PSa" }, | 
252  |  |                                                  { GDI_SPDSnaoxn, "SPDSnaoxn" }, | 
253  |  |                                                  { GDI_SPDSonoxn, "SPDSonoxn" }, | 
254  |  |                                                  { GDI_PSxn, "PSxn" }, | 
255  |  |                                                  { GDI_SPDnoa, "SPDnoa" }, | 
256  |  |                                                  { GDI_SPDSxoxn, "SPDSxoxn" }, | 
257  |  |                                                  { GDI_SDPnax, "SDPnax" }, | 
258  |  |                                                  { GDI_PSDPoaxn, "PSDPoaxn" }, | 
259  |  |                                                  { GDI_SDPoa, "SDPoa" }, | 
260  |  |                                                  { GDI_SPDoxn, "SPDoxn" }, | 
261  |  |                                                  { GDI_DPSDxax, "DPSDxax" }, | 
262  |  |                                                  { GDI_SPDSaoxn, "SPDSaoxn" }, | 
263  |  |                                                  { GDI_SRCCOPY, "S" }, | 
264  |  |                                                  { GDI_SDPono, "SDPono" }, | 
265  |  |                                                  { GDI_SDPnao, "SDPnao" }, | 
266  |  |                                                  { GDI_SPno, "SPno" }, | 
267  |  |                                                  { GDI_PSDnoa, "PSDnoa" }, | 
268  |  |                                                  { GDI_PSDPxoxn, "PSDPxoxn" }, | 
269  |  |                                                  { GDI_PDSnax, "PDSnax" }, | 
270  |  |                                                  { GDI_SPDSoaxn, "SPDSoaxn" }, | 
271  |  |                                                  { GDI_SSPxPDxax, "SSPxPDxax" }, | 
272  |  |                                                  { GDI_DPSanan, "DPSanan" }, | 
273  |  |                                                  { GDI_PSDPSaoxx, "PSDPSaoxx" }, | 
274  |  |                                                  { GDI_DPSxan, "DPSxan" }, | 
275  |  |                                                  { GDI_PDSPxax, "PDSPxax" }, | 
276  |  |                                                  { GDI_SDPSaoxn, "SDPSaoxn" }, | 
277  |  |                                                  { GDI_DPSDanax, "DPSDanax" }, | 
278  |  |                                                  { GDI_SPxDSxan, "SPxDSxan" }, | 
279  |  |                                                  { GDI_SPDnao, "SPDnao" }, | 
280  |  |                                                  { GDI_SDno, "SDno" }, | 
281  |  |                                                  { GDI_SDPxo, "SDPxo" }, | 
282  |  |                                                  { GDI_SDPano, "SDPano" }, | 
283  |  |                                                  { GDI_PDSoa, "PDSoa" }, | 
284  |  |                                                  { GDI_PDSoxn, "PDSoxn" }, | 
285  |  |                                                  { GDI_DSPDxax, "DSPDxax" }, | 
286  |  |                                                  { GDI_PSDPaoxn, "PSDPaoxn" }, | 
287  |  |                                                  { GDI_SDPSxax, "SDPSxax" }, | 
288  |  |                                                  { GDI_PDSPaoxn, "PDSPaoxn" }, | 
289  |  |                                                  { GDI_SDPSanax, "SDPSanax" }, | 
290  |  |                                                  { GDI_SPxPDxan, "SPxPDxan" }, | 
291  |  |                                                  { GDI_SSPxDSxax, "SSPxDSxax" }, | 
292  |  |                                                  { GDI_DSPDSanaxxn, "DSPDSanaxxn" }, | 
293  |  |                                                  { GDI_DPSao, "DPSao" }, | 
294  |  |                                                  { GDI_DPSxno, "DPSxno" }, | 
295  |  |                                                  { GDI_SDPao, "SDPao" }, | 
296  |  |                                                  { GDI_SDPxno, "SDPxno" }, | 
297  |  |                                                  { GDI_SRCPAINT, "DSo" }, | 
298  |  |                                                  { GDI_SDPnoo, "SDPnoo" }, | 
299  |  |                                                  { GDI_PATCOPY, "P" }, | 
300  |  |                                                  { GDI_PDSono, "PDSono" }, | 
301  |  |                                                  { GDI_PDSnao, "PDSnao" }, | 
302  |  |                                                  { GDI_PSno, "PSno" }, | 
303  |  |                                                  { GDI_PSDnao, "PSDnao" }, | 
304  |  |                                                  { GDI_PDno, "PDno" }, | 
305  |  |                                                  { GDI_PDSxo, "PDSxo" }, | 
306  |  |                                                  { GDI_PDSano, "PDSano" }, | 
307  |  |                                                  { GDI_PDSao, "PDSao" }, | 
308  |  |                                                  { GDI_PDSxno, "PDSxno" }, | 
309  |  |                                                  { GDI_DPo, "DPo" }, | 
310  |  |                                                  { GDI_PATPAINT, "DPSnoo" }, | 
311  |  |                                                  { GDI_PSo, "PSo" }, | 
312  |  |                                                  { GDI_PSDnoo, "PSDnoo" }, | 
313  |  |                                                  { GDI_DPSoo, "DPSoo" }, | 
314  |  |                                                  { GDI_WHITENESS, "1" } }; | 
315  |  |  | 
316  |  | /* Hatch Patterns as monochrome data */  | 
317  |  | static const BYTE GDI_BS_HATCHED_PATTERNS[] = { | 
318  |  |   0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, /* HS_HORIZONTAL */  | 
319  |  |   0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, /* HS_VERTICAL */  | 
320  |  |   0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F, /* HS_FDIAGONAL */  | 
321  |  |   0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE, /* HS_BDIAGONAL */  | 
322  |  |   0xF7, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0xF7, 0xF7, /* HS_CROSS */  | 
323  |  |   0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E  /* HS_DIACROSS */  | 
324  |  | };  | 
325  |  |  | 
326  |  | BOOL gdi_decode_color(rdpGdi* gdi, const UINT32 srcColor, UINT32* color, UINT32* format)  | 
327  | 0  | { | 
328  | 0  |   UINT32 SrcFormat = 0;  | 
329  |  | 
  | 
330  | 0  |   if (!gdi || !color || !gdi->context || !gdi->context->settings)  | 
331  | 0  |     return FALSE;  | 
332  |  |  | 
333  | 0  |   const UINT32 ColorDepth =  | 
334  | 0  |       freerdp_settings_get_uint32(gdi->context->settings, FreeRDP_ColorDepth);  | 
335  |  | 
  | 
336  | 0  |   switch (ColorDepth)  | 
337  | 0  |   { | 
338  | 0  |     case 32:  | 
339  | 0  |     case 24:  | 
340  | 0  |       SrcFormat = PIXEL_FORMAT_BGR24;  | 
341  | 0  |       break;  | 
342  |  |  | 
343  | 0  |     case 16:  | 
344  | 0  |       SrcFormat = PIXEL_FORMAT_RGB16;  | 
345  | 0  |       break;  | 
346  |  |  | 
347  | 0  |     case 15:  | 
348  | 0  |       SrcFormat = PIXEL_FORMAT_RGB15;  | 
349  | 0  |       break;  | 
350  |  |  | 
351  | 0  |     case 8:  | 
352  | 0  |       SrcFormat = PIXEL_FORMAT_RGB8;  | 
353  | 0  |       break;  | 
354  |  |  | 
355  | 0  |     default:  | 
356  | 0  |       return FALSE;  | 
357  | 0  |   }  | 
358  |  |  | 
359  | 0  |   if (format)  | 
360  | 0  |     *format = gdi->dstFormat;  | 
361  |  | 
  | 
362  | 0  |   *color = FreeRDPConvertColor(srcColor, SrcFormat, gdi->dstFormat, &gdi->palette);  | 
363  | 0  |   return TRUE;  | 
364  | 0  | }  | 
365  |  |  | 
366  |  | /* GDI Helper Functions */  | 
367  |  | DWORD gdi_rop3_code(BYTE code)  | 
368  | 0  | { | 
369  | 0  |   return rop3_code_table[code].code;  | 
370  | 0  | }  | 
371  |  |  | 
372  |  | const char* gdi_rop3_code_string(BYTE code)  | 
373  | 0  | { | 
374  | 0  |   return rop3_code_table[code].name;  | 
375  | 0  | }  | 
376  |  |  | 
377  |  | const char* gdi_rop3_string(DWORD rop)  | 
378  | 0  | { | 
379  | 0  |   const size_t count = sizeof(rop3_code_table) / sizeof(rop3_code_table[0]);  | 
380  |  | 
  | 
381  | 0  |   for (size_t x = 0; x < count; x++)  | 
382  | 0  |   { | 
383  | 0  |     if (rop3_code_table[x].code == rop)  | 
384  | 0  |       return rop3_code_table[x].name;  | 
385  | 0  |   }  | 
386  |  |  | 
387  | 0  |   return "UNKNOWN";  | 
388  | 0  | }  | 
389  |  |  | 
390  |  | UINT32 gdi_get_pixel_format(UINT32 bitsPerPixel)  | 
391  | 0  | { | 
392  | 0  |   UINT32 format = 0;  | 
393  |  | 
  | 
394  | 0  |   switch (bitsPerPixel)  | 
395  | 0  |   { | 
396  | 0  |     case 32:  | 
397  | 0  |       format = PIXEL_FORMAT_BGRA32;  | 
398  | 0  |       break;  | 
399  |  |  | 
400  | 0  |     case 24:  | 
401  | 0  |       format = PIXEL_FORMAT_BGR24;  | 
402  | 0  |       break;  | 
403  |  |  | 
404  | 0  |     case 16:  | 
405  | 0  |       format = PIXEL_FORMAT_RGB16;  | 
406  | 0  |       break;  | 
407  |  |  | 
408  | 0  |     case 15:  | 
409  | 0  |       format = PIXEL_FORMAT_RGB15;  | 
410  | 0  |       break;  | 
411  |  |  | 
412  | 0  |     case 8:  | 
413  | 0  |       format = PIXEL_FORMAT_RGB8;  | 
414  | 0  |       break;  | 
415  |  |  | 
416  | 0  |     default:  | 
417  | 0  |       WLog_ERR(TAG, "Unsupported color depth %" PRIu32, bitsPerPixel);  | 
418  | 0  |       format = 0;  | 
419  | 0  |       break;  | 
420  | 0  |   }  | 
421  |  |  | 
422  | 0  |   return format;  | 
423  | 0  | }  | 
424  |  |  | 
425  |  | gdiBitmap* gdi_bitmap_new_ex(rdpGdi* gdi, int width, int height, int bpp, BYTE* data)  | 
426  | 0  | { | 
427  | 0  |   gdiBitmap* bitmap = NULL;  | 
428  | 0  |   bitmap = (gdiBitmap*)calloc(1, sizeof(gdiBitmap));  | 
429  |  | 
  | 
430  | 0  |   if (!bitmap)  | 
431  | 0  |     goto fail_bitmap;  | 
432  |  |  | 
433  | 0  |   if (!(bitmap->hdc = gdi_CreateCompatibleDC(gdi->hdc)))  | 
434  | 0  |     goto fail_hdc;  | 
435  |  |  | 
436  | 0  |   WLog_Print(gdi->log, WLOG_DEBUG, "gdi_bitmap_new: width:%d height:%d bpp:%d", width, height,  | 
437  | 0  |              bpp);  | 
438  |  | 
  | 
439  | 0  |   if (!data)  | 
440  | 0  |     bitmap->bitmap = gdi_CreateCompatibleBitmap(gdi->hdc, width, height);  | 
441  | 0  |   else  | 
442  | 0  |     bitmap->bitmap = gdi_create_bitmap(gdi, width, height, bpp, data);  | 
443  |  | 
  | 
444  | 0  |   if (!bitmap->bitmap)  | 
445  | 0  |     goto fail_bitmap_bitmap;  | 
446  |  |  | 
447  | 0  |   gdi_SelectObject(bitmap->hdc, (HGDIOBJECT)bitmap->bitmap);  | 
448  | 0  |   bitmap->org_bitmap = NULL;  | 
449  | 0  |   return bitmap;  | 
450  | 0  | fail_bitmap_bitmap:  | 
451  | 0  |   gdi_DeleteDC(bitmap->hdc);  | 
452  | 0  | fail_hdc:  | 
453  | 0  |   free(bitmap);  | 
454  | 0  | fail_bitmap:  | 
455  | 0  |   return NULL;  | 
456  | 0  | }  | 
457  |  |  | 
458  |  | void gdi_bitmap_free_ex(gdiBitmap* bitmap)  | 
459  | 0  | { | 
460  | 0  |   if (bitmap)  | 
461  | 0  |   { | 
462  | 0  |     gdi_SelectObject(bitmap->hdc, (HGDIOBJECT)bitmap->org_bitmap);  | 
463  | 0  |     gdi_DeleteObject((HGDIOBJECT)bitmap->bitmap);  | 
464  | 0  |     gdi_DeleteDC(bitmap->hdc);  | 
465  | 0  |     free(bitmap);  | 
466  | 0  |   }  | 
467  | 0  | }  | 
468  |  |  | 
469  |  | BOOL gdi_bitmap_update(rdpContext* context, const BITMAP_UPDATE* bitmapUpdate)  | 
470  | 0  | { | 
471  | 0  |   if (!context || !bitmapUpdate || !context->gdi || !context->codecs)  | 
472  | 0  |   { | 
473  | 0  |     WLog_ERR(TAG,  | 
474  | 0  |              "Invalid arguments: context=%p, bitmapUpdate=%p, context->gdi=%p, "  | 
475  | 0  |              "context->codecs=%p",  | 
476  | 0  |              context, bitmapUpdate, context ? context->gdi : NULL,  | 
477  | 0  |              context ? context->codecs : NULL);  | 
478  | 0  |     return FALSE;  | 
479  | 0  |   }  | 
480  |  |  | 
481  | 0  |   for (UINT32 index = 0; index < bitmapUpdate->number; index++)  | 
482  | 0  |   { | 
483  | 0  |     const BITMAP_DATA* bitmap = &(bitmapUpdate->rectangles[index]);  | 
484  | 0  |     rdpBitmap* bmp = Bitmap_Alloc(context);  | 
485  |  | 
  | 
486  | 0  |     if (!bmp)  | 
487  | 0  |     { | 
488  | 0  |       WLog_ERR(TAG, "Bitmap_Alloc failed");  | 
489  | 0  |       return FALSE;  | 
490  | 0  |     }  | 
491  |  |  | 
492  | 0  |     Bitmap_SetDimensions(bmp, bitmap->width, bitmap->height);  | 
493  | 0  |     Bitmap_SetRectangle(bmp, bitmap->destLeft, bitmap->destTop, bitmap->destRight,  | 
494  | 0  |                         bitmap->destBottom);  | 
495  |  | 
  | 
496  | 0  |     if (!bmp->Decompress(context, bmp, bitmap->bitmapDataStream, bitmap->width, bitmap->height,  | 
497  | 0  |                          bitmap->bitsPerPixel, bitmap->bitmapLength, bitmap->compressed,  | 
498  | 0  |                          RDP_CODEC_ID_NONE))  | 
499  | 0  |     { | 
500  | 0  |       WLog_ERR(TAG, "bmp->Decompress failed");  | 
501  | 0  |       Bitmap_Free(context, bmp);  | 
502  | 0  |       return FALSE;  | 
503  | 0  |     }  | 
504  |  |  | 
505  | 0  |     if (!bmp->New(context, bmp))  | 
506  | 0  |     { | 
507  | 0  |       WLog_ERR(TAG, "bmp->New failed");  | 
508  | 0  |       Bitmap_Free(context, bmp);  | 
509  | 0  |       return FALSE;  | 
510  | 0  |     }  | 
511  |  |  | 
512  | 0  |     if (!bmp->Paint(context, bmp))  | 
513  | 0  |     { | 
514  | 0  |       WLog_ERR(TAG, "bmp->Paint failed");  | 
515  | 0  |       Bitmap_Free(context, bmp);  | 
516  | 0  |       return FALSE;  | 
517  | 0  |     }  | 
518  |  |  | 
519  | 0  |     Bitmap_Free(context, bmp);  | 
520  | 0  |   }  | 
521  |  |  | 
522  | 0  |   return TRUE;  | 
523  | 0  | }  | 
524  |  |  | 
525  |  | static BOOL gdi_palette_update(rdpContext* context, const PALETTE_UPDATE* palette)  | 
526  | 0  | { | 
527  | 0  |   rdpGdi* gdi = NULL;  | 
528  |  | 
  | 
529  | 0  |   if (!context || !palette)  | 
530  | 0  |     return FALSE;  | 
531  |  |  | 
532  | 0  |   gdi = context->gdi;  | 
533  | 0  |   gdi->palette.format = gdi->dstFormat;  | 
534  |  | 
  | 
535  | 0  |   for (UINT32 index = 0; index < palette->number; index++)  | 
536  | 0  |   { | 
537  | 0  |     const PALETTE_ENTRY* pe = &(palette->entries[index]);  | 
538  | 0  |     gdi->palette.palette[index] =  | 
539  | 0  |         FreeRDPGetColor(gdi->dstFormat, pe->red, pe->green, pe->blue, 0xFF);  | 
540  | 0  |   }  | 
541  |  | 
  | 
542  | 0  |   return TRUE;  | 
543  | 0  | }  | 
544  |  |  | 
545  |  | static BOOL gdi_set_bounds(rdpContext* context, const rdpBounds* bounds)  | 
546  | 0  | { | 
547  | 0  |   rdpGdi* gdi = NULL;  | 
548  |  | 
  | 
549  | 0  |   if (!context)  | 
550  | 0  |     return FALSE;  | 
551  |  |  | 
552  | 0  |   gdi = context->gdi;  | 
553  |  | 
  | 
554  | 0  |   if (bounds)  | 
555  | 0  |   { | 
556  | 0  |     gdi_SetClipRgn(gdi->drawing->hdc, bounds->left, bounds->top,  | 
557  | 0  |                    bounds->right - bounds->left + 1, bounds->bottom - bounds->top + 1);  | 
558  | 0  |   }  | 
559  | 0  |   else  | 
560  | 0  |     gdi_SetNullClipRgn(gdi->drawing->hdc);  | 
561  |  | 
  | 
562  | 0  |   return TRUE;  | 
563  | 0  | }  | 
564  |  |  | 
565  |  | static BOOL gdi_dstblt(rdpContext* context, const DSTBLT_ORDER* dstblt)  | 
566  | 0  | { | 
567  | 0  |   rdpGdi* gdi = NULL;  | 
568  |  | 
  | 
569  | 0  |   if (!context || !dstblt)  | 
570  | 0  |     return FALSE;  | 
571  |  |  | 
572  | 0  |   gdi = context->gdi;  | 
573  | 0  |   return gdi_BitBlt(gdi->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth,  | 
574  | 0  |                     dstblt->nHeight, NULL, 0, 0, gdi_rop3_code(dstblt->bRop), &gdi->palette);  | 
575  | 0  | }  | 
576  |  |  | 
577  |  | static BOOL gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)  | 
578  | 0  | { | 
579  | 0  |   const rdpBrush* brush = &patblt->brush;  | 
580  | 0  |   UINT32 foreColor = 0;  | 
581  | 0  |   UINT32 backColor = 0;  | 
582  | 0  |   UINT32 originalColor = 0;  | 
583  | 0  |   HGDI_BRUSH originalBrush = NULL;  | 
584  | 0  |   HGDI_BRUSH hbrush = NULL;  | 
585  | 0  |   rdpGdi* gdi = context->gdi;  | 
586  | 0  |   BOOL ret = FALSE;  | 
587  | 0  |   const DWORD rop = gdi_rop3_code(patblt->bRop);  | 
588  | 0  |   INT32 nXSrc = 0;  | 
589  | 0  |   INT32 nYSrc = 0;  | 
590  | 0  |   BYTE data[8 * 8 * 4];  | 
591  | 0  |   HGDI_BITMAP hBmp = NULL;  | 
592  |  | 
  | 
593  | 0  |   if (!gdi_decode_color(gdi, patblt->foreColor, &foreColor, NULL))  | 
594  | 0  |     return FALSE;  | 
595  |  |  | 
596  | 0  |   if (!gdi_decode_color(gdi, patblt->backColor, &backColor, NULL))  | 
597  | 0  |     return FALSE;  | 
598  |  |  | 
599  | 0  |   originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);  | 
600  | 0  |   originalBrush = gdi->drawing->hdc->brush;  | 
601  |  | 
  | 
602  | 0  |   switch (brush->style)  | 
603  | 0  |   { | 
604  | 0  |     case GDI_BS_SOLID:  | 
605  | 0  |       hbrush = gdi_CreateSolidBrush(foreColor);  | 
606  | 0  |       break;  | 
607  |  |  | 
608  | 0  |     case GDI_BS_HATCHED:  | 
609  | 0  |     { | 
610  | 0  |       const BYTE* hatched = NULL;  | 
611  | 0  |       hatched = GDI_BS_HATCHED_PATTERNS + (8ULL * brush->hatch);  | 
612  |  | 
  | 
613  | 0  |       if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,  | 
614  | 0  |                                               hatched, backColor, foreColor, &gdi->palette))  | 
615  | 0  |         goto out_error;  | 
616  |  |  | 
617  | 0  |       hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);  | 
618  |  | 
  | 
619  | 0  |       if (!hBmp)  | 
620  | 0  |         goto out_error;  | 
621  |  |  | 
622  | 0  |       hbrush = gdi_CreateHatchBrush(hBmp);  | 
623  | 0  |     }  | 
624  | 0  |     break;  | 
625  |  |  | 
626  | 0  |     case GDI_BS_PATTERN:  | 
627  | 0  |     { | 
628  | 0  |       UINT32 brushFormat = 0;  | 
629  |  | 
  | 
630  | 0  |       if (brush->bpp > 1)  | 
631  | 0  |       { | 
632  | 0  |         UINT32 bpp = brush->bpp;  | 
633  |  | 
  | 
634  | 0  |         if ((bpp == 16) &&  | 
635  | 0  |             (freerdp_settings_get_uint32(context->settings, FreeRDP_ColorDepth) == 15))  | 
636  | 0  |           bpp = 15;  | 
637  |  | 
  | 
638  | 0  |         brushFormat = gdi_get_pixel_format(bpp);  | 
639  |  | 
  | 
640  | 0  |         if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,  | 
641  | 0  |                                            brush->data, brushFormat, 0, 0, 0, &gdi->palette,  | 
642  | 0  |                                            FREERDP_FLIP_NONE))  | 
643  | 0  |           goto out_error;  | 
644  | 0  |       }  | 
645  | 0  |       else  | 
646  | 0  |       { | 
647  | 0  |         if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,  | 
648  | 0  |                                                 8, brush->data, backColor, foreColor,  | 
649  | 0  |                                                 &gdi->palette))  | 
650  | 0  |           goto out_error;  | 
651  | 0  |       }  | 
652  |  |  | 
653  | 0  |       hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);  | 
654  |  | 
  | 
655  | 0  |       if (!hBmp)  | 
656  | 0  |         goto out_error;  | 
657  |  |  | 
658  | 0  |       hbrush = gdi_CreatePatternBrush(hBmp);  | 
659  | 0  |     }  | 
660  | 0  |     break;  | 
661  |  |  | 
662  | 0  |     default:  | 
663  | 0  |       WLog_ERR(TAG, "unimplemented brush style:%" PRIu32 "", brush->style);  | 
664  | 0  |       break;  | 
665  | 0  |   }  | 
666  |  |  | 
667  | 0  |   if (hbrush)  | 
668  | 0  |   { | 
669  | 0  |     hbrush->nXOrg = brush->x;  | 
670  | 0  |     hbrush->nYOrg = brush->y;  | 
671  | 0  |     gdi->drawing->hdc->brush = hbrush;  | 
672  | 0  |     ret = gdi_BitBlt(gdi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,  | 
673  | 0  |                      patblt->nHeight, gdi->primary->hdc, nXSrc, nYSrc, rop, &gdi->palette);  | 
674  | 0  |   }  | 
675  |  | 
  | 
676  | 0  | out_error:  | 
677  | 0  |   gdi_DeleteObject((HGDIOBJECT)hBmp);  | 
678  | 0  |   gdi_DeleteObject((HGDIOBJECT)hbrush);  | 
679  | 0  |   gdi->drawing->hdc->brush = originalBrush;  | 
680  | 0  |   gdi_SetTextColor(gdi->drawing->hdc, originalColor);  | 
681  | 0  |   return ret;  | 
682  | 0  | }  | 
683  |  |  | 
684  |  | static BOOL gdi_scrblt(rdpContext* context, const SCRBLT_ORDER* scrblt)  | 
685  | 0  | { | 
686  | 0  |   rdpGdi* gdi = NULL;  | 
687  |  | 
  | 
688  | 0  |   if (!context || !context->gdi)  | 
689  | 0  |     return FALSE;  | 
690  |  |  | 
691  | 0  |   gdi = context->gdi;  | 
692  | 0  |   return gdi_BitBlt(gdi->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth,  | 
693  | 0  |                     scrblt->nHeight, gdi->primary->hdc, scrblt->nXSrc, scrblt->nYSrc,  | 
694  | 0  |                     gdi_rop3_code(scrblt->bRop), &gdi->palette);  | 
695  | 0  | }  | 
696  |  |  | 
697  |  | static BOOL gdi_opaque_rect(rdpContext* context, const OPAQUE_RECT_ORDER* opaque_rect)  | 
698  | 0  | { | 
699  | 0  |   GDI_RECT rect;  | 
700  | 0  |   HGDI_BRUSH hBrush = NULL;  | 
701  | 0  |   UINT32 brush_color = 0;  | 
702  | 0  |   rdpGdi* gdi = context->gdi;  | 
703  | 0  |   BOOL ret = 0;  | 
704  | 0  |   INT32 x = opaque_rect->nLeftRect;  | 
705  | 0  |   INT32 y = opaque_rect->nTopRect;  | 
706  | 0  |   INT32 w = opaque_rect->nWidth;  | 
707  | 0  |   INT32 h = opaque_rect->nHeight;  | 
708  | 0  |   gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);  | 
709  | 0  |   gdi_CRgnToRect(x, y, w, h, &rect);  | 
710  |  | 
  | 
711  | 0  |   if (!gdi_decode_color(gdi, opaque_rect->color, &brush_color, NULL))  | 
712  | 0  |     return FALSE;  | 
713  |  |  | 
714  | 0  |   if (!(hBrush = gdi_CreateSolidBrush(brush_color)))  | 
715  | 0  |     return FALSE;  | 
716  |  |  | 
717  | 0  |   ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);  | 
718  | 0  |   gdi_DeleteObject((HGDIOBJECT)hBrush);  | 
719  | 0  |   return ret;  | 
720  | 0  | }  | 
721  |  |  | 
722  |  | static BOOL gdi_multi_opaque_rect(rdpContext* context,  | 
723  |  |                                   const MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)  | 
724  | 0  | { | 
725  | 0  |   GDI_RECT rect;  | 
726  | 0  |   HGDI_BRUSH hBrush = NULL;  | 
727  | 0  |   UINT32 brush_color = 0;  | 
728  | 0  |   rdpGdi* gdi = context->gdi;  | 
729  | 0  |   BOOL ret = TRUE;  | 
730  |  | 
  | 
731  | 0  |   if (!gdi_decode_color(gdi, multi_opaque_rect->color, &brush_color, NULL))  | 
732  | 0  |     return FALSE;  | 
733  |  |  | 
734  | 0  |   hBrush = gdi_CreateSolidBrush(brush_color);  | 
735  |  | 
  | 
736  | 0  |   if (!hBrush)  | 
737  | 0  |     return FALSE;  | 
738  |  |  | 
739  | 0  |   for (UINT32 i = 0; i < multi_opaque_rect->numRectangles; i++)  | 
740  | 0  |   { | 
741  | 0  |     const DELTA_RECT* rectangle = &multi_opaque_rect->rectangles[i];  | 
742  | 0  |     INT32 x = rectangle->left;  | 
743  | 0  |     INT32 y = rectangle->top;  | 
744  | 0  |     INT32 w = rectangle->width;  | 
745  | 0  |     INT32 h = rectangle->height;  | 
746  | 0  |     gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);  | 
747  | 0  |     gdi_CRgnToRect(x, y, w, h, &rect);  | 
748  | 0  |     ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);  | 
749  |  | 
  | 
750  | 0  |     if (!ret)  | 
751  | 0  |       break;  | 
752  | 0  |   }  | 
753  |  | 
  | 
754  | 0  |   gdi_DeleteObject((HGDIOBJECT)hBrush);  | 
755  | 0  |   return ret;  | 
756  | 0  | }  | 
757  |  |  | 
758  |  | static BOOL gdi_line_to(rdpContext* context, const LINE_TO_ORDER* lineTo)  | 
759  | 0  | { | 
760  | 0  |   UINT32 color = 0;  | 
761  | 0  |   HGDI_PEN hPen = NULL;  | 
762  | 0  |   rdpGdi* gdi = context->gdi;  | 
763  | 0  |   INT32 xStart = lineTo->nXStart;  | 
764  | 0  |   INT32 yStart = lineTo->nYStart;  | 
765  | 0  |   INT32 xEnd = lineTo->nXEnd;  | 
766  | 0  |   INT32 yEnd = lineTo->nYEnd;  | 
767  | 0  |   INT32 w = 0;  | 
768  | 0  |   INT32 h = 0;  | 
769  | 0  |   gdi_ClipCoords(gdi->drawing->hdc, &xStart, &yStart, &w, &h, NULL, NULL);  | 
770  | 0  |   gdi_ClipCoords(gdi->drawing->hdc, &xEnd, &yEnd, &w, &h, NULL, NULL);  | 
771  |  | 
  | 
772  | 0  |   if (!gdi_decode_color(gdi, lineTo->penColor, &color, NULL))  | 
773  | 0  |     return FALSE;  | 
774  |  |  | 
775  | 0  |   if (!(hPen = gdi_CreatePen(lineTo->penStyle, lineTo->penWidth, color, gdi->drawing->hdc->format,  | 
776  | 0  |                              &gdi->palette)))  | 
777  | 0  |     return FALSE;  | 
778  |  |  | 
779  | 0  |   gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT)hPen);  | 
780  | 0  |   gdi_SetROP2(gdi->drawing->hdc, lineTo->bRop2);  | 
781  | 0  |   gdi_MoveToEx(gdi->drawing->hdc, lineTo->nXStart, lineTo->nYStart, NULL);  | 
782  | 0  |   gdi_LineTo(gdi->drawing->hdc, lineTo->nXEnd, lineTo->nYEnd);  | 
783  | 0  |   gdi_DeleteObject((HGDIOBJECT)hPen);  | 
784  | 0  |   return TRUE;  | 
785  | 0  | }  | 
786  |  |  | 
787  |  | static BOOL gdi_polyline(rdpContext* context, const POLYLINE_ORDER* polyline)  | 
788  | 0  | { | 
789  | 0  |   INT32 x = 0;  | 
790  | 0  |   INT32 y = 0;  | 
791  | 0  |   UINT32 color = 0;  | 
792  | 0  |   HGDI_PEN hPen = NULL;  | 
793  | 0  |   DELTA_POINT* points = NULL;  | 
794  | 0  |   rdpGdi* gdi = context->gdi;  | 
795  | 0  |   INT32 w = 0;  | 
796  | 0  |   INT32 h = 0;  | 
797  |  | 
  | 
798  | 0  |   if (!gdi_decode_color(gdi, polyline->penColor, &color, NULL))  | 
799  | 0  |     return FALSE;  | 
800  |  |  | 
801  | 0  |   if (!(hPen = gdi_CreatePen(GDI_PS_SOLID, 1, color, gdi->drawing->hdc->format, &gdi->palette)))  | 
802  | 0  |     return FALSE;  | 
803  |  |  | 
804  | 0  |   gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT)hPen);  | 
805  | 0  |   gdi_SetROP2(gdi->drawing->hdc, polyline->bRop2);  | 
806  | 0  |   x = polyline->xStart;  | 
807  | 0  |   y = polyline->yStart;  | 
808  | 0  |   gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);  | 
809  | 0  |   gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL);  | 
810  | 0  |   points = polyline->points;  | 
811  |  | 
  | 
812  | 0  |   for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)  | 
813  | 0  |   { | 
814  | 0  |     x += points[i].x;  | 
815  | 0  |     y += points[i].y;  | 
816  | 0  |     gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);  | 
817  | 0  |     gdi_LineTo(gdi->drawing->hdc, x, y);  | 
818  | 0  |     gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL);  | 
819  | 0  |   }  | 
820  |  | 
  | 
821  | 0  |   gdi_DeleteObject((HGDIOBJECT)hPen);  | 
822  | 0  |   return TRUE;  | 
823  | 0  | }  | 
824  |  |  | 
825  |  | static BOOL gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)  | 
826  | 0  | { | 
827  | 0  |   gdiBitmap* bitmap = NULL;  | 
828  | 0  |   rdpGdi* gdi = NULL;  | 
829  |  | 
  | 
830  | 0  |   if (!context || !memblt || !context->gdi || !memblt->bitmap)  | 
831  | 0  |     return FALSE;  | 
832  |  |  | 
833  | 0  |   bitmap = (gdiBitmap*)memblt->bitmap;  | 
834  | 0  |   gdi = context->gdi;  | 
835  | 0  |   return gdi_BitBlt(gdi->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,  | 
836  | 0  |                     memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc,  | 
837  | 0  |                     gdi_rop3_code(memblt->bRop), &gdi->palette);  | 
838  | 0  | }  | 
839  |  |  | 
840  |  | static BOOL gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)  | 
841  | 0  | { | 
842  | 0  |   HGDI_BRUSH originalBrush = NULL;  | 
843  | 0  |   rdpGdi* gdi = context->gdi;  | 
844  | 0  |   BOOL ret = TRUE;  | 
845  | 0  |   const rdpBrush* brush = &mem3blt->brush;  | 
846  | 0  |   gdiBitmap* bitmap = (gdiBitmap*)mem3blt->bitmap;  | 
847  | 0  |   UINT32 foreColor = 0;  | 
848  | 0  |   UINT32 backColor = 0;  | 
849  | 0  |   UINT32 originalColor = 0;  | 
850  |  | 
  | 
851  | 0  |   if (!gdi_decode_color(gdi, mem3blt->foreColor, &foreColor, NULL))  | 
852  | 0  |     return FALSE;  | 
853  |  |  | 
854  | 0  |   if (!gdi_decode_color(gdi, mem3blt->backColor, &backColor, NULL))  | 
855  | 0  |     return FALSE;  | 
856  |  |  | 
857  | 0  |   originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);  | 
858  |  | 
  | 
859  | 0  |   switch (brush->style)  | 
860  | 0  |   { | 
861  | 0  |     case GDI_BS_SOLID:  | 
862  | 0  |       originalBrush = gdi->drawing->hdc->brush;  | 
863  | 0  |       gdi->drawing->hdc->brush = gdi_CreateSolidBrush(foreColor);  | 
864  |  | 
  | 
865  | 0  |       if (!gdi->drawing->hdc->brush)  | 
866  | 0  |       { | 
867  | 0  |         ret = FALSE;  | 
868  | 0  |         goto out_fail;  | 
869  | 0  |       }  | 
870  |  |  | 
871  | 0  |       ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,  | 
872  | 0  |                        mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,  | 
873  | 0  |                        mem3blt->nYSrc, gdi_rop3_code(mem3blt->bRop), &gdi->palette);  | 
874  | 0  |       gdi_DeleteObject((HGDIOBJECT)gdi->drawing->hdc->brush);  | 
875  | 0  |       gdi->drawing->hdc->brush = originalBrush;  | 
876  | 0  |       break;  | 
877  |  |  | 
878  | 0  |     case GDI_BS_PATTERN:  | 
879  | 0  |     { | 
880  | 0  |       HGDI_BITMAP hBmp = NULL;  | 
881  | 0  |       UINT32 brushFormat = 0;  | 
882  | 0  |       BYTE* data = (BYTE*)winpr_aligned_malloc(  | 
883  | 0  |           8ULL * 8ULL * FreeRDPGetBytesPerPixel(gdi->drawing->hdc->format), 16);  | 
884  |  | 
  | 
885  | 0  |       if (!data)  | 
886  | 0  |       { | 
887  | 0  |         ret = FALSE;  | 
888  | 0  |         goto out_fail;  | 
889  | 0  |       }  | 
890  |  |  | 
891  | 0  |       if (brush->bpp > 1)  | 
892  | 0  |       { | 
893  | 0  |         UINT32 bpp = brush->bpp;  | 
894  |  | 
  | 
895  | 0  |         const UINT32 ColorDepth =  | 
896  | 0  |             freerdp_settings_get_uint32(gdi->context->settings, FreeRDP_ColorDepth);  | 
897  | 0  |         if ((bpp == 16) && (ColorDepth == 15))  | 
898  | 0  |           bpp = 15;  | 
899  |  | 
  | 
900  | 0  |         brushFormat = gdi_get_pixel_format(bpp);  | 
901  |  | 
  | 
902  | 0  |         if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,  | 
903  | 0  |                                            brush->data, brushFormat, 0, 0, 0, &gdi->palette,  | 
904  | 0  |                                            FREERDP_FLIP_NONE))  | 
905  | 0  |         { | 
906  | 0  |           ret = FALSE;  | 
907  | 0  |           winpr_aligned_free(data);  | 
908  | 0  |           goto out_fail;  | 
909  | 0  |         }  | 
910  | 0  |       }  | 
911  | 0  |       else  | 
912  | 0  |       { | 
913  | 0  |         if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,  | 
914  | 0  |                                                 8, brush->data, backColor, foreColor,  | 
915  | 0  |                                                 &gdi->palette))  | 
916  | 0  |         { | 
917  | 0  |           ret = FALSE;  | 
918  | 0  |           winpr_aligned_free(data);  | 
919  | 0  |           goto out_fail;  | 
920  | 0  |         }  | 
921  | 0  |       }  | 
922  |  |  | 
923  | 0  |       hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->format, data);  | 
924  |  | 
  | 
925  | 0  |       if (!hBmp)  | 
926  | 0  |       { | 
927  | 0  |         ret = FALSE;  | 
928  | 0  |         winpr_aligned_free(data);  | 
929  | 0  |         goto out_fail;  | 
930  | 0  |       }  | 
931  |  |  | 
932  | 0  |       originalBrush = gdi->drawing->hdc->brush;  | 
933  | 0  |       gdi->drawing->hdc->brush = gdi_CreatePatternBrush(hBmp);  | 
934  |  | 
  | 
935  | 0  |       if (!gdi->drawing->hdc->brush)  | 
936  | 0  |       { | 
937  | 0  |         gdi_DeleteObject((HGDIOBJECT)hBmp);  | 
938  | 0  |         goto out_fail;  | 
939  | 0  |       }  | 
940  |  |  | 
941  | 0  |       gdi->drawing->hdc->brush->nXOrg = brush->x;  | 
942  | 0  |       gdi->drawing->hdc->brush->nYOrg = brush->y;  | 
943  | 0  |       ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,  | 
944  | 0  |                        mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,  | 
945  | 0  |                        mem3blt->nYSrc, gdi_rop3_code(mem3blt->bRop), &gdi->palette);  | 
946  | 0  |       gdi_DeleteObject((HGDIOBJECT)gdi->drawing->hdc->brush);  | 
947  | 0  |       gdi_DeleteObject((HGDIOBJECT)hBmp);  | 
948  | 0  |       gdi->drawing->hdc->brush = originalBrush;  | 
949  | 0  |     }  | 
950  | 0  |     break;  | 
951  |  |  | 
952  | 0  |     default:  | 
953  | 0  |       WLog_ERR(TAG, "Mem3Blt unimplemented brush style:%" PRIu32 "", brush->style);  | 
954  | 0  |       break;  | 
955  | 0  |   }  | 
956  |  |  | 
957  | 0  | out_fail:  | 
958  | 0  |   gdi_SetTextColor(gdi->drawing->hdc, originalColor);  | 
959  | 0  |   return ret;  | 
960  | 0  | }  | 
961  |  |  | 
962  |  | static BOOL gdi_polygon_sc(rdpContext* context, const POLYGON_SC_ORDER* polygon_sc)  | 
963  | 0  | { | 
964  | 0  |   WLog_WARN(TAG, "not implemented");  | 
965  | 0  |   return FALSE;  | 
966  | 0  | }  | 
967  |  |  | 
968  |  | static BOOL gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)  | 
969  | 0  | { | 
970  | 0  |   WLog_WARN(TAG, "not implemented");  | 
971  | 0  |   return FALSE;  | 
972  | 0  | }  | 
973  |  |  | 
974  |  | static BOOL gdi_ellipse_sc(rdpContext* context, const ELLIPSE_SC_ORDER* ellipse_sc)  | 
975  | 0  | { | 
976  | 0  |   WLog_WARN(TAG, "not implemented");  | 
977  | 0  |   return FALSE;  | 
978  | 0  | }  | 
979  |  |  | 
980  |  | static BOOL gdi_ellipse_cb(rdpContext* context, const ELLIPSE_CB_ORDER* ellipse_cb)  | 
981  | 0  | { | 
982  | 0  |   WLog_WARN(TAG, "not implemented");  | 
983  | 0  |   return FALSE;  | 
984  | 0  | }  | 
985  |  |  | 
986  |  | static BOOL gdi_frame_marker(rdpContext* context, const FRAME_MARKER_ORDER* frameMarker)  | 
987  | 0  | { | 
988  | 0  |   return TRUE;  | 
989  | 0  | }  | 
990  |  |  | 
991  |  | static BOOL gdi_surface_frame_marker(rdpContext* context,  | 
992  |  |                                      const SURFACE_FRAME_MARKER* surfaceFrameMarker)  | 
993  | 0  | { | 
994  | 0  |   WLog_Print(context->gdi->log, WLOG_DEBUG, "frameId %" PRIu32 " frameAction %" PRIu32 "",  | 
995  | 0  |              surfaceFrameMarker->frameId, surfaceFrameMarker->frameAction);  | 
996  |  | 
  | 
997  | 0  |   switch (surfaceFrameMarker->frameAction)  | 
998  | 0  |   { | 
999  | 0  |     case SURFACECMD_FRAMEACTION_BEGIN:  | 
1000  | 0  |       break;  | 
1001  |  |  | 
1002  | 0  |     case SURFACECMD_FRAMEACTION_END:  | 
1003  | 0  |       if (freerdp_settings_get_uint32(context->settings, FreeRDP_FrameAcknowledge) > 0)  | 
1004  | 0  |       { | 
1005  | 0  |         IFCALL(context->update->SurfaceFrameAcknowledge, context,  | 
1006  | 0  |                surfaceFrameMarker->frameId);  | 
1007  | 0  |       }  | 
1008  |  | 
  | 
1009  | 0  |       break;  | 
1010  | 0  |   }  | 
1011  |  |  | 
1012  | 0  |   return TRUE;  | 
1013  | 0  | }  | 
1014  |  |  | 
1015  |  | static BOOL intersect_rect(const rdpGdi* gdi, const SURFACE_BITS_COMMAND* cmd, RECTANGLE_16* prect)  | 
1016  | 0  | { | 
1017  | 0  |   const UINT32 w = (const UINT32)gdi->width;  | 
1018  | 0  |   const UINT32 h = (const UINT32)gdi->height;  | 
1019  |  | 
  | 
1020  | 0  |   if (cmd->destLeft > w)  | 
1021  | 0  |     return FALSE;  | 
1022  | 0  |   if (cmd->destRight > w)  | 
1023  | 0  |     return FALSE;  | 
1024  | 0  |   if (cmd->destLeft > cmd->destRight)  | 
1025  | 0  |     return FALSE;  | 
1026  | 0  |   if (cmd->destRight > UINT16_MAX)  | 
1027  | 0  |     return FALSE;  | 
1028  |  |  | 
1029  | 0  |   if (cmd->destTop > h)  | 
1030  | 0  |     return FALSE;  | 
1031  | 0  |   if (cmd->destBottom > h)  | 
1032  | 0  |     return FALSE;  | 
1033  | 0  |   if (cmd->destTop > cmd->destBottom)  | 
1034  | 0  |     return FALSE;  | 
1035  | 0  |   if (cmd->destBottom > UINT16_MAX)  | 
1036  | 0  |     return FALSE;  | 
1037  |  |  | 
1038  | 0  |   prect->left = (const UINT16)cmd->destLeft;  | 
1039  | 0  |   prect->top = (const UINT16)cmd->destTop;  | 
1040  | 0  |   prect->right = MIN((UINT16)cmd->destRight, prect->left + cmd->bmp.width);  | 
1041  | 0  |   prect->bottom = MIN((UINT16)cmd->destBottom, prect->top + cmd->bmp.height);  | 
1042  | 0  |   return TRUE;  | 
1043  | 0  | }  | 
1044  |  |  | 
1045  |  | static BOOL gdi_surface_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cmd)  | 
1046  | 0  | { | 
1047  | 0  |   BOOL result = FALSE;  | 
1048  | 0  |   DWORD format = 0;  | 
1049  | 0  |   rdpGdi* gdi = NULL;  | 
1050  | 0  |   size_t size = 0;  | 
1051  | 0  |   REGION16 region;  | 
1052  | 0  |   RECTANGLE_16 cmdRect = { 0 }; | 
1053  | 0  |   UINT32 nbRects = 0;  | 
1054  | 0  |   const RECTANGLE_16* rects = NULL;  | 
1055  |  | 
  | 
1056  | 0  |   if (!context || !cmd)  | 
1057  | 0  |     return FALSE;  | 
1058  |  |  | 
1059  | 0  |   gdi = context->gdi;  | 
1060  | 0  |   WLog_Print(  | 
1061  | 0  |       gdi->log, WLOG_DEBUG,  | 
1062  | 0  |       "destLeft %" PRIu32 " destTop %" PRIu32 " destRight %" PRIu32 " destBottom %" PRIu32 " "  | 
1063  | 0  |       "bpp %" PRIu8 " flags %" PRIx8 " codecID %" PRIu16 " width %" PRIu16 " height %" PRIu16  | 
1064  | 0  |       " length %" PRIu32 "",  | 
1065  | 0  |       cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bmp.bpp, cmd->bmp.flags,  | 
1066  | 0  |       cmd->bmp.codecID, cmd->bmp.width, cmd->bmp.height, cmd->bmp.bitmapDataLength);  | 
1067  | 0  |   region16_init(®ion);  | 
1068  |  | 
  | 
1069  | 0  |   if (!intersect_rect(gdi, cmd, &cmdRect))  | 
1070  | 0  |     goto out;  | 
1071  |  |  | 
1072  | 0  |   switch (cmd->bmp.codecID)  | 
1073  | 0  |   { | 
1074  | 0  |     case RDP_CODEC_ID_REMOTEFX:  | 
1075  | 0  |     case RDP_CODEC_ID_IMAGE_REMOTEFX:  | 
1076  | 0  |       if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData,  | 
1077  | 0  |                                cmd->bmp.bitmapDataLength, cmdRect.left, cmdRect.top,  | 
1078  | 0  |                                gdi->primary_buffer, gdi->dstFormat, gdi->stride, gdi->height,  | 
1079  | 0  |                                ®ion))  | 
1080  | 0  |       { | 
1081  | 0  |         WLog_ERR(TAG, "Failed to process RemoteFX message");  | 
1082  | 0  |         goto out;  | 
1083  | 0  |       }  | 
1084  |  |  | 
1085  | 0  |       break;  | 
1086  |  |  | 
1087  | 0  |     case RDP_CODEC_ID_NSCODEC:  | 
1088  | 0  |       format = gdi->dstFormat;  | 
1089  |  | 
  | 
1090  | 0  |       if (!nsc_process_message(  | 
1091  | 0  |               context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, cmd->bmp.height,  | 
1092  | 0  |               cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, format,  | 
1093  | 0  |               gdi->stride, cmdRect.left, cmdRect.top, cmdRect.right - cmdRect.left,  | 
1094  | 0  |               cmdRect.bottom - cmdRect.top, FREERDP_FLIP_VERTICAL))  | 
1095  | 0  |       { | 
1096  | 0  |         WLog_ERR(TAG, "Failed to process NSCodec message");  | 
1097  | 0  |         goto out;  | 
1098  | 0  |       }  | 
1099  |  |  | 
1100  | 0  |       region16_union_rect(®ion, ®ion, &cmdRect);  | 
1101  | 0  |       break;  | 
1102  |  |  | 
1103  | 0  |     case RDP_CODEC_ID_NONE:  | 
1104  | 0  |       format = gdi_get_pixel_format(cmd->bmp.bpp);  | 
1105  | 0  |       size = 1ull * cmd->bmp.width * cmd->bmp.height * FreeRDPGetBytesPerPixel(format);  | 
1106  | 0  |       if (size > cmd->bmp.bitmapDataLength)  | 
1107  | 0  |       { | 
1108  | 0  |         WLog_ERR(TAG, "Short nocodec message: got %" PRIu32 " bytes, require %" PRIuz,  | 
1109  | 0  |                  cmd->bmp.bitmapDataLength, size);  | 
1110  | 0  |         goto out;  | 
1111  | 0  |       }  | 
1112  |  |  | 
1113  | 0  |       if (!freerdp_image_copy_no_overlap(  | 
1114  | 0  |               gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmdRect.left, cmdRect.top,  | 
1115  | 0  |               cmdRect.right - cmdRect.left, cmdRect.bottom - cmdRect.top, cmd->bmp.bitmapData,  | 
1116  | 0  |               format, 0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))  | 
1117  | 0  |       { | 
1118  | 0  |         WLog_ERR(TAG, "Failed to process nocodec message");  | 
1119  | 0  |         goto out;  | 
1120  | 0  |       }  | 
1121  |  |  | 
1122  | 0  |       region16_union_rect(®ion, ®ion, &cmdRect);  | 
1123  | 0  |       break;  | 
1124  |  |  | 
1125  | 0  |     default:  | 
1126  | 0  |       WLog_ERR(TAG, "Unsupported codecID %" PRIu32 "", cmd->bmp.codecID);  | 
1127  | 0  |       break;  | 
1128  | 0  |   }  | 
1129  |  |  | 
1130  | 0  |   if (!(rects = region16_rects(®ion, &nbRects)))  | 
1131  | 0  |     goto out;  | 
1132  |  |  | 
1133  | 0  |   for (UINT32 i = 0; i < nbRects; i++)  | 
1134  | 0  |   { | 
1135  | 0  |     UINT32 left = rects[i].left;  | 
1136  | 0  |     UINT32 top = rects[i].top;  | 
1137  | 0  |     UINT32 width = rects[i].right - rects[i].left;  | 
1138  | 0  |     UINT32 height = rects[i].bottom - rects[i].top;  | 
1139  |  | 
  | 
1140  | 0  |     if (!gdi_InvalidateRegion(gdi->primary->hdc, left, top, width, height))  | 
1141  | 0  |     { | 
1142  | 0  |       WLog_ERR(TAG, "Failed to update invalid region");  | 
1143  | 0  |       goto out;  | 
1144  | 0  |     }  | 
1145  | 0  |   }  | 
1146  |  |  | 
1147  | 0  |   result = TRUE;  | 
1148  | 0  | out:  | 
1149  | 0  |   region16_uninit(®ion);  | 
1150  | 0  |   return result;  | 
1151  | 0  | }  | 
1152  |  |  | 
1153  |  | /**  | 
1154  |  |  * Register GDI callbacks with libfreerdp-core.  | 
1155  |  |  * @param update current instance  | 
1156  |  |  */  | 
1157  |  |  | 
1158  |  | static void gdi_register_update_callbacks(rdpUpdate* update)  | 
1159  | 0  | { | 
1160  | 0  |   rdpPrimaryUpdate* primary = NULL;  | 
1161  | 0  |   const rdpSettings* settings = NULL;  | 
1162  |  | 
  | 
1163  | 0  |   WINPR_ASSERT(update);  | 
1164  | 0  |   WINPR_ASSERT(update->context);  | 
1165  |  |  | 
1166  | 0  |   settings = update->context->settings;  | 
1167  | 0  |   WINPR_ASSERT(settings);  | 
1168  |  |  | 
1169  | 0  |   primary = update->primary;  | 
1170  | 0  |   WINPR_ASSERT(primary);  | 
1171  |  |  | 
1172  | 0  |   if (freerdp_settings_get_bool(settings, FreeRDP_DeactivateClientDecoding))  | 
1173  | 0  |     return;  | 
1174  | 0  |   update->Palette = gdi_palette_update;  | 
1175  | 0  |   update->SetBounds = gdi_set_bounds;  | 
1176  | 0  |   primary->DstBlt = gdi_dstblt;  | 
1177  | 0  |   primary->PatBlt = gdi_patblt;  | 
1178  | 0  |   primary->ScrBlt = gdi_scrblt;  | 
1179  | 0  |   primary->OpaqueRect = gdi_opaque_rect;  | 
1180  | 0  |   primary->DrawNineGrid = NULL;  | 
1181  | 0  |   primary->MultiDstBlt = NULL;  | 
1182  | 0  |   primary->MultiPatBlt = NULL;  | 
1183  | 0  |   primary->MultiScrBlt = NULL;  | 
1184  | 0  |   primary->MultiOpaqueRect = gdi_multi_opaque_rect;  | 
1185  | 0  |   primary->MultiDrawNineGrid = NULL;  | 
1186  | 0  |   primary->LineTo = gdi_line_to;  | 
1187  | 0  |   primary->Polyline = gdi_polyline;  | 
1188  | 0  |   primary->MemBlt = gdi_memblt;  | 
1189  | 0  |   primary->Mem3Blt = gdi_mem3blt;  | 
1190  | 0  |   primary->SaveBitmap = NULL;  | 
1191  | 0  |   primary->GlyphIndex = NULL;  | 
1192  | 0  |   primary->FastIndex = NULL;  | 
1193  | 0  |   primary->FastGlyph = NULL;  | 
1194  | 0  |   primary->PolygonSC = gdi_polygon_sc;  | 
1195  | 0  |   primary->PolygonCB = gdi_polygon_cb;  | 
1196  | 0  |   primary->EllipseSC = gdi_ellipse_sc;  | 
1197  | 0  |   primary->EllipseCB = gdi_ellipse_cb;  | 
1198  | 0  |   update->SurfaceBits = gdi_surface_bits;  | 
1199  | 0  |   update->SurfaceFrameMarker = gdi_surface_frame_marker;  | 
1200  | 0  |   update->altsec->FrameMarker = gdi_frame_marker;  | 
1201  | 0  | }  | 
1202  |  |  | 
1203  |  | static BOOL gdi_init_primary(rdpGdi* gdi, UINT32 stride, UINT32 format, BYTE* buffer,  | 
1204  |  |                              void (*pfree)(void*), BOOL isLocked)  | 
1205  | 0  | { | 
1206  | 0  |   WINPR_ASSERT(gdi);  | 
1207  | 0  |   WINPR_ASSERT(gdi->context);  | 
1208  | 0  |   WINPR_ASSERT(gdi->context->update);  | 
1209  | 0  |   if (!isLocked)  | 
1210  | 0  |     rdp_update_lock(gdi->context->update);  | 
1211  |  | 
  | 
1212  | 0  |   gdi->primary = (gdiBitmap*)calloc(1, sizeof(gdiBitmap));  | 
1213  |  | 
  | 
1214  | 0  |   if (format > 0)  | 
1215  | 0  |     gdi->dstFormat = format;  | 
1216  |  | 
  | 
1217  | 0  |   if (stride > 0)  | 
1218  | 0  |     gdi->stride = stride;  | 
1219  | 0  |   else  | 
1220  | 0  |     gdi->stride = gdi->width * FreeRDPGetBytesPerPixel(gdi->dstFormat);  | 
1221  |  | 
  | 
1222  | 0  |   if (!gdi->primary)  | 
1223  | 0  |     goto fail_primary;  | 
1224  |  |  | 
1225  | 0  |   if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc)))  | 
1226  | 0  |     goto fail_hdc;  | 
1227  |  |  | 
1228  | 0  |   if (!buffer)  | 
1229  | 0  |   { | 
1230  | 0  |     gdi->primary->bitmap = gdi_CreateCompatibleBitmap(gdi->hdc, gdi->width, gdi->height);  | 
1231  | 0  |   }  | 
1232  | 0  |   else  | 
1233  | 0  |   { | 
1234  | 0  |     gdi->primary->bitmap =  | 
1235  | 0  |         gdi_CreateBitmapEx(gdi->width, gdi->height, gdi->dstFormat, gdi->stride, buffer, pfree);  | 
1236  | 0  |   }  | 
1237  |  | 
  | 
1238  | 0  |   if (!gdi->primary->bitmap)  | 
1239  | 0  |     goto fail_bitmap;  | 
1240  |  |  | 
1241  | 0  |   gdi->stride = gdi->primary->bitmap->scanline;  | 
1242  | 0  |   gdi_SelectObject(gdi->primary->hdc, (HGDIOBJECT)gdi->primary->bitmap);  | 
1243  | 0  |   gdi->primary->org_bitmap = NULL;  | 
1244  | 0  |   gdi->primary_buffer = gdi->primary->bitmap->data;  | 
1245  |  | 
  | 
1246  | 0  |   if (!(gdi->primary->hdc->hwnd = (HGDI_WND)calloc(1, sizeof(GDI_WND))))  | 
1247  | 0  |     goto fail_hwnd;  | 
1248  |  |  | 
1249  | 0  |   if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0)))  | 
1250  | 0  |     goto fail_hwnd;  | 
1251  |  |  | 
1252  | 0  |   gdi->primary->hdc->hwnd->invalid->null = TRUE;  | 
1253  | 0  |   gdi->primary->hdc->hwnd->count = 32;  | 
1254  |  | 
  | 
1255  | 0  |   if (!(gdi->primary->hdc->hwnd->cinvalid =  | 
1256  | 0  |             (HGDI_RGN)calloc(gdi->primary->hdc->hwnd->count, sizeof(GDI_RGN))))  | 
1257  | 0  |     goto fail_hwnd;  | 
1258  |  |  | 
1259  | 0  |   gdi->primary->hdc->hwnd->ninvalid = 0;  | 
1260  |  | 
  | 
1261  | 0  |   if (!gdi->drawing)  | 
1262  | 0  |     gdi->drawing = gdi->primary;  | 
1263  |  | 
  | 
1264  | 0  |   rdp_update_unlock(gdi->context->update);  | 
1265  | 0  |   return TRUE;  | 
1266  | 0  | fail_hwnd:  | 
1267  | 0  |   gdi_DeleteObject((HGDIOBJECT)gdi->primary->bitmap);  | 
1268  | 0  | fail_bitmap:  | 
1269  | 0  |   gdi_DeleteDC(gdi->primary->hdc);  | 
1270  | 0  | fail_hdc:  | 
1271  | 0  |   free(gdi->primary);  | 
1272  | 0  |   gdi->primary = NULL;  | 
1273  | 0  | fail_primary:  | 
1274  | 0  |   rdp_update_unlock(gdi->context->update);  | 
1275  | 0  |   return FALSE;  | 
1276  | 0  | }  | 
1277  |  |  | 
1278  |  | BOOL gdi_resize(rdpGdi* gdi, UINT32 width, UINT32 height)  | 
1279  | 0  | { | 
1280  | 0  |   return gdi_resize_ex(gdi, width, height, 0, 0, NULL, NULL);  | 
1281  | 0  | }  | 
1282  |  |  | 
1283  |  | BOOL gdi_resize_ex(rdpGdi* gdi, UINT32 width, UINT32 height, UINT32 stride, UINT32 format,  | 
1284  |  |                    BYTE* buffer, void (*pfree)(void*))  | 
1285  | 0  | { | 
1286  | 0  |   if (!gdi || !gdi->primary)  | 
1287  | 0  |     return FALSE;  | 
1288  |  |  | 
1289  | 0  |   if ((width > INT32_MAX) || (height > INT32_MAX))  | 
1290  | 0  |     return FALSE;  | 
1291  |  |  | 
1292  | 0  |   if ((gdi->width == (INT32)width) && (gdi->height == (INT32)height) &&  | 
1293  | 0  |       (!buffer || (gdi->primary_buffer == buffer)))  | 
1294  | 0  |     return TRUE;  | 
1295  |  |  | 
1296  | 0  |   WINPR_ASSERT(gdi->context);  | 
1297  | 0  |   WINPR_ASSERT(gdi->context->update);  | 
1298  |  |  | 
1299  |  |   /* EndPaint might not have been called, ensure the update lock is released */  | 
1300  | 0  |   update_end_paint(gdi->context->update);  | 
1301  | 0  |   rdp_update_lock(gdi->context->update);  | 
1302  |  | 
  | 
1303  | 0  |   if (gdi->drawing == gdi->primary)  | 
1304  | 0  |     gdi->drawing = NULL;  | 
1305  |  | 
  | 
1306  | 0  |   gdi->width = (INT32)width;  | 
1307  | 0  |   gdi->height = (INT32)height;  | 
1308  | 0  |   gdi_bitmap_free_ex(gdi->primary);  | 
1309  | 0  |   gdi->primary = NULL;  | 
1310  | 0  |   gdi->primary_buffer = NULL;  | 
1311  | 0  |   return gdi_init_primary(gdi, stride, format, buffer, pfree, TRUE);  | 
1312  | 0  | }  | 
1313  |  |  | 
1314  |  | /**  | 
1315  |  |  * Initialize GDI  | 
1316  |  |  *  | 
1317  |  |  * @param instance A pointer to the instance to use  | 
1318  |  |  * @param format The color format for the local framebuffer  | 
1319  |  |  * @return \b TRUE for success, \b FALSE for failure  | 
1320  |  |  */  | 
1321  |  | BOOL gdi_init(freerdp* instance, UINT32 format)  | 
1322  | 0  | { | 
1323  | 0  |   return gdi_init_ex(instance, format, 0, NULL, winpr_aligned_free);  | 
1324  | 0  | }  | 
1325  |  |  | 
1326  |  | /**  | 
1327  |  |  * Initialize GDI  | 
1328  |  |  *  | 
1329  |  |  * @param instance A pointer to the instance to use  | 
1330  |  |  * @param format The color format for the local framebuffer  | 
1331  |  |  * @param stride The size of a framebuffer line in bytes  | 
1332  |  |  * @param buffer A pointer to a buffer to be used as framebuffer  | 
1333  |  |  * @param pfree A custom function pointer to use to free the framebuffer  | 
1334  |  |  *  | 
1335  |  |  * @return \b TRUE for success, \b FALSE for failure  | 
1336  |  |  */  | 
1337  |  | BOOL gdi_init_ex(freerdp* instance, UINT32 format, UINT32 stride, BYTE* buffer,  | 
1338  |  |                  void (*pfree)(void*))  | 
1339  | 0  | { | 
1340  | 0  |   rdpContext* context = NULL;  | 
1341  | 0  |   UINT32 SrcFormat = 0;  | 
1342  | 0  |   rdpGdi* gdi = NULL;  | 
1343  |  | 
  | 
1344  | 0  |   WINPR_ASSERT(instance);  | 
1345  |  |  | 
1346  | 0  |   context = instance->context;  | 
1347  | 0  |   WINPR_ASSERT(context);  | 
1348  | 0  |   WINPR_ASSERT(context->settings);  | 
1349  |  |  | 
1350  | 0  |   const UINT32 ColorDepth = freerdp_settings_get_uint32(context->settings, FreeRDP_ColorDepth);  | 
1351  | 0  |   SrcFormat = gdi_get_pixel_format(ColorDepth);  | 
1352  | 0  |   gdi = (rdpGdi*)calloc(1, sizeof(rdpGdi));  | 
1353  |  | 
  | 
1354  | 0  |   if (!gdi)  | 
1355  | 0  |     goto fail;  | 
1356  |  |  | 
1357  | 0  |   context->gdi = gdi;  | 
1358  | 0  |   gdi->log = WLog_Get(TAG);  | 
1359  |  | 
  | 
1360  | 0  |   if (!gdi->log)  | 
1361  | 0  |     goto fail;  | 
1362  |  |  | 
1363  | 0  |   gdi->context = context;  | 
1364  | 0  |   gdi->width = freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth);  | 
1365  | 0  |   gdi->height = freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopHeight);  | 
1366  | 0  |   gdi->dstFormat = format;  | 
1367  |  |   /* default internal buffer format */  | 
1368  | 0  |   WLog_Print(gdi->log, WLOG_INFO, "Local framebuffer format  %s",  | 
1369  | 0  |              FreeRDPGetColorFormatName(gdi->dstFormat));  | 
1370  | 0  |   WLog_Print(gdi->log, WLOG_INFO, "Remote framebuffer format %s",  | 
1371  | 0  |              FreeRDPGetColorFormatName(SrcFormat));  | 
1372  |  | 
  | 
1373  | 0  |   if (!(gdi->hdc = gdi_GetDC()))  | 
1374  | 0  |     goto fail;  | 
1375  |  |  | 
1376  | 0  |   gdi->hdc->format = gdi->dstFormat;  | 
1377  |  | 
  | 
1378  | 0  |   if (!gdi_init_primary(gdi, stride, gdi->dstFormat, buffer, pfree, FALSE))  | 
1379  | 0  |     goto fail;  | 
1380  |  |  | 
1381  | 0  |   if (!(context->cache = cache_new(context)))  | 
1382  | 0  |     goto fail;  | 
1383  |  |  | 
1384  | 0  |   gdi_register_update_callbacks(context->update);  | 
1385  | 0  |   brush_cache_register_callbacks(context->update);  | 
1386  | 0  |   glyph_cache_register_callbacks(context->update);  | 
1387  | 0  |   bitmap_cache_register_callbacks(context->update);  | 
1388  | 0  |   offscreen_cache_register_callbacks(context->update);  | 
1389  | 0  |   palette_cache_register_callbacks(context->update);  | 
1390  |  | 
  | 
1391  | 0  |   if (!gdi_register_graphics(context->graphics))  | 
1392  | 0  |     goto fail;  | 
1393  |  |  | 
1394  | 0  |   return TRUE;  | 
1395  | 0  | fail:  | 
1396  | 0  |   gdi_free(instance);  | 
1397  | 0  |   WLog_ERR(TAG, "failed to initialize gdi");  | 
1398  | 0  |   return FALSE;  | 
1399  | 0  | }  | 
1400  |  |  | 
1401  |  | void gdi_free(freerdp* instance)  | 
1402  | 0  | { | 
1403  | 0  |   rdpGdi* gdi = NULL;  | 
1404  | 0  |   rdpContext* context = NULL;  | 
1405  |  | 
  | 
1406  | 0  |   if (!instance || !instance->context)  | 
1407  | 0  |     return;  | 
1408  |  |  | 
1409  | 0  |   gdi = instance->context->gdi;  | 
1410  |  | 
  | 
1411  | 0  |   if (gdi)  | 
1412  | 0  |   { | 
1413  | 0  |     gdi_bitmap_free_ex(gdi->primary);  | 
1414  | 0  |     gdi_DeleteDC(gdi->hdc);  | 
1415  | 0  |     free(gdi);  | 
1416  | 0  |   }  | 
1417  |  | 
  | 
1418  | 0  |   context = instance->context;  | 
1419  | 0  |   cache_free(context->cache);  | 
1420  | 0  |   context->cache = NULL;  | 
1421  | 0  |   instance->context->gdi = (rdpGdi*)NULL;  | 
1422  | 0  | }  | 
1423  |  |  | 
1424  |  | BOOL gdi_send_suppress_output(rdpGdi* gdi, BOOL suppress)  | 
1425  | 0  | { | 
1426  | 0  |   RECTANGLE_16 rect;  | 
1427  | 0  |   rdpSettings* settings = NULL;  | 
1428  | 0  |   rdpUpdate* update = NULL;  | 
1429  |  | 
  | 
1430  | 0  |   if (!gdi || !gdi->context->settings || !gdi->context->update)  | 
1431  | 0  |     return FALSE;  | 
1432  |  |  | 
1433  | 0  |   if (gdi->suppressOutput == suppress)  | 
1434  | 0  |     return TRUE;  | 
1435  |  |  | 
1436  | 0  |   gdi->suppressOutput = suppress;  | 
1437  | 0  |   settings = gdi->context->settings;  | 
1438  | 0  |   update = gdi->context->update;  | 
1439  | 0  |   rect.left = 0;  | 
1440  | 0  |   rect.top = 0;  | 
1441  | 0  |   rect.right = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);  | 
1442  | 0  |   rect.bottom = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);  | 
1443  | 0  |   return update->SuppressOutput(gdi->context, !suppress, &rect);  | 
1444  | 0  | }  |