22 #include <freerdp/config.h>
27 #include <winpr/crt.h>
28 #include <winpr/assert.h>
29 #include <winpr/cast.h>
31 #include <freerdp/api.h>
32 #include <freerdp/log.h>
33 #include <freerdp/freerdp.h>
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>
47 #include "../core/graphics.h"
48 #include "../core/update.h"
49 #include "../cache/cache.h"
51 #define TAG FREERDP_TAG("gdi")
60 static const rop_table_entry rop3_code_table[] = { { GDI_BLACKNESS,
"0" },
61 { GDI_DPSoon,
"DPSoon" },
62 { GDI_DPSona,
"DPSona" },
64 { GDI_SDPona,
"SDPona" },
66 { GDI_PDSxnon,
"PDSxnon" },
67 { GDI_PDSaon,
"PDSaon" },
68 { GDI_SDPnaa,
"SDPnaa" },
69 { GDI_PDSxon,
"PDSxon" },
71 { GDI_PSDnaon,
"PSDnaon" },
73 { GDI_PDSnaon,
"PDSnaon" },
74 { GDI_PDSonon,
"PDSonon" },
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" },
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" },
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" },
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" },
311 { GDI_PATPAINT,
"DPSnoo" },
313 { GDI_PSDnoo,
"PSDnoo" },
314 { GDI_DPSoo,
"DPSoo" },
315 { GDI_WHITENESS,
"1" } };
318 static const BYTE GDI_BS_HATCHED_PATTERNS[] = {
319 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
320 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7,
321 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F,
322 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE,
323 0xF7, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0xF7, 0xF7,
324 0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E
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,
331 WINPR_ASSERT_AT(code <= UINT8_MAX, file, fkt, line);
332 return gdi_rop3_code((UINT8)code);
335 BOOL gdi_decode_color(rdpGdi* gdi,
const UINT32 srcColor, UINT32* color, UINT32* format)
337 UINT32 SrcFormat = 0;
339 if (!gdi || !color || !gdi->context || !gdi->context->settings)
342 const UINT32 ColorDepth =
349 SrcFormat = PIXEL_FORMAT_BGR24;
353 SrcFormat = PIXEL_FORMAT_RGB16;
357 SrcFormat = PIXEL_FORMAT_RGB15;
361 SrcFormat = PIXEL_FORMAT_RGB8;
369 *format = gdi->dstFormat;
371 *color = FreeRDPConvertColor(srcColor, SrcFormat, gdi->dstFormat, &gdi->palette);
376 DWORD gdi_rop3_code(BYTE code)
378 return rop3_code_table[code].code;
381 const char* gdi_rop3_code_string(BYTE code)
383 return rop3_code_table[code].name;
386 const char* gdi_rop3_string(DWORD rop)
388 const size_t count =
sizeof(rop3_code_table) /
sizeof(rop3_code_table[0]);
390 for (
size_t x = 0; x < count; x++)
392 if (rop3_code_table[x].code == rop)
393 return rop3_code_table[x].name;
399 UINT32 gdi_get_pixel_format(UINT32 bitsPerPixel)
403 switch (bitsPerPixel)
406 format = PIXEL_FORMAT_BGRA32;
410 format = PIXEL_FORMAT_BGR24;
414 format = PIXEL_FORMAT_RGB16;
418 format = PIXEL_FORMAT_RGB15;
422 format = PIXEL_FORMAT_RGB8;
426 WLog_ERR(TAG,
"Unsupported color depth %" PRIu32, bitsPerPixel);
434 gdiBitmap* gdi_bitmap_new_ex(rdpGdi* gdi,
int width,
int height,
int bpp, BYTE* data)
436 gdiBitmap* bitmap = NULL;
437 bitmap = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
442 if (!(bitmap->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
445 WLog_Print(gdi->log, WLOG_DEBUG,
"gdi_bitmap_new: width:%d height:%d bpp:%d", width, height,
450 gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, width),
451 WINPR_ASSERTING_INT_CAST(uint32_t, height));
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);
458 goto fail_bitmap_bitmap;
460 gdi_SelectObject(bitmap->hdc, (
HGDIOBJECT)bitmap->bitmap);
461 bitmap->org_bitmap = NULL;
464 gdi_DeleteDC(bitmap->hdc);
471 void gdi_bitmap_free_ex(gdiBitmap* bitmap)
475 gdi_SelectObject(bitmap->hdc, (
HGDIOBJECT)bitmap->org_bitmap);
477 gdi_DeleteDC(bitmap->hdc);
482 BOOL gdi_bitmap_update(rdpContext* context,
const BITMAP_UPDATE* bitmapUpdate)
484 if (!context || !bitmapUpdate || !context->gdi || !context->codecs)
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);
494 for (UINT32 index = 0; index < bitmapUpdate->number; index++)
497 const BITMAP_DATA* bitmap = &(bitmapUpdate->rectangles[index]);
498 rdpBitmap* bmp = Bitmap_Alloc(context);
503 if (!Bitmap_SetDimensions(bmp, WINPR_ASSERTING_INT_CAST(UINT16, bitmap->width),
504 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->height)))
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)))
513 if (!bmp->Decompress(context, bmp, bitmap->bitmapDataStream, bitmap->width, bitmap->height,
514 bitmap->bitsPerPixel, bitmap->bitmapLength, bitmap->compressed,
518 if (!bmp->New(context, bmp))
521 if (!bmp->Paint(context, bmp))
526 Bitmap_Free(context, bmp);
534 static BOOL gdi_palette_update(rdpContext* context,
const PALETTE_UPDATE* palette)
538 if (!context || !palette)
542 gdi->palette.format = gdi->dstFormat;
544 for (UINT32 index = 0; index < palette->number; index++)
547 gdi->palette.palette[index] =
548 FreeRDPGetColor(gdi->dstFormat, pe->red, pe->green, pe->blue, 0xFF);
554 static BOOL gdi_set_bounds(rdpContext* context,
const rdpBounds* bounds)
565 gdi_SetClipRgn(gdi->drawing->hdc, bounds->left, bounds->top,
566 bounds->right - bounds->left + 1, bounds->bottom - bounds->top + 1);
569 gdi_SetNullClipRgn(gdi->drawing->hdc);
574 static BOOL gdi_dstblt(rdpContext* context,
const DSTBLT_ORDER* dstblt)
578 if (!context || !dstblt)
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),
587 static BOOL gdi_patblt(rdpContext* context,
PATBLT_ORDER* patblt)
589 const rdpBrush* brush = &patblt->brush;
590 UINT32 foreColor = 0;
591 UINT32 backColor = 0;
592 UINT32 originalColor = 0;
595 rdpGdi* gdi = context->gdi;
597 const DWORD rop = gdi_rop3_code_checked(patblt->bRop);
600 BYTE data[8 * 8 * 4];
603 if (!gdi_decode_color(gdi, patblt->foreColor, &foreColor, NULL))
606 if (!gdi_decode_color(gdi, patblt->backColor, &backColor, NULL))
609 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
610 originalBrush = gdi->drawing->hdc->brush;
612 switch (brush->style)
615 hbrush = gdi_CreateSolidBrush(foreColor);
620 const BYTE* hatched = NULL;
621 hatched = GDI_BS_HATCHED_PATTERNS + (8ULL * brush->hatch);
623 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
624 hatched, backColor, foreColor, &gdi->palette))
627 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
632 hbrush = gdi_CreateHatchBrush(hBmp);
638 UINT32 brushFormat = 0;
642 UINT32 bpp = brush->bpp;
648 brushFormat = gdi_get_pixel_format(bpp);
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,
657 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
658 8, brush->data, backColor, foreColor,
663 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
668 hbrush = gdi_CreatePatternBrush(hBmp);
673 WLog_ERR(TAG,
"unimplemented brush style:%" PRIu32
"", brush->style);
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);
689 gdi->drawing->hdc->brush = originalBrush;
690 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
694 static BOOL gdi_scrblt(rdpContext* context,
const SCRBLT_ORDER* scrblt)
698 if (!context || !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);
707 static BOOL gdi_opaque_rect(rdpContext* context,
const OPAQUE_RECT_ORDER* opaque_rect)
711 UINT32 brush_color = 0;
712 rdpGdi* gdi = context->gdi;
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);
721 if (!gdi_decode_color(gdi, opaque_rect->color, &brush_color, NULL))
724 if (!(hBrush = gdi_CreateSolidBrush(brush_color)))
727 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
732 static BOOL gdi_multi_opaque_rect(rdpContext* context,
737 UINT32 brush_color = 0;
738 rdpGdi* gdi = context->gdi;
741 if (!gdi_decode_color(gdi, multi_opaque_rect->color, &brush_color, NULL))
744 hBrush = gdi_CreateSolidBrush(brush_color);
749 for (UINT32 i = 0; i < multi_opaque_rect->numRectangles; i++)
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);
768 static BOOL gdi_line_to(rdpContext* context,
const LINE_TO_ORDER* lineTo)
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;
779 gdi_ClipCoords(gdi->drawing->hdc, &xStart, &yStart, &w, &h, NULL, NULL);
780 gdi_ClipCoords(gdi->drawing->hdc, &xEnd, &yEnd, &w, &h, NULL, NULL);
782 if (!gdi_decode_color(gdi, lineTo->penColor, &color, NULL))
785 if (!(hPen = gdi_CreatePen(lineTo->penStyle, lineTo->penWidth, color, gdi->drawing->hdc->format,
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);
797 static BOOL gdi_polyline(rdpContext* context,
const POLYLINE_ORDER* polyline)
804 rdpGdi* gdi = context->gdi;
808 if (!gdi_decode_color(gdi, polyline->penColor, &color, NULL))
811 if (!(hPen = gdi_CreatePen(GDI_PS_SOLID, 1, color, gdi->drawing->hdc->format, &gdi->palette)))
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;
822 for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
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);
835 static BOOL gdi_memblt(rdpContext* context,
MEMBLT_ORDER* memblt)
837 gdiBitmap* bitmap = NULL;
840 if (!context || !memblt || !context->gdi || !memblt->bitmap)
843 bitmap = (gdiBitmap*)memblt->bitmap;
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);
850 static BOOL gdi_mem3blt(rdpContext* context,
MEM3BLT_ORDER* mem3blt)
853 rdpGdi* gdi = context->gdi;
855 const rdpBrush* brush = &mem3blt->brush;
856 gdiBitmap* bitmap = (gdiBitmap*)mem3blt->bitmap;
857 UINT32 foreColor = 0;
858 UINT32 backColor = 0;
859 UINT32 originalColor = 0;
861 if (!gdi_decode_color(gdi, mem3blt->foreColor, &foreColor, NULL))
864 if (!gdi_decode_color(gdi, mem3blt->backColor, &backColor, NULL))
867 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
869 switch (brush->style)
872 originalBrush = gdi->drawing->hdc->brush;
873 gdi->drawing->hdc->brush = gdi_CreateSolidBrush(foreColor);
875 if (!gdi->drawing->hdc->brush)
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;
891 UINT32 brushFormat = 0;
892 BYTE* data = (BYTE*)winpr_aligned_malloc(
893 8ULL * 8ULL * FreeRDPGetBytesPerPixel(gdi->drawing->hdc->format), 16);
903 UINT32 bpp = brush->bpp;
905 const UINT32 ColorDepth =
907 if ((bpp == 16) && (ColorDepth == 15))
910 brushFormat = gdi_get_pixel_format(bpp);
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,
917 winpr_aligned_free(data);
923 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
924 8, brush->data, backColor, foreColor,
928 winpr_aligned_free(data);
933 hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->format, data);
938 winpr_aligned_free(data);
942 originalBrush = gdi->drawing->hdc->brush;
943 gdi->drawing->hdc->brush = gdi_CreatePatternBrush(hBmp);
945 if (!gdi->drawing->hdc->brush)
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);
958 gdi->drawing->hdc->brush = originalBrush;
963 WLog_ERR(TAG,
"Mem3Blt unimplemented brush style:%" PRIu32
"", brush->style);
968 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
972 static BOOL gdi_polygon_sc(rdpContext* context,
const POLYGON_SC_ORDER* polygon_sc)
974 WLog_WARN(TAG,
"not implemented");
978 static BOOL gdi_polygon_cb(rdpContext* context,
POLYGON_CB_ORDER* polygon_cb)
980 WLog_WARN(TAG,
"not implemented");
984 static BOOL gdi_ellipse_sc(rdpContext* context,
const ELLIPSE_SC_ORDER* ellipse_sc)
986 WLog_WARN(TAG,
"not implemented");
990 static BOOL gdi_ellipse_cb(rdpContext* context,
const ELLIPSE_CB_ORDER* ellipse_cb)
992 WLog_WARN(TAG,
"not implemented");
996 static BOOL gdi_frame_marker(rdpContext* context,
const FRAME_MARKER_ORDER* frameMarker)
1001 static BOOL gdi_surface_frame_marker(rdpContext* context,
1004 WLog_Print(context->gdi->log, WLOG_DEBUG,
"frameId %" PRIu32
" frameAction %" PRIu32
"",
1005 surfaceFrameMarker->frameId, surfaceFrameMarker->frameAction);
1007 switch (surfaceFrameMarker->frameAction)
1009 case SURFACECMD_FRAMEACTION_BEGIN:
1012 case SURFACECMD_FRAMEACTION_END:
1015 IFCALL(context->update->SurfaceFrameAcknowledge, context,
1016 surfaceFrameMarker->frameId);
1029 const UINT32 w = (
const UINT32)gdi->width;
1030 const UINT32 h = (
const UINT32)gdi->height;
1032 if (cmd->destLeft > w)
1034 if (cmd->destRight > w)
1036 if (cmd->destLeft > cmd->destRight)
1038 if (cmd->destRight > UINT16_MAX)
1041 if (cmd->destTop > h)
1043 if (cmd->destBottom > h)
1045 if (cmd->destTop > cmd->destBottom)
1047 if (cmd->destBottom > UINT16_MAX)
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);
1059 BOOL result = FALSE;
1068 if (!context || !cmd)
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(®ion);
1081 if (!intersect_rect(gdi, cmd, &cmdRect))
1084 switch (cmd->bmp.codecID)
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), ®ion))
1093 WLog_ERR(TAG,
"Failed to process RemoteFX message");
1099 case RDP_CODEC_ID_NSCODEC:
1100 format = gdi->dstFormat;
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))
1108 WLog_ERR(TAG,
"Failed to process NSCodec message");
1112 region16_union_rect(®ion, ®ion, &cmdRect);
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)
1120 WLog_ERR(TAG,
"Short nocodec message: got %" PRIu32
" bytes, require %" PRIuz,
1121 cmd->bmp.bitmapDataLength, size);
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))
1130 WLog_ERR(TAG,
"Failed to process nocodec message");
1134 region16_union_rect(®ion, ®ion, &cmdRect);
1138 WLog_ERR(TAG,
"Unsupported codecID %" PRIu32
"", cmd->bmp.codecID);
1142 if (!(rects = region16_rects(®ion, &nbRects)))
1145 for (UINT32 i = 0; i < nbRects; i++)
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;
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)))
1157 WLog_ERR(TAG,
"Failed to update invalid region");
1164 region16_uninit(®ion);
1173 static void gdi_register_update_callbacks(rdpUpdate* update)
1175 rdpPrimaryUpdate* primary = NULL;
1176 const rdpSettings* settings = NULL;
1178 WINPR_ASSERT(update);
1179 WINPR_ASSERT(update->context);
1181 settings = update->context->settings;
1182 WINPR_ASSERT(settings);
1184 primary = update->primary;
1185 WINPR_ASSERT(primary);
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;
1218 static BOOL gdi_init_primary(rdpGdi* gdi, UINT32 stride, UINT32 format, BYTE* buffer,
1219 void (*pfree)(
void*), BOOL isLocked)
1222 WINPR_ASSERT(gdi->context);
1223 WINPR_ASSERT(gdi->context->update);
1225 rdp_update_lock(gdi->context->update);
1227 gdi->primary = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
1230 gdi->dstFormat = format;
1233 gdi->stride = stride;
1235 gdi->stride = WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width) *
1236 FreeRDPGetBytesPerPixel(gdi->dstFormat);
1241 if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
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));
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);
1257 if (!gdi->primary->bitmap)
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;
1265 if (!(gdi->primary->hdc->hwnd = (
HGDI_WND)calloc(1,
sizeof(
GDI_WND))))
1268 if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0)))
1271 gdi->primary->hdc->hwnd->invalid->null = TRUE;
1272 gdi->primary->hdc->hwnd->count = 32;
1274 if (!(gdi->primary->hdc->hwnd->cinvalid =
1278 gdi->primary->hdc->hwnd->ninvalid = 0;
1281 gdi->drawing = gdi->primary;
1283 rdp_update_unlock(gdi->context->update);
1286 gdi_DeleteObject((
HGDIOBJECT)gdi->primary->bitmap);
1288 gdi_DeleteDC(gdi->primary->hdc);
1291 gdi->primary = NULL;
1293 rdp_update_unlock(gdi->context->update);
1297 BOOL gdi_resize(rdpGdi* gdi, UINT32 width, UINT32 height)
1299 return gdi_resize_ex(gdi, width, height, 0, 0, NULL, NULL);
1302 BOOL gdi_resize_ex(rdpGdi* gdi, UINT32 width, UINT32 height, UINT32 stride, UINT32 format,
1303 BYTE* buffer,
void (*pfree)(
void*))
1305 if (!gdi || !gdi->primary)
1308 if ((width > INT32_MAX) || (height > INT32_MAX))
1311 if ((gdi->width == (INT32)width) && (gdi->height == (INT32)height) &&
1312 (!buffer || (gdi->primary_buffer == buffer)))
1315 WINPR_ASSERT(gdi->context);
1316 WINPR_ASSERT(gdi->context->update);
1319 update_end_paint(gdi->context->update);
1320 rdp_update_lock(gdi->context->update);
1322 if (gdi->drawing == gdi->primary)
1323 gdi->drawing = NULL;
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);
1340 BOOL gdi_init(freerdp* instance, UINT32 format)
1342 return gdi_init_ex(instance, format, 0, NULL, winpr_aligned_free);
1356 BOOL gdi_init_ex(freerdp* instance, UINT32 format, UINT32 stride, BYTE* buffer,
1357 void (*pfree)(
void*))
1359 rdpContext* context = NULL;
1360 UINT32 SrcFormat = 0;
1363 WINPR_ASSERT(instance);
1365 context = instance->context;
1366 WINPR_ASSERT(context);
1367 WINPR_ASSERT(context->settings);
1370 SrcFormat = gdi_get_pixel_format(ColorDepth);
1371 gdi = (rdpGdi*)calloc(1,
sizeof(rdpGdi));
1377 gdi->log = WLog_Get(TAG);
1382 gdi->context = context;
1383 gdi->width = WINPR_ASSERTING_INT_CAST(
1385 gdi->height = WINPR_ASSERTING_INT_CAST(
1387 gdi->dstFormat = 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));
1394 if (!(gdi->hdc = gdi_GetDC()))
1397 gdi->hdc->format = gdi->dstFormat;
1399 if (!gdi_init_primary(gdi, stride, gdi->dstFormat, buffer, pfree, FALSE))
1402 if (!(context->cache = cache_new(context)))
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);
1412 if (!gdi_register_graphics(context->graphics))
1418 WLog_ERR(TAG,
"failed to initialize gdi");
1422 void gdi_free(freerdp* instance)
1425 rdpContext* context = NULL;
1427 if (!instance || !instance->context)
1430 gdi = instance->context->gdi;
1434 gdi_bitmap_free_ex(gdi->primary);
1435 gdi_DeleteDC(gdi->hdc);
1439 context = instance->context;
1440 cache_free(context->cache);
1441 context->cache = NULL;
1442 instance->context->gdi = (rdpGdi*)NULL;
1445 BOOL gdi_send_suppress_output(rdpGdi* gdi, BOOL suppress)
1448 rdpSettings* settings = NULL;
1449 rdpUpdate* update = NULL;
1451 if (!gdi || !gdi->context->settings || !gdi->context->update)
1454 if (gdi->suppressOutput == suppress)
1457 gdi->suppressOutput = suppress;
1458 settings = gdi->context->settings;
1459 update = gdi->context->update;
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);
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.