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)
731 if (!gdi_CRgnToRect(x, y, w, h, &rect))
734 if (!gdi_decode_color(gdi, opaque_rect->color, &brush_color,
nullptr))
737 if (!(hBrush = gdi_CreateSolidBrush(brush_color)))
740 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
745static BOOL gdi_multi_opaque_rect(rdpContext* context,
748 WINPR_ASSERT(context);
749 WINPR_ASSERT(multi_opaque_rect);
752 UINT32 brush_color = 0;
753 rdpGdi* gdi = context->gdi;
756 if (!gdi || !gdi->drawing)
759 if (!gdi_decode_color(gdi, multi_opaque_rect->color, &brush_color,
nullptr))
762 HGDI_BRUSH hBrush = gdi_CreateSolidBrush(brush_color);
767 for (UINT32 i = 0; i < multi_opaque_rect->numRectangles; i++)
769 const DELTA_RECT* rectangle = &multi_opaque_rect->rectangles[i];
770 const INT32 x = rectangle->left;
771 const INT32 y = rectangle->top;
772 const INT32 w = rectangle->width;
773 const INT32 h = rectangle->height;
776 if (!gdi_CRgnToRect(x, y, w, h, &rect))
778 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
788static BOOL gdi_line_to(rdpContext* context,
const LINE_TO_ORDER* lineTo)
792 WINPR_ASSERT(context);
793 WINPR_ASSERT(lineTo);
795 rdpGdi* gdi = context->gdi;
796 if (!gdi || !gdi->drawing || !gdi->drawing->hdc)
799 if (!gdi_decode_color(gdi, lineTo->penColor, &color,
nullptr))
802 HGDI_PEN hPen = gdi_CreatePen(lineTo->penStyle, lineTo->penWidth, color,
803 gdi->drawing->hdc->format, &gdi->palette);
807 WINPR_ASSERT(gdi->drawing);
809 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)hPen);
810 gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, lineTo->bRop2));
811 if (!gdi_MoveToEx(gdi->drawing->hdc, lineTo->nXStart, lineTo->nYStart,
nullptr))
813 if (!gdi_LineTo(gdi->drawing->hdc, lineTo->nXEnd, lineTo->nYEnd))
822static BOOL gdi_polyline(rdpContext* context,
const POLYLINE_ORDER* polyline)
825 WINPR_ASSERT(context);
826 WINPR_ASSERT(polyline);
828 rdpGdi* gdi = context->gdi;
829 if (!gdi || !gdi->drawing || !gdi->drawing->hdc)
833 if (!gdi_decode_color(gdi, polyline->penColor, &color,
nullptr))
836 WINPR_ASSERT(gdi->drawing);
837 WINPR_ASSERT(gdi->drawing->hdc);
839 HGDI_PEN hPen = gdi_CreatePen(GDI_PS_SOLID, 1, color, gdi->drawing->hdc->format, &gdi->palette);
843 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)hPen);
844 gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, polyline->bRop2));
845 INT32 x = polyline->xStart;
846 INT32 y = polyline->yStart;
847 if (!gdi_MoveToEx(gdi->drawing->hdc, x, y,
nullptr))
851 for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
855 if (!gdi_LineTo(gdi->drawing->hdc, x, y))
857 if (!gdi_MoveToEx(gdi->drawing->hdc, x, y,
nullptr))
867static BOOL gdi_memblt(rdpContext* context,
MEMBLT_ORDER* memblt)
869 if (!context || !memblt || !memblt->bitmap)
872 gdiBitmap* bitmap = (gdiBitmap*)memblt->bitmap;
873 rdpGdi* gdi = context->gdi;
874 if (!gdi || !gdi->drawing)
876 return gdi_BitBlt(gdi->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
877 memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc,
878 gdi_rop3_code_checked(memblt->bRop), &gdi->palette);
881static BOOL gdi_mem3blt(rdpContext* context,
MEM3BLT_ORDER* mem3blt)
883 WINPR_ASSERT(context);
884 WINPR_ASSERT(mem3blt);
887 rdpGdi* gdi = context->gdi;
888 if (!gdi || !gdi->drawing)
892 const rdpBrush* brush = &mem3blt->brush;
893 gdiBitmap* bitmap = (gdiBitmap*)mem3blt->bitmap;
894 UINT32 foreColor = 0;
895 UINT32 backColor = 0;
896 UINT32 originalColor = 0;
898 if (!gdi_decode_color(gdi, mem3blt->foreColor, &foreColor,
nullptr))
901 if (!gdi_decode_color(gdi, mem3blt->backColor, &backColor,
nullptr))
904 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
906 switch (brush->style)
909 originalBrush = gdi->drawing->hdc->brush;
910 gdi->drawing->hdc->brush = gdi_CreateSolidBrush(foreColor);
912 if (!gdi->drawing->hdc->brush)
918 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
919 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
920 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
921 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
922 gdi->drawing->hdc->brush = originalBrush;
928 UINT32 brushFormat = 0;
929 BYTE* data = (BYTE*)winpr_aligned_malloc(
930 8ULL * 8ULL * FreeRDPGetBytesPerPixel(gdi->drawing->hdc->format), 16);
940 UINT32 bpp = brush->bpp;
942 const UINT32 ColorDepth =
944 if ((bpp == 16) && (ColorDepth == 15))
947 brushFormat = gdi_get_pixel_format(bpp);
949 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
950 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
954 winpr_aligned_free(data);
960 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
961 8, brush->data, backColor, foreColor,
965 winpr_aligned_free(data);
970 hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->format, data);
975 winpr_aligned_free(data);
979 originalBrush = gdi->drawing->hdc->brush;
980 gdi->drawing->hdc->brush = gdi_CreatePatternBrush(hBmp);
982 if (!gdi->drawing->hdc->brush)
988 gdi->drawing->hdc->brush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
989 gdi->drawing->hdc->brush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
990 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
991 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
992 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
993 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
995 gdi->drawing->hdc->brush = originalBrush;
1000 WLog_ERR(TAG,
"Mem3Blt unimplemented brush style:%" PRIu32
"", brush->style);
1005 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
1009static BOOL gdi_polygon_sc(WINPR_ATTR_UNUSED rdpContext* context,
1012 WLog_WARN(TAG,
"not implemented");
1016static BOOL gdi_polygon_cb(WINPR_ATTR_UNUSED rdpContext* context,
1019 WLog_WARN(TAG,
"not implemented");
1023static BOOL gdi_ellipse_sc(WINPR_ATTR_UNUSED rdpContext* context,
1026 WLog_WARN(TAG,
"not implemented");
1030static BOOL gdi_ellipse_cb(WINPR_ATTR_UNUSED rdpContext* context,
1033 WLog_WARN(TAG,
"not implemented");
1037static BOOL gdi_frame_marker(WINPR_ATTR_UNUSED rdpContext* context,
1043static BOOL gdi_surface_frame_marker(rdpContext* context,
1046 WINPR_ASSERT(context);
1047 WINPR_ASSERT(context->gdi);
1048 WINPR_ASSERT(context->update);
1049 WINPR_ASSERT(surfaceFrameMarker);
1051 WLog_Print(context->gdi->log, WLOG_DEBUG,
"frameId %" PRIu32
" frameAction %" PRIu32
"",
1052 surfaceFrameMarker->frameId, surfaceFrameMarker->frameAction);
1054 switch (surfaceFrameMarker->frameAction)
1056 case SURFACECMD_FRAMEACTION_BEGIN:
1059 case SURFACECMD_FRAMEACTION_END:
1062 if (!IFCALLRESULT(TRUE, context->update->SurfaceFrameAcknowledge, context,
1063 surfaceFrameMarker->frameId))
1079 WINPR_ASSERT(prect);
1081 const UINT32 w = (
const UINT32)gdi->width;
1082 const UINT32 h = (
const UINT32)gdi->height;
1084 if (cmd->destLeft > w)
1086 if (cmd->destRight > w)
1088 if (cmd->destLeft > cmd->destRight)
1090 if (cmd->destRight > UINT16_MAX)
1093 if (cmd->destTop > h)
1095 if (cmd->destBottom > h)
1097 if (cmd->destTop > cmd->destBottom)
1099 if (cmd->destBottom > UINT16_MAX)
1102 prect->left = (
const UINT16)cmd->destLeft;
1103 prect->top = (
const UINT16)cmd->destTop;
1104 prect->right = MIN((UINT16)cmd->destRight, prect->left + cmd->bmp.width);
1105 prect->bottom = MIN((UINT16)cmd->destBottom, prect->top + cmd->bmp.height);
1111 BOOL result = FALSE;
1117 if (!context || !cmd)
1120 rdpGdi* gdi = context->gdi;
1124 WLog_Print(gdi->log, WLOG_DEBUG,
1125 "destLeft %" PRIu32
" destTop %" PRIu32
" destRight %" PRIu32
" destBottom %" PRIu32
1127 "bpp %" PRIu8
" flags %" PRIx8
" codecID %s [0x%04" PRIu16
"] width %" PRIu16
1128 " height %" PRIu16
" length %" PRIu32
"",
1129 cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bmp.bpp,
1130 cmd->bmp.flags, freerdp_codec_id_to_str(cmd->bmp.codecID), cmd->bmp.codecID,
1131 cmd->bmp.width, cmd->bmp.height, cmd->bmp.bitmapDataLength);
1132 region16_init(®ion);
1134 if (!intersect_rect(gdi, cmd, &cmdRect))
1137 switch (cmd->bmp.codecID)
1139 case RDP_CODEC_ID_REMOTEFX:
1140 case RDP_CODEC_ID_IMAGE_REMOTEFX:
1141 if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData,
1142 cmd->bmp.bitmapDataLength, cmdRect.left, cmdRect.top,
1143 gdi->primary_buffer, gdi->dstFormat, gdi->stride,
1144 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height), ®ion))
1146 WLog_ERR(TAG,
"Failed to process RemoteFX message");
1152 case RDP_CODEC_ID_NSCODEC:
1153 format = gdi->dstFormat;
1155 if (!nsc_process_message(
1156 context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, cmd->bmp.height,
1157 cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, format,
1158 gdi->stride, cmdRect.left, cmdRect.top,
1159 WINPR_ASSERTING_INT_CAST(UINT32, gdi->width),
1160 WINPR_ASSERTING_INT_CAST(UINT32, gdi->height), FREERDP_FLIP_VERTICAL))
1162 WLog_ERR(TAG,
"Failed to process NSCodec message");
1166 if (!region16_union_rect(®ion, ®ion, &cmdRect))
1170 case RDP_CODEC_ID_NONE:
1171 format = gdi_get_pixel_format(cmd->bmp.bpp);
1172 size = 1ull * cmd->bmp.width * cmd->bmp.height * FreeRDPGetBytesPerPixel(format);
1173 if (size > cmd->bmp.bitmapDataLength)
1175 WLog_ERR(TAG,
"Short nocodec message: got %" PRIu32
" bytes, require %" PRIuz,
1176 cmd->bmp.bitmapDataLength, size);
1180 if (!freerdp_image_copy_no_overlap(
1181 gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmdRect.left, cmdRect.top,
1182 cmdRect.right - cmdRect.left, cmdRect.bottom - cmdRect.top, cmd->bmp.bitmapData,
1183 format, 0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))
1185 WLog_ERR(TAG,
"Failed to process nocodec message");
1189 if (!region16_union_rect(®ion, ®ion, &cmdRect))
1194 WLog_ERR(TAG,
"Unsupported codecID %" PRIu32
"", cmd->bmp.codecID);
1200 const RECTANGLE_16* rects = region16_rects(®ion, &nbRects);
1201 if (!rects && (nbRects > 0))
1206 const int32_t w = cmdRect.right - cmdRect.left;
1207 const int32_t h = cmdRect.bottom - cmdRect.top;
1208 if (!gdi_InvalidateRegion(gdi->primary->hdc, cmdRect.left, cmdRect.top, w, h))
1211 for (UINT32 i = 0; i < nbRects; i++)
1215 UINT32 left = rect->left;
1216 UINT32 top = rect->top;
1217 UINT32 width = rect->right - rect->left;
1218 UINT32 height = rect->bottom - rect->top;
1220 if (!gdi_InvalidateRegion(gdi->primary->hdc, WINPR_ASSERTING_INT_CAST(int32_t, left),
1221 WINPR_ASSERTING_INT_CAST(int32_t, top),
1222 WINPR_ASSERTING_INT_CAST(int32_t, width),
1223 WINPR_ASSERTING_INT_CAST(int32_t, height)))
1225 WLog_ERR(TAG,
"Failed to update invalid region");
1232 region16_uninit(®ion);
1241static void gdi_register_update_callbacks(rdpUpdate* update)
1243 WINPR_ASSERT(update);
1244 WINPR_ASSERT(update->context);
1246 const rdpSettings* settings = update->context->settings;
1247 WINPR_ASSERT(settings);
1249 rdpPrimaryUpdate* primary = update->primary;
1250 WINPR_ASSERT(primary);
1254 update->Palette = gdi_palette_update;
1255 update->SetBounds = gdi_set_bounds;
1256 primary->DstBlt = gdi_dstblt;
1257 primary->PatBlt = gdi_patblt;
1258 primary->ScrBlt = gdi_scrblt;
1259 primary->OpaqueRect = gdi_opaque_rect;
1260 primary->DrawNineGrid =
nullptr;
1261 primary->MultiDstBlt =
nullptr;
1262 primary->MultiPatBlt =
nullptr;
1263 primary->MultiScrBlt =
nullptr;
1264 primary->MultiOpaqueRect = gdi_multi_opaque_rect;
1265 primary->MultiDrawNineGrid =
nullptr;
1266 primary->LineTo = gdi_line_to;
1267 primary->Polyline = gdi_polyline;
1268 primary->MemBlt = gdi_memblt;
1269 primary->Mem3Blt = gdi_mem3blt;
1270 primary->SaveBitmap =
nullptr;
1271 primary->GlyphIndex =
nullptr;
1272 primary->FastIndex =
nullptr;
1273 primary->FastGlyph =
nullptr;
1274 primary->PolygonSC = gdi_polygon_sc;
1275 primary->PolygonCB = gdi_polygon_cb;
1276 primary->EllipseSC = gdi_ellipse_sc;
1277 primary->EllipseCB = gdi_ellipse_cb;
1278 update->SurfaceBits = gdi_surface_bits;
1279 update->SurfaceFrameMarker = gdi_surface_frame_marker;
1280 update->altsec->FrameMarker = gdi_frame_marker;
1283static BOOL gdi_init_primary(rdpGdi* gdi, UINT32 stride, UINT32 format, BYTE* buffer,
1284 void (*pfree)(
void*), BOOL isLocked)
1287 WINPR_ASSERT(gdi->context);
1288 WINPR_ASSERT(gdi->context->update);
1290 rdp_update_lock(gdi->context->update);
1292 gdi->primary = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
1295 gdi->dstFormat = format;
1298 gdi->stride = stride;
1300 gdi->stride = WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width) *
1301 FreeRDPGetBytesPerPixel(gdi->dstFormat);
1306 if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
1311 gdi->primary->bitmap =
1312 gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1313 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height));
1317 gdi->primary->bitmap = gdi_CreateBitmapEx(WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1318 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height),
1319 gdi->dstFormat, gdi->stride, buffer, pfree);
1322 if (!gdi->primary->bitmap)
1325 gdi->stride = gdi->primary->bitmap->scanline;
1326 gdi_SelectObject(gdi->primary->hdc, (
HGDIOBJECT)gdi->primary->bitmap);
1327 gdi->primary->org_bitmap =
nullptr;
1328 gdi->primary_buffer = gdi->primary->bitmap->data;
1330 if (!(gdi->primary->hdc->hwnd = (
HGDI_WND)calloc(1,
sizeof(
GDI_WND))))
1333 if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0)))
1336 gdi->primary->hdc->hwnd->invalid->null = TRUE;
1337 gdi->primary->hdc->hwnd->count = 32;
1339 if (!(gdi->primary->hdc->hwnd->cinvalid =
1340 (
GDI_RGN*)calloc(gdi->primary->hdc->hwnd->count,
sizeof(
GDI_RGN))))
1343 gdi->primary->hdc->hwnd->ninvalid = 0;
1346 gdi->drawing = gdi->primary;
1348 rdp_update_unlock(gdi->context->update);
1351 gdi_DeleteObject((
HGDIOBJECT)gdi->primary->bitmap);
1353 gdi_DeleteDC(gdi->primary->hdc);
1356 gdi->primary =
nullptr;
1358 rdp_update_unlock(gdi->context->update);
1362BOOL gdi_resize(rdpGdi* gdi, UINT32 width, UINT32 height)
1364 return gdi_resize_ex(gdi, width, height, 0, 0,
nullptr,
nullptr);
1367BOOL gdi_resize_ex(rdpGdi* gdi, UINT32 width, UINT32 height, UINT32 stride, UINT32 format,
1368 BYTE* buffer,
void (*pfree)(
void*))
1370 if (!gdi || !gdi->primary)
1373 if ((width > INT32_MAX) || (height > INT32_MAX))
1376 if ((gdi->width == (INT32)width) && (gdi->height == (INT32)height) &&
1377 (!buffer || (gdi->primary_buffer == buffer)))
1380 WINPR_ASSERT(gdi->context);
1381 WINPR_ASSERT(gdi->context->update);
1384 if (!update_end_paint(gdi->context->update))
1386 rdp_update_lock(gdi->context->update);
1388 if (gdi->drawing == gdi->primary)
1389 gdi->drawing =
nullptr;
1391 gdi->width = (INT32)width;
1392 gdi->height = (INT32)height;
1393 gdi_bitmap_free_ex(gdi->primary);
1394 gdi->primary =
nullptr;
1395 gdi->primary_buffer =
nullptr;
1396 return gdi_init_primary(gdi, stride, format, buffer, pfree, TRUE);
1406BOOL gdi_init(freerdp* instance, UINT32 format)
1408 return gdi_init_ex(instance, format, 0,
nullptr, winpr_aligned_free);
1422BOOL gdi_init_ex(freerdp* instance, UINT32 format, UINT32 stride, BYTE* buffer,
1423 void (*pfree)(
void*))
1425 rdpContext* context =
nullptr;
1426 UINT32 SrcFormat = 0;
1427 rdpGdi* gdi =
nullptr;
1429 WINPR_ASSERT(instance);
1431 context = instance->context;
1432 WINPR_ASSERT(context);
1433 WINPR_ASSERT(context->settings);
1436 SrcFormat = gdi_get_pixel_format(ColorDepth);
1437 gdi = (rdpGdi*)calloc(1,
sizeof(rdpGdi));
1443 gdi->log = WLog_Get(TAG);
1448 gdi->context = context;
1449 gdi->width = WINPR_ASSERTING_INT_CAST(
1451 gdi->height = WINPR_ASSERTING_INT_CAST(
1453 gdi->dstFormat = format;
1455 WLog_Print(gdi->log, WLOG_INFO,
"Local framebuffer format %s",
1456 FreeRDPGetColorFormatName(gdi->dstFormat));
1457 WLog_Print(gdi->log, WLOG_INFO,
"Remote framebuffer format %s",
1458 FreeRDPGetColorFormatName(SrcFormat));
1460 if (!(gdi->hdc = gdi_GetDC()))
1463 gdi->hdc->format = gdi->dstFormat;
1465 if (!gdi_init_primary(gdi, stride, gdi->dstFormat, buffer, pfree, FALSE))
1468 if (!(context->cache = cache_new(context)))
1471 gdi_register_update_callbacks(context->update);
1472 brush_cache_register_callbacks(context->update);
1473 glyph_cache_register_callbacks(context->update);
1474 bitmap_cache_register_callbacks(context->update);
1475 offscreen_cache_register_callbacks(context->update);
1476 palette_cache_register_callbacks(context->update);
1478 if (!gdi_register_graphics(context->graphics))
1484 WLog_ERR(TAG,
"failed to initialize gdi");
1488void gdi_free(freerdp* instance)
1490 rdpGdi* gdi =
nullptr;
1491 rdpContext* context =
nullptr;
1493 if (!instance || !instance->context)
1496 gdi = instance->context->gdi;
1500 gdi_bitmap_free_ex(gdi->primary);
1501 gdi_DeleteDC(gdi->hdc);
1505 context = instance->context;
1506 cache_free(context->cache);
1507 context->cache =
nullptr;
1508 instance->context->gdi = (rdpGdi*)
nullptr;
1511BOOL gdi_send_suppress_output(rdpGdi* gdi, BOOL suppress)
1513 if (!gdi || !gdi->context)
1516 if (gdi->suppressOutput == suppress)
1519 gdi->suppressOutput = suppress;
1521 rdpContext* context = gdi->context;
1522 rdpSettings* settings = context->settings;
1523 WINPR_ASSERT(settings);
1525 rdpUpdate* update = context->update;
1526 WINPR_ASSERT(update);
1533 .right = WINPR_ASSERTING_INT_CAST(UINT16, w),
1534 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, h) };
1536 WINPR_ASSERT(update->SuppressOutput);
1537 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.