22#include <freerdp/config.h>
28#include <winpr/assert.h>
29#include <winpr/cast.h>
31#include <freerdp/api.h>
32#include <freerdp/log.h>
33#include <freerdp/freerdp.h>
34#include <freerdp/codecs.h>
36#include <freerdp/gdi/gdi.h>
37#include <freerdp/gdi/dc.h>
38#include <freerdp/gdi/pen.h>
39#include <freerdp/gdi/shape.h>
40#include <freerdp/gdi/region.h>
41#include <freerdp/gdi/bitmap.h>
48#include "../core/graphics.h"
49#include "../core/update.h"
50#include "../cache/cache.h"
52#define TAG FREERDP_TAG("gdi")
61static const rop_table_entry rop3_code_table[] = { { GDI_BLACKNESS,
"0" },
62 { GDI_DPSoon,
"DPSoon" },
63 { GDI_DPSona,
"DPSona" },
65 { GDI_SDPona,
"SDPona" },
67 { GDI_PDSxnon,
"PDSxnon" },
68 { GDI_PDSaon,
"PDSaon" },
69 { GDI_SDPnaa,
"SDPnaa" },
70 { GDI_PDSxon,
"PDSxon" },
72 { GDI_PSDnaon,
"PSDnaon" },
74 { GDI_PDSnaon,
"PDSnaon" },
75 { GDI_PDSonon,
"PDSonon" },
77 { GDI_PDSona,
"PDSona" },
78 { GDI_NOTSRCERASE,
"DSon" },
79 { GDI_SDPxnon,
"SDPxnon" },
80 { GDI_SDPaon,
"SDPaon" },
81 { GDI_DPSxnon,
"DPSxnon" },
82 { GDI_DPSaon,
"DPSaon" },
83 { GDI_PSDPSanaxx,
"PSDPSanaxx" },
84 { GDI_SSPxDSxaxn,
"SSPxDSxaxn" },
85 { GDI_SPxPDxa,
"SPxPDxa" },
86 { GDI_SDPSanaxn,
"SDPSanaxn" },
87 { GDI_PDSPaox,
"PDSPaox" },
88 { GDI_SDPSxaxn,
"SDPSxaxn" },
89 { GDI_PSDPaox,
"PSDPaox" },
90 { GDI_DSPDxaxn,
"DSPDxaxn" },
91 { GDI_PDSox,
"PDSox" },
92 { GDI_PDSoan,
"PDSoan" },
93 { GDI_DPSnaa,
"DPSnaa" },
94 { GDI_SDPxon,
"SDPxon" },
96 { GDI_SPDnaon,
"SPDnaon" },
97 { GDI_SPxDSxa,
"SPxDSxa" },
98 { GDI_PDSPanaxn,
"PDSPanaxn" },
99 { GDI_SDPSaox,
"SDPSaox" },
100 { GDI_SDPSxnox,
"SDPSxnox" },
101 { GDI_DPSxa,
"DPSxa" },
102 { GDI_PSDPSaoxxn,
"PSDPSaoxxn" },
103 { GDI_DPSana,
"DPSana" },
104 { GDI_SSPxPDxaxn,
"SSPxPDxaxn" },
105 { GDI_SPDSoax,
"SPDSoax" },
106 { GDI_PSDnox,
"PSDnox" },
107 { GDI_PSDPxox,
"PSDPxox" },
108 { GDI_PSDnoan,
"PSDnoan" },
109 { GDI_PSna,
"PSna" },
110 { GDI_SDPnaon,
"SDPnaon" },
111 { GDI_SDPSoox,
"SDPSoox" },
112 { GDI_NOTSRCCOPY,
"Sn" },
113 { GDI_SPDSaox,
"SPDSaox" },
114 { GDI_SPDSxnox,
"SPDSxnox" },
115 { GDI_SDPox,
"SDPox" },
116 { GDI_SDPoan,
"SDPoan" },
117 { GDI_PSDPoax,
"PSDPoax" },
118 { GDI_SPDnox,
"SPDnox" },
119 { GDI_SPDSxox,
"SPDSxox" },
120 { GDI_SPDnoan,
"SPDnoan" },
122 { GDI_SPDSonox,
"SPDSonox" },
123 { GDI_SPDSnaox,
"SPDSnaox" },
124 { GDI_PSan,
"PSan" },
125 { GDI_PSDnaa,
"PSDnaa" },
126 { GDI_DPSxon,
"DPSxon" },
127 { GDI_SDxPDxa,
"SDxPDxa" },
128 { GDI_SPDSanaxn,
"SPDSanaxn" },
129 { GDI_SRCERASE,
"SDna" },
130 { GDI_DPSnaon,
"DPSnaon" },
131 { GDI_DSPDaox,
"DSPDaox" },
132 { GDI_PSDPxaxn,
"PSDPxaxn" },
133 { GDI_SDPxa,
"SDPxa" },
134 { GDI_PDSPDaoxxn,
"PDSPDaoxxn" },
135 { GDI_DPSDoax,
"DPSDoax" },
136 { GDI_PDSnox,
"PDSnox" },
137 { GDI_SDPana,
"SDPana" },
138 { GDI_SSPxDSxoxn,
"SSPxDSxoxn" },
139 { GDI_PDSPxox,
"PDSPxox" },
140 { GDI_PDSnoan,
"PDSnoan" },
141 { GDI_PDna,
"PDna" },
142 { GDI_DSPnaon,
"DSPnaon" },
143 { GDI_DPSDaox,
"DPSDaox" },
144 { GDI_SPDSxaxn,
"SPDSxaxn" },
145 { GDI_DPSonon,
"DPSonon" },
146 { GDI_DSTINVERT,
"Dn" },
147 { GDI_DPSox,
"DPSox" },
148 { GDI_DPSoan,
"DPSoan" },
149 { GDI_PDSPoax,
"PDSPoax" },
150 { GDI_DPSnox,
"DPSnox" },
151 { GDI_PATINVERT,
"DPx" },
152 { GDI_DPSDonox,
"DPSDonox" },
153 { GDI_DPSDxox,
"DPSDxox" },
154 { GDI_DPSnoan,
"DPSnoan" },
155 { GDI_DPSDnaox,
"DPSDnaox" },
156 { GDI_DPan,
"DPan" },
157 { GDI_PDSxa,
"PDSxa" },
158 { GDI_DSPDSaoxxn,
"DSPDSaoxxn" },
159 { GDI_DSPDoax,
"DSPDoax" },
160 { GDI_SDPnox,
"SDPnox" },
161 { GDI_SDPSoax,
"SDPSoax" },
162 { GDI_DSPnox,
"DSPnox" },
163 { GDI_SRCINVERT,
"DSx" },
164 { GDI_SDPSonox,
"SDPSonox" },
165 { GDI_DSPDSonoxxn,
"DSPDSonoxxn" },
166 { GDI_PDSxxn,
"PDSxxn" },
167 { GDI_DPSax,
"DPSax" },
168 { GDI_PSDPSoaxxn,
"PSDPSoaxxn" },
169 { GDI_SDPax,
"SDPax" },
170 { GDI_PDSPDoaxxn,
"PDSPDoaxxn" },
171 { GDI_SDPSnoax,
"SDPSnoax" },
172 { GDI_PDSxnan,
"PDSxnan" },
173 { GDI_PDSana,
"PDSana" },
174 { GDI_SSDxPDxaxn,
"SSDxPDxaxn" },
175 { GDI_SDPSxox,
"SDPSxox" },
176 { GDI_SDPnoan,
"SDPnoan" },
177 { GDI_DSPDxox,
"DSPDxox" },
178 { GDI_DSPnoan,
"DSPnoan" },
179 { GDI_SDPSnaox,
"SDPSnaox" },
180 { GDI_DSan,
"DSan" },
181 { GDI_PDSax,
"PDSax" },
182 { GDI_DSPDSoaxxn,
"DSPDSoaxxn" },
183 { GDI_DPSDnoax,
"DPSDnoax" },
184 { GDI_SDPxnan,
"SDPxnan" },
185 { GDI_SPDSnoax,
"SPDSnoax" },
186 { GDI_DPSxnan,
"DPSxnan" },
187 { GDI_SPxDSxo,
"SPxDSxo" },
188 { GDI_DPSaan,
"DPSaan" },
189 { GDI_DPSaa,
"DPSaa" },
190 { GDI_SPxDSxon,
"SPxDSxon" },
191 { GDI_DPSxna,
"DPSxna" },
192 { GDI_SPDSnoaxn,
"SPDSnoaxn" },
193 { GDI_SDPxna,
"SDPxna" },
194 { GDI_PDSPnoaxn,
"PDSPnoaxn" },
195 { GDI_DSPDSoaxx,
"DSPDSoaxx" },
196 { GDI_PDSaxn,
"PDSaxn" },
197 { GDI_SRCAND,
"DSa" },
198 { GDI_SDPSnaoxn,
"SDPSnaoxn" },
199 { GDI_DSPnoa,
"DSPnoa" },
200 { GDI_DSPDxoxn,
"DSPDxoxn" },
201 { GDI_SDPnoa,
"SDPnoa" },
202 { GDI_SDPSxoxn,
"SDPSxoxn" },
203 { GDI_SSDxPDxax,
"SSDxPDxax" },
204 { GDI_PDSanan,
"PDSanan" },
205 { GDI_PDSxna,
"PDSxna" },
206 { GDI_SDPSnoaxn,
"SDPSnoaxn" },
207 { GDI_DPSDPoaxx,
"DPSDPoaxx" },
208 { GDI_SPDaxn,
"SPDaxn" },
209 { GDI_PSDPSoaxx,
"PSDPSoaxx" },
210 { GDI_DPSaxn,
"DPSaxn" },
211 { GDI_DPSxx,
"DPSxx" },
212 { GDI_PSDPSonoxx,
"PSDPSonoxx" },
213 { GDI_SDPSonoxn,
"SDPSonoxn" },
214 { GDI_DSxn,
"DSxn" },
215 { GDI_DPSnax,
"DPSnax" },
216 { GDI_SDPSoaxn,
"SDPSoaxn" },
217 { GDI_SPDnax,
"SPDnax" },
218 { GDI_DSPDoaxn,
"DSPDoaxn" },
219 { GDI_DSPDSaoxx,
"DSPDSaoxx" },
220 { GDI_PDSxan,
"PDSxan" },
222 { GDI_PDSPnaoxn,
"PDSPnaoxn" },
223 { GDI_DPSnoa,
"DPSnoa" },
224 { GDI_DPSDxoxn,
"DPSDxoxn" },
225 { GDI_PDSPonoxn,
"PDSPonoxn" },
226 { GDI_PDxn,
"PDxn" },
227 { GDI_DSPnax,
"DSPnax" },
228 { GDI_PDSPoaxn,
"PDSPoaxn" },
229 { GDI_DPSoa,
"DPSoa" },
230 { GDI_DPSoxn,
"DPSoxn" },
231 { GDI_DSTCOPY,
"D" },
232 { GDI_DPSono,
"DPSono" },
233 { GDI_SPDSxax,
"SPDSxax" },
234 { GDI_DPSDaoxn,
"DPSDaoxn" },
235 { GDI_DSPnao,
"DSPnao" },
236 { GDI_DPno,
"DPno" },
237 { GDI_PDSnoa,
"PDSnoa" },
238 { GDI_PDSPxoxn,
"PDSPxoxn" },
239 { GDI_SSPxDSxox,
"SSPxDSxox" },
240 { GDI_SDPanan,
"SDPanan" },
241 { GDI_PSDnax,
"PSDnax" },
242 { GDI_DPSDoaxn,
"DPSDoaxn" },
243 { GDI_DPSDPaoxx,
"DPSDPaoxx" },
244 { GDI_SDPxan,
"SDPxan" },
245 { GDI_PSDPxax,
"PSDPxax" },
246 { GDI_DSPDaoxn,
"DSPDaoxn" },
247 { GDI_DPSnao,
"DPSnao" },
248 { GDI_MERGEPAINT,
"DSno" },
249 { GDI_SPDSanax,
"SPDSanax" },
250 { GDI_SDxPDxan,
"SDxPDxan" },
251 { GDI_DPSxo,
"DPSxo" },
252 { GDI_DPSano,
"DPSano" },
253 { GDI_MERGECOPY,
"PSa" },
254 { GDI_SPDSnaoxn,
"SPDSnaoxn" },
255 { GDI_SPDSonoxn,
"SPDSonoxn" },
256 { GDI_PSxn,
"PSxn" },
257 { GDI_SPDnoa,
"SPDnoa" },
258 { GDI_SPDSxoxn,
"SPDSxoxn" },
259 { GDI_SDPnax,
"SDPnax" },
260 { GDI_PSDPoaxn,
"PSDPoaxn" },
261 { GDI_SDPoa,
"SDPoa" },
262 { GDI_SPDoxn,
"SPDoxn" },
263 { GDI_DPSDxax,
"DPSDxax" },
264 { GDI_SPDSaoxn,
"SPDSaoxn" },
265 { GDI_SRCCOPY,
"S" },
266 { GDI_SDPono,
"SDPono" },
267 { GDI_SDPnao,
"SDPnao" },
268 { GDI_SPno,
"SPno" },
269 { GDI_PSDnoa,
"PSDnoa" },
270 { GDI_PSDPxoxn,
"PSDPxoxn" },
271 { GDI_PDSnax,
"PDSnax" },
272 { GDI_SPDSoaxn,
"SPDSoaxn" },
273 { GDI_SSPxPDxax,
"SSPxPDxax" },
274 { GDI_DPSanan,
"DPSanan" },
275 { GDI_PSDPSaoxx,
"PSDPSaoxx" },
276 { GDI_DPSxan,
"DPSxan" },
277 { GDI_PDSPxax,
"PDSPxax" },
278 { GDI_SDPSaoxn,
"SDPSaoxn" },
279 { GDI_DPSDanax,
"DPSDanax" },
280 { GDI_SPxDSxan,
"SPxDSxan" },
281 { GDI_SPDnao,
"SPDnao" },
282 { GDI_SDno,
"SDno" },
283 { GDI_SDPxo,
"SDPxo" },
284 { GDI_SDPano,
"SDPano" },
285 { GDI_PDSoa,
"PDSoa" },
286 { GDI_PDSoxn,
"PDSoxn" },
287 { GDI_DSPDxax,
"DSPDxax" },
288 { GDI_PSDPaoxn,
"PSDPaoxn" },
289 { GDI_SDPSxax,
"SDPSxax" },
290 { GDI_PDSPaoxn,
"PDSPaoxn" },
291 { GDI_SDPSanax,
"SDPSanax" },
292 { GDI_SPxPDxan,
"SPxPDxan" },
293 { GDI_SSPxDSxax,
"SSPxDSxax" },
294 { GDI_DSPDSanaxxn,
"DSPDSanaxxn" },
295 { GDI_DPSao,
"DPSao" },
296 { GDI_DPSxno,
"DPSxno" },
297 { GDI_SDPao,
"SDPao" },
298 { GDI_SDPxno,
"SDPxno" },
299 { GDI_SRCPAINT,
"DSo" },
300 { GDI_SDPnoo,
"SDPnoo" },
301 { GDI_PATCOPY,
"P" },
302 { GDI_PDSono,
"PDSono" },
303 { GDI_PDSnao,
"PDSnao" },
304 { GDI_PSno,
"PSno" },
305 { GDI_PSDnao,
"PSDnao" },
306 { GDI_PDno,
"PDno" },
307 { GDI_PDSxo,
"PDSxo" },
308 { GDI_PDSano,
"PDSano" },
309 { GDI_PDSao,
"PDSao" },
310 { GDI_PDSxno,
"PDSxno" },
312 { GDI_PATPAINT,
"DPSnoo" },
314 { GDI_PSDnoo,
"PSDnoo" },
315 { GDI_DPSoo,
"DPSoo" },
316 { GDI_WHITENESS,
"1" } };
319static const BYTE GDI_BS_HATCHED_PATTERNS[] = {
320 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
321 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7,
322 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F,
323 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE,
324 0xF7, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0xF7, 0xF7,
325 0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E
328#define gdi_rop3_code_checked(code) gdi_rop3_code_checked_int((code), __FILE__, __func__, __LINE__)
329static inline DWORD gdi_rop3_code_checked_int(UINT32 code, WINPR_ATTR_UNUSED
const char* file,
330 WINPR_ATTR_UNUSED
const char* fkt,
331 WINPR_ATTR_UNUSED
size_t line)
333 WINPR_ASSERT_AT(code <= UINT8_MAX, file, fkt, line);
334 return gdi_rop3_code((UINT8)code);
337BOOL gdi_decode_color(rdpGdi* gdi, UINT32 srcColor, UINT32* color, UINT32* format)
339 UINT32 SrcFormat = 0;
341 if (!gdi || !color || !gdi->context || !gdi->context->settings)
344 const UINT32 ColorDepth =
351 SrcFormat = PIXEL_FORMAT_BGR24;
355 SrcFormat = PIXEL_FORMAT_RGB16;
359 SrcFormat = PIXEL_FORMAT_RGB15;
363 SrcFormat = PIXEL_FORMAT_RGB8;
371 *format = gdi->dstFormat;
373 *color = FreeRDPConvertColor(srcColor, SrcFormat, gdi->dstFormat, &gdi->palette);
378DWORD gdi_rop3_code(BYTE code)
380 return rop3_code_table[code].code;
383const char* gdi_rop3_code_string(BYTE code)
385 return rop3_code_table[code].name;
388const char* gdi_rop3_string(DWORD rop)
390 const size_t count =
sizeof(rop3_code_table) /
sizeof(rop3_code_table[0]);
392 for (
size_t x = 0; x < count; x++)
394 if (rop3_code_table[x].code == rop)
395 return rop3_code_table[x].name;
401UINT32 gdi_get_pixel_format(UINT32 bitsPerPixel)
405 switch (bitsPerPixel)
408 format = PIXEL_FORMAT_BGRA32;
412 format = PIXEL_FORMAT_BGR24;
416 format = PIXEL_FORMAT_RGB16;
420 format = PIXEL_FORMAT_RGB15;
424 format = PIXEL_FORMAT_RGB8;
428 WLog_ERR(TAG,
"Unsupported color depth %" PRIu32, bitsPerPixel);
436gdiBitmap* gdi_bitmap_new_ex(rdpGdi* gdi,
int width,
int height,
int bpp, BYTE* data)
438 gdiBitmap* bitmap = NULL;
439 bitmap = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
444 if (!(bitmap->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
447 WLog_Print(gdi->log, WLOG_DEBUG,
"gdi_bitmap_new: width:%d height:%d bpp:%d", width, height,
452 gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, width),
453 WINPR_ASSERTING_INT_CAST(uint32_t, height));
455 bitmap->bitmap = gdi_create_bitmap(gdi, WINPR_ASSERTING_INT_CAST(uint32_t, width),
456 WINPR_ASSERTING_INT_CAST(uint32_t, height),
457 WINPR_ASSERTING_INT_CAST(uint32_t, bpp), data);
460 goto fail_bitmap_bitmap;
462 gdi_SelectObject(bitmap->hdc, (
HGDIOBJECT)bitmap->bitmap);
463 bitmap->org_bitmap = NULL;
466 gdi_DeleteDC(bitmap->hdc);
473void gdi_bitmap_free_ex(gdiBitmap* bitmap)
477 gdi_SelectObject(bitmap->hdc, (
HGDIOBJECT)bitmap->org_bitmap);
479 gdi_DeleteDC(bitmap->hdc);
484BOOL gdi_bitmap_update(rdpContext* context,
const BITMAP_UPDATE* bitmapUpdate)
486 if (!context || !bitmapUpdate || !context->gdi || !context->codecs)
489 "Invalid arguments: context=%p, bitmapUpdate=%p, context->gdi=%p, "
490 "context->codecs=%p",
491 context, bitmapUpdate, context ? context->gdi : NULL,
492 context ? context->codecs : NULL);
496 for (UINT32 index = 0; index < bitmapUpdate->number; index++)
499 const BITMAP_DATA* bitmap = &(bitmapUpdate->rectangles[index]);
500 rdpBitmap* bmp = Bitmap_Alloc(context);
505 if (!Bitmap_SetDimensions(bmp, WINPR_ASSERTING_INT_CAST(UINT16, bitmap->width),
506 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->height)))
509 if (!Bitmap_SetRectangle(bmp, WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destLeft),
510 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destTop),
511 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destRight),
512 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destBottom)))
515 if (!bmp->Decompress(context, bmp, bitmap->bitmapDataStream, bitmap->width, bitmap->height,
516 bitmap->bitsPerPixel, bitmap->bitmapLength, bitmap->compressed,
520 if (!bmp->New(context, bmp))
523 if (!bmp->Paint(context, bmp))
528 Bitmap_Free(context, bmp);
536static BOOL gdi_palette_update(rdpContext* context,
const PALETTE_UPDATE* palette)
540 if (!context || !palette)
544 gdi->palette.format = gdi->dstFormat;
546 for (UINT32 index = 0; index < palette->number; index++)
549 gdi->palette.palette[index] =
550 FreeRDPGetColor(gdi->dstFormat, pe->red, pe->green, pe->blue, 0xFF);
556static BOOL gdi_set_bounds(rdpContext* context,
const rdpBounds* bounds)
567 gdi_SetClipRgn(gdi->drawing->hdc, bounds->left, bounds->top,
568 bounds->right - bounds->left + 1, bounds->bottom - bounds->top + 1);
571 gdi_SetNullClipRgn(gdi->drawing->hdc);
576static BOOL gdi_dstblt(rdpContext* context,
const DSTBLT_ORDER* dstblt)
580 if (!context || !dstblt)
584 return gdi_BitBlt(gdi->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth,
585 dstblt->nHeight, NULL, 0, 0, gdi_rop3_code_checked(dstblt->bRop),
589static BOOL gdi_patblt(rdpContext* context,
PATBLT_ORDER* patblt)
591 const rdpBrush* brush = &patblt->brush;
592 UINT32 foreColor = 0;
593 UINT32 backColor = 0;
594 UINT32 originalColor = 0;
597 rdpGdi* gdi = context->gdi;
599 const DWORD rop = gdi_rop3_code_checked(patblt->bRop);
602 BYTE data[8 * 8 * 4];
605 if (!gdi_decode_color(gdi, patblt->foreColor, &foreColor, NULL))
608 if (!gdi_decode_color(gdi, patblt->backColor, &backColor, NULL))
611 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
612 originalBrush = gdi->drawing->hdc->brush;
614 switch (brush->style)
617 hbrush = gdi_CreateSolidBrush(foreColor);
622 const BYTE* hatched = NULL;
623 hatched = GDI_BS_HATCHED_PATTERNS + (8ULL * brush->hatch);
625 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
626 hatched, backColor, foreColor, &gdi->palette))
629 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
634 hbrush = gdi_CreateHatchBrush(hBmp);
640 UINT32 brushFormat = 0;
644 UINT32 bpp = brush->bpp;
650 brushFormat = gdi_get_pixel_format(bpp);
652 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
653 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
659 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
660 8, brush->data, backColor, foreColor,
665 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
670 hbrush = gdi_CreatePatternBrush(hBmp);
675 WLog_ERR(TAG,
"unimplemented brush style:%" PRIu32
"", brush->style);
681 hbrush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
682 hbrush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
683 gdi->drawing->hdc->brush = hbrush;
684 ret = gdi_BitBlt(gdi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
685 patblt->nHeight, gdi->primary->hdc, nXSrc, nYSrc, rop, &gdi->palette);
691 gdi->drawing->hdc->brush = originalBrush;
692 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
696static BOOL gdi_scrblt(rdpContext* context,
const SCRBLT_ORDER* scrblt)
700 if (!context || !context->gdi)
704 return gdi_BitBlt(gdi->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth,
705 scrblt->nHeight, gdi->primary->hdc, scrblt->nXSrc, scrblt->nYSrc,
706 gdi_rop3_code_checked(scrblt->bRop), &gdi->palette);
709static BOOL gdi_opaque_rect(rdpContext* context,
const OPAQUE_RECT_ORDER* opaque_rect)
713 UINT32 brush_color = 0;
714 rdpGdi* gdi = context->gdi;
716 INT32 x = opaque_rect->nLeftRect;
717 INT32 y = opaque_rect->nTopRect;
718 INT32 w = opaque_rect->nWidth;
719 INT32 h = opaque_rect->nHeight;
720 gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
721 gdi_CRgnToRect(x, y, w, h, &rect);
723 if (!gdi_decode_color(gdi, opaque_rect->color, &brush_color, NULL))
726 if (!(hBrush = gdi_CreateSolidBrush(brush_color)))
729 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
734static BOOL gdi_multi_opaque_rect(rdpContext* context,
739 UINT32 brush_color = 0;
740 rdpGdi* gdi = context->gdi;
743 if (!gdi_decode_color(gdi, multi_opaque_rect->color, &brush_color, NULL))
746 hBrush = gdi_CreateSolidBrush(brush_color);
751 for (UINT32 i = 0; i < multi_opaque_rect->numRectangles; i++)
753 const DELTA_RECT* rectangle = &multi_opaque_rect->rectangles[i];
754 INT32 x = rectangle->left;
755 INT32 y = rectangle->top;
756 INT32 w = rectangle->width;
757 INT32 h = rectangle->height;
758 gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
759 gdi_CRgnToRect(x, y, w, h, &rect);
760 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
770static BOOL gdi_line_to(rdpContext* context,
const LINE_TO_ORDER* lineTo)
774 rdpGdi* gdi = context->gdi;
775 INT32 xStart = lineTo->nXStart;
776 INT32 yStart = lineTo->nYStart;
777 INT32 xEnd = lineTo->nXEnd;
778 INT32 yEnd = lineTo->nYEnd;
781 gdi_ClipCoords(gdi->drawing->hdc, &xStart, &yStart, &w, &h, NULL, NULL);
782 gdi_ClipCoords(gdi->drawing->hdc, &xEnd, &yEnd, &w, &h, NULL, NULL);
784 if (!gdi_decode_color(gdi, lineTo->penColor, &color, NULL))
787 if (!(hPen = gdi_CreatePen(lineTo->penStyle, lineTo->penWidth, color, gdi->drawing->hdc->format,
791 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)hPen);
792 gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, lineTo->bRop2));
793 gdi_MoveToEx(gdi->drawing->hdc, lineTo->nXStart, lineTo->nYStart, NULL);
794 gdi_LineTo(gdi->drawing->hdc, lineTo->nXEnd, lineTo->nYEnd);
799static BOOL gdi_polyline(rdpContext* context,
const POLYLINE_ORDER* polyline)
806 rdpGdi* gdi = context->gdi;
810 if (!gdi_decode_color(gdi, polyline->penColor, &color, NULL))
813 if (!(hPen = gdi_CreatePen(GDI_PS_SOLID, 1, color, gdi->drawing->hdc->format, &gdi->palette)))
816 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)hPen);
817 gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, polyline->bRop2));
818 x = polyline->xStart;
819 y = polyline->yStart;
820 gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
821 gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL);
822 points = polyline->points;
824 for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
828 gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
829 gdi_LineTo(gdi->drawing->hdc, x, y);
830 gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL);
837static BOOL gdi_memblt(rdpContext* context,
MEMBLT_ORDER* memblt)
839 gdiBitmap* bitmap = NULL;
842 if (!context || !memblt || !context->gdi || !memblt->bitmap)
845 bitmap = (gdiBitmap*)memblt->bitmap;
847 return gdi_BitBlt(gdi->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
848 memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc,
849 gdi_rop3_code_checked(memblt->bRop), &gdi->palette);
852static BOOL gdi_mem3blt(rdpContext* context,
MEM3BLT_ORDER* mem3blt)
855 rdpGdi* gdi = context->gdi;
857 const rdpBrush* brush = &mem3blt->brush;
858 gdiBitmap* bitmap = (gdiBitmap*)mem3blt->bitmap;
859 UINT32 foreColor = 0;
860 UINT32 backColor = 0;
861 UINT32 originalColor = 0;
863 if (!gdi_decode_color(gdi, mem3blt->foreColor, &foreColor, NULL))
866 if (!gdi_decode_color(gdi, mem3blt->backColor, &backColor, NULL))
869 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
871 switch (brush->style)
874 originalBrush = gdi->drawing->hdc->brush;
875 gdi->drawing->hdc->brush = gdi_CreateSolidBrush(foreColor);
877 if (!gdi->drawing->hdc->brush)
883 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
884 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
885 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
886 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
887 gdi->drawing->hdc->brush = originalBrush;
893 UINT32 brushFormat = 0;
894 BYTE* data = (BYTE*)winpr_aligned_malloc(
895 8ULL * 8ULL * FreeRDPGetBytesPerPixel(gdi->drawing->hdc->format), 16);
905 UINT32 bpp = brush->bpp;
907 const UINT32 ColorDepth =
909 if ((bpp == 16) && (ColorDepth == 15))
912 brushFormat = gdi_get_pixel_format(bpp);
914 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
915 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
919 winpr_aligned_free(data);
925 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
926 8, brush->data, backColor, foreColor,
930 winpr_aligned_free(data);
935 hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->format, data);
940 winpr_aligned_free(data);
944 originalBrush = gdi->drawing->hdc->brush;
945 gdi->drawing->hdc->brush = gdi_CreatePatternBrush(hBmp);
947 if (!gdi->drawing->hdc->brush)
953 gdi->drawing->hdc->brush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
954 gdi->drawing->hdc->brush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
955 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
956 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
957 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
958 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
960 gdi->drawing->hdc->brush = originalBrush;
965 WLog_ERR(TAG,
"Mem3Blt unimplemented brush style:%" PRIu32
"", brush->style);
970 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
974static BOOL gdi_polygon_sc(WINPR_ATTR_UNUSED rdpContext* context,
977 WLog_WARN(TAG,
"not implemented");
981static BOOL gdi_polygon_cb(WINPR_ATTR_UNUSED rdpContext* context,
984 WLog_WARN(TAG,
"not implemented");
988static BOOL gdi_ellipse_sc(WINPR_ATTR_UNUSED rdpContext* context,
991 WLog_WARN(TAG,
"not implemented");
995static BOOL gdi_ellipse_cb(WINPR_ATTR_UNUSED rdpContext* context,
998 WLog_WARN(TAG,
"not implemented");
1002static BOOL gdi_frame_marker(WINPR_ATTR_UNUSED rdpContext* context,
1008static BOOL gdi_surface_frame_marker(rdpContext* context,
1011 WLog_Print(context->gdi->log, WLOG_DEBUG,
"frameId %" PRIu32
" frameAction %" PRIu32
"",
1012 surfaceFrameMarker->frameId, surfaceFrameMarker->frameAction);
1014 switch (surfaceFrameMarker->frameAction)
1016 case SURFACECMD_FRAMEACTION_BEGIN:
1019 case SURFACECMD_FRAMEACTION_END:
1022 IFCALL(context->update->SurfaceFrameAcknowledge, context,
1023 surfaceFrameMarker->frameId);
1036 const UINT32 w = (
const UINT32)gdi->width;
1037 const UINT32 h = (
const UINT32)gdi->height;
1039 if (cmd->destLeft > w)
1041 if (cmd->destRight > w)
1043 if (cmd->destLeft > cmd->destRight)
1045 if (cmd->destRight > UINT16_MAX)
1048 if (cmd->destTop > h)
1050 if (cmd->destBottom > h)
1052 if (cmd->destTop > cmd->destBottom)
1054 if (cmd->destBottom > UINT16_MAX)
1057 prect->left = (
const UINT16)cmd->destLeft;
1058 prect->top = (
const UINT16)cmd->destTop;
1059 prect->right = MIN((UINT16)cmd->destRight, prect->left + cmd->bmp.width);
1060 prect->bottom = MIN((UINT16)cmd->destBottom, prect->top + cmd->bmp.height);
1066 BOOL result = FALSE;
1073 if (!context || !cmd)
1077 WLog_Print(gdi->log, WLOG_DEBUG,
1078 "destLeft %" PRIu32
" destTop %" PRIu32
" destRight %" PRIu32
" destBottom %" PRIu32
1080 "bpp %" PRIu8
" flags %" PRIx8
" codecID %s [0x%04" PRIu16
"] width %" PRIu16
1081 " height %" PRIu16
" length %" PRIu32
"",
1082 cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bmp.bpp,
1083 cmd->bmp.flags, freerdp_codec_id_to_str(cmd->bmp.codecID), cmd->bmp.codecID,
1084 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);
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.