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