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