22#include <freerdp/config.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>
34#include <freerdp/codecs.h>
36#include <freerdp/gdi/gdi.h>
37#include <freerdp/gdi/dc.h>
38#include <freerdp/gdi/pen.h>
39#include <freerdp/gdi/shape.h>
40#include <freerdp/gdi/region.h>
41#include <freerdp/gdi/bitmap.h>
48#include "../core/graphics.h"
49#include "../core/update.h"
50#include "../cache/cache.h"
52#define TAG FREERDP_TAG("gdi")
61static const rop_table_entry rop3_code_table[] = { { GDI_BLACKNESS,
"0" },
62 { GDI_DPSoon,
"DPSoon" },
63 { GDI_DPSona,
"DPSona" },
65 { GDI_SDPona,
"SDPona" },
67 { GDI_PDSxnon,
"PDSxnon" },
68 { GDI_PDSaon,
"PDSaon" },
69 { GDI_SDPnaa,
"SDPnaa" },
70 { GDI_PDSxon,
"PDSxon" },
72 { GDI_PSDnaon,
"PSDnaon" },
74 { GDI_PDSnaon,
"PDSnaon" },
75 { GDI_PDSonon,
"PDSonon" },
77 { GDI_PDSona,
"PDSona" },
78 { GDI_NOTSRCERASE,
"DSon" },
79 { GDI_SDPxnon,
"SDPxnon" },
80 { GDI_SDPaon,
"SDPaon" },
81 { GDI_DPSxnon,
"DPSxnon" },
82 { GDI_DPSaon,
"DPSaon" },
83 { GDI_PSDPSanaxx,
"PSDPSanaxx" },
84 { GDI_SSPxDSxaxn,
"SSPxDSxaxn" },
85 { GDI_SPxPDxa,
"SPxPDxa" },
86 { GDI_SDPSanaxn,
"SDPSanaxn" },
87 { GDI_PDSPaox,
"PDSPaox" },
88 { GDI_SDPSxaxn,
"SDPSxaxn" },
89 { GDI_PSDPaox,
"PSDPaox" },
90 { GDI_DSPDxaxn,
"DSPDxaxn" },
91 { GDI_PDSox,
"PDSox" },
92 { GDI_PDSoan,
"PDSoan" },
93 { GDI_DPSnaa,
"DPSnaa" },
94 { GDI_SDPxon,
"SDPxon" },
96 { GDI_SPDnaon,
"SPDnaon" },
97 { GDI_SPxDSxa,
"SPxDSxa" },
98 { GDI_PDSPanaxn,
"PDSPanaxn" },
99 { GDI_SDPSaox,
"SDPSaox" },
100 { GDI_SDPSxnox,
"SDPSxnox" },
101 { GDI_DPSxa,
"DPSxa" },
102 { GDI_PSDPSaoxxn,
"PSDPSaoxxn" },
103 { GDI_DPSana,
"DPSana" },
104 { GDI_SSPxPDxaxn,
"SSPxPDxaxn" },
105 { GDI_SPDSoax,
"SPDSoax" },
106 { GDI_PSDnox,
"PSDnox" },
107 { GDI_PSDPxox,
"PSDPxox" },
108 { GDI_PSDnoan,
"PSDnoan" },
109 { GDI_PSna,
"PSna" },
110 { GDI_SDPnaon,
"SDPnaon" },
111 { GDI_SDPSoox,
"SDPSoox" },
112 { GDI_NOTSRCCOPY,
"Sn" },
113 { GDI_SPDSaox,
"SPDSaox" },
114 { GDI_SPDSxnox,
"SPDSxnox" },
115 { GDI_SDPox,
"SDPox" },
116 { GDI_SDPoan,
"SDPoan" },
117 { GDI_PSDPoax,
"PSDPoax" },
118 { GDI_SPDnox,
"SPDnox" },
119 { GDI_SPDSxox,
"SPDSxox" },
120 { GDI_SPDnoan,
"SPDnoan" },
122 { GDI_SPDSonox,
"SPDSonox" },
123 { GDI_SPDSnaox,
"SPDSnaox" },
124 { GDI_PSan,
"PSan" },
125 { GDI_PSDnaa,
"PSDnaa" },
126 { GDI_DPSxon,
"DPSxon" },
127 { GDI_SDxPDxa,
"SDxPDxa" },
128 { GDI_SPDSanaxn,
"SPDSanaxn" },
129 { GDI_SRCERASE,
"SDna" },
130 { GDI_DPSnaon,
"DPSnaon" },
131 { GDI_DSPDaox,
"DSPDaox" },
132 { GDI_PSDPxaxn,
"PSDPxaxn" },
133 { GDI_SDPxa,
"SDPxa" },
134 { GDI_PDSPDaoxxn,
"PDSPDaoxxn" },
135 { GDI_DPSDoax,
"DPSDoax" },
136 { GDI_PDSnox,
"PDSnox" },
137 { GDI_SDPana,
"SDPana" },
138 { GDI_SSPxDSxoxn,
"SSPxDSxoxn" },
139 { GDI_PDSPxox,
"PDSPxox" },
140 { GDI_PDSnoan,
"PDSnoan" },
141 { GDI_PDna,
"PDna" },
142 { GDI_DSPnaon,
"DSPnaon" },
143 { GDI_DPSDaox,
"DPSDaox" },
144 { GDI_SPDSxaxn,
"SPDSxaxn" },
145 { GDI_DPSonon,
"DPSonon" },
146 { GDI_DSTINVERT,
"Dn" },
147 { GDI_DPSox,
"DPSox" },
148 { GDI_DPSoan,
"DPSoan" },
149 { GDI_PDSPoax,
"PDSPoax" },
150 { GDI_DPSnox,
"DPSnox" },
151 { GDI_PATINVERT,
"DPx" },
152 { GDI_DPSDonox,
"DPSDonox" },
153 { GDI_DPSDxox,
"DPSDxox" },
154 { GDI_DPSnoan,
"DPSnoan" },
155 { GDI_DPSDnaox,
"DPSDnaox" },
156 { GDI_DPan,
"DPan" },
157 { GDI_PDSxa,
"PDSxa" },
158 { GDI_DSPDSaoxxn,
"DSPDSaoxxn" },
159 { GDI_DSPDoax,
"DSPDoax" },
160 { GDI_SDPnox,
"SDPnox" },
161 { GDI_SDPSoax,
"SDPSoax" },
162 { GDI_DSPnox,
"DSPnox" },
163 { GDI_SRCINVERT,
"DSx" },
164 { GDI_SDPSonox,
"SDPSonox" },
165 { GDI_DSPDSonoxxn,
"DSPDSonoxxn" },
166 { GDI_PDSxxn,
"PDSxxn" },
167 { GDI_DPSax,
"DPSax" },
168 { GDI_PSDPSoaxxn,
"PSDPSoaxxn" },
169 { GDI_SDPax,
"SDPax" },
170 { GDI_PDSPDoaxxn,
"PDSPDoaxxn" },
171 { GDI_SDPSnoax,
"SDPSnoax" },
172 { GDI_PDSxnan,
"PDSxnan" },
173 { GDI_PDSana,
"PDSana" },
174 { GDI_SSDxPDxaxn,
"SSDxPDxaxn" },
175 { GDI_SDPSxox,
"SDPSxox" },
176 { GDI_SDPnoan,
"SDPnoan" },
177 { GDI_DSPDxox,
"DSPDxox" },
178 { GDI_DSPnoan,
"DSPnoan" },
179 { GDI_SDPSnaox,
"SDPSnaox" },
180 { GDI_DSan,
"DSan" },
181 { GDI_PDSax,
"PDSax" },
182 { GDI_DSPDSoaxxn,
"DSPDSoaxxn" },
183 { GDI_DPSDnoax,
"DPSDnoax" },
184 { GDI_SDPxnan,
"SDPxnan" },
185 { GDI_SPDSnoax,
"SPDSnoax" },
186 { GDI_DPSxnan,
"DPSxnan" },
187 { GDI_SPxDSxo,
"SPxDSxo" },
188 { GDI_DPSaan,
"DPSaan" },
189 { GDI_DPSaa,
"DPSaa" },
190 { GDI_SPxDSxon,
"SPxDSxon" },
191 { GDI_DPSxna,
"DPSxna" },
192 { GDI_SPDSnoaxn,
"SPDSnoaxn" },
193 { GDI_SDPxna,
"SDPxna" },
194 { GDI_PDSPnoaxn,
"PDSPnoaxn" },
195 { GDI_DSPDSoaxx,
"DSPDSoaxx" },
196 { GDI_PDSaxn,
"PDSaxn" },
197 { GDI_SRCAND,
"DSa" },
198 { GDI_SDPSnaoxn,
"SDPSnaoxn" },
199 { GDI_DSPnoa,
"DSPnoa" },
200 { GDI_DSPDxoxn,
"DSPDxoxn" },
201 { GDI_SDPnoa,
"SDPnoa" },
202 { GDI_SDPSxoxn,
"SDPSxoxn" },
203 { GDI_SSDxPDxax,
"SSDxPDxax" },
204 { GDI_PDSanan,
"PDSanan" },
205 { GDI_PDSxna,
"PDSxna" },
206 { GDI_SDPSnoaxn,
"SDPSnoaxn" },
207 { GDI_DPSDPoaxx,
"DPSDPoaxx" },
208 { GDI_SPDaxn,
"SPDaxn" },
209 { GDI_PSDPSoaxx,
"PSDPSoaxx" },
210 { GDI_DPSaxn,
"DPSaxn" },
211 { GDI_DPSxx,
"DPSxx" },
212 { GDI_PSDPSonoxx,
"PSDPSonoxx" },
213 { GDI_SDPSonoxn,
"SDPSonoxn" },
214 { GDI_DSxn,
"DSxn" },
215 { GDI_DPSnax,
"DPSnax" },
216 { GDI_SDPSoaxn,
"SDPSoaxn" },
217 { GDI_SPDnax,
"SPDnax" },
218 { GDI_DSPDoaxn,
"DSPDoaxn" },
219 { GDI_DSPDSaoxx,
"DSPDSaoxx" },
220 { GDI_PDSxan,
"PDSxan" },
222 { GDI_PDSPnaoxn,
"PDSPnaoxn" },
223 { GDI_DPSnoa,
"DPSnoa" },
224 { GDI_DPSDxoxn,
"DPSDxoxn" },
225 { GDI_PDSPonoxn,
"PDSPonoxn" },
226 { GDI_PDxn,
"PDxn" },
227 { GDI_DSPnax,
"DSPnax" },
228 { GDI_PDSPoaxn,
"PDSPoaxn" },
229 { GDI_DPSoa,
"DPSoa" },
230 { GDI_DPSoxn,
"DPSoxn" },
231 { GDI_DSTCOPY,
"D" },
232 { GDI_DPSono,
"DPSono" },
233 { GDI_SPDSxax,
"SPDSxax" },
234 { GDI_DPSDaoxn,
"DPSDaoxn" },
235 { GDI_DSPnao,
"DSPnao" },
236 { GDI_DPno,
"DPno" },
237 { GDI_PDSnoa,
"PDSnoa" },
238 { GDI_PDSPxoxn,
"PDSPxoxn" },
239 { GDI_SSPxDSxox,
"SSPxDSxox" },
240 { GDI_SDPanan,
"SDPanan" },
241 { GDI_PSDnax,
"PSDnax" },
242 { GDI_DPSDoaxn,
"DPSDoaxn" },
243 { GDI_DPSDPaoxx,
"DPSDPaoxx" },
244 { GDI_SDPxan,
"SDPxan" },
245 { GDI_PSDPxax,
"PSDPxax" },
246 { GDI_DSPDaoxn,
"DSPDaoxn" },
247 { GDI_DPSnao,
"DPSnao" },
248 { GDI_MERGEPAINT,
"DSno" },
249 { GDI_SPDSanax,
"SPDSanax" },
250 { GDI_SDxPDxan,
"SDxPDxan" },
251 { GDI_DPSxo,
"DPSxo" },
252 { GDI_DPSano,
"DPSano" },
253 { GDI_MERGECOPY,
"PSa" },
254 { GDI_SPDSnaoxn,
"SPDSnaoxn" },
255 { GDI_SPDSonoxn,
"SPDSonoxn" },
256 { GDI_PSxn,
"PSxn" },
257 { GDI_SPDnoa,
"SPDnoa" },
258 { GDI_SPDSxoxn,
"SPDSxoxn" },
259 { GDI_SDPnax,
"SDPnax" },
260 { GDI_PSDPoaxn,
"PSDPoaxn" },
261 { GDI_SDPoa,
"SDPoa" },
262 { GDI_SPDoxn,
"SPDoxn" },
263 { GDI_DPSDxax,
"DPSDxax" },
264 { GDI_SPDSaoxn,
"SPDSaoxn" },
265 { GDI_SRCCOPY,
"S" },
266 { GDI_SDPono,
"SDPono" },
267 { GDI_SDPnao,
"SDPnao" },
268 { GDI_SPno,
"SPno" },
269 { GDI_PSDnoa,
"PSDnoa" },
270 { GDI_PSDPxoxn,
"PSDPxoxn" },
271 { GDI_PDSnax,
"PDSnax" },
272 { GDI_SPDSoaxn,
"SPDSoaxn" },
273 { GDI_SSPxPDxax,
"SSPxPDxax" },
274 { GDI_DPSanan,
"DPSanan" },
275 { GDI_PSDPSaoxx,
"PSDPSaoxx" },
276 { GDI_DPSxan,
"DPSxan" },
277 { GDI_PDSPxax,
"PDSPxax" },
278 { GDI_SDPSaoxn,
"SDPSaoxn" },
279 { GDI_DPSDanax,
"DPSDanax" },
280 { GDI_SPxDSxan,
"SPxDSxan" },
281 { GDI_SPDnao,
"SPDnao" },
282 { GDI_SDno,
"SDno" },
283 { GDI_SDPxo,
"SDPxo" },
284 { GDI_SDPano,
"SDPano" },
285 { GDI_PDSoa,
"PDSoa" },
286 { GDI_PDSoxn,
"PDSoxn" },
287 { GDI_DSPDxax,
"DSPDxax" },
288 { GDI_PSDPaoxn,
"PSDPaoxn" },
289 { GDI_SDPSxax,
"SDPSxax" },
290 { GDI_PDSPaoxn,
"PDSPaoxn" },
291 { GDI_SDPSanax,
"SDPSanax" },
292 { GDI_SPxPDxan,
"SPxPDxan" },
293 { GDI_SSPxDSxax,
"SSPxDSxax" },
294 { GDI_DSPDSanaxxn,
"DSPDSanaxxn" },
295 { GDI_DPSao,
"DPSao" },
296 { GDI_DPSxno,
"DPSxno" },
297 { GDI_SDPao,
"SDPao" },
298 { GDI_SDPxno,
"SDPxno" },
299 { GDI_SRCPAINT,
"DSo" },
300 { GDI_SDPnoo,
"SDPnoo" },
301 { GDI_PATCOPY,
"P" },
302 { GDI_PDSono,
"PDSono" },
303 { GDI_PDSnao,
"PDSnao" },
304 { GDI_PSno,
"PSno" },
305 { GDI_PSDnao,
"PSDnao" },
306 { GDI_PDno,
"PDno" },
307 { GDI_PDSxo,
"PDSxo" },
308 { GDI_PDSano,
"PDSano" },
309 { GDI_PDSao,
"PDSao" },
310 { GDI_PDSxno,
"PDSxno" },
312 { GDI_PATPAINT,
"DPSnoo" },
314 { GDI_PSDnoo,
"PSDnoo" },
315 { GDI_DPSoo,
"DPSoo" },
316 { GDI_WHITENESS,
"1" } };
319static const BYTE GDI_BS_HATCHED_PATTERNS[] = {
320 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
321 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7,
322 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F,
323 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE,
324 0xF7, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0xF7, 0xF7,
325 0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E
328#define gdi_rop3_code_checked(code) gdi_rop3_code_checked_int((code), __FILE__, __func__, __LINE__)
329static inline DWORD gdi_rop3_code_checked_int(UINT32 code, WINPR_ATTR_UNUSED
const char* file,
330 WINPR_ATTR_UNUSED
const char* fkt,
331 WINPR_ATTR_UNUSED
size_t line)
333 WINPR_ASSERT_AT(code <= UINT8_MAX, file, fkt, line);
334 return gdi_rop3_code((UINT8)code);
337BOOL gdi_decode_color(rdpGdi* gdi, UINT32 srcColor, UINT32* color, UINT32* format)
339 UINT32 SrcFormat = 0;
341 if (!gdi || !color || !gdi->context || !gdi->context->settings)
344 const UINT32 ColorDepth =
351 SrcFormat = PIXEL_FORMAT_BGR24;
355 SrcFormat = PIXEL_FORMAT_RGB16;
359 SrcFormat = PIXEL_FORMAT_RGB15;
363 SrcFormat = PIXEL_FORMAT_RGB8;
371 *format = gdi->dstFormat;
373 *color = FreeRDPConvertColor(srcColor, SrcFormat, gdi->dstFormat, &gdi->palette);
378DWORD gdi_rop3_code(BYTE code)
380 return rop3_code_table[code].code;
383const char* gdi_rop3_code_string(BYTE code)
385 return rop3_code_table[code].name;
388const char* gdi_rop3_string(DWORD rop)
390 const size_t count =
sizeof(rop3_code_table) /
sizeof(rop3_code_table[0]);
392 for (
size_t x = 0; x < count; x++)
394 if (rop3_code_table[x].code == rop)
395 return rop3_code_table[x].name;
401UINT32 gdi_get_pixel_format(UINT32 bitsPerPixel)
405 switch (bitsPerPixel)
408 format = PIXEL_FORMAT_BGRA32;
412 format = PIXEL_FORMAT_BGR24;
416 format = PIXEL_FORMAT_RGB16;
420 format = PIXEL_FORMAT_RGB15;
424 format = PIXEL_FORMAT_RGB8;
428 WLog_ERR(TAG,
"Unsupported color depth %" PRIu32, bitsPerPixel);
436gdiBitmap* gdi_bitmap_new_ex(rdpGdi* gdi,
int width,
int height,
int bpp, BYTE* data)
438 gdiBitmap* bitmap = NULL;
439 bitmap = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
444 if (!(bitmap->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
447 WLog_Print(gdi->log, WLOG_DEBUG,
"gdi_bitmap_new: width:%d height:%d bpp:%d", width, height,
452 gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, width),
453 WINPR_ASSERTING_INT_CAST(uint32_t, height));
455 bitmap->bitmap = gdi_create_bitmap(gdi, WINPR_ASSERTING_INT_CAST(uint32_t, width),
456 WINPR_ASSERTING_INT_CAST(uint32_t, height),
457 WINPR_ASSERTING_INT_CAST(uint32_t, bpp), data);
460 goto fail_bitmap_bitmap;
462 gdi_SelectObject(bitmap->hdc, (
HGDIOBJECT)bitmap->bitmap);
463 bitmap->org_bitmap = NULL;
466 gdi_DeleteDC(bitmap->hdc);
473void gdi_bitmap_free_ex(gdiBitmap* bitmap)
477 gdi_SelectObject(bitmap->hdc, (
HGDIOBJECT)bitmap->org_bitmap);
479 gdi_DeleteDC(bitmap->hdc);
484BOOL gdi_bitmap_update(rdpContext* context,
const BITMAP_UPDATE* bitmapUpdate)
486 if (!context || !bitmapUpdate || !context->gdi || !context->codecs)
489 "Invalid arguments: context=%p, bitmapUpdate=%p, context->gdi=%p, "
490 "context->codecs=%p",
491 context, bitmapUpdate, context ? context->gdi : NULL,
492 context ? context->codecs : NULL);
496 for (UINT32 index = 0; index < bitmapUpdate->number; index++)
499 const BITMAP_DATA* bitmap = &(bitmapUpdate->rectangles[index]);
500 rdpBitmap* bmp = Bitmap_Alloc(context);
505 if (!Bitmap_SetDimensions(bmp, WINPR_ASSERTING_INT_CAST(UINT16, bitmap->width),
506 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->height)))
509 if (!Bitmap_SetRectangle(bmp, WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destLeft),
510 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destTop),
511 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destRight),
512 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destBottom)))
515 if (!bmp->Decompress(context, bmp, bitmap->bitmapDataStream, bitmap->width, bitmap->height,
516 bitmap->bitsPerPixel, bitmap->bitmapLength, bitmap->compressed,
520 if (!bmp->New(context, bmp))
523 if (!bmp->Paint(context, bmp))
528 Bitmap_Free(context, bmp);
536static BOOL gdi_palette_update(rdpContext* context,
const PALETTE_UPDATE* palette)
540 if (!context || !palette)
544 gdi->palette.format = gdi->dstFormat;
546 for (UINT32 index = 0; index < palette->number; index++)
549 gdi->palette.palette[index] =
550 FreeRDPGetColor(gdi->dstFormat, pe->red, pe->green, pe->blue, 0xFF);
556static BOOL gdi_set_bounds(rdpContext* context,
const rdpBounds* bounds)
567 gdi_SetClipRgn(gdi->drawing->hdc, bounds->left, bounds->top,
568 bounds->right - bounds->left + 1, bounds->bottom - bounds->top + 1);
571 gdi_SetNullClipRgn(gdi->drawing->hdc);
576static BOOL gdi_dstblt(rdpContext* context,
const DSTBLT_ORDER* dstblt)
580 if (!context || !dstblt)
584 return gdi_BitBlt(gdi->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth,
585 dstblt->nHeight, NULL, 0, 0, gdi_rop3_code_checked(dstblt->bRop),
589static BOOL gdi_patblt(rdpContext* context,
PATBLT_ORDER* patblt)
591 const rdpBrush* brush = &patblt->brush;
592 UINT32 foreColor = 0;
593 UINT32 backColor = 0;
594 UINT32 originalColor = 0;
597 rdpGdi* gdi = context->gdi;
599 const DWORD rop = gdi_rop3_code_checked(patblt->bRop);
602 BYTE data[8 * 8 * 4];
605 if (!gdi_decode_color(gdi, patblt->foreColor, &foreColor, NULL))
608 if (!gdi_decode_color(gdi, patblt->backColor, &backColor, NULL))
611 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
612 originalBrush = gdi->drawing->hdc->brush;
614 switch (brush->style)
617 hbrush = gdi_CreateSolidBrush(foreColor);
622 const BYTE* hatched = NULL;
623 hatched = GDI_BS_HATCHED_PATTERNS + (8ULL * brush->hatch);
625 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
626 hatched, backColor, foreColor, &gdi->palette))
629 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
634 hbrush = gdi_CreateHatchBrush(hBmp);
640 UINT32 brushFormat = 0;
644 UINT32 bpp = brush->bpp;
650 brushFormat = gdi_get_pixel_format(bpp);
652 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
653 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
659 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
660 8, brush->data, backColor, foreColor,
665 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
670 hbrush = gdi_CreatePatternBrush(hBmp);
675 WLog_ERR(TAG,
"unimplemented brush style:%" PRIu32
"", brush->style);
681 hbrush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
682 hbrush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
683 gdi->drawing->hdc->brush = hbrush;
684 ret = gdi_BitBlt(gdi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
685 patblt->nHeight, gdi->primary->hdc, nXSrc, nYSrc, rop, &gdi->palette);
691 gdi->drawing->hdc->brush = originalBrush;
692 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
696static BOOL gdi_scrblt(rdpContext* context,
const SCRBLT_ORDER* scrblt)
700 if (!context || !context->gdi)
704 return gdi_BitBlt(gdi->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth,
705 scrblt->nHeight, gdi->primary->hdc, scrblt->nXSrc, scrblt->nYSrc,
706 gdi_rop3_code_checked(scrblt->bRop), &gdi->palette);
709static BOOL gdi_opaque_rect(rdpContext* context,
const OPAQUE_RECT_ORDER* opaque_rect)
713 UINT32 brush_color = 0;
714 rdpGdi* gdi = context->gdi;
716 INT32 x = opaque_rect->nLeftRect;
717 INT32 y = opaque_rect->nTopRect;
718 INT32 w = opaque_rect->nWidth;
719 INT32 h = opaque_rect->nHeight;
720 gdi_CRgnToRect(x, y, w, h, &rect);
722 if (!gdi_decode_color(gdi, opaque_rect->color, &brush_color, NULL))
725 if (!(hBrush = gdi_CreateSolidBrush(brush_color)))
728 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
733static BOOL gdi_multi_opaque_rect(rdpContext* context,
738 UINT32 brush_color = 0;
739 rdpGdi* gdi = context->gdi;
742 if (!gdi_decode_color(gdi, multi_opaque_rect->color, &brush_color, NULL))
745 hBrush = gdi_CreateSolidBrush(brush_color);
750 for (UINT32 i = 0; i < multi_opaque_rect->numRectangles; i++)
752 const DELTA_RECT* rectangle = &multi_opaque_rect->rectangles[i];
753 const INT32 x = rectangle->left;
754 const INT32 y = rectangle->top;
755 const INT32 w = rectangle->width;
756 const INT32 h = rectangle->height;
758 gdi_CRgnToRect(x, y, w, h, &rect);
759 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
769static BOOL gdi_line_to(rdpContext* context,
const LINE_TO_ORDER* lineTo)
772 WINPR_ASSERT(context);
773 WINPR_ASSERT(lineTo);
775 rdpGdi* gdi = context->gdi;
778 if (!gdi_decode_color(gdi, lineTo->penColor, &color, NULL))
781 HGDI_PEN hPen = gdi_CreatePen(lineTo->penStyle, lineTo->penWidth, color,
782 gdi->drawing->hdc->format, &gdi->palette);
786 WINPR_ASSERT(gdi->drawing);
788 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)hPen);
789 gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, lineTo->bRop2));
790 gdi_MoveToEx(gdi->drawing->hdc, lineTo->nXStart, lineTo->nYStart, NULL);
791 gdi_LineTo(gdi->drawing->hdc, lineTo->nXEnd, lineTo->nYEnd);
796static BOOL gdi_polyline(rdpContext* context,
const POLYLINE_ORDER* polyline)
798 WINPR_ASSERT(context);
799 WINPR_ASSERT(polyline);
801 rdpGdi* gdi = context->gdi;
805 if (!gdi_decode_color(gdi, polyline->penColor, &color, NULL))
808 WINPR_ASSERT(gdi->drawing);
809 WINPR_ASSERT(gdi->drawing->hdc);
811 HGDI_PEN hPen = gdi_CreatePen(GDI_PS_SOLID, 1, color, gdi->drawing->hdc->format, &gdi->palette);
815 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)hPen);
816 gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, polyline->bRop2));
817 INT32 x = polyline->xStart;
818 INT32 y = polyline->yStart;
819 gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL);
822 for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
826 gdi_LineTo(gdi->drawing->hdc, x, y);
827 gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL);
834static BOOL gdi_memblt(rdpContext* context,
MEMBLT_ORDER* memblt)
836 gdiBitmap* bitmap = NULL;
839 if (!context || !memblt || !context->gdi || !memblt->bitmap)
842 bitmap = (gdiBitmap*)memblt->bitmap;
844 return gdi_BitBlt(gdi->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
845 memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc,
846 gdi_rop3_code_checked(memblt->bRop), &gdi->palette);
849static BOOL gdi_mem3blt(rdpContext* context,
MEM3BLT_ORDER* mem3blt)
852 rdpGdi* gdi = context->gdi;
854 const rdpBrush* brush = &mem3blt->brush;
855 gdiBitmap* bitmap = (gdiBitmap*)mem3blt->bitmap;
856 UINT32 foreColor = 0;
857 UINT32 backColor = 0;
858 UINT32 originalColor = 0;
860 if (!gdi_decode_color(gdi, mem3blt->foreColor, &foreColor, NULL))
863 if (!gdi_decode_color(gdi, mem3blt->backColor, &backColor, NULL))
866 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
868 switch (brush->style)
871 originalBrush = gdi->drawing->hdc->brush;
872 gdi->drawing->hdc->brush = gdi_CreateSolidBrush(foreColor);
874 if (!gdi->drawing->hdc->brush)
880 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
881 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
882 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
883 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
884 gdi->drawing->hdc->brush = originalBrush;
890 UINT32 brushFormat = 0;
891 BYTE* data = (BYTE*)winpr_aligned_malloc(
892 8ULL * 8ULL * FreeRDPGetBytesPerPixel(gdi->drawing->hdc->format), 16);
902 UINT32 bpp = brush->bpp;
904 const UINT32 ColorDepth =
906 if ((bpp == 16) && (ColorDepth == 15))
909 brushFormat = gdi_get_pixel_format(bpp);
911 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
912 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
916 winpr_aligned_free(data);
922 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
923 8, brush->data, backColor, foreColor,
927 winpr_aligned_free(data);
932 hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->format, data);
937 winpr_aligned_free(data);
941 originalBrush = gdi->drawing->hdc->brush;
942 gdi->drawing->hdc->brush = gdi_CreatePatternBrush(hBmp);
944 if (!gdi->drawing->hdc->brush)
950 gdi->drawing->hdc->brush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
951 gdi->drawing->hdc->brush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
952 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
953 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
954 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
955 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
957 gdi->drawing->hdc->brush = originalBrush;
962 WLog_ERR(TAG,
"Mem3Blt unimplemented brush style:%" PRIu32
"", brush->style);
967 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
971static BOOL gdi_polygon_sc(WINPR_ATTR_UNUSED rdpContext* context,
974 WLog_WARN(TAG,
"not implemented");
978static BOOL gdi_polygon_cb(WINPR_ATTR_UNUSED rdpContext* context,
981 WLog_WARN(TAG,
"not implemented");
985static BOOL gdi_ellipse_sc(WINPR_ATTR_UNUSED rdpContext* context,
988 WLog_WARN(TAG,
"not implemented");
992static BOOL gdi_ellipse_cb(WINPR_ATTR_UNUSED rdpContext* context,
995 WLog_WARN(TAG,
"not implemented");
999static BOOL gdi_frame_marker(WINPR_ATTR_UNUSED rdpContext* context,
1005static BOOL gdi_surface_frame_marker(rdpContext* context,
1008 WLog_Print(context->gdi->log, WLOG_DEBUG,
"frameId %" PRIu32
" frameAction %" PRIu32
"",
1009 surfaceFrameMarker->frameId, surfaceFrameMarker->frameAction);
1011 switch (surfaceFrameMarker->frameAction)
1013 case SURFACECMD_FRAMEACTION_BEGIN:
1016 case SURFACECMD_FRAMEACTION_END:
1019 IFCALL(context->update->SurfaceFrameAcknowledge, context,
1020 surfaceFrameMarker->frameId);
1033 const UINT32 w = (
const UINT32)gdi->width;
1034 const UINT32 h = (
const UINT32)gdi->height;
1036 if (cmd->destLeft > w)
1038 if (cmd->destRight > w)
1040 if (cmd->destLeft > cmd->destRight)
1042 if (cmd->destRight > UINT16_MAX)
1045 if (cmd->destTop > h)
1047 if (cmd->destBottom > h)
1049 if (cmd->destTop > cmd->destBottom)
1051 if (cmd->destBottom > UINT16_MAX)
1054 prect->left = (
const UINT16)cmd->destLeft;
1055 prect->top = (
const UINT16)cmd->destTop;
1056 prect->right = MIN((UINT16)cmd->destRight, prect->left + cmd->bmp.width);
1057 prect->bottom = MIN((UINT16)cmd->destBottom, prect->top + cmd->bmp.height);
1063 BOOL result = FALSE;
1070 if (!context || !cmd)
1074 WLog_Print(gdi->log, WLOG_DEBUG,
1075 "destLeft %" PRIu32
" destTop %" PRIu32
" destRight %" PRIu32
" destBottom %" PRIu32
1077 "bpp %" PRIu8
" flags %" PRIx8
" codecID %s [0x%04" PRIu16
"] width %" PRIu16
1078 " height %" PRIu16
" length %" PRIu32
"",
1079 cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bmp.bpp,
1080 cmd->bmp.flags, freerdp_codec_id_to_str(cmd->bmp.codecID), cmd->bmp.codecID,
1081 cmd->bmp.width, cmd->bmp.height, cmd->bmp.bitmapDataLength);
1082 region16_init(®ion);
1084 if (!intersect_rect(gdi, cmd, &cmdRect))
1087 switch (cmd->bmp.codecID)
1089 case RDP_CODEC_ID_REMOTEFX:
1090 case RDP_CODEC_ID_IMAGE_REMOTEFX:
1091 if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData,
1092 cmd->bmp.bitmapDataLength, cmdRect.left, cmdRect.top,
1093 gdi->primary_buffer, gdi->dstFormat, gdi->stride,
1094 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height), ®ion))
1096 WLog_ERR(TAG,
"Failed to process RemoteFX message");
1102 case RDP_CODEC_ID_NSCODEC:
1103 format = gdi->dstFormat;
1105 if (!nsc_process_message(
1106 context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, cmd->bmp.height,
1107 cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, format,
1108 gdi->stride, cmdRect.left, cmdRect.top, cmdRect.right - cmdRect.left,
1109 cmdRect.bottom - cmdRect.top, FREERDP_FLIP_VERTICAL))
1111 WLog_ERR(TAG,
"Failed to process NSCodec message");
1115 region16_union_rect(®ion, ®ion, &cmdRect);
1118 case RDP_CODEC_ID_NONE:
1119 format = gdi_get_pixel_format(cmd->bmp.bpp);
1120 size = 1ull * cmd->bmp.width * cmd->bmp.height * FreeRDPGetBytesPerPixel(format);
1121 if (size > cmd->bmp.bitmapDataLength)
1123 WLog_ERR(TAG,
"Short nocodec message: got %" PRIu32
" bytes, require %" PRIuz,
1124 cmd->bmp.bitmapDataLength, size);
1128 if (!freerdp_image_copy_no_overlap(
1129 gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmdRect.left, cmdRect.top,
1130 cmdRect.right - cmdRect.left, cmdRect.bottom - cmdRect.top, cmd->bmp.bitmapData,
1131 format, 0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))
1133 WLog_ERR(TAG,
"Failed to process nocodec message");
1137 region16_union_rect(®ion, ®ion, &cmdRect);
1141 WLog_ERR(TAG,
"Unsupported codecID %" PRIu32
"", cmd->bmp.codecID);
1146 const RECTANGLE_16* rects = region16_rects(®ion, &nbRects);
1147 if (!rects && (nbRects > 0))
1152 const int32_t w = cmdRect.right - cmdRect.left;
1153 const int32_t h = cmdRect.bottom - cmdRect.top;
1154 if (!gdi_InvalidateRegion(gdi->primary->hdc, cmdRect.left, cmdRect.top, w, h))
1157 for (UINT32 i = 0; i < nbRects; i++)
1161 UINT32 left = rect->left;
1162 UINT32 top = rect->top;
1163 UINT32 width = rect->right - rect->left;
1164 UINT32 height = rect->bottom - rect->top;
1166 if (!gdi_InvalidateRegion(gdi->primary->hdc, WINPR_ASSERTING_INT_CAST(int32_t, left),
1167 WINPR_ASSERTING_INT_CAST(int32_t, top),
1168 WINPR_ASSERTING_INT_CAST(int32_t, width),
1169 WINPR_ASSERTING_INT_CAST(int32_t, height)))
1171 WLog_ERR(TAG,
"Failed to update invalid region");
1178 region16_uninit(®ion);
1187static void gdi_register_update_callbacks(rdpUpdate* update)
1189 rdpPrimaryUpdate* primary = NULL;
1190 const rdpSettings* settings = NULL;
1192 WINPR_ASSERT(update);
1193 WINPR_ASSERT(update->context);
1195 settings = update->context->settings;
1196 WINPR_ASSERT(settings);
1198 primary = update->primary;
1199 WINPR_ASSERT(primary);
1203 update->Palette = gdi_palette_update;
1204 update->SetBounds = gdi_set_bounds;
1205 primary->DstBlt = gdi_dstblt;
1206 primary->PatBlt = gdi_patblt;
1207 primary->ScrBlt = gdi_scrblt;
1208 primary->OpaqueRect = gdi_opaque_rect;
1209 primary->DrawNineGrid = NULL;
1210 primary->MultiDstBlt = NULL;
1211 primary->MultiPatBlt = NULL;
1212 primary->MultiScrBlt = NULL;
1213 primary->MultiOpaqueRect = gdi_multi_opaque_rect;
1214 primary->MultiDrawNineGrid = NULL;
1215 primary->LineTo = gdi_line_to;
1216 primary->Polyline = gdi_polyline;
1217 primary->MemBlt = gdi_memblt;
1218 primary->Mem3Blt = gdi_mem3blt;
1219 primary->SaveBitmap = NULL;
1220 primary->GlyphIndex = NULL;
1221 primary->FastIndex = NULL;
1222 primary->FastGlyph = NULL;
1223 primary->PolygonSC = gdi_polygon_sc;
1224 primary->PolygonCB = gdi_polygon_cb;
1225 primary->EllipseSC = gdi_ellipse_sc;
1226 primary->EllipseCB = gdi_ellipse_cb;
1227 update->SurfaceBits = gdi_surface_bits;
1228 update->SurfaceFrameMarker = gdi_surface_frame_marker;
1229 update->altsec->FrameMarker = gdi_frame_marker;
1232static BOOL gdi_init_primary(rdpGdi* gdi, UINT32 stride, UINT32 format, BYTE* buffer,
1233 void (*pfree)(
void*), BOOL isLocked)
1236 WINPR_ASSERT(gdi->context);
1237 WINPR_ASSERT(gdi->context->update);
1239 rdp_update_lock(gdi->context->update);
1241 gdi->primary = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
1244 gdi->dstFormat = format;
1247 gdi->stride = stride;
1249 gdi->stride = WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width) *
1250 FreeRDPGetBytesPerPixel(gdi->dstFormat);
1255 if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
1260 gdi->primary->bitmap =
1261 gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1262 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height));
1266 gdi->primary->bitmap = gdi_CreateBitmapEx(WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1267 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height),
1268 gdi->dstFormat, gdi->stride, buffer, pfree);
1271 if (!gdi->primary->bitmap)
1274 gdi->stride = gdi->primary->bitmap->scanline;
1275 gdi_SelectObject(gdi->primary->hdc, (
HGDIOBJECT)gdi->primary->bitmap);
1276 gdi->primary->org_bitmap = NULL;
1277 gdi->primary_buffer = gdi->primary->bitmap->data;
1279 if (!(gdi->primary->hdc->hwnd = (
HGDI_WND)calloc(1,
sizeof(
GDI_WND))))
1282 if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0)))
1285 gdi->primary->hdc->hwnd->invalid->null = TRUE;
1286 gdi->primary->hdc->hwnd->count = 32;
1288 if (!(gdi->primary->hdc->hwnd->cinvalid =
1289 (
GDI_RGN*)calloc(gdi->primary->hdc->hwnd->count,
sizeof(
GDI_RGN))))
1292 gdi->primary->hdc->hwnd->ninvalid = 0;
1295 gdi->drawing = gdi->primary;
1297 rdp_update_unlock(gdi->context->update);
1300 gdi_DeleteObject((
HGDIOBJECT)gdi->primary->bitmap);
1302 gdi_DeleteDC(gdi->primary->hdc);
1305 gdi->primary = NULL;
1307 rdp_update_unlock(gdi->context->update);
1311BOOL gdi_resize(rdpGdi* gdi, UINT32 width, UINT32 height)
1313 return gdi_resize_ex(gdi, width, height, 0, 0, NULL, NULL);
1316BOOL gdi_resize_ex(rdpGdi* gdi, UINT32 width, UINT32 height, UINT32 stride, UINT32 format,
1317 BYTE* buffer,
void (*pfree)(
void*))
1319 if (!gdi || !gdi->primary)
1322 if ((width > INT32_MAX) || (height > INT32_MAX))
1325 if ((gdi->width == (INT32)width) && (gdi->height == (INT32)height) &&
1326 (!buffer || (gdi->primary_buffer == buffer)))
1329 WINPR_ASSERT(gdi->context);
1330 WINPR_ASSERT(gdi->context->update);
1333 if (!update_end_paint(gdi->context->update))
1335 rdp_update_lock(gdi->context->update);
1337 if (gdi->drawing == gdi->primary)
1338 gdi->drawing = NULL;
1340 gdi->width = (INT32)width;
1341 gdi->height = (INT32)height;
1342 gdi_bitmap_free_ex(gdi->primary);
1343 gdi->primary = NULL;
1344 gdi->primary_buffer = NULL;
1345 return gdi_init_primary(gdi, stride, format, buffer, pfree, TRUE);
1355BOOL gdi_init(freerdp* instance, UINT32 format)
1357 return gdi_init_ex(instance, format, 0, NULL, winpr_aligned_free);
1371BOOL gdi_init_ex(freerdp* instance, UINT32 format, UINT32 stride, BYTE* buffer,
1372 void (*pfree)(
void*))
1374 rdpContext* context = NULL;
1375 UINT32 SrcFormat = 0;
1378 WINPR_ASSERT(instance);
1380 context = instance->context;
1381 WINPR_ASSERT(context);
1382 WINPR_ASSERT(context->settings);
1385 SrcFormat = gdi_get_pixel_format(ColorDepth);
1386 gdi = (rdpGdi*)calloc(1,
sizeof(rdpGdi));
1392 gdi->log = WLog_Get(TAG);
1397 gdi->context = context;
1398 gdi->width = WINPR_ASSERTING_INT_CAST(
1400 gdi->height = WINPR_ASSERTING_INT_CAST(
1402 gdi->dstFormat = format;
1404 WLog_Print(gdi->log, WLOG_INFO,
"Local framebuffer format %s",
1405 FreeRDPGetColorFormatName(gdi->dstFormat));
1406 WLog_Print(gdi->log, WLOG_INFO,
"Remote framebuffer format %s",
1407 FreeRDPGetColorFormatName(SrcFormat));
1409 if (!(gdi->hdc = gdi_GetDC()))
1412 gdi->hdc->format = gdi->dstFormat;
1414 if (!gdi_init_primary(gdi, stride, gdi->dstFormat, buffer, pfree, FALSE))
1417 if (!(context->cache = cache_new(context)))
1420 gdi_register_update_callbacks(context->update);
1421 brush_cache_register_callbacks(context->update);
1422 glyph_cache_register_callbacks(context->update);
1423 bitmap_cache_register_callbacks(context->update);
1424 offscreen_cache_register_callbacks(context->update);
1425 palette_cache_register_callbacks(context->update);
1427 if (!gdi_register_graphics(context->graphics))
1433 WLog_ERR(TAG,
"failed to initialize gdi");
1437void gdi_free(freerdp* instance)
1440 rdpContext* context = NULL;
1442 if (!instance || !instance->context)
1445 gdi = instance->context->gdi;
1449 gdi_bitmap_free_ex(gdi->primary);
1450 gdi_DeleteDC(gdi->hdc);
1454 context = instance->context;
1455 cache_free(context->cache);
1456 context->cache = NULL;
1457 instance->context->gdi = (rdpGdi*)NULL;
1460BOOL gdi_send_suppress_output(rdpGdi* gdi, BOOL suppress)
1462 if (!gdi || !gdi->context)
1465 if (gdi->suppressOutput == suppress)
1468 gdi->suppressOutput = suppress;
1470 rdpContext* context = gdi->context;
1471 rdpSettings* settings = context->settings;
1472 WINPR_ASSERT(settings);
1474 rdpUpdate* update = context->update;
1475 WINPR_ASSERT(update);
1482 .right = WINPR_ASSERTING_INT_CAST(UINT16, w),
1483 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, h) };
1485 WINPR_ASSERT(update->SuppressOutput);
1486 return update->SuppressOutput(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.