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