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>
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")
60static 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" } };
318static 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__)
328static inline DWORD gdi_rop3_code_checked_int(UINT32 code, WINPR_ATTR_UNUSED
const char* file,
329 WINPR_ATTR_UNUSED
const char* fkt,
330 WINPR_ATTR_UNUSED
size_t line)
332 WINPR_ASSERT_AT(code <= UINT8_MAX, file, fkt, line);
333 return gdi_rop3_code((UINT8)code);
336BOOL gdi_decode_color(rdpGdi* gdi, UINT32 srcColor, UINT32* color, UINT32* format)
338 UINT32 SrcFormat = 0;
340 if (!gdi || !color || !gdi->context || !gdi->context->settings)
343 const UINT32 ColorDepth =
350 SrcFormat = PIXEL_FORMAT_BGR24;
354 SrcFormat = PIXEL_FORMAT_RGB16;
358 SrcFormat = PIXEL_FORMAT_RGB15;
362 SrcFormat = PIXEL_FORMAT_RGB8;
370 *format = gdi->dstFormat;
372 *color = FreeRDPConvertColor(srcColor, SrcFormat, gdi->dstFormat, &gdi->palette);
377DWORD gdi_rop3_code(BYTE code)
379 return rop3_code_table[code].code;
382const char* gdi_rop3_code_string(BYTE code)
384 return rop3_code_table[code].name;
387const char* gdi_rop3_string(DWORD rop)
389 const size_t count =
sizeof(rop3_code_table) /
sizeof(rop3_code_table[0]);
391 for (
size_t x = 0; x < count; x++)
393 if (rop3_code_table[x].code == rop)
394 return rop3_code_table[x].name;
400UINT32 gdi_get_pixel_format(UINT32 bitsPerPixel)
404 switch (bitsPerPixel)
407 format = PIXEL_FORMAT_BGRA32;
411 format = PIXEL_FORMAT_BGR24;
415 format = PIXEL_FORMAT_RGB16;
419 format = PIXEL_FORMAT_RGB15;
423 format = PIXEL_FORMAT_RGB8;
427 WLog_ERR(TAG,
"Unsupported color depth %" PRIu32, bitsPerPixel);
435gdiBitmap* gdi_bitmap_new_ex(rdpGdi* gdi,
int width,
int height,
int bpp, BYTE* data)
437 gdiBitmap* bitmap = NULL;
438 bitmap = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
443 if (!(bitmap->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
446 WLog_Print(gdi->log, WLOG_DEBUG,
"gdi_bitmap_new: width:%d height:%d bpp:%d", width, height,
451 gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, width),
452 WINPR_ASSERTING_INT_CAST(uint32_t, height));
454 bitmap->bitmap = gdi_create_bitmap(gdi, WINPR_ASSERTING_INT_CAST(uint32_t, width),
455 WINPR_ASSERTING_INT_CAST(uint32_t, height),
456 WINPR_ASSERTING_INT_CAST(uint32_t, bpp), data);
459 goto fail_bitmap_bitmap;
461 gdi_SelectObject(bitmap->hdc, (
HGDIOBJECT)bitmap->bitmap);
462 bitmap->org_bitmap = NULL;
465 gdi_DeleteDC(bitmap->hdc);
472void gdi_bitmap_free_ex(gdiBitmap* bitmap)
476 gdi_SelectObject(bitmap->hdc, (
HGDIOBJECT)bitmap->org_bitmap);
478 gdi_DeleteDC(bitmap->hdc);
483BOOL gdi_bitmap_update(rdpContext* context,
const BITMAP_UPDATE* bitmapUpdate)
485 if (!context || !bitmapUpdate || !context->gdi || !context->codecs)
488 "Invalid arguments: context=%p, bitmapUpdate=%p, context->gdi=%p, "
489 "context->codecs=%p",
490 context, bitmapUpdate, context ? context->gdi : NULL,
491 context ? context->codecs : NULL);
495 for (UINT32 index = 0; index < bitmapUpdate->number; index++)
498 const BITMAP_DATA* bitmap = &(bitmapUpdate->rectangles[index]);
499 rdpBitmap* bmp = Bitmap_Alloc(context);
504 if (!Bitmap_SetDimensions(bmp, WINPR_ASSERTING_INT_CAST(UINT16, bitmap->width),
505 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->height)))
508 if (!Bitmap_SetRectangle(bmp, WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destLeft),
509 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destTop),
510 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destRight),
511 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destBottom)))
514 if (!bmp->Decompress(context, bmp, bitmap->bitmapDataStream, bitmap->width, bitmap->height,
515 bitmap->bitsPerPixel, bitmap->bitmapLength, bitmap->compressed,
519 if (!bmp->New(context, bmp))
522 if (!bmp->Paint(context, bmp))
527 Bitmap_Free(context, bmp);
535static BOOL gdi_palette_update(rdpContext* context,
const PALETTE_UPDATE* palette)
539 if (!context || !palette)
543 gdi->palette.format = gdi->dstFormat;
545 for (UINT32 index = 0; index < palette->number; index++)
548 gdi->palette.palette[index] =
549 FreeRDPGetColor(gdi->dstFormat, pe->red, pe->green, pe->blue, 0xFF);
555static BOOL gdi_set_bounds(rdpContext* context,
const rdpBounds* bounds)
566 gdi_SetClipRgn(gdi->drawing->hdc, bounds->left, bounds->top,
567 bounds->right - bounds->left + 1, bounds->bottom - bounds->top + 1);
570 gdi_SetNullClipRgn(gdi->drawing->hdc);
575static BOOL gdi_dstblt(rdpContext* context,
const DSTBLT_ORDER* dstblt)
579 if (!context || !dstblt)
583 return gdi_BitBlt(gdi->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth,
584 dstblt->nHeight, NULL, 0, 0, gdi_rop3_code_checked(dstblt->bRop),
588static BOOL gdi_patblt(rdpContext* context,
PATBLT_ORDER* patblt)
590 const rdpBrush* brush = &patblt->brush;
591 UINT32 foreColor = 0;
592 UINT32 backColor = 0;
593 UINT32 originalColor = 0;
596 rdpGdi* gdi = context->gdi;
598 const DWORD rop = gdi_rop3_code_checked(patblt->bRop);
601 BYTE data[8 * 8 * 4];
604 if (!gdi_decode_color(gdi, patblt->foreColor, &foreColor, NULL))
607 if (!gdi_decode_color(gdi, patblt->backColor, &backColor, NULL))
610 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
611 originalBrush = gdi->drawing->hdc->brush;
613 switch (brush->style)
616 hbrush = gdi_CreateSolidBrush(foreColor);
621 const BYTE* hatched = NULL;
622 hatched = GDI_BS_HATCHED_PATTERNS + (8ULL * brush->hatch);
624 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
625 hatched, backColor, foreColor, &gdi->palette))
628 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
633 hbrush = gdi_CreateHatchBrush(hBmp);
639 UINT32 brushFormat = 0;
643 UINT32 bpp = brush->bpp;
649 brushFormat = gdi_get_pixel_format(bpp);
651 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
652 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
658 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
659 8, brush->data, backColor, foreColor,
664 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
669 hbrush = gdi_CreatePatternBrush(hBmp);
674 WLog_ERR(TAG,
"unimplemented brush style:%" PRIu32
"", brush->style);
680 hbrush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
681 hbrush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
682 gdi->drawing->hdc->brush = hbrush;
683 ret = gdi_BitBlt(gdi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
684 patblt->nHeight, gdi->primary->hdc, nXSrc, nYSrc, rop, &gdi->palette);
690 gdi->drawing->hdc->brush = originalBrush;
691 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
695static BOOL gdi_scrblt(rdpContext* context,
const SCRBLT_ORDER* scrblt)
699 if (!context || !context->gdi)
703 return gdi_BitBlt(gdi->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth,
704 scrblt->nHeight, gdi->primary->hdc, scrblt->nXSrc, scrblt->nYSrc,
705 gdi_rop3_code_checked(scrblt->bRop), &gdi->palette);
708static BOOL gdi_opaque_rect(rdpContext* context,
const OPAQUE_RECT_ORDER* opaque_rect)
712 UINT32 brush_color = 0;
713 rdpGdi* gdi = context->gdi;
715 INT32 x = opaque_rect->nLeftRect;
716 INT32 y = opaque_rect->nTopRect;
717 INT32 w = opaque_rect->nWidth;
718 INT32 h = opaque_rect->nHeight;
719 gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
720 gdi_CRgnToRect(x, y, w, h, &rect);
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 INT32 x = rectangle->left;
754 INT32 y = rectangle->top;
755 INT32 w = rectangle->width;
756 INT32 h = rectangle->height;
757 gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
758 gdi_CRgnToRect(x, y, w, h, &rect);
759 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
769static BOOL gdi_line_to(rdpContext* context,
const LINE_TO_ORDER* lineTo)
773 rdpGdi* gdi = context->gdi;
774 INT32 xStart = lineTo->nXStart;
775 INT32 yStart = lineTo->nYStart;
776 INT32 xEnd = lineTo->nXEnd;
777 INT32 yEnd = lineTo->nYEnd;
780 gdi_ClipCoords(gdi->drawing->hdc, &xStart, &yStart, &w, &h, NULL, NULL);
781 gdi_ClipCoords(gdi->drawing->hdc, &xEnd, &yEnd, &w, &h, NULL, NULL);
783 if (!gdi_decode_color(gdi, lineTo->penColor, &color, NULL))
786 if (!(hPen = gdi_CreatePen(lineTo->penStyle, lineTo->penWidth, color, gdi->drawing->hdc->format,
790 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)hPen);
791 gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, lineTo->bRop2));
792 gdi_MoveToEx(gdi->drawing->hdc, lineTo->nXStart, lineTo->nYStart, NULL);
793 gdi_LineTo(gdi->drawing->hdc, lineTo->nXEnd, lineTo->nYEnd);
798static BOOL gdi_polyline(rdpContext* context,
const POLYLINE_ORDER* polyline)
805 rdpGdi* gdi = context->gdi;
809 if (!gdi_decode_color(gdi, polyline->penColor, &color, NULL))
812 if (!(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 x = polyline->xStart;
818 y = polyline->yStart;
819 gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
820 gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL);
821 points = polyline->points;
823 for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
827 gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
828 gdi_LineTo(gdi->drawing->hdc, x, y);
829 gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL);
836static BOOL gdi_memblt(rdpContext* context,
MEMBLT_ORDER* memblt)
838 gdiBitmap* bitmap = NULL;
841 if (!context || !memblt || !context->gdi || !memblt->bitmap)
844 bitmap = (gdiBitmap*)memblt->bitmap;
846 return gdi_BitBlt(gdi->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
847 memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc,
848 gdi_rop3_code_checked(memblt->bRop), &gdi->palette);
851static BOOL gdi_mem3blt(rdpContext* context,
MEM3BLT_ORDER* mem3blt)
854 rdpGdi* gdi = context->gdi;
856 const rdpBrush* brush = &mem3blt->brush;
857 gdiBitmap* bitmap = (gdiBitmap*)mem3blt->bitmap;
858 UINT32 foreColor = 0;
859 UINT32 backColor = 0;
860 UINT32 originalColor = 0;
862 if (!gdi_decode_color(gdi, mem3blt->foreColor, &foreColor, NULL))
865 if (!gdi_decode_color(gdi, mem3blt->backColor, &backColor, NULL))
868 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
870 switch (brush->style)
873 originalBrush = gdi->drawing->hdc->brush;
874 gdi->drawing->hdc->brush = gdi_CreateSolidBrush(foreColor);
876 if (!gdi->drawing->hdc->brush)
882 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
883 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
884 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
885 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
886 gdi->drawing->hdc->brush = originalBrush;
892 UINT32 brushFormat = 0;
893 BYTE* data = (BYTE*)winpr_aligned_malloc(
894 8ULL * 8ULL * FreeRDPGetBytesPerPixel(gdi->drawing->hdc->format), 16);
904 UINT32 bpp = brush->bpp;
906 const UINT32 ColorDepth =
908 if ((bpp == 16) && (ColorDepth == 15))
911 brushFormat = gdi_get_pixel_format(bpp);
913 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
914 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
918 winpr_aligned_free(data);
924 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
925 8, brush->data, backColor, foreColor,
929 winpr_aligned_free(data);
934 hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->format, data);
939 winpr_aligned_free(data);
943 originalBrush = gdi->drawing->hdc->brush;
944 gdi->drawing->hdc->brush = gdi_CreatePatternBrush(hBmp);
946 if (!gdi->drawing->hdc->brush)
952 gdi->drawing->hdc->brush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
953 gdi->drawing->hdc->brush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
954 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
955 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
956 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
957 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
959 gdi->drawing->hdc->brush = originalBrush;
964 WLog_ERR(TAG,
"Mem3Blt unimplemented brush style:%" PRIu32
"", brush->style);
969 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
973static BOOL gdi_polygon_sc(WINPR_ATTR_UNUSED rdpContext* context,
976 WLog_WARN(TAG,
"not implemented");
980static BOOL gdi_polygon_cb(WINPR_ATTR_UNUSED rdpContext* context,
983 WLog_WARN(TAG,
"not implemented");
987static BOOL gdi_ellipse_sc(WINPR_ATTR_UNUSED rdpContext* context,
990 WLog_WARN(TAG,
"not implemented");
994static BOOL gdi_ellipse_cb(WINPR_ATTR_UNUSED rdpContext* context,
997 WLog_WARN(TAG,
"not implemented");
1001static BOOL gdi_frame_marker(WINPR_ATTR_UNUSED rdpContext* context,
1007static BOOL gdi_surface_frame_marker(rdpContext* context,
1010 WLog_Print(context->gdi->log, WLOG_DEBUG,
"frameId %" PRIu32
" frameAction %" PRIu32
"",
1011 surfaceFrameMarker->frameId, surfaceFrameMarker->frameAction);
1013 switch (surfaceFrameMarker->frameAction)
1015 case SURFACECMD_FRAMEACTION_BEGIN:
1018 case SURFACECMD_FRAMEACTION_END:
1021 IFCALL(context->update->SurfaceFrameAcknowledge, context,
1022 surfaceFrameMarker->frameId);
1035 const UINT32 w = (
const UINT32)gdi->width;
1036 const UINT32 h = (
const UINT32)gdi->height;
1038 if (cmd->destLeft > w)
1040 if (cmd->destRight > w)
1042 if (cmd->destLeft > cmd->destRight)
1044 if (cmd->destRight > UINT16_MAX)
1047 if (cmd->destTop > h)
1049 if (cmd->destBottom > h)
1051 if (cmd->destTop > cmd->destBottom)
1053 if (cmd->destBottom > UINT16_MAX)
1056 prect->left = (
const UINT16)cmd->destLeft;
1057 prect->top = (
const UINT16)cmd->destTop;
1058 prect->right = MIN((UINT16)cmd->destRight, prect->left + cmd->bmp.width);
1059 prect->bottom = MIN((UINT16)cmd->destBottom, prect->top + cmd->bmp.height);
1065 BOOL result = FALSE;
1074 if (!context || !cmd)
1079 gdi->log, WLOG_DEBUG,
1080 "destLeft %" PRIu32
" destTop %" PRIu32
" destRight %" PRIu32
" destBottom %" PRIu32
" "
1081 "bpp %" PRIu8
" flags %" PRIx8
" codecID %" PRIu16
" width %" PRIu16
" height %" PRIu16
1082 " length %" PRIu32
"",
1083 cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bmp.bpp, cmd->bmp.flags,
1084 cmd->bmp.codecID, cmd->bmp.width, cmd->bmp.height, cmd->bmp.bitmapDataLength);
1085 region16_init(®ion);
1087 if (!intersect_rect(gdi, cmd, &cmdRect))
1090 switch (cmd->bmp.codecID)
1092 case RDP_CODEC_ID_REMOTEFX:
1093 case RDP_CODEC_ID_IMAGE_REMOTEFX:
1094 if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData,
1095 cmd->bmp.bitmapDataLength, cmdRect.left, cmdRect.top,
1096 gdi->primary_buffer, gdi->dstFormat, gdi->stride,
1097 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height), ®ion))
1099 WLog_ERR(TAG,
"Failed to process RemoteFX message");
1105 case RDP_CODEC_ID_NSCODEC:
1106 format = gdi->dstFormat;
1108 if (!nsc_process_message(
1109 context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, cmd->bmp.height,
1110 cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, format,
1111 gdi->stride, cmdRect.left, cmdRect.top, cmdRect.right - cmdRect.left,
1112 cmdRect.bottom - cmdRect.top, FREERDP_FLIP_VERTICAL))
1114 WLog_ERR(TAG,
"Failed to process NSCodec message");
1118 region16_union_rect(®ion, ®ion, &cmdRect);
1121 case RDP_CODEC_ID_NONE:
1122 format = gdi_get_pixel_format(cmd->bmp.bpp);
1123 size = 1ull * cmd->bmp.width * cmd->bmp.height * FreeRDPGetBytesPerPixel(format);
1124 if (size > cmd->bmp.bitmapDataLength)
1126 WLog_ERR(TAG,
"Short nocodec message: got %" PRIu32
" bytes, require %" PRIuz,
1127 cmd->bmp.bitmapDataLength, size);
1131 if (!freerdp_image_copy_no_overlap(
1132 gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmdRect.left, cmdRect.top,
1133 cmdRect.right - cmdRect.left, cmdRect.bottom - cmdRect.top, cmd->bmp.bitmapData,
1134 format, 0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))
1136 WLog_ERR(TAG,
"Failed to process nocodec message");
1140 region16_union_rect(®ion, ®ion, &cmdRect);
1144 WLog_ERR(TAG,
"Unsupported codecID %" PRIu32
"", cmd->bmp.codecID);
1148 if (!(rects = region16_rects(®ion, &nbRects)))
1151 for (UINT32 i = 0; i < nbRects; i++)
1153 UINT32 left = rects[i].left;
1154 UINT32 top = rects[i].top;
1155 UINT32 width = rects[i].right - rects[i].left;
1156 UINT32 height = rects[i].bottom - rects[i].top;
1158 if (!gdi_InvalidateRegion(gdi->primary->hdc, WINPR_ASSERTING_INT_CAST(int32_t, left),
1159 WINPR_ASSERTING_INT_CAST(int32_t, top),
1160 WINPR_ASSERTING_INT_CAST(int32_t, width),
1161 WINPR_ASSERTING_INT_CAST(int32_t, height)))
1163 WLog_ERR(TAG,
"Failed to update invalid region");
1170 region16_uninit(®ion);
1179static void gdi_register_update_callbacks(rdpUpdate* update)
1181 rdpPrimaryUpdate* primary = NULL;
1182 const rdpSettings* settings = NULL;
1184 WINPR_ASSERT(update);
1185 WINPR_ASSERT(update->context);
1187 settings = update->context->settings;
1188 WINPR_ASSERT(settings);
1190 primary = update->primary;
1191 WINPR_ASSERT(primary);
1195 update->Palette = gdi_palette_update;
1196 update->SetBounds = gdi_set_bounds;
1197 primary->DstBlt = gdi_dstblt;
1198 primary->PatBlt = gdi_patblt;
1199 primary->ScrBlt = gdi_scrblt;
1200 primary->OpaqueRect = gdi_opaque_rect;
1201 primary->DrawNineGrid = NULL;
1202 primary->MultiDstBlt = NULL;
1203 primary->MultiPatBlt = NULL;
1204 primary->MultiScrBlt = NULL;
1205 primary->MultiOpaqueRect = gdi_multi_opaque_rect;
1206 primary->MultiDrawNineGrid = NULL;
1207 primary->LineTo = gdi_line_to;
1208 primary->Polyline = gdi_polyline;
1209 primary->MemBlt = gdi_memblt;
1210 primary->Mem3Blt = gdi_mem3blt;
1211 primary->SaveBitmap = NULL;
1212 primary->GlyphIndex = NULL;
1213 primary->FastIndex = NULL;
1214 primary->FastGlyph = NULL;
1215 primary->PolygonSC = gdi_polygon_sc;
1216 primary->PolygonCB = gdi_polygon_cb;
1217 primary->EllipseSC = gdi_ellipse_sc;
1218 primary->EllipseCB = gdi_ellipse_cb;
1219 update->SurfaceBits = gdi_surface_bits;
1220 update->SurfaceFrameMarker = gdi_surface_frame_marker;
1221 update->altsec->FrameMarker = gdi_frame_marker;
1224static BOOL gdi_init_primary(rdpGdi* gdi, UINT32 stride, UINT32 format, BYTE* buffer,
1225 void (*pfree)(
void*), BOOL isLocked)
1228 WINPR_ASSERT(gdi->context);
1229 WINPR_ASSERT(gdi->context->update);
1231 rdp_update_lock(gdi->context->update);
1233 gdi->primary = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
1236 gdi->dstFormat = format;
1239 gdi->stride = stride;
1241 gdi->stride = WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width) *
1242 FreeRDPGetBytesPerPixel(gdi->dstFormat);
1247 if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
1252 gdi->primary->bitmap =
1253 gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1254 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height));
1258 gdi->primary->bitmap = gdi_CreateBitmapEx(WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1259 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height),
1260 gdi->dstFormat, gdi->stride, buffer, pfree);
1263 if (!gdi->primary->bitmap)
1266 gdi->stride = gdi->primary->bitmap->scanline;
1267 gdi_SelectObject(gdi->primary->hdc, (
HGDIOBJECT)gdi->primary->bitmap);
1268 gdi->primary->org_bitmap = NULL;
1269 gdi->primary_buffer = gdi->primary->bitmap->data;
1271 if (!(gdi->primary->hdc->hwnd = (
HGDI_WND)calloc(1,
sizeof(
GDI_WND))))
1274 if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0)))
1277 gdi->primary->hdc->hwnd->invalid->null = TRUE;
1278 gdi->primary->hdc->hwnd->count = 32;
1280 if (!(gdi->primary->hdc->hwnd->cinvalid =
1281 (
GDI_RGN*)calloc(gdi->primary->hdc->hwnd->count,
sizeof(
GDI_RGN))))
1284 gdi->primary->hdc->hwnd->ninvalid = 0;
1287 gdi->drawing = gdi->primary;
1289 rdp_update_unlock(gdi->context->update);
1292 gdi_DeleteObject((
HGDIOBJECT)gdi->primary->bitmap);
1294 gdi_DeleteDC(gdi->primary->hdc);
1297 gdi->primary = NULL;
1299 rdp_update_unlock(gdi->context->update);
1303BOOL gdi_resize(rdpGdi* gdi, UINT32 width, UINT32 height)
1305 return gdi_resize_ex(gdi, width, height, 0, 0, NULL, NULL);
1308BOOL gdi_resize_ex(rdpGdi* gdi, UINT32 width, UINT32 height, UINT32 stride, UINT32 format,
1309 BYTE* buffer,
void (*pfree)(
void*))
1311 if (!gdi || !gdi->primary)
1314 if ((width > INT32_MAX) || (height > INT32_MAX))
1317 if ((gdi->width == (INT32)width) && (gdi->height == (INT32)height) &&
1318 (!buffer || (gdi->primary_buffer == buffer)))
1321 WINPR_ASSERT(gdi->context);
1322 WINPR_ASSERT(gdi->context->update);
1325 if (!update_end_paint(gdi->context->update))
1327 rdp_update_lock(gdi->context->update);
1329 if (gdi->drawing == gdi->primary)
1330 gdi->drawing = NULL;
1332 gdi->width = (INT32)width;
1333 gdi->height = (INT32)height;
1334 gdi_bitmap_free_ex(gdi->primary);
1335 gdi->primary = NULL;
1336 gdi->primary_buffer = NULL;
1337 return gdi_init_primary(gdi, stride, format, buffer, pfree, TRUE);
1347BOOL gdi_init(freerdp* instance, UINT32 format)
1349 return gdi_init_ex(instance, format, 0, NULL, winpr_aligned_free);
1363BOOL gdi_init_ex(freerdp* instance, UINT32 format, UINT32 stride, BYTE* buffer,
1364 void (*pfree)(
void*))
1366 rdpContext* context = NULL;
1367 UINT32 SrcFormat = 0;
1370 WINPR_ASSERT(instance);
1372 context = instance->context;
1373 WINPR_ASSERT(context);
1374 WINPR_ASSERT(context->settings);
1377 SrcFormat = gdi_get_pixel_format(ColorDepth);
1378 gdi = (rdpGdi*)calloc(1,
sizeof(rdpGdi));
1384 gdi->log = WLog_Get(TAG);
1389 gdi->context = context;
1390 gdi->width = WINPR_ASSERTING_INT_CAST(
1392 gdi->height = WINPR_ASSERTING_INT_CAST(
1394 gdi->dstFormat = format;
1396 WLog_Print(gdi->log, WLOG_INFO,
"Local framebuffer format %s",
1397 FreeRDPGetColorFormatName(gdi->dstFormat));
1398 WLog_Print(gdi->log, WLOG_INFO,
"Remote framebuffer format %s",
1399 FreeRDPGetColorFormatName(SrcFormat));
1401 if (!(gdi->hdc = gdi_GetDC()))
1404 gdi->hdc->format = gdi->dstFormat;
1406 if (!gdi_init_primary(gdi, stride, gdi->dstFormat, buffer, pfree, FALSE))
1409 if (!(context->cache = cache_new(context)))
1412 gdi_register_update_callbacks(context->update);
1413 brush_cache_register_callbacks(context->update);
1414 glyph_cache_register_callbacks(context->update);
1415 bitmap_cache_register_callbacks(context->update);
1416 offscreen_cache_register_callbacks(context->update);
1417 palette_cache_register_callbacks(context->update);
1419 if (!gdi_register_graphics(context->graphics))
1425 WLog_ERR(TAG,
"failed to initialize gdi");
1429void gdi_free(freerdp* instance)
1432 rdpContext* context = NULL;
1434 if (!instance || !instance->context)
1437 gdi = instance->context->gdi;
1441 gdi_bitmap_free_ex(gdi->primary);
1442 gdi_DeleteDC(gdi->hdc);
1446 context = instance->context;
1447 cache_free(context->cache);
1448 context->cache = NULL;
1449 instance->context->gdi = (rdpGdi*)NULL;
1452BOOL gdi_send_suppress_output(rdpGdi* gdi, BOOL suppress)
1454 if (!gdi || !gdi->context)
1457 if (gdi->suppressOutput == suppress)
1460 gdi->suppressOutput = suppress;
1462 rdpContext* context = gdi->context;
1463 rdpSettings* settings = context->settings;
1464 WINPR_ASSERT(settings);
1466 rdpUpdate* update = context->update;
1467 WINPR_ASSERT(update);
1474 .right = WINPR_ASSERTING_INT_CAST(UINT16, w),
1475 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, h) };
1477 WINPR_ASSERT(update->SuppressOutput);
1478 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.