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 = (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 =
nullptr;
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 WINPR_CXX_COMPAT_CAST(
const void*, context),
491 WINPR_CXX_COMPAT_CAST(
const void*, bitmapUpdate),
492 WINPR_CXX_COMPAT_CAST(
const void*, context ? context->gdi : nullptr),
493 WINPR_CXX_COMPAT_CAST(const void*, context ? context->codecs : nullptr));
497 for (UINT32 index = 0; index < bitmapUpdate->number; index++)
500 const BITMAP_DATA* bitmap = &(bitmapUpdate->rectangles[index]);
501 rdpBitmap* bmp = Bitmap_Alloc(context);
506 if (!Bitmap_SetDimensions(bmp, WINPR_ASSERTING_INT_CAST(UINT16, bitmap->width),
507 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->height)))
510 if (!Bitmap_SetRectangle(bmp, WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destLeft),
511 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destTop),
512 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destRight),
513 WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destBottom)))
516 if (!bmp->Decompress(context, bmp, bitmap->bitmapDataStream, bitmap->width, bitmap->height,
517 bitmap->bitsPerPixel, bitmap->bitmapLength, bitmap->compressed,
521 if (!bmp->New(context, bmp))
524 if (!bmp->Paint(context, bmp))
529 Bitmap_Free(context, bmp);
537static BOOL gdi_palette_update(rdpContext* context,
const PALETTE_UPDATE* palette)
539 if (!context || !palette)
542 rdpGdi* gdi = context->gdi;
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)
563 rdpGdi* gdi = context->gdi;
564 if (!gdi || !gdi->drawing)
568 return gdi_SetClipRgn(gdi->drawing->hdc, bounds->left, bounds->top,
569 bounds->right - bounds->left + 1, bounds->bottom - bounds->top + 1);
571 return gdi_SetNullClipRgn(gdi->drawing->hdc);
574static BOOL gdi_dstblt(rdpContext* context,
const DSTBLT_ORDER* dstblt)
576 if (!context || !dstblt)
579 rdpGdi* gdi = context->gdi;
580 if (!gdi || !gdi->drawing)
582 return gdi_BitBlt(gdi->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth,
583 dstblt->nHeight,
nullptr, 0, 0, gdi_rop3_code_checked(dstblt->bRop),
587static BOOL gdi_patblt(rdpContext* context,
PATBLT_ORDER* patblt)
589 WINPR_ASSERT(context);
590 WINPR_ASSERT(patblt);
592 const rdpBrush* brush = &patblt->brush;
593 UINT32 foreColor = 0;
594 UINT32 backColor = 0;
595 UINT32 originalColor = 0;
598 rdpGdi* gdi = context->gdi;
600 const DWORD rop = gdi_rop3_code_checked(patblt->bRop);
603 BYTE data[8 * 8 * 4];
606 if (!gdi || !gdi->drawing || !gdi->drawing->hdc)
609 if (!gdi_decode_color(gdi, patblt->foreColor, &foreColor,
nullptr))
612 if (!gdi_decode_color(gdi, patblt->backColor, &backColor,
nullptr))
615 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
616 originalBrush = gdi->drawing->hdc->brush;
618 switch (brush->style)
621 hbrush = gdi_CreateSolidBrush(foreColor);
626 const BYTE* hatched =
nullptr;
627 hatched = GDI_BS_HATCHED_PATTERNS + (8ULL * brush->hatch);
629 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
630 hatched, backColor, foreColor, &gdi->palette))
633 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data,
nullptr);
638 hbrush = gdi_CreateHatchBrush(hBmp);
644 UINT32 brushFormat = 0;
648 UINT32 bpp = brush->bpp;
654 brushFormat = gdi_get_pixel_format(bpp);
656 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
657 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
663 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
664 8, brush->data, backColor, foreColor,
669 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data,
nullptr);
674 hbrush = gdi_CreatePatternBrush(hBmp);
679 WLog_ERR(TAG,
"unimplemented brush style:%" PRIu32
"", brush->style);
685 hbrush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
686 hbrush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
687 gdi->drawing->hdc->brush = hbrush;
688 ret = gdi_BitBlt(gdi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
689 patblt->nHeight, gdi->primary->hdc, nXSrc, nYSrc, rop, &gdi->palette);
695 gdi->drawing->hdc->brush = originalBrush;
696 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
700static BOOL gdi_scrblt(rdpContext* context,
const SCRBLT_ORDER* scrblt)
702 if (!context || !context->gdi)
705 rdpGdi* gdi = context->gdi;
706 if (!gdi->drawing || !gdi->primary)
709 return gdi_BitBlt(gdi->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth,
710 scrblt->nHeight, gdi->primary->hdc, scrblt->nXSrc, scrblt->nYSrc,
711 gdi_rop3_code_checked(scrblt->bRop), &gdi->palette);
714static BOOL gdi_opaque_rect(rdpContext* context,
const OPAQUE_RECT_ORDER* opaque_rect)
716 WINPR_ASSERT(context);
717 WINPR_ASSERT(opaque_rect);
721 UINT32 brush_color = 0;
722 rdpGdi* gdi = context->gdi;
724 INT32 x = opaque_rect->nLeftRect;
725 INT32 y = opaque_rect->nTopRect;
726 INT32 w = opaque_rect->nWidth;
727 INT32 h = opaque_rect->nHeight;
728 if (!gdi || !gdi->drawing)
734 if (!gdi_CRgnToRect(x, y, w, h, &rect))
737 if (!gdi_decode_color(gdi, opaque_rect->color, &brush_color,
nullptr))
740 if (!(hBrush = gdi_CreateSolidBrush(brush_color)))
743 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
748static BOOL gdi_multi_opaque_rect(rdpContext* context,
751 WINPR_ASSERT(context);
752 WINPR_ASSERT(multi_opaque_rect);
755 UINT32 brush_color = 0;
756 rdpGdi* gdi = context->gdi;
759 if (!gdi || !gdi->drawing)
762 if (!gdi_decode_color(gdi, multi_opaque_rect->color, &brush_color,
nullptr))
765 HGDI_BRUSH hBrush = gdi_CreateSolidBrush(brush_color);
770 for (UINT32 i = 0; i < multi_opaque_rect->numRectangles; i++)
772 const DELTA_RECT* rectangle = &multi_opaque_rect->rectangles[i];
773 const INT32 x = rectangle->left;
774 const INT32 y = rectangle->top;
775 const INT32 w = rectangle->width;
776 const INT32 h = rectangle->height;
781 if (!gdi_CRgnToRect(x, y, w, h, &rect))
784 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
794static BOOL gdi_line_to(rdpContext* context,
const LINE_TO_ORDER* lineTo)
798 WINPR_ASSERT(context);
799 WINPR_ASSERT(lineTo);
801 rdpGdi* gdi = context->gdi;
802 if (!gdi || !gdi->drawing || !gdi->drawing->hdc)
805 if (!gdi_decode_color(gdi, lineTo->penColor, &color,
nullptr))
808 HGDI_PEN hPen = gdi_CreatePen(lineTo->penStyle, lineTo->penWidth, color,
809 gdi->drawing->hdc->format, &gdi->palette);
813 WINPR_ASSERT(gdi->drawing);
815 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)hPen);
816 gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, lineTo->bRop2));
817 if (!gdi_MoveToEx(gdi->drawing->hdc, lineTo->nXStart, lineTo->nYStart,
nullptr))
819 if (!gdi_LineTo(gdi->drawing->hdc, lineTo->nXEnd, lineTo->nYEnd))
828static BOOL gdi_polyline(rdpContext* context,
const POLYLINE_ORDER* polyline)
831 WINPR_ASSERT(context);
832 WINPR_ASSERT(polyline);
834 rdpGdi* gdi = context->gdi;
835 if (!gdi || !gdi->drawing || !gdi->drawing->hdc)
839 if (!gdi_decode_color(gdi, polyline->penColor, &color,
nullptr))
842 WINPR_ASSERT(gdi->drawing);
843 WINPR_ASSERT(gdi->drawing->hdc);
845 HGDI_PEN hPen = gdi_CreatePen(GDI_PS_SOLID, 1, color, gdi->drawing->hdc->format, &gdi->palette);
849 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)hPen);
850 gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, polyline->bRop2));
851 INT32 x = polyline->xStart;
852 INT32 y = polyline->yStart;
853 if (!gdi_MoveToEx(gdi->drawing->hdc, x, y,
nullptr))
857 for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
861 if (!gdi_LineTo(gdi->drawing->hdc, x, y))
863 if (!gdi_MoveToEx(gdi->drawing->hdc, x, y,
nullptr))
873static BOOL gdi_memblt(rdpContext* context,
MEMBLT_ORDER* memblt)
875 if (!context || !memblt || !memblt->bitmap)
878 gdiBitmap* bitmap = (gdiBitmap*)memblt->bitmap;
879 rdpGdi* gdi = context->gdi;
880 if (!gdi || !gdi->drawing)
882 return gdi_BitBlt(gdi->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
883 memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc,
884 gdi_rop3_code_checked(memblt->bRop), &gdi->palette);
887static BOOL gdi_mem3blt(rdpContext* context,
MEM3BLT_ORDER* mem3blt)
889 WINPR_ASSERT(context);
890 WINPR_ASSERT(mem3blt);
893 rdpGdi* gdi = context->gdi;
894 if (!gdi || !gdi->drawing)
898 const rdpBrush* brush = &mem3blt->brush;
899 gdiBitmap* bitmap = (gdiBitmap*)mem3blt->bitmap;
900 UINT32 foreColor = 0;
901 UINT32 backColor = 0;
902 UINT32 originalColor = 0;
904 if (!gdi_decode_color(gdi, mem3blt->foreColor, &foreColor,
nullptr))
907 if (!gdi_decode_color(gdi, mem3blt->backColor, &backColor,
nullptr))
910 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
912 switch (brush->style)
915 originalBrush = gdi->drawing->hdc->brush;
916 gdi->drawing->hdc->brush = gdi_CreateSolidBrush(foreColor);
918 if (!gdi->drawing->hdc->brush)
924 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
925 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
926 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
927 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
928 gdi->drawing->hdc->brush = originalBrush;
934 UINT32 brushFormat = 0;
935 BYTE* data = (BYTE*)winpr_aligned_malloc(
936 8ULL * 8ULL * FreeRDPGetBytesPerPixel(gdi->drawing->hdc->format), 16);
946 UINT32 bpp = brush->bpp;
948 const UINT32 ColorDepth =
950 if ((bpp == 16) && (ColorDepth == 15))
953 brushFormat = gdi_get_pixel_format(bpp);
955 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
956 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
960 winpr_aligned_free(data);
966 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
967 8, brush->data, backColor, foreColor,
971 winpr_aligned_free(data);
976 hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->format, data);
981 winpr_aligned_free(data);
985 originalBrush = gdi->drawing->hdc->brush;
986 gdi->drawing->hdc->brush = gdi_CreatePatternBrush(hBmp);
988 if (!gdi->drawing->hdc->brush)
994 gdi->drawing->hdc->brush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
995 gdi->drawing->hdc->brush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
996 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
997 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
998 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
999 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
1001 gdi->drawing->hdc->brush = originalBrush;
1006 WLog_ERR(TAG,
"Mem3Blt unimplemented brush style:%" PRIu32
"", brush->style);
1011 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
1015static BOOL gdi_polygon_sc(WINPR_ATTR_UNUSED rdpContext* context,
1018 WLog_WARN(TAG,
"not implemented");
1022static BOOL gdi_polygon_cb(WINPR_ATTR_UNUSED rdpContext* context,
1025 WLog_WARN(TAG,
"not implemented");
1029static BOOL gdi_ellipse_sc(WINPR_ATTR_UNUSED rdpContext* context,
1032 WLog_WARN(TAG,
"not implemented");
1036static BOOL gdi_ellipse_cb(WINPR_ATTR_UNUSED rdpContext* context,
1039 WLog_WARN(TAG,
"not implemented");
1043static BOOL gdi_frame_marker(WINPR_ATTR_UNUSED rdpContext* context,
1049static BOOL gdi_surface_frame_marker(rdpContext* context,
1052 WINPR_ASSERT(context);
1053 WINPR_ASSERT(context->gdi);
1054 WINPR_ASSERT(context->update);
1055 WINPR_ASSERT(surfaceFrameMarker);
1057 WLog_Print(context->gdi->log, WLOG_DEBUG,
"frameId %" PRIu32
" frameAction %" PRIu32
"",
1058 surfaceFrameMarker->frameId, surfaceFrameMarker->frameAction);
1060 switch (surfaceFrameMarker->frameAction)
1062 case SURFACECMD_FRAMEACTION_BEGIN:
1065 case SURFACECMD_FRAMEACTION_END:
1068 if (!IFCALLRESULT(TRUE, context->update->SurfaceFrameAcknowledge, context,
1069 surfaceFrameMarker->frameId))
1085 WINPR_ASSERT(prect);
1087 const UINT32 w = (
const UINT32)gdi->width;
1088 const UINT32 h = (
const UINT32)gdi->height;
1090 if (cmd->destLeft > w)
1092 if (cmd->destRight > w)
1094 if (cmd->destLeft > cmd->destRight)
1096 if (cmd->destRight > UINT16_MAX)
1099 if (cmd->destTop > h)
1101 if (cmd->destBottom > h)
1103 if (cmd->destTop > cmd->destBottom)
1105 if (cmd->destBottom > UINT16_MAX)
1108 prect->left = (
const UINT16)cmd->destLeft;
1109 prect->top = (
const UINT16)cmd->destTop;
1110 prect->right = MIN((UINT16)cmd->destRight, prect->left + cmd->bmp.width);
1111 prect->bottom = MIN((UINT16)cmd->destBottom, prect->top + cmd->bmp.height);
1117 BOOL result = FALSE;
1123 if (!context || !cmd)
1126 rdpGdi* gdi = context->gdi;
1130 WLog_Print(gdi->log, WLOG_DEBUG,
1131 "destLeft %" PRIu32
" destTop %" PRIu32
" destRight %" PRIu32
" destBottom %" PRIu32
1133 "bpp %" PRIu8
" flags %" PRIx8
" codecID %s [0x%04" PRIu16
"] width %" PRIu16
1134 " height %" PRIu16
" length %" PRIu32
"",
1135 cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bmp.bpp,
1136 cmd->bmp.flags, freerdp_codec_id_to_str(cmd->bmp.codecID), cmd->bmp.codecID,
1137 cmd->bmp.width, cmd->bmp.height, cmd->bmp.bitmapDataLength);
1138 region16_init(®ion);
1140 if (!intersect_rect(gdi, cmd, &cmdRect))
1143 switch (cmd->bmp.codecID)
1145 case RDP_CODEC_ID_REMOTEFX:
1146 case RDP_CODEC_ID_IMAGE_REMOTEFX:
1147 if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData,
1148 cmd->bmp.bitmapDataLength, cmdRect.left, cmdRect.top,
1149 gdi->primary_buffer, gdi->dstFormat, gdi->stride,
1150 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height), ®ion))
1152 WLog_ERR(TAG,
"Failed to process RemoteFX message");
1158 case RDP_CODEC_ID_NSCODEC:
1159 format = gdi->dstFormat;
1161 if (!nsc_process_message(
1162 context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, cmd->bmp.height,
1163 cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, format,
1164 gdi->stride, cmdRect.left, cmdRect.top,
1165 WINPR_ASSERTING_INT_CAST(UINT32, gdi->width),
1166 WINPR_ASSERTING_INT_CAST(UINT32, gdi->height), FREERDP_FLIP_VERTICAL))
1168 WLog_ERR(TAG,
"Failed to process NSCodec message");
1172 if (!region16_union_rect(®ion, ®ion, &cmdRect))
1176 case RDP_CODEC_ID_NONE:
1177 format = gdi_get_pixel_format(cmd->bmp.bpp);
1178 size = 1ull * cmd->bmp.width * cmd->bmp.height * FreeRDPGetBytesPerPixel(format);
1179 if (size > cmd->bmp.bitmapDataLength)
1181 WLog_ERR(TAG,
"Short nocodec message: got %" PRIu32
" bytes, require %" PRIuz,
1182 cmd->bmp.bitmapDataLength, size);
1186 if (!freerdp_image_copy_no_overlap(
1187 gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmdRect.left, cmdRect.top,
1188 cmdRect.right - cmdRect.left, cmdRect.bottom - cmdRect.top, cmd->bmp.bitmapData,
1189 format, 0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))
1191 WLog_ERR(TAG,
"Failed to process nocodec message");
1195 if (!region16_union_rect(®ion, ®ion, &cmdRect))
1200 WLog_ERR(TAG,
"Unsupported codecID %" PRIu32
"", cmd->bmp.codecID);
1206 const RECTANGLE_16* rects = region16_rects(®ion, &nbRects);
1207 if (!rects && (nbRects > 0))
1212 const int32_t w = cmdRect.right - cmdRect.left;
1213 const int32_t h = cmdRect.bottom - cmdRect.top;
1214 if (!gdi_InvalidateRegion(gdi->primary->hdc, cmdRect.left, cmdRect.top, w, h))
1217 for (UINT32 i = 0; i < nbRects; i++)
1221 UINT32 left = rect->left;
1222 UINT32 top = rect->top;
1223 UINT32 width = rect->right - rect->left;
1224 UINT32 height = rect->bottom - rect->top;
1226 if (!gdi_InvalidateRegion(gdi->primary->hdc, WINPR_ASSERTING_INT_CAST(int32_t, left),
1227 WINPR_ASSERTING_INT_CAST(int32_t, top),
1228 WINPR_ASSERTING_INT_CAST(int32_t, width),
1229 WINPR_ASSERTING_INT_CAST(int32_t, height)))
1231 WLog_ERR(TAG,
"Failed to update invalid region");
1238 region16_uninit(®ion);
1247static void gdi_register_update_callbacks(rdpUpdate* update)
1249 WINPR_ASSERT(update);
1250 WINPR_ASSERT(update->context);
1252 const rdpSettings* settings = update->context->settings;
1253 WINPR_ASSERT(settings);
1255 rdpPrimaryUpdate* primary = update->primary;
1256 WINPR_ASSERT(primary);
1260 update->Palette = gdi_palette_update;
1261 update->SetBounds = gdi_set_bounds;
1262 primary->DstBlt = gdi_dstblt;
1263 primary->PatBlt = gdi_patblt;
1264 primary->ScrBlt = gdi_scrblt;
1265 primary->OpaqueRect = gdi_opaque_rect;
1266 primary->DrawNineGrid =
nullptr;
1267 primary->MultiDstBlt =
nullptr;
1268 primary->MultiPatBlt =
nullptr;
1269 primary->MultiScrBlt =
nullptr;
1270 primary->MultiOpaqueRect = gdi_multi_opaque_rect;
1271 primary->MultiDrawNineGrid =
nullptr;
1272 primary->LineTo = gdi_line_to;
1273 primary->Polyline = gdi_polyline;
1274 primary->MemBlt = gdi_memblt;
1275 primary->Mem3Blt = gdi_mem3blt;
1276 primary->SaveBitmap =
nullptr;
1277 primary->GlyphIndex =
nullptr;
1278 primary->FastIndex =
nullptr;
1279 primary->FastGlyph =
nullptr;
1280 primary->PolygonSC = gdi_polygon_sc;
1281 primary->PolygonCB = gdi_polygon_cb;
1282 primary->EllipseSC = gdi_ellipse_sc;
1283 primary->EllipseCB = gdi_ellipse_cb;
1284 update->SurfaceBits = gdi_surface_bits;
1285 update->SurfaceFrameMarker = gdi_surface_frame_marker;
1286 update->altsec->FrameMarker = gdi_frame_marker;
1289static BOOL gdi_init_primary(rdpGdi* gdi, UINT32 stride, UINT32 format, BYTE* buffer,
1290 void (*pfree)(
void*), BOOL isLocked)
1293 WINPR_ASSERT(gdi->context);
1294 WINPR_ASSERT(gdi->context->update);
1296 rdp_update_lock(gdi->context->update);
1298 gdi->primary = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
1301 gdi->dstFormat = format;
1304 gdi->stride = stride;
1306 gdi->stride = WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width) *
1307 FreeRDPGetBytesPerPixel(gdi->dstFormat);
1312 if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
1317 gdi->primary->bitmap =
1318 gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1319 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height));
1323 gdi->primary->bitmap = gdi_CreateBitmapEx(WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1324 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height),
1325 gdi->dstFormat, gdi->stride, buffer, pfree);
1328 if (!gdi->primary->bitmap)
1331 gdi->stride = gdi->primary->bitmap->scanline;
1332 gdi_SelectObject(gdi->primary->hdc, (
HGDIOBJECT)gdi->primary->bitmap);
1333 gdi->primary->org_bitmap =
nullptr;
1334 gdi->primary_buffer = gdi->primary->bitmap->data;
1336 if (!(gdi->primary->hdc->hwnd = (
HGDI_WND)calloc(1,
sizeof(
GDI_WND))))
1339 if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0)))
1342 gdi->primary->hdc->hwnd->invalid->null = TRUE;
1343 gdi->primary->hdc->hwnd->count = 32;
1345 if (!(gdi->primary->hdc->hwnd->cinvalid =
1346 (
GDI_RGN*)calloc(gdi->primary->hdc->hwnd->count,
sizeof(
GDI_RGN))))
1349 gdi->primary->hdc->hwnd->ninvalid = 0;
1352 gdi->drawing = gdi->primary;
1354 rdp_update_unlock(gdi->context->update);
1357 gdi_DeleteObject((
HGDIOBJECT)gdi->primary->bitmap);
1359 gdi_DeleteDC(gdi->primary->hdc);
1362 gdi->primary =
nullptr;
1364 rdp_update_unlock(gdi->context->update);
1368BOOL gdi_resize(rdpGdi* gdi, UINT32 width, UINT32 height)
1370 return gdi_resize_ex(gdi, width, height, 0, 0,
nullptr,
nullptr);
1373BOOL gdi_resize_ex(rdpGdi* gdi, UINT32 width, UINT32 height, UINT32 stride, UINT32 format,
1374 BYTE* buffer,
void (*pfree)(
void*))
1376 if (!gdi || !gdi->primary)
1379 if ((width > INT32_MAX) || (height > INT32_MAX))
1382 if ((gdi->width == (INT32)width) && (gdi->height == (INT32)height) &&
1383 (!buffer || (gdi->primary_buffer == buffer)))
1386 WINPR_ASSERT(gdi->context);
1387 WINPR_ASSERT(gdi->context->update);
1390 if (!update_end_paint(gdi->context->update))
1392 rdp_update_lock(gdi->context->update);
1394 if (gdi->drawing == gdi->primary)
1395 gdi->drawing =
nullptr;
1397 gdi->width = (INT32)width;
1398 gdi->height = (INT32)height;
1399 gdi_bitmap_free_ex(gdi->primary);
1400 gdi->primary =
nullptr;
1401 gdi->primary_buffer =
nullptr;
1402 return gdi_init_primary(gdi, stride, format, buffer, pfree, TRUE);
1412BOOL gdi_init(freerdp* instance, UINT32 format)
1414 return gdi_init_ex(instance, format, 0,
nullptr, winpr_aligned_free);
1428BOOL gdi_init_ex(freerdp* instance, UINT32 format, UINT32 stride, BYTE* buffer,
1429 void (*pfree)(
void*))
1431 rdpContext* context =
nullptr;
1432 UINT32 SrcFormat = 0;
1433 rdpGdi* gdi =
nullptr;
1435 WINPR_ASSERT(instance);
1437 context = instance->context;
1438 WINPR_ASSERT(context);
1439 WINPR_ASSERT(context->settings);
1442 SrcFormat = gdi_get_pixel_format(ColorDepth);
1443 gdi = (rdpGdi*)calloc(1,
sizeof(rdpGdi));
1449 gdi->log = WLog_Get(TAG);
1454 gdi->context = context;
1455 gdi->width = WINPR_ASSERTING_INT_CAST(
1457 gdi->height = WINPR_ASSERTING_INT_CAST(
1459 gdi->dstFormat = format;
1461 WLog_Print(gdi->log, WLOG_INFO,
"Local framebuffer format %s",
1462 FreeRDPGetColorFormatName(gdi->dstFormat));
1463 WLog_Print(gdi->log, WLOG_INFO,
"Remote framebuffer format %s",
1464 FreeRDPGetColorFormatName(SrcFormat));
1466 if (!(gdi->hdc = gdi_GetDC()))
1469 gdi->hdc->format = gdi->dstFormat;
1471 if (!gdi_init_primary(gdi, stride, gdi->dstFormat, buffer, pfree, FALSE))
1474 if (!(context->cache = cache_new(context)))
1477 gdi_register_update_callbacks(context->update);
1478 brush_cache_register_callbacks(context->update);
1479 glyph_cache_register_callbacks(context->update);
1480 bitmap_cache_register_callbacks(context->update);
1481 offscreen_cache_register_callbacks(context->update);
1482 palette_cache_register_callbacks(context->update);
1484 if (!gdi_register_graphics(context->graphics))
1490 WLog_ERR(TAG,
"failed to initialize gdi");
1494void gdi_free(freerdp* instance)
1496 rdpGdi* gdi =
nullptr;
1497 rdpContext* context =
nullptr;
1499 if (!instance || !instance->context)
1502 gdi = instance->context->gdi;
1506 gdi_bitmap_free_ex(gdi->primary);
1507 gdi_DeleteDC(gdi->hdc);
1511 context = instance->context;
1512 cache_free(context->cache);
1513 context->cache =
nullptr;
1514 instance->context->gdi = (rdpGdi*)
nullptr;
1517BOOL gdi_send_suppress_output(rdpGdi* gdi, BOOL suppress)
1519 if (!gdi || !gdi->context)
1522 if (gdi->suppressOutput == suppress)
1525 gdi->suppressOutput = suppress;
1527 rdpContext* context = gdi->context;
1528 rdpSettings* settings = context->settings;
1529 WINPR_ASSERT(settings);
1531 rdpUpdate* update = context->update;
1532 WINPR_ASSERT(update);
1539 .right = WINPR_ASSERTING_INT_CAST(UINT16, w),
1540 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, h) };
1542 WINPR_ASSERT(update->SuppressOutput);
1543 return update->SuppressOutput(context, !suppress, &rect);
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.