FreeRDP
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 */
54 typedef struct
55 {
56  DWORD code;
57  const char* name;
58 } rop_table_entry;
59 
60 static 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 */
318 static 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__)
328 static inline DWORD gdi_rop3_code_checked_int(UINT32 code, const char* file, const char* fkt,
329  size_t line)
330 {
331  WINPR_ASSERT_AT(code <= UINT8_MAX, file, fkt, line);
332  return gdi_rop3_code((UINT8)code);
333 }
334 
335 BOOL gdi_decode_color(rdpGdi* gdi, const UINT32 srcColor, UINT32* color, UINT32* format)
336 {
337  UINT32 SrcFormat = 0;
338 
339  if (!gdi || !color || !gdi->context || !gdi->context->settings)
340  return FALSE;
341 
342  const UINT32 ColorDepth =
343  freerdp_settings_get_uint32(gdi->context->settings, FreeRDP_ColorDepth);
344 
345  switch (ColorDepth)
346  {
347  case 32:
348  case 24:
349  SrcFormat = PIXEL_FORMAT_BGR24;
350  break;
351 
352  case 16:
353  SrcFormat = PIXEL_FORMAT_RGB16;
354  break;
355 
356  case 15:
357  SrcFormat = PIXEL_FORMAT_RGB15;
358  break;
359 
360  case 8:
361  SrcFormat = PIXEL_FORMAT_RGB8;
362  break;
363 
364  default:
365  return FALSE;
366  }
367 
368  if (format)
369  *format = gdi->dstFormat;
370 
371  *color = FreeRDPConvertColor(srcColor, SrcFormat, gdi->dstFormat, &gdi->palette);
372  return TRUE;
373 }
374 
375 /* GDI Helper Functions */
376 DWORD gdi_rop3_code(BYTE code)
377 {
378  return rop3_code_table[code].code;
379 }
380 
381 const char* gdi_rop3_code_string(BYTE code)
382 {
383  return rop3_code_table[code].name;
384 }
385 
386 const char* gdi_rop3_string(DWORD rop)
387 {
388  const size_t count = sizeof(rop3_code_table) / sizeof(rop3_code_table[0]);
389 
390  for (size_t x = 0; x < count; x++)
391  {
392  if (rop3_code_table[x].code == rop)
393  return rop3_code_table[x].name;
394  }
395 
396  return "UNKNOWN";
397 }
398 
399 UINT32 gdi_get_pixel_format(UINT32 bitsPerPixel)
400 {
401  UINT32 format = 0;
402 
403  switch (bitsPerPixel)
404  {
405  case 32:
406  format = PIXEL_FORMAT_BGRA32;
407  break;
408 
409  case 24:
410  format = PIXEL_FORMAT_BGR24;
411  break;
412 
413  case 16:
414  format = PIXEL_FORMAT_RGB16;
415  break;
416 
417  case 15:
418  format = PIXEL_FORMAT_RGB15;
419  break;
420 
421  case 8:
422  format = PIXEL_FORMAT_RGB8;
423  break;
424 
425  default:
426  WLog_ERR(TAG, "Unsupported color depth %" PRIu32, bitsPerPixel);
427  format = 0;
428  break;
429  }
430 
431  return format;
432 }
433 
434 gdiBitmap* gdi_bitmap_new_ex(rdpGdi* gdi, int width, int height, int bpp, BYTE* data)
435 {
436  gdiBitmap* bitmap = NULL;
437  bitmap = (gdiBitmap*)calloc(1, sizeof(gdiBitmap));
438 
439  if (!bitmap)
440  goto fail_bitmap;
441 
442  if (!(bitmap->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
443  goto fail_hdc;
444 
445  WLog_Print(gdi->log, WLOG_DEBUG, "gdi_bitmap_new: width:%d height:%d bpp:%d", width, height,
446  bpp);
447 
448  if (!data)
449  bitmap->bitmap =
450  gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, width),
451  WINPR_ASSERTING_INT_CAST(uint32_t, height));
452  else
453  bitmap->bitmap = gdi_create_bitmap(gdi, WINPR_ASSERTING_INT_CAST(uint32_t, width),
454  WINPR_ASSERTING_INT_CAST(uint32_t, height),
455  WINPR_ASSERTING_INT_CAST(uint32_t, bpp), data);
456 
457  if (!bitmap->bitmap)
458  goto fail_bitmap_bitmap;
459 
460  gdi_SelectObject(bitmap->hdc, (HGDIOBJECT)bitmap->bitmap);
461  bitmap->org_bitmap = NULL;
462  return bitmap;
463 fail_bitmap_bitmap:
464  gdi_DeleteDC(bitmap->hdc);
465 fail_hdc:
466  free(bitmap);
467 fail_bitmap:
468  return NULL;
469 }
470 
471 void gdi_bitmap_free_ex(gdiBitmap* bitmap)
472 {
473  if (bitmap)
474  {
475  gdi_SelectObject(bitmap->hdc, (HGDIOBJECT)bitmap->org_bitmap);
476  gdi_DeleteObject((HGDIOBJECT)bitmap->bitmap);
477  gdi_DeleteDC(bitmap->hdc);
478  free(bitmap);
479  }
480 }
481 
482 BOOL gdi_bitmap_update(rdpContext* context, const BITMAP_UPDATE* bitmapUpdate)
483 {
484  if (!context || !bitmapUpdate || !context->gdi || !context->codecs)
485  {
486  WLog_ERR(TAG,
487  "Invalid arguments: context=%p, bitmapUpdate=%p, context->gdi=%p, "
488  "context->codecs=%p",
489  context, bitmapUpdate, context ? context->gdi : NULL,
490  context ? context->codecs : NULL);
491  return FALSE;
492  }
493 
494  for (UINT32 index = 0; index < bitmapUpdate->number; index++)
495  {
496  BOOL rc = FALSE;
497  const BITMAP_DATA* bitmap = &(bitmapUpdate->rectangles[index]);
498  rdpBitmap* bmp = Bitmap_Alloc(context);
499 
500  if (!bmp)
501  goto fail;
502 
503  if (!Bitmap_SetDimensions(bmp, WINPR_ASSERTING_INT_CAST(UINT16, bitmap->width),
504  WINPR_ASSERTING_INT_CAST(UINT16, bitmap->height)))
505  goto fail;
506 
507  if (!Bitmap_SetRectangle(bmp, WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destLeft),
508  WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destTop),
509  WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destRight),
510  WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destBottom)))
511  goto fail;
512 
513  if (!bmp->Decompress(context, bmp, bitmap->bitmapDataStream, bitmap->width, bitmap->height,
514  bitmap->bitsPerPixel, bitmap->bitmapLength, bitmap->compressed,
515  RDP_CODEC_ID_NONE))
516  goto fail;
517 
518  if (!bmp->New(context, bmp))
519  goto fail;
520 
521  if (!bmp->Paint(context, bmp))
522  goto fail;
523 
524  rc = TRUE;
525  fail:
526  Bitmap_Free(context, bmp);
527  if (!rc)
528  return FALSE;
529  }
530 
531  return TRUE;
532 }
533 
534 static BOOL gdi_palette_update(rdpContext* context, const PALETTE_UPDATE* palette)
535 {
536  rdpGdi* gdi = NULL;
537 
538  if (!context || !palette)
539  return FALSE;
540 
541  gdi = context->gdi;
542  gdi->palette.format = gdi->dstFormat;
543 
544  for (UINT32 index = 0; index < palette->number; index++)
545  {
546  const PALETTE_ENTRY* pe = &(palette->entries[index]);
547  gdi->palette.palette[index] =
548  FreeRDPGetColor(gdi->dstFormat, pe->red, pe->green, pe->blue, 0xFF);
549  }
550 
551  return TRUE;
552 }
553 
554 static BOOL gdi_set_bounds(rdpContext* context, const rdpBounds* bounds)
555 {
556  rdpGdi* gdi = NULL;
557 
558  if (!context)
559  return FALSE;
560 
561  gdi = context->gdi;
562 
563  if (bounds)
564  {
565  gdi_SetClipRgn(gdi->drawing->hdc, bounds->left, bounds->top,
566  bounds->right - bounds->left + 1, bounds->bottom - bounds->top + 1);
567  }
568  else
569  gdi_SetNullClipRgn(gdi->drawing->hdc);
570 
571  return TRUE;
572 }
573 
574 static BOOL gdi_dstblt(rdpContext* context, const DSTBLT_ORDER* dstblt)
575 {
576  rdpGdi* gdi = NULL;
577 
578  if (!context || !dstblt)
579  return FALSE;
580 
581  gdi = context->gdi;
582  return gdi_BitBlt(gdi->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth,
583  dstblt->nHeight, NULL, 0, 0, gdi_rop3_code_checked(dstblt->bRop),
584  &gdi->palette);
585 }
586 
587 static BOOL gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
588 {
589  const rdpBrush* brush = &patblt->brush;
590  UINT32 foreColor = 0;
591  UINT32 backColor = 0;
592  UINT32 originalColor = 0;
593  HGDI_BRUSH originalBrush = NULL;
594  HGDI_BRUSH hbrush = NULL;
595  rdpGdi* gdi = context->gdi;
596  BOOL ret = FALSE;
597  const DWORD rop = gdi_rop3_code_checked(patblt->bRop);
598  INT32 nXSrc = 0;
599  INT32 nYSrc = 0;
600  BYTE data[8 * 8 * 4];
601  HGDI_BITMAP hBmp = NULL;
602 
603  if (!gdi_decode_color(gdi, patblt->foreColor, &foreColor, NULL))
604  return FALSE;
605 
606  if (!gdi_decode_color(gdi, patblt->backColor, &backColor, NULL))
607  return FALSE;
608 
609  originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
610  originalBrush = gdi->drawing->hdc->brush;
611 
612  switch (brush->style)
613  {
614  case GDI_BS_SOLID:
615  hbrush = gdi_CreateSolidBrush(foreColor);
616  break;
617 
618  case GDI_BS_HATCHED:
619  {
620  const BYTE* hatched = NULL;
621  hatched = GDI_BS_HATCHED_PATTERNS + (8ULL * brush->hatch);
622 
623  if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
624  hatched, backColor, foreColor, &gdi->palette))
625  goto out_error;
626 
627  hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
628 
629  if (!hBmp)
630  goto out_error;
631 
632  hbrush = gdi_CreateHatchBrush(hBmp);
633  }
634  break;
635 
636  case GDI_BS_PATTERN:
637  {
638  UINT32 brushFormat = 0;
639 
640  if (brush->bpp > 1)
641  {
642  UINT32 bpp = brush->bpp;
643 
644  if ((bpp == 16) &&
645  (freerdp_settings_get_uint32(context->settings, FreeRDP_ColorDepth) == 15))
646  bpp = 15;
647 
648  brushFormat = gdi_get_pixel_format(bpp);
649 
650  if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
651  brush->data, brushFormat, 0, 0, 0, &gdi->palette,
652  FREERDP_FLIP_NONE))
653  goto out_error;
654  }
655  else
656  {
657  if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
658  8, brush->data, backColor, foreColor,
659  &gdi->palette))
660  goto out_error;
661  }
662 
663  hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
664 
665  if (!hBmp)
666  goto out_error;
667 
668  hbrush = gdi_CreatePatternBrush(hBmp);
669  }
670  break;
671 
672  default:
673  WLog_ERR(TAG, "unimplemented brush style:%" PRIu32 "", brush->style);
674  break;
675  }
676 
677  if (hbrush)
678  {
679  hbrush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
680  hbrush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
681  gdi->drawing->hdc->brush = hbrush;
682  ret = gdi_BitBlt(gdi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
683  patblt->nHeight, gdi->primary->hdc, nXSrc, nYSrc, rop, &gdi->palette);
684  }
685 
686 out_error:
687  gdi_DeleteObject((HGDIOBJECT)hBmp);
688  gdi_DeleteObject((HGDIOBJECT)hbrush);
689  gdi->drawing->hdc->brush = originalBrush;
690  gdi_SetTextColor(gdi->drawing->hdc, originalColor);
691  return ret;
692 }
693 
694 static BOOL gdi_scrblt(rdpContext* context, const SCRBLT_ORDER* scrblt)
695 {
696  rdpGdi* gdi = NULL;
697 
698  if (!context || !context->gdi)
699  return FALSE;
700 
701  gdi = context->gdi;
702  return gdi_BitBlt(gdi->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth,
703  scrblt->nHeight, gdi->primary->hdc, scrblt->nXSrc, scrblt->nYSrc,
704  gdi_rop3_code_checked(scrblt->bRop), &gdi->palette);
705 }
706 
707 static BOOL gdi_opaque_rect(rdpContext* context, const OPAQUE_RECT_ORDER* opaque_rect)
708 {
709  GDI_RECT rect;
710  HGDI_BRUSH hBrush = NULL;
711  UINT32 brush_color = 0;
712  rdpGdi* gdi = context->gdi;
713  BOOL ret = 0;
714  INT32 x = opaque_rect->nLeftRect;
715  INT32 y = opaque_rect->nTopRect;
716  INT32 w = opaque_rect->nWidth;
717  INT32 h = opaque_rect->nHeight;
718  gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
719  gdi_CRgnToRect(x, y, w, h, &rect);
720 
721  if (!gdi_decode_color(gdi, opaque_rect->color, &brush_color, NULL))
722  return FALSE;
723 
724  if (!(hBrush = gdi_CreateSolidBrush(brush_color)))
725  return FALSE;
726 
727  ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
728  gdi_DeleteObject((HGDIOBJECT)hBrush);
729  return ret;
730 }
731 
732 static BOOL gdi_multi_opaque_rect(rdpContext* context,
733  const MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)
734 {
735  GDI_RECT rect;
736  HGDI_BRUSH hBrush = NULL;
737  UINT32 brush_color = 0;
738  rdpGdi* gdi = context->gdi;
739  BOOL ret = TRUE;
740 
741  if (!gdi_decode_color(gdi, multi_opaque_rect->color, &brush_color, NULL))
742  return FALSE;
743 
744  hBrush = gdi_CreateSolidBrush(brush_color);
745 
746  if (!hBrush)
747  return FALSE;
748 
749  for (UINT32 i = 0; i < multi_opaque_rect->numRectangles; i++)
750  {
751  const DELTA_RECT* rectangle = &multi_opaque_rect->rectangles[i];
752  INT32 x = rectangle->left;
753  INT32 y = rectangle->top;
754  INT32 w = rectangle->width;
755  INT32 h = rectangle->height;
756  gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
757  gdi_CRgnToRect(x, y, w, h, &rect);
758  ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
759 
760  if (!ret)
761  break;
762  }
763 
764  gdi_DeleteObject((HGDIOBJECT)hBrush);
765  return ret;
766 }
767 
768 static BOOL gdi_line_to(rdpContext* context, const LINE_TO_ORDER* lineTo)
769 {
770  UINT32 color = 0;
771  HGDI_PEN hPen = NULL;
772  rdpGdi* gdi = context->gdi;
773  INT32 xStart = lineTo->nXStart;
774  INT32 yStart = lineTo->nYStart;
775  INT32 xEnd = lineTo->nXEnd;
776  INT32 yEnd = lineTo->nYEnd;
777  INT32 w = 0;
778  INT32 h = 0;
779  gdi_ClipCoords(gdi->drawing->hdc, &xStart, &yStart, &w, &h, NULL, NULL);
780  gdi_ClipCoords(gdi->drawing->hdc, &xEnd, &yEnd, &w, &h, NULL, NULL);
781 
782  if (!gdi_decode_color(gdi, lineTo->penColor, &color, NULL))
783  return FALSE;
784 
785  if (!(hPen = gdi_CreatePen(lineTo->penStyle, lineTo->penWidth, color, gdi->drawing->hdc->format,
786  &gdi->palette)))
787  return FALSE;
788 
789  gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT)hPen);
790  gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, lineTo->bRop2));
791  gdi_MoveToEx(gdi->drawing->hdc, lineTo->nXStart, lineTo->nYStart, NULL);
792  gdi_LineTo(gdi->drawing->hdc, lineTo->nXEnd, lineTo->nYEnd);
793  gdi_DeleteObject((HGDIOBJECT)hPen);
794  return TRUE;
795 }
796 
797 static BOOL gdi_polyline(rdpContext* context, const POLYLINE_ORDER* polyline)
798 {
799  INT32 x = 0;
800  INT32 y = 0;
801  UINT32 color = 0;
802  HGDI_PEN hPen = NULL;
803  DELTA_POINT* points = NULL;
804  rdpGdi* gdi = context->gdi;
805  INT32 w = 0;
806  INT32 h = 0;
807 
808  if (!gdi_decode_color(gdi, polyline->penColor, &color, NULL))
809  return FALSE;
810 
811  if (!(hPen = gdi_CreatePen(GDI_PS_SOLID, 1, color, gdi->drawing->hdc->format, &gdi->palette)))
812  return FALSE;
813 
814  gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT)hPen);
815  gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, polyline->bRop2));
816  x = polyline->xStart;
817  y = polyline->yStart;
818  gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
819  gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL);
820  points = polyline->points;
821 
822  for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
823  {
824  x += points[i].x;
825  y += points[i].y;
826  gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
827  gdi_LineTo(gdi->drawing->hdc, x, y);
828  gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL);
829  }
830 
831  gdi_DeleteObject((HGDIOBJECT)hPen);
832  return TRUE;
833 }
834 
835 static BOOL gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
836 {
837  gdiBitmap* bitmap = NULL;
838  rdpGdi* gdi = NULL;
839 
840  if (!context || !memblt || !context->gdi || !memblt->bitmap)
841  return FALSE;
842 
843  bitmap = (gdiBitmap*)memblt->bitmap;
844  gdi = context->gdi;
845  return gdi_BitBlt(gdi->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
846  memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc,
847  gdi_rop3_code_checked(memblt->bRop), &gdi->palette);
848 }
849 
850 static BOOL gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
851 {
852  HGDI_BRUSH originalBrush = NULL;
853  rdpGdi* gdi = context->gdi;
854  BOOL ret = TRUE;
855  const rdpBrush* brush = &mem3blt->brush;
856  gdiBitmap* bitmap = (gdiBitmap*)mem3blt->bitmap;
857  UINT32 foreColor = 0;
858  UINT32 backColor = 0;
859  UINT32 originalColor = 0;
860 
861  if (!gdi_decode_color(gdi, mem3blt->foreColor, &foreColor, NULL))
862  return FALSE;
863 
864  if (!gdi_decode_color(gdi, mem3blt->backColor, &backColor, NULL))
865  return FALSE;
866 
867  originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
868 
869  switch (brush->style)
870  {
871  case GDI_BS_SOLID:
872  originalBrush = gdi->drawing->hdc->brush;
873  gdi->drawing->hdc->brush = gdi_CreateSolidBrush(foreColor);
874 
875  if (!gdi->drawing->hdc->brush)
876  {
877  ret = FALSE;
878  goto out_fail;
879  }
880 
881  ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
882  mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
883  mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
884  gdi_DeleteObject((HGDIOBJECT)gdi->drawing->hdc->brush);
885  gdi->drawing->hdc->brush = originalBrush;
886  break;
887 
888  case GDI_BS_PATTERN:
889  {
890  HGDI_BITMAP hBmp = NULL;
891  UINT32 brushFormat = 0;
892  BYTE* data = (BYTE*)winpr_aligned_malloc(
893  8ULL * 8ULL * FreeRDPGetBytesPerPixel(gdi->drawing->hdc->format), 16);
894 
895  if (!data)
896  {
897  ret = FALSE;
898  goto out_fail;
899  }
900 
901  if (brush->bpp > 1)
902  {
903  UINT32 bpp = brush->bpp;
904 
905  const UINT32 ColorDepth =
906  freerdp_settings_get_uint32(gdi->context->settings, FreeRDP_ColorDepth);
907  if ((bpp == 16) && (ColorDepth == 15))
908  bpp = 15;
909 
910  brushFormat = gdi_get_pixel_format(bpp);
911 
912  if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
913  brush->data, brushFormat, 0, 0, 0, &gdi->palette,
914  FREERDP_FLIP_NONE))
915  {
916  ret = FALSE;
917  winpr_aligned_free(data);
918  goto out_fail;
919  }
920  }
921  else
922  {
923  if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
924  8, brush->data, backColor, foreColor,
925  &gdi->palette))
926  {
927  ret = FALSE;
928  winpr_aligned_free(data);
929  goto out_fail;
930  }
931  }
932 
933  hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->format, data);
934 
935  if (!hBmp)
936  {
937  ret = FALSE;
938  winpr_aligned_free(data);
939  goto out_fail;
940  }
941 
942  originalBrush = gdi->drawing->hdc->brush;
943  gdi->drawing->hdc->brush = gdi_CreatePatternBrush(hBmp);
944 
945  if (!gdi->drawing->hdc->brush)
946  {
947  gdi_DeleteObject((HGDIOBJECT)hBmp);
948  goto out_fail;
949  }
950 
951  gdi->drawing->hdc->brush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
952  gdi->drawing->hdc->brush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
953  ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
954  mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
955  mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
956  gdi_DeleteObject((HGDIOBJECT)gdi->drawing->hdc->brush);
957  gdi_DeleteObject((HGDIOBJECT)hBmp);
958  gdi->drawing->hdc->brush = originalBrush;
959  }
960  break;
961 
962  default:
963  WLog_ERR(TAG, "Mem3Blt unimplemented brush style:%" PRIu32 "", brush->style);
964  break;
965  }
966 
967 out_fail:
968  gdi_SetTextColor(gdi->drawing->hdc, originalColor);
969  return ret;
970 }
971 
972 static BOOL gdi_polygon_sc(rdpContext* context, const POLYGON_SC_ORDER* polygon_sc)
973 {
974  WLog_WARN(TAG, "not implemented");
975  return FALSE;
976 }
977 
978 static BOOL gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
979 {
980  WLog_WARN(TAG, "not implemented");
981  return FALSE;
982 }
983 
984 static BOOL gdi_ellipse_sc(rdpContext* context, const ELLIPSE_SC_ORDER* ellipse_sc)
985 {
986  WLog_WARN(TAG, "not implemented");
987  return FALSE;
988 }
989 
990 static BOOL gdi_ellipse_cb(rdpContext* context, const ELLIPSE_CB_ORDER* ellipse_cb)
991 {
992  WLog_WARN(TAG, "not implemented");
993  return FALSE;
994 }
995 
996 static BOOL gdi_frame_marker(rdpContext* context, const FRAME_MARKER_ORDER* frameMarker)
997 {
998  return TRUE;
999 }
1000 
1001 static BOOL gdi_surface_frame_marker(rdpContext* context,
1002  const SURFACE_FRAME_MARKER* surfaceFrameMarker)
1003 {
1004  WLog_Print(context->gdi->log, WLOG_DEBUG, "frameId %" PRIu32 " frameAction %" PRIu32 "",
1005  surfaceFrameMarker->frameId, surfaceFrameMarker->frameAction);
1006 
1007  switch (surfaceFrameMarker->frameAction)
1008  {
1009  case SURFACECMD_FRAMEACTION_BEGIN:
1010  break;
1011 
1012  case SURFACECMD_FRAMEACTION_END:
1013  if (freerdp_settings_get_uint32(context->settings, FreeRDP_FrameAcknowledge) > 0)
1014  {
1015  IFCALL(context->update->SurfaceFrameAcknowledge, context,
1016  surfaceFrameMarker->frameId);
1017  }
1018 
1019  break;
1020  default:
1021  break;
1022  }
1023 
1024  return TRUE;
1025 }
1026 
1027 static BOOL intersect_rect(const rdpGdi* gdi, const SURFACE_BITS_COMMAND* cmd, RECTANGLE_16* prect)
1028 {
1029  const UINT32 w = (const UINT32)gdi->width;
1030  const UINT32 h = (const UINT32)gdi->height;
1031 
1032  if (cmd->destLeft > w)
1033  return FALSE;
1034  if (cmd->destRight > w)
1035  return FALSE;
1036  if (cmd->destLeft > cmd->destRight)
1037  return FALSE;
1038  if (cmd->destRight > UINT16_MAX)
1039  return FALSE;
1040 
1041  if (cmd->destTop > h)
1042  return FALSE;
1043  if (cmd->destBottom > h)
1044  return FALSE;
1045  if (cmd->destTop > cmd->destBottom)
1046  return FALSE;
1047  if (cmd->destBottom > UINT16_MAX)
1048  return FALSE;
1049 
1050  prect->left = (const UINT16)cmd->destLeft;
1051  prect->top = (const UINT16)cmd->destTop;
1052  prect->right = MIN((UINT16)cmd->destRight, prect->left + cmd->bmp.width);
1053  prect->bottom = MIN((UINT16)cmd->destBottom, prect->top + cmd->bmp.height);
1054  return TRUE;
1055 }
1056 
1057 static BOOL gdi_surface_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cmd)
1058 {
1059  BOOL result = FALSE;
1060  DWORD format = 0;
1061  rdpGdi* gdi = NULL;
1062  size_t size = 0;
1063  REGION16 region;
1064  RECTANGLE_16 cmdRect = { 0 };
1065  UINT32 nbRects = 0;
1066  const RECTANGLE_16* rects = NULL;
1067 
1068  if (!context || !cmd)
1069  return FALSE;
1070 
1071  gdi = context->gdi;
1072  WLog_Print(
1073  gdi->log, WLOG_DEBUG,
1074  "destLeft %" PRIu32 " destTop %" PRIu32 " destRight %" PRIu32 " destBottom %" PRIu32 " "
1075  "bpp %" PRIu8 " flags %" PRIx8 " codecID %" PRIu16 " width %" PRIu16 " height %" PRIu16
1076  " length %" PRIu32 "",
1077  cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bmp.bpp, cmd->bmp.flags,
1078  cmd->bmp.codecID, cmd->bmp.width, cmd->bmp.height, cmd->bmp.bitmapDataLength);
1079  region16_init(&region);
1080 
1081  if (!intersect_rect(gdi, cmd, &cmdRect))
1082  goto out;
1083 
1084  switch (cmd->bmp.codecID)
1085  {
1086  case RDP_CODEC_ID_REMOTEFX:
1087  case RDP_CODEC_ID_IMAGE_REMOTEFX:
1088  if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData,
1089  cmd->bmp.bitmapDataLength, cmdRect.left, cmdRect.top,
1090  gdi->primary_buffer, gdi->dstFormat, gdi->stride,
1091  WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height), &region))
1092  {
1093  WLog_ERR(TAG, "Failed to process RemoteFX message");
1094  goto out;
1095  }
1096 
1097  break;
1098 
1099  case RDP_CODEC_ID_NSCODEC:
1100  format = gdi->dstFormat;
1101 
1102  if (!nsc_process_message(
1103  context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, cmd->bmp.height,
1104  cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, format,
1105  gdi->stride, cmdRect.left, cmdRect.top, cmdRect.right - cmdRect.left,
1106  cmdRect.bottom - cmdRect.top, FREERDP_FLIP_VERTICAL))
1107  {
1108  WLog_ERR(TAG, "Failed to process NSCodec message");
1109  goto out;
1110  }
1111 
1112  region16_union_rect(&region, &region, &cmdRect);
1113  break;
1114 
1115  case RDP_CODEC_ID_NONE:
1116  format = gdi_get_pixel_format(cmd->bmp.bpp);
1117  size = 1ull * cmd->bmp.width * cmd->bmp.height * FreeRDPGetBytesPerPixel(format);
1118  if (size > cmd->bmp.bitmapDataLength)
1119  {
1120  WLog_ERR(TAG, "Short nocodec message: got %" PRIu32 " bytes, require %" PRIuz,
1121  cmd->bmp.bitmapDataLength, size);
1122  goto out;
1123  }
1124 
1125  if (!freerdp_image_copy_no_overlap(
1126  gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmdRect.left, cmdRect.top,
1127  cmdRect.right - cmdRect.left, cmdRect.bottom - cmdRect.top, cmd->bmp.bitmapData,
1128  format, 0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))
1129  {
1130  WLog_ERR(TAG, "Failed to process nocodec message");
1131  goto out;
1132  }
1133 
1134  region16_union_rect(&region, &region, &cmdRect);
1135  break;
1136 
1137  default:
1138  WLog_ERR(TAG, "Unsupported codecID %" PRIu32 "", cmd->bmp.codecID);
1139  break;
1140  }
1141 
1142  if (!(rects = region16_rects(&region, &nbRects)))
1143  goto out;
1144 
1145  for (UINT32 i = 0; i < nbRects; i++)
1146  {
1147  UINT32 left = rects[i].left;
1148  UINT32 top = rects[i].top;
1149  UINT32 width = rects[i].right - rects[i].left;
1150  UINT32 height = rects[i].bottom - rects[i].top;
1151 
1152  if (!gdi_InvalidateRegion(gdi->primary->hdc, WINPR_ASSERTING_INT_CAST(int32_t, left),
1153  WINPR_ASSERTING_INT_CAST(int32_t, top),
1154  WINPR_ASSERTING_INT_CAST(int32_t, width),
1155  WINPR_ASSERTING_INT_CAST(int32_t, height)))
1156  {
1157  WLog_ERR(TAG, "Failed to update invalid region");
1158  goto out;
1159  }
1160  }
1161 
1162  result = TRUE;
1163 out:
1164  region16_uninit(&region);
1165  return result;
1166 }
1167 
1173 static void gdi_register_update_callbacks(rdpUpdate* update)
1174 {
1175  rdpPrimaryUpdate* primary = NULL;
1176  const rdpSettings* settings = NULL;
1177 
1178  WINPR_ASSERT(update);
1179  WINPR_ASSERT(update->context);
1180 
1181  settings = update->context->settings;
1182  WINPR_ASSERT(settings);
1183 
1184  primary = update->primary;
1185  WINPR_ASSERT(primary);
1186 
1187  if (freerdp_settings_get_bool(settings, FreeRDP_DeactivateClientDecoding))
1188  return;
1189  update->Palette = gdi_palette_update;
1190  update->SetBounds = gdi_set_bounds;
1191  primary->DstBlt = gdi_dstblt;
1192  primary->PatBlt = gdi_patblt;
1193  primary->ScrBlt = gdi_scrblt;
1194  primary->OpaqueRect = gdi_opaque_rect;
1195  primary->DrawNineGrid = NULL;
1196  primary->MultiDstBlt = NULL;
1197  primary->MultiPatBlt = NULL;
1198  primary->MultiScrBlt = NULL;
1199  primary->MultiOpaqueRect = gdi_multi_opaque_rect;
1200  primary->MultiDrawNineGrid = NULL;
1201  primary->LineTo = gdi_line_to;
1202  primary->Polyline = gdi_polyline;
1203  primary->MemBlt = gdi_memblt;
1204  primary->Mem3Blt = gdi_mem3blt;
1205  primary->SaveBitmap = NULL;
1206  primary->GlyphIndex = NULL;
1207  primary->FastIndex = NULL;
1208  primary->FastGlyph = NULL;
1209  primary->PolygonSC = gdi_polygon_sc;
1210  primary->PolygonCB = gdi_polygon_cb;
1211  primary->EllipseSC = gdi_ellipse_sc;
1212  primary->EllipseCB = gdi_ellipse_cb;
1213  update->SurfaceBits = gdi_surface_bits;
1214  update->SurfaceFrameMarker = gdi_surface_frame_marker;
1215  update->altsec->FrameMarker = gdi_frame_marker;
1216 }
1217 
1218 static BOOL gdi_init_primary(rdpGdi* gdi, UINT32 stride, UINT32 format, BYTE* buffer,
1219  void (*pfree)(void*), BOOL isLocked)
1220 {
1221  WINPR_ASSERT(gdi);
1222  WINPR_ASSERT(gdi->context);
1223  WINPR_ASSERT(gdi->context->update);
1224  if (!isLocked)
1225  rdp_update_lock(gdi->context->update);
1226 
1227  gdi->primary = (gdiBitmap*)calloc(1, sizeof(gdiBitmap));
1228 
1229  if (format > 0)
1230  gdi->dstFormat = format;
1231 
1232  if (stride > 0)
1233  gdi->stride = stride;
1234  else
1235  gdi->stride = WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width) *
1236  FreeRDPGetBytesPerPixel(gdi->dstFormat);
1237 
1238  if (!gdi->primary)
1239  goto fail_primary;
1240 
1241  if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
1242  goto fail_hdc;
1243 
1244  if (!buffer)
1245  {
1246  gdi->primary->bitmap =
1247  gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1248  WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height));
1249  }
1250  else
1251  {
1252  gdi->primary->bitmap = gdi_CreateBitmapEx(WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1253  WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height),
1254  gdi->dstFormat, gdi->stride, buffer, pfree);
1255  }
1256 
1257  if (!gdi->primary->bitmap)
1258  goto fail_bitmap;
1259 
1260  gdi->stride = gdi->primary->bitmap->scanline;
1261  gdi_SelectObject(gdi->primary->hdc, (HGDIOBJECT)gdi->primary->bitmap);
1262  gdi->primary->org_bitmap = NULL;
1263  gdi->primary_buffer = gdi->primary->bitmap->data;
1264 
1265  if (!(gdi->primary->hdc->hwnd = (HGDI_WND)calloc(1, sizeof(GDI_WND))))
1266  goto fail_hwnd;
1267 
1268  if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0)))
1269  goto fail_hwnd;
1270 
1271  gdi->primary->hdc->hwnd->invalid->null = TRUE;
1272  gdi->primary->hdc->hwnd->count = 32;
1273 
1274  if (!(gdi->primary->hdc->hwnd->cinvalid =
1275  (HGDI_RGN)calloc(gdi->primary->hdc->hwnd->count, sizeof(GDI_RGN))))
1276  goto fail_hwnd;
1277 
1278  gdi->primary->hdc->hwnd->ninvalid = 0;
1279 
1280  if (!gdi->drawing)
1281  gdi->drawing = gdi->primary;
1282 
1283  rdp_update_unlock(gdi->context->update);
1284  return TRUE;
1285 fail_hwnd:
1286  gdi_DeleteObject((HGDIOBJECT)gdi->primary->bitmap);
1287 fail_bitmap:
1288  gdi_DeleteDC(gdi->primary->hdc);
1289 fail_hdc:
1290  free(gdi->primary);
1291  gdi->primary = NULL;
1292 fail_primary:
1293  rdp_update_unlock(gdi->context->update);
1294  return FALSE;
1295 }
1296 
1297 BOOL gdi_resize(rdpGdi* gdi, UINT32 width, UINT32 height)
1298 {
1299  return gdi_resize_ex(gdi, width, height, 0, 0, NULL, NULL);
1300 }
1301 
1302 BOOL gdi_resize_ex(rdpGdi* gdi, UINT32 width, UINT32 height, UINT32 stride, UINT32 format,
1303  BYTE* buffer, void (*pfree)(void*))
1304 {
1305  if (!gdi || !gdi->primary)
1306  return FALSE;
1307 
1308  if ((width > INT32_MAX) || (height > INT32_MAX))
1309  return FALSE;
1310 
1311  if ((gdi->width == (INT32)width) && (gdi->height == (INT32)height) &&
1312  (!buffer || (gdi->primary_buffer == buffer)))
1313  return TRUE;
1314 
1315  WINPR_ASSERT(gdi->context);
1316  WINPR_ASSERT(gdi->context->update);
1317 
1318  /* EndPaint might not have been called, ensure the update lock is released */
1319  update_end_paint(gdi->context->update);
1320  rdp_update_lock(gdi->context->update);
1321 
1322  if (gdi->drawing == gdi->primary)
1323  gdi->drawing = NULL;
1324 
1325  gdi->width = (INT32)width;
1326  gdi->height = (INT32)height;
1327  gdi_bitmap_free_ex(gdi->primary);
1328  gdi->primary = NULL;
1329  gdi->primary_buffer = NULL;
1330  return gdi_init_primary(gdi, stride, format, buffer, pfree, TRUE);
1331 }
1332 
1340 BOOL gdi_init(freerdp* instance, UINT32 format)
1341 {
1342  return gdi_init_ex(instance, format, 0, NULL, winpr_aligned_free);
1343 }
1344 
1356 BOOL gdi_init_ex(freerdp* instance, UINT32 format, UINT32 stride, BYTE* buffer,
1357  void (*pfree)(void*))
1358 {
1359  rdpContext* context = NULL;
1360  UINT32 SrcFormat = 0;
1361  rdpGdi* gdi = NULL;
1362 
1363  WINPR_ASSERT(instance);
1364 
1365  context = instance->context;
1366  WINPR_ASSERT(context);
1367  WINPR_ASSERT(context->settings);
1368 
1369  const UINT32 ColorDepth = freerdp_settings_get_uint32(context->settings, FreeRDP_ColorDepth);
1370  SrcFormat = gdi_get_pixel_format(ColorDepth);
1371  gdi = (rdpGdi*)calloc(1, sizeof(rdpGdi));
1372 
1373  if (!gdi)
1374  goto fail;
1375 
1376  context->gdi = gdi;
1377  gdi->log = WLog_Get(TAG);
1378 
1379  if (!gdi->log)
1380  goto fail;
1381 
1382  gdi->context = context;
1383  gdi->width = WINPR_ASSERTING_INT_CAST(
1384  int32_t, freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth));
1385  gdi->height = WINPR_ASSERTING_INT_CAST(
1386  int32_t, freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopHeight));
1387  gdi->dstFormat = format;
1388  /* default internal buffer format */
1389  WLog_Print(gdi->log, WLOG_INFO, "Local framebuffer format %s",
1390  FreeRDPGetColorFormatName(gdi->dstFormat));
1391  WLog_Print(gdi->log, WLOG_INFO, "Remote framebuffer format %s",
1392  FreeRDPGetColorFormatName(SrcFormat));
1393 
1394  if (!(gdi->hdc = gdi_GetDC()))
1395  goto fail;
1396 
1397  gdi->hdc->format = gdi->dstFormat;
1398 
1399  if (!gdi_init_primary(gdi, stride, gdi->dstFormat, buffer, pfree, FALSE))
1400  goto fail;
1401 
1402  if (!(context->cache = cache_new(context)))
1403  goto fail;
1404 
1405  gdi_register_update_callbacks(context->update);
1406  brush_cache_register_callbacks(context->update);
1407  glyph_cache_register_callbacks(context->update);
1408  bitmap_cache_register_callbacks(context->update);
1409  offscreen_cache_register_callbacks(context->update);
1410  palette_cache_register_callbacks(context->update);
1411 
1412  if (!gdi_register_graphics(context->graphics))
1413  goto fail;
1414 
1415  return TRUE;
1416 fail:
1417  gdi_free(instance);
1418  WLog_ERR(TAG, "failed to initialize gdi");
1419  return FALSE;
1420 }
1421 
1422 void gdi_free(freerdp* instance)
1423 {
1424  rdpGdi* gdi = NULL;
1425  rdpContext* context = NULL;
1426 
1427  if (!instance || !instance->context)
1428  return;
1429 
1430  gdi = instance->context->gdi;
1431 
1432  if (gdi)
1433  {
1434  gdi_bitmap_free_ex(gdi->primary);
1435  gdi_DeleteDC(gdi->hdc);
1436  free(gdi);
1437  }
1438 
1439  context = instance->context;
1440  cache_free(context->cache);
1441  context->cache = NULL;
1442  instance->context->gdi = (rdpGdi*)NULL;
1443 }
1444 
1445 BOOL gdi_send_suppress_output(rdpGdi* gdi, BOOL suppress)
1446 {
1447  RECTANGLE_16 rect;
1448  rdpSettings* settings = NULL;
1449  rdpUpdate* update = NULL;
1450 
1451  if (!gdi || !gdi->context->settings || !gdi->context->update)
1452  return FALSE;
1453 
1454  if (gdi->suppressOutput == suppress)
1455  return TRUE;
1456 
1457  gdi->suppressOutput = suppress;
1458  settings = gdi->context->settings;
1459  update = gdi->context->update;
1460  rect.left = 0;
1461  rect.top = 0;
1462 
1463  const UINT32 w = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
1464  const UINT32 h = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
1465  rect.right = WINPR_ASSERTING_INT_CAST(UINT16, w);
1466  rect.bottom = WINPR_ASSERTING_INT_CAST(UINT16, h);
1467  return update->SuppressOutput(gdi->context, !suppress, &rect);
1468 }
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