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 WINPR_CXX_COMPAT_CAST(
const void*, context),
492 WINPR_CXX_COMPAT_CAST(
const void*, bitmapUpdate),
493 WINPR_CXX_COMPAT_CAST(
const void*, context ? context->gdi : NULL),
494 WINPR_CXX_COMPAT_CAST(const void*, context ? context->codecs : NULL));
498 for (UINT32 index = 0; index < bitmapUpdate->number; index++)
501 const BITMAP_DATA* bitmap = &(bitmapUpdate->rectangles[index]);
502 rdpBitmap* bmp = Bitmap_Alloc(context);
507 if (!Bitmap_SetDimensions(bmp, WINPR_ASSERTING_INT_CAST(UINT16, bitmap->width),
508 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->height)))
511 if (!Bitmap_SetRectangle(bmp, WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destLeft),
512 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destTop),
513 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destRight),
514 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destBottom)))
517 if (!bmp->Decompress(context, bmp, bitmap->bitmapDataStream, bitmap->width, bitmap->height,
518 bitmap->bitsPerPixel, bitmap->bitmapLength, bitmap->compressed,
522 if (!bmp->New(context, bmp))
525 if (!bmp->Paint(context, bmp))
530 Bitmap_Free(context, bmp);
538static BOOL gdi_palette_update(rdpContext* context,
const PALETTE_UPDATE* palette)
542 if (!context || !palette)
546 gdi->palette.format = gdi->dstFormat;
548 for (UINT32 index = 0; index < palette->number; index++)
551 gdi->palette.palette[index] =
552 FreeRDPGetColor(gdi->dstFormat, pe->red, pe->green, pe->blue, 0xFF);
558static BOOL gdi_set_bounds(rdpContext* context,
const rdpBounds* bounds)
569 gdi_SetClipRgn(gdi->drawing->hdc, bounds->left, bounds->top,
570 bounds->right - bounds->left + 1, bounds->bottom - bounds->top + 1);
573 gdi_SetNullClipRgn(gdi->drawing->hdc);
578static BOOL gdi_dstblt(rdpContext* context,
const DSTBLT_ORDER* dstblt)
582 if (!context || !dstblt)
586 return gdi_BitBlt(gdi->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth,
587 dstblt->nHeight, NULL, 0, 0, gdi_rop3_code_checked(dstblt->bRop),
591static BOOL gdi_patblt(rdpContext* context,
PATBLT_ORDER* patblt)
593 const rdpBrush* brush = &patblt->brush;
594 UINT32 foreColor = 0;
595 UINT32 backColor = 0;
596 UINT32 originalColor = 0;
599 rdpGdi* gdi = context->gdi;
601 const DWORD rop = gdi_rop3_code_checked(patblt->bRop);
604 BYTE data[8 * 8 * 4];
607 if (!gdi_decode_color(gdi, patblt->foreColor, &foreColor, NULL))
610 if (!gdi_decode_color(gdi, patblt->backColor, &backColor, NULL))
613 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
614 originalBrush = gdi->drawing->hdc->brush;
616 switch (brush->style)
619 hbrush = gdi_CreateSolidBrush(foreColor);
624 const BYTE* hatched = NULL;
625 hatched = GDI_BS_HATCHED_PATTERNS + (8ULL * brush->hatch);
627 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
628 hatched, backColor, foreColor, &gdi->palette))
631 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
636 hbrush = gdi_CreateHatchBrush(hBmp);
642 UINT32 brushFormat = 0;
646 UINT32 bpp = brush->bpp;
652 brushFormat = gdi_get_pixel_format(bpp);
654 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
655 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
661 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
662 8, brush->data, backColor, foreColor,
667 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
672 hbrush = gdi_CreatePatternBrush(hBmp);
677 WLog_ERR(TAG,
"unimplemented brush style:%" PRIu32
"", brush->style);
683 hbrush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
684 hbrush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
685 gdi->drawing->hdc->brush = hbrush;
686 ret = gdi_BitBlt(gdi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
687 patblt->nHeight, gdi->primary->hdc, nXSrc, nYSrc, rop, &gdi->palette);
693 gdi->drawing->hdc->brush = originalBrush;
694 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
698static BOOL gdi_scrblt(rdpContext* context,
const SCRBLT_ORDER* scrblt)
702 if (!context || !context->gdi)
706 return gdi_BitBlt(gdi->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth,
707 scrblt->nHeight, gdi->primary->hdc, scrblt->nXSrc, scrblt->nYSrc,
708 gdi_rop3_code_checked(scrblt->bRop), &gdi->palette);
711static BOOL gdi_opaque_rect(rdpContext* context,
const OPAQUE_RECT_ORDER* opaque_rect)
715 UINT32 brush_color = 0;
716 rdpGdi* gdi = context->gdi;
718 INT32 x = opaque_rect->nLeftRect;
719 INT32 y = opaque_rect->nTopRect;
720 INT32 w = opaque_rect->nWidth;
721 INT32 h = opaque_rect->nHeight;
722 gdi_CRgnToRect(x, y, w, h, &rect);
724 if (!gdi_decode_color(gdi, opaque_rect->color, &brush_color, NULL))
727 if (!(hBrush = gdi_CreateSolidBrush(brush_color)))
730 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
735static BOOL gdi_multi_opaque_rect(rdpContext* context,
740 UINT32 brush_color = 0;
741 rdpGdi* gdi = context->gdi;
744 if (!gdi_decode_color(gdi, multi_opaque_rect->color, &brush_color, NULL))
747 hBrush = gdi_CreateSolidBrush(brush_color);
752 for (UINT32 i = 0; i < multi_opaque_rect->numRectangles; i++)
754 const DELTA_RECT* rectangle = &multi_opaque_rect->rectangles[i];
755 const INT32 x = rectangle->left;
756 const INT32 y = rectangle->top;
757 const INT32 w = rectangle->width;
758 const INT32 h = rectangle->height;
760 gdi_CRgnToRect(x, y, w, h, &rect);
761 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
771static BOOL gdi_line_to(rdpContext* context,
const LINE_TO_ORDER* lineTo)
774 WINPR_ASSERT(context);
775 WINPR_ASSERT(lineTo);
777 rdpGdi* gdi = context->gdi;
780 if (!gdi_decode_color(gdi, lineTo->penColor, &color, NULL))
783 HGDI_PEN hPen = gdi_CreatePen(lineTo->penStyle, lineTo->penWidth, color,
784 gdi->drawing->hdc->format, &gdi->palette);
788 WINPR_ASSERT(gdi->drawing);
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)
800 WINPR_ASSERT(context);
801 WINPR_ASSERT(polyline);
803 rdpGdi* gdi = context->gdi;
807 if (!gdi_decode_color(gdi, polyline->penColor, &color, NULL))
810 WINPR_ASSERT(gdi->drawing);
811 WINPR_ASSERT(gdi->drawing->hdc);
813 HGDI_PEN hPen = gdi_CreatePen(GDI_PS_SOLID, 1, color, gdi->drawing->hdc->format, &gdi->palette);
817 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)hPen);
818 gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, polyline->bRop2));
819 INT32 x = polyline->xStart;
820 INT32 y = polyline->yStart;
821 gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL);
824 for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
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)
1076 WLog_Print(gdi->log, WLOG_DEBUG,
1077 "destLeft %" PRIu32
" destTop %" PRIu32
" destRight %" PRIu32
" destBottom %" PRIu32
1079 "bpp %" PRIu8
" flags %" PRIx8
" codecID %s [0x%04" PRIu16
"] width %" PRIu16
1080 " height %" PRIu16
" length %" PRIu32
"",
1081 cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bmp.bpp,
1082 cmd->bmp.flags, freerdp_codec_id_to_str(cmd->bmp.codecID), cmd->bmp.codecID,
1083 cmd->bmp.width, cmd->bmp.height, cmd->bmp.bitmapDataLength);
1084 region16_init(®ion);
1086 if (!intersect_rect(gdi, cmd, &cmdRect))
1089 switch (cmd->bmp.codecID)
1091 case RDP_CODEC_ID_REMOTEFX:
1092 case RDP_CODEC_ID_IMAGE_REMOTEFX:
1093 if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData,
1094 cmd->bmp.bitmapDataLength, cmdRect.left, cmdRect.top,
1095 gdi->primary_buffer, gdi->dstFormat, gdi->stride,
1096 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height), ®ion))
1098 WLog_ERR(TAG,
"Failed to process RemoteFX message");
1104 case RDP_CODEC_ID_NSCODEC:
1105 format = gdi->dstFormat;
1107 if (!nsc_process_message(
1108 context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, cmd->bmp.height,
1109 cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, format,
1110 gdi->stride, cmdRect.left, cmdRect.top, cmdRect.right - cmdRect.left,
1111 cmdRect.bottom - cmdRect.top, FREERDP_FLIP_VERTICAL))
1113 WLog_ERR(TAG,
"Failed to process NSCodec message");
1117 region16_union_rect(®ion, ®ion, &cmdRect);
1120 case RDP_CODEC_ID_NONE:
1121 format = gdi_get_pixel_format(cmd->bmp.bpp);
1122 size = 1ull * cmd->bmp.width * cmd->bmp.height * FreeRDPGetBytesPerPixel(format);
1123 if (size > cmd->bmp.bitmapDataLength)
1125 WLog_ERR(TAG,
"Short nocodec message: got %" PRIu32
" bytes, require %" PRIuz,
1126 cmd->bmp.bitmapDataLength, size);
1130 if (!freerdp_image_copy_no_overlap(
1131 gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmdRect.left, cmdRect.top,
1132 cmdRect.right - cmdRect.left, cmdRect.bottom - cmdRect.top, cmd->bmp.bitmapData,
1133 format, 0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))
1135 WLog_ERR(TAG,
"Failed to process nocodec message");
1139 region16_union_rect(®ion, ®ion, &cmdRect);
1143 WLog_ERR(TAG,
"Unsupported codecID %" PRIu32
"", cmd->bmp.codecID);
1149 const RECTANGLE_16* rects = region16_rects(®ion, &nbRects);
1150 if (!rects && (nbRects > 0))
1155 const int32_t w = cmdRect.right - cmdRect.left;
1156 const int32_t h = cmdRect.bottom - cmdRect.top;
1157 if (!gdi_InvalidateRegion(gdi->primary->hdc, cmdRect.left, cmdRect.top, w, h))
1160 for (UINT32 i = 0; i < nbRects; i++)
1164 UINT32 left = rect->left;
1165 UINT32 top = rect->top;
1166 UINT32 width = rect->right - rect->left;
1167 UINT32 height = rect->bottom - rect->top;
1169 if (!gdi_InvalidateRegion(gdi->primary->hdc, WINPR_ASSERTING_INT_CAST(int32_t, left),
1170 WINPR_ASSERTING_INT_CAST(int32_t, top),
1171 WINPR_ASSERTING_INT_CAST(int32_t, width),
1172 WINPR_ASSERTING_INT_CAST(int32_t, height)))
1174 WLog_ERR(TAG,
"Failed to update invalid region");
1181 region16_uninit(®ion);
1190static void gdi_register_update_callbacks(rdpUpdate* update)
1192 rdpPrimaryUpdate* primary = NULL;
1193 const rdpSettings* settings = NULL;
1195 WINPR_ASSERT(update);
1196 WINPR_ASSERT(update->context);
1198 settings = update->context->settings;
1199 WINPR_ASSERT(settings);
1201 primary = update->primary;
1202 WINPR_ASSERT(primary);
1206 update->Palette = gdi_palette_update;
1207 update->SetBounds = gdi_set_bounds;
1208 primary->DstBlt = gdi_dstblt;
1209 primary->PatBlt = gdi_patblt;
1210 primary->ScrBlt = gdi_scrblt;
1211 primary->OpaqueRect = gdi_opaque_rect;
1212 primary->DrawNineGrid = NULL;
1213 primary->MultiDstBlt = NULL;
1214 primary->MultiPatBlt = NULL;
1215 primary->MultiScrBlt = NULL;
1216 primary->MultiOpaqueRect = gdi_multi_opaque_rect;
1217 primary->MultiDrawNineGrid = NULL;
1218 primary->LineTo = gdi_line_to;
1219 primary->Polyline = gdi_polyline;
1220 primary->MemBlt = gdi_memblt;
1221 primary->Mem3Blt = gdi_mem3blt;
1222 primary->SaveBitmap = NULL;
1223 primary->GlyphIndex = NULL;
1224 primary->FastIndex = NULL;
1225 primary->FastGlyph = NULL;
1226 primary->PolygonSC = gdi_polygon_sc;
1227 primary->PolygonCB = gdi_polygon_cb;
1228 primary->EllipseSC = gdi_ellipse_sc;
1229 primary->EllipseCB = gdi_ellipse_cb;
1230 update->SurfaceBits = gdi_surface_bits;
1231 update->SurfaceFrameMarker = gdi_surface_frame_marker;
1232 update->altsec->FrameMarker = gdi_frame_marker;
1235static BOOL gdi_init_primary(rdpGdi* gdi, UINT32 stride, UINT32 format, BYTE* buffer,
1236 void (*pfree)(
void*), BOOL isLocked)
1239 WINPR_ASSERT(gdi->context);
1240 WINPR_ASSERT(gdi->context->update);
1242 rdp_update_lock(gdi->context->update);
1244 gdi->primary = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
1247 gdi->dstFormat = format;
1250 gdi->stride = stride;
1252 gdi->stride = WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width) *
1253 FreeRDPGetBytesPerPixel(gdi->dstFormat);
1258 if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
1263 gdi->primary->bitmap =
1264 gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1265 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height));
1269 gdi->primary->bitmap = gdi_CreateBitmapEx(WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1270 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height),
1271 gdi->dstFormat, gdi->stride, buffer, pfree);
1274 if (!gdi->primary->bitmap)
1277 gdi->stride = gdi->primary->bitmap->scanline;
1278 gdi_SelectObject(gdi->primary->hdc, (
HGDIOBJECT)gdi->primary->bitmap);
1279 gdi->primary->org_bitmap = NULL;
1280 gdi->primary_buffer = gdi->primary->bitmap->data;
1282 if (!(gdi->primary->hdc->hwnd = (
HGDI_WND)calloc(1,
sizeof(
GDI_WND))))
1285 if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0)))
1288 gdi->primary->hdc->hwnd->invalid->null = TRUE;
1289 gdi->primary->hdc->hwnd->count = 32;
1291 if (!(gdi->primary->hdc->hwnd->cinvalid =
1292 (
GDI_RGN*)calloc(gdi->primary->hdc->hwnd->count,
sizeof(
GDI_RGN))))
1295 gdi->primary->hdc->hwnd->ninvalid = 0;
1298 gdi->drawing = gdi->primary;
1300 rdp_update_unlock(gdi->context->update);
1303 gdi_DeleteObject((
HGDIOBJECT)gdi->primary->bitmap);
1305 gdi_DeleteDC(gdi->primary->hdc);
1308 gdi->primary = NULL;
1310 rdp_update_unlock(gdi->context->update);
1314BOOL gdi_resize(rdpGdi* gdi, UINT32 width, UINT32 height)
1316 return gdi_resize_ex(gdi, width, height, 0, 0, NULL, NULL);
1319BOOL gdi_resize_ex(rdpGdi* gdi, UINT32 width, UINT32 height, UINT32 stride, UINT32 format,
1320 BYTE* buffer,
void (*pfree)(
void*))
1322 if (!gdi || !gdi->primary)
1325 if ((width > INT32_MAX) || (height > INT32_MAX))
1328 if ((gdi->width == (INT32)width) && (gdi->height == (INT32)height) &&
1329 (!buffer || (gdi->primary_buffer == buffer)))
1332 WINPR_ASSERT(gdi->context);
1333 WINPR_ASSERT(gdi->context->update);
1336 if (!update_end_paint(gdi->context->update))
1338 rdp_update_lock(gdi->context->update);
1340 if (gdi->drawing == gdi->primary)
1341 gdi->drawing = NULL;
1343 gdi->width = (INT32)width;
1344 gdi->height = (INT32)height;
1345 gdi_bitmap_free_ex(gdi->primary);
1346 gdi->primary = NULL;
1347 gdi->primary_buffer = NULL;
1348 return gdi_init_primary(gdi, stride, format, buffer, pfree, TRUE);
1358BOOL gdi_init(freerdp* instance, UINT32 format)
1360 return gdi_init_ex(instance, format, 0, NULL, winpr_aligned_free);
1374BOOL gdi_init_ex(freerdp* instance, UINT32 format, UINT32 stride, BYTE* buffer,
1375 void (*pfree)(
void*))
1377 rdpContext* context = NULL;
1378 UINT32 SrcFormat = 0;
1381 WINPR_ASSERT(instance);
1383 context = instance->context;
1384 WINPR_ASSERT(context);
1385 WINPR_ASSERT(context->settings);
1388 SrcFormat = gdi_get_pixel_format(ColorDepth);
1389 gdi = (rdpGdi*)calloc(1,
sizeof(rdpGdi));
1395 gdi->log = WLog_Get(TAG);
1400 gdi->context = context;
1401 gdi->width = WINPR_ASSERTING_INT_CAST(
1403 gdi->height = WINPR_ASSERTING_INT_CAST(
1405 gdi->dstFormat = format;
1407 WLog_Print(gdi->log, WLOG_INFO,
"Local framebuffer format %s",
1408 FreeRDPGetColorFormatName(gdi->dstFormat));
1409 WLog_Print(gdi->log, WLOG_INFO,
"Remote framebuffer format %s",
1410 FreeRDPGetColorFormatName(SrcFormat));
1412 if (!(gdi->hdc = gdi_GetDC()))
1415 gdi->hdc->format = gdi->dstFormat;
1417 if (!gdi_init_primary(gdi, stride, gdi->dstFormat, buffer, pfree, FALSE))
1420 if (!(context->cache = cache_new(context)))
1423 gdi_register_update_callbacks(context->update);
1424 brush_cache_register_callbacks(context->update);
1425 glyph_cache_register_callbacks(context->update);
1426 bitmap_cache_register_callbacks(context->update);
1427 offscreen_cache_register_callbacks(context->update);
1428 palette_cache_register_callbacks(context->update);
1430 if (!gdi_register_graphics(context->graphics))
1436 WLog_ERR(TAG,
"failed to initialize gdi");
1440void gdi_free(freerdp* instance)
1443 rdpContext* context = NULL;
1445 if (!instance || !instance->context)
1448 gdi = instance->context->gdi;
1452 gdi_bitmap_free_ex(gdi->primary);
1453 gdi_DeleteDC(gdi->hdc);
1457 context = instance->context;
1458 cache_free(context->cache);
1459 context->cache = NULL;
1460 instance->context->gdi = (rdpGdi*)NULL;
1463BOOL gdi_send_suppress_output(rdpGdi* gdi, BOOL suppress)
1465 if (!gdi || !gdi->context)
1468 if (gdi->suppressOutput == suppress)
1471 gdi->suppressOutput = suppress;
1473 rdpContext* context = gdi->context;
1474 rdpSettings* settings = context->settings;
1475 WINPR_ASSERT(settings);
1477 rdpUpdate* update = context->update;
1478 WINPR_ASSERT(update);
1485 .right = WINPR_ASSERTING_INT_CAST(UINT16, w),
1486 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, h) };
1488 WINPR_ASSERT(update->SuppressOutput);
1489 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.