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;
1072 if (!context || !cmd)
1077 gdi->log, WLOG_DEBUG,
1078 "destLeft %" PRIu32
" destTop %" PRIu32
" destRight %" PRIu32
" destBottom %" PRIu32
" "
1079 "bpp %" PRIu8
" flags %" PRIx8
" codecID %" PRIu16
" width %" PRIu16
" height %" PRIu16
1080 " length %" PRIu32
"",
1081 cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bmp.bpp, cmd->bmp.flags,
1082 cmd->bmp.codecID, cmd->bmp.width, cmd->bmp.height, cmd->bmp.bitmapDataLength);
1083 region16_init(®ion);
1085 if (!intersect_rect(gdi, cmd, &cmdRect))
1088 switch (cmd->bmp.codecID)
1090 case RDP_CODEC_ID_REMOTEFX:
1091 case RDP_CODEC_ID_IMAGE_REMOTEFX:
1092 if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData,
1093 cmd->bmp.bitmapDataLength, cmdRect.left, cmdRect.top,
1094 gdi->primary_buffer, gdi->dstFormat, gdi->stride,
1095 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height), ®ion))
1097 WLog_ERR(TAG,
"Failed to process RemoteFX message");
1103 case RDP_CODEC_ID_NSCODEC:
1104 format = gdi->dstFormat;
1106 if (!nsc_process_message(
1107 context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, cmd->bmp.height,
1108 cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, format,
1109 gdi->stride, cmdRect.left, cmdRect.top, cmdRect.right - cmdRect.left,
1110 cmdRect.bottom - cmdRect.top, FREERDP_FLIP_VERTICAL))
1112 WLog_ERR(TAG,
"Failed to process NSCodec message");
1116 region16_union_rect(®ion, ®ion, &cmdRect);
1119 case RDP_CODEC_ID_NONE:
1120 format = gdi_get_pixel_format(cmd->bmp.bpp);
1121 size = 1ull * cmd->bmp.width * cmd->bmp.height * FreeRDPGetBytesPerPixel(format);
1122 if (size > cmd->bmp.bitmapDataLength)
1124 WLog_ERR(TAG,
"Short nocodec message: got %" PRIu32
" bytes, require %" PRIuz,
1125 cmd->bmp.bitmapDataLength, size);
1129 if (!freerdp_image_copy_no_overlap(
1130 gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmdRect.left, cmdRect.top,
1131 cmdRect.right - cmdRect.left, cmdRect.bottom - cmdRect.top, cmd->bmp.bitmapData,
1132 format, 0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))
1134 WLog_ERR(TAG,
"Failed to process nocodec message");
1138 region16_union_rect(®ion, ®ion, &cmdRect);
1142 WLog_ERR(TAG,
"Unsupported codecID %" PRIu32
"", cmd->bmp.codecID);
1147 const RECTANGLE_16* rects = region16_rects(®ion, &nbRects);
1148 if (!rects && (nbRects > 0))
1153 const int32_t w = cmdRect.right - cmdRect.left;
1154 const int32_t h = cmdRect.bottom - cmdRect.top;
1155 if (!gdi_InvalidateRegion(gdi->primary->hdc, cmdRect.left, cmdRect.top, w, h))
1158 for (UINT32 i = 0; i < nbRects; i++)
1162 UINT32 left = rect->left;
1163 UINT32 top = rect->top;
1164 UINT32 width = rect->right - rect->left;
1165 UINT32 height = rect->bottom - rect->top;
1167 if (!gdi_InvalidateRegion(gdi->primary->hdc, WINPR_ASSERTING_INT_CAST(int32_t, left),
1168 WINPR_ASSERTING_INT_CAST(int32_t, top),
1169 WINPR_ASSERTING_INT_CAST(int32_t, width),
1170 WINPR_ASSERTING_INT_CAST(int32_t, height)))
1172 WLog_ERR(TAG,
"Failed to update invalid region");
1179 region16_uninit(®ion);
1188static void gdi_register_update_callbacks(rdpUpdate* update)
1190 rdpPrimaryUpdate* primary = NULL;
1191 const rdpSettings* settings = NULL;
1193 WINPR_ASSERT(update);
1194 WINPR_ASSERT(update->context);
1196 settings = update->context->settings;
1197 WINPR_ASSERT(settings);
1199 primary = update->primary;
1200 WINPR_ASSERT(primary);
1204 update->Palette = gdi_palette_update;
1205 update->SetBounds = gdi_set_bounds;
1206 primary->DstBlt = gdi_dstblt;
1207 primary->PatBlt = gdi_patblt;
1208 primary->ScrBlt = gdi_scrblt;
1209 primary->OpaqueRect = gdi_opaque_rect;
1210 primary->DrawNineGrid = NULL;
1211 primary->MultiDstBlt = NULL;
1212 primary->MultiPatBlt = NULL;
1213 primary->MultiScrBlt = NULL;
1214 primary->MultiOpaqueRect = gdi_multi_opaque_rect;
1215 primary->MultiDrawNineGrid = NULL;
1216 primary->LineTo = gdi_line_to;
1217 primary->Polyline = gdi_polyline;
1218 primary->MemBlt = gdi_memblt;
1219 primary->Mem3Blt = gdi_mem3blt;
1220 primary->SaveBitmap = NULL;
1221 primary->GlyphIndex = NULL;
1222 primary->FastIndex = NULL;
1223 primary->FastGlyph = NULL;
1224 primary->PolygonSC = gdi_polygon_sc;
1225 primary->PolygonCB = gdi_polygon_cb;
1226 primary->EllipseSC = gdi_ellipse_sc;
1227 primary->EllipseCB = gdi_ellipse_cb;
1228 update->SurfaceBits = gdi_surface_bits;
1229 update->SurfaceFrameMarker = gdi_surface_frame_marker;
1230 update->altsec->FrameMarker = gdi_frame_marker;
1233static BOOL gdi_init_primary(rdpGdi* gdi, UINT32 stride, UINT32 format, BYTE* buffer,
1234 void (*pfree)(
void*), BOOL isLocked)
1237 WINPR_ASSERT(gdi->context);
1238 WINPR_ASSERT(gdi->context->update);
1240 rdp_update_lock(gdi->context->update);
1242 gdi->primary = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
1245 gdi->dstFormat = format;
1248 gdi->stride = stride;
1250 gdi->stride = WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width) *
1251 FreeRDPGetBytesPerPixel(gdi->dstFormat);
1256 if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
1261 gdi->primary->bitmap =
1262 gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1263 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height));
1267 gdi->primary->bitmap = gdi_CreateBitmapEx(WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1268 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height),
1269 gdi->dstFormat, gdi->stride, buffer, pfree);
1272 if (!gdi->primary->bitmap)
1275 gdi->stride = gdi->primary->bitmap->scanline;
1276 gdi_SelectObject(gdi->primary->hdc, (
HGDIOBJECT)gdi->primary->bitmap);
1277 gdi->primary->org_bitmap = NULL;
1278 gdi->primary_buffer = gdi->primary->bitmap->data;
1280 if (!(gdi->primary->hdc->hwnd = (
HGDI_WND)calloc(1,
sizeof(
GDI_WND))))
1283 if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0)))
1286 gdi->primary->hdc->hwnd->invalid->null = TRUE;
1287 gdi->primary->hdc->hwnd->count = 32;
1289 if (!(gdi->primary->hdc->hwnd->cinvalid =
1290 (
GDI_RGN*)calloc(gdi->primary->hdc->hwnd->count,
sizeof(
GDI_RGN))))
1293 gdi->primary->hdc->hwnd->ninvalid = 0;
1296 gdi->drawing = gdi->primary;
1298 rdp_update_unlock(gdi->context->update);
1301 gdi_DeleteObject((
HGDIOBJECT)gdi->primary->bitmap);
1303 gdi_DeleteDC(gdi->primary->hdc);
1306 gdi->primary = NULL;
1308 rdp_update_unlock(gdi->context->update);
1312BOOL gdi_resize(rdpGdi* gdi, UINT32 width, UINT32 height)
1314 return gdi_resize_ex(gdi, width, height, 0, 0, NULL, NULL);
1317BOOL gdi_resize_ex(rdpGdi* gdi, UINT32 width, UINT32 height, UINT32 stride, UINT32 format,
1318 BYTE* buffer,
void (*pfree)(
void*))
1320 if (!gdi || !gdi->primary)
1323 if ((width > INT32_MAX) || (height > INT32_MAX))
1326 if ((gdi->width == (INT32)width) && (gdi->height == (INT32)height) &&
1327 (!buffer || (gdi->primary_buffer == buffer)))
1330 WINPR_ASSERT(gdi->context);
1331 WINPR_ASSERT(gdi->context->update);
1334 if (!update_end_paint(gdi->context->update))
1336 rdp_update_lock(gdi->context->update);
1338 if (gdi->drawing == gdi->primary)
1339 gdi->drawing = NULL;
1341 gdi->width = (INT32)width;
1342 gdi->height = (INT32)height;
1343 gdi_bitmap_free_ex(gdi->primary);
1344 gdi->primary = NULL;
1345 gdi->primary_buffer = NULL;
1346 return gdi_init_primary(gdi, stride, format, buffer, pfree, TRUE);
1356BOOL gdi_init(freerdp* instance, UINT32 format)
1358 return gdi_init_ex(instance, format, 0, NULL, winpr_aligned_free);
1372BOOL gdi_init_ex(freerdp* instance, UINT32 format, UINT32 stride, BYTE* buffer,
1373 void (*pfree)(
void*))
1375 rdpContext* context = NULL;
1376 UINT32 SrcFormat = 0;
1379 WINPR_ASSERT(instance);
1381 context = instance->context;
1382 WINPR_ASSERT(context);
1383 WINPR_ASSERT(context->settings);
1386 SrcFormat = gdi_get_pixel_format(ColorDepth);
1387 gdi = (rdpGdi*)calloc(1,
sizeof(rdpGdi));
1393 gdi->log = WLog_Get(TAG);
1398 gdi->context = context;
1399 gdi->width = WINPR_ASSERTING_INT_CAST(
1401 gdi->height = WINPR_ASSERTING_INT_CAST(
1403 gdi->dstFormat = format;
1405 WLog_Print(gdi->log, WLOG_INFO,
"Local framebuffer format %s",
1406 FreeRDPGetColorFormatName(gdi->dstFormat));
1407 WLog_Print(gdi->log, WLOG_INFO,
"Remote framebuffer format %s",
1408 FreeRDPGetColorFormatName(SrcFormat));
1410 if (!(gdi->hdc = gdi_GetDC()))
1413 gdi->hdc->format = gdi->dstFormat;
1415 if (!gdi_init_primary(gdi, stride, gdi->dstFormat, buffer, pfree, FALSE))
1418 if (!(context->cache = cache_new(context)))
1421 gdi_register_update_callbacks(context->update);
1422 brush_cache_register_callbacks(context->update);
1423 glyph_cache_register_callbacks(context->update);
1424 bitmap_cache_register_callbacks(context->update);
1425 offscreen_cache_register_callbacks(context->update);
1426 palette_cache_register_callbacks(context->update);
1428 if (!gdi_register_graphics(context->graphics))
1434 WLog_ERR(TAG,
"failed to initialize gdi");
1438void gdi_free(freerdp* instance)
1441 rdpContext* context = NULL;
1443 if (!instance || !instance->context)
1446 gdi = instance->context->gdi;
1450 gdi_bitmap_free_ex(gdi->primary);
1451 gdi_DeleteDC(gdi->hdc);
1455 context = instance->context;
1456 cache_free(context->cache);
1457 context->cache = NULL;
1458 instance->context->gdi = (rdpGdi*)NULL;
1461BOOL gdi_send_suppress_output(rdpGdi* gdi, BOOL suppress)
1463 if (!gdi || !gdi->context)
1466 if (gdi->suppressOutput == suppress)
1469 gdi->suppressOutput = suppress;
1471 rdpContext* context = gdi->context;
1472 rdpSettings* settings = context->settings;
1473 WINPR_ASSERT(settings);
1475 rdpUpdate* update = context->update;
1476 WINPR_ASSERT(update);
1483 .right = WINPR_ASSERTING_INT_CAST(UINT16, w),
1484 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, h) };
1486 WINPR_ASSERT(update->SuppressOutput);
1487 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.