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 = NULL;
465 gdi_DeleteDC(bitmap->hdc);
472void gdi_bitmap_free_ex(gdiBitmap* bitmap)
476 gdi_SelectObject(bitmap->hdc, (
HGDIOBJECT)bitmap->org_bitmap);
478 gdi_DeleteDC(bitmap->hdc);
483BOOL gdi_bitmap_update(rdpContext* context,
const BITMAP_UPDATE* bitmapUpdate)
485 if (!context || !bitmapUpdate || !context->gdi || !context->codecs)
488 "Invalid arguments: context=%p, bitmapUpdate=%p, context->gdi=%p, "
489 "context->codecs=%p",
490 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 : NULL),
493 WINPR_CXX_COMPAT_CAST(const void*, context ? context->codecs : NULL));
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)
569 gdi_SetClipRgn(gdi->drawing->hdc, bounds->left, bounds->top,
570 bounds->right - bounds->left + 1, bounds->bottom - bounds->top + 1);
573 gdi_SetNullClipRgn(gdi->drawing->hdc);
578static BOOL gdi_dstblt(rdpContext* context,
const DSTBLT_ORDER* dstblt)
580 if (!context || !dstblt)
583 rdpGdi* gdi = context->gdi;
584 if (!gdi || !gdi->drawing)
586 return gdi_BitBlt(gdi->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth,
587 dstblt->nHeight, NULL, 0, 0, gdi_rop3_code_checked(dstblt->bRop),
591static BOOL gdi_patblt(rdpContext* context,
PATBLT_ORDER* patblt)
593 WINPR_ASSERT(context);
594 WINPR_ASSERT(patblt);
596 const rdpBrush* brush = &patblt->brush;
597 UINT32 foreColor = 0;
598 UINT32 backColor = 0;
599 UINT32 originalColor = 0;
602 rdpGdi* gdi = context->gdi;
604 const DWORD rop = gdi_rop3_code_checked(patblt->bRop);
607 BYTE data[8 * 8 * 4];
610 if (!gdi || !gdi->drawing || !gdi->drawing->hdc)
613 if (!gdi_decode_color(gdi, patblt->foreColor, &foreColor, NULL))
616 if (!gdi_decode_color(gdi, patblt->backColor, &backColor, NULL))
619 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
620 originalBrush = gdi->drawing->hdc->brush;
622 switch (brush->style)
625 hbrush = gdi_CreateSolidBrush(foreColor);
630 const BYTE* hatched = NULL;
631 hatched = GDI_BS_HATCHED_PATTERNS + (8ULL * brush->hatch);
633 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
634 hatched, backColor, foreColor, &gdi->palette))
637 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
642 hbrush = gdi_CreateHatchBrush(hBmp);
648 UINT32 brushFormat = 0;
652 UINT32 bpp = brush->bpp;
658 brushFormat = gdi_get_pixel_format(bpp);
660 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
661 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
667 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
668 8, brush->data, backColor, foreColor,
673 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
678 hbrush = gdi_CreatePatternBrush(hBmp);
683 WLog_ERR(TAG,
"unimplemented brush style:%" PRIu32
"", brush->style);
689 hbrush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
690 hbrush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
691 gdi->drawing->hdc->brush = hbrush;
692 ret = gdi_BitBlt(gdi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
693 patblt->nHeight, gdi->primary->hdc, nXSrc, nYSrc, rop, &gdi->palette);
699 gdi->drawing->hdc->brush = originalBrush;
700 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
704static BOOL gdi_scrblt(rdpContext* context,
const SCRBLT_ORDER* scrblt)
706 if (!context || !context->gdi)
709 rdpGdi* gdi = context->gdi;
710 if (!gdi->drawing || !gdi->primary)
713 return gdi_BitBlt(gdi->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth,
714 scrblt->nHeight, gdi->primary->hdc, scrblt->nXSrc, scrblt->nYSrc,
715 gdi_rop3_code_checked(scrblt->bRop), &gdi->palette);
718static BOOL gdi_opaque_rect(rdpContext* context,
const OPAQUE_RECT_ORDER* opaque_rect)
720 WINPR_ASSERT(context);
721 WINPR_ASSERT(opaque_rect);
725 UINT32 brush_color = 0;
726 rdpGdi* gdi = context->gdi;
728 INT32 x = opaque_rect->nLeftRect;
729 INT32 y = opaque_rect->nTopRect;
730 INT32 w = opaque_rect->nWidth;
731 INT32 h = opaque_rect->nHeight;
732 if (!gdi || !gdi->drawing)
735 gdi_CRgnToRect(x, y, w, h, &rect);
737 if (!gdi_decode_color(gdi, opaque_rect->color, &brush_color, NULL))
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, NULL))
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;
778 gdi_CRgnToRect(x, y, w, h, &rect);
779 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
789static 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, NULL))
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 gdi_MoveToEx(gdi->drawing->hdc, lineTo->nXStart, lineTo->nYStart, NULL);
812 gdi_LineTo(gdi->drawing->hdc, lineTo->nXEnd, lineTo->nYEnd);
817static BOOL gdi_polyline(rdpContext* context,
const POLYLINE_ORDER* polyline)
819 WINPR_ASSERT(context);
820 WINPR_ASSERT(polyline);
822 rdpGdi* gdi = context->gdi;
823 if (!gdi || !gdi->drawing || !gdi->drawing->hdc)
827 if (!gdi_decode_color(gdi, polyline->penColor, &color, NULL))
830 WINPR_ASSERT(gdi->drawing);
831 WINPR_ASSERT(gdi->drawing->hdc);
833 HGDI_PEN hPen = gdi_CreatePen(GDI_PS_SOLID, 1, color, gdi->drawing->hdc->format, &gdi->palette);
837 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)hPen);
838 gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, polyline->bRop2));
839 INT32 x = polyline->xStart;
840 INT32 y = polyline->yStart;
841 gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL);
844 for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
848 gdi_LineTo(gdi->drawing->hdc, x, y);
849 gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL);
856static BOOL gdi_memblt(rdpContext* context,
MEMBLT_ORDER* memblt)
858 if (!context || !memblt || !memblt->bitmap)
861 gdiBitmap* bitmap = (gdiBitmap*)memblt->bitmap;
862 rdpGdi* gdi = context->gdi;
863 if (!gdi || !gdi->drawing)
865 return gdi_BitBlt(gdi->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
866 memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc,
867 gdi_rop3_code_checked(memblt->bRop), &gdi->palette);
870static BOOL gdi_mem3blt(rdpContext* context,
MEM3BLT_ORDER* mem3blt)
872 WINPR_ASSERT(context);
873 WINPR_ASSERT(mem3blt);
876 rdpGdi* gdi = context->gdi;
877 if (!gdi || !gdi->drawing)
881 const rdpBrush* brush = &mem3blt->brush;
882 gdiBitmap* bitmap = (gdiBitmap*)mem3blt->bitmap;
883 UINT32 foreColor = 0;
884 UINT32 backColor = 0;
885 UINT32 originalColor = 0;
887 if (!gdi_decode_color(gdi, mem3blt->foreColor, &foreColor, NULL))
890 if (!gdi_decode_color(gdi, mem3blt->backColor, &backColor, NULL))
893 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
895 switch (brush->style)
898 originalBrush = gdi->drawing->hdc->brush;
899 gdi->drawing->hdc->brush = gdi_CreateSolidBrush(foreColor);
901 if (!gdi->drawing->hdc->brush)
907 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
908 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
909 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
910 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
911 gdi->drawing->hdc->brush = originalBrush;
917 UINT32 brushFormat = 0;
918 BYTE* data = (BYTE*)winpr_aligned_malloc(
919 8ULL * 8ULL * FreeRDPGetBytesPerPixel(gdi->drawing->hdc->format), 16);
929 UINT32 bpp = brush->bpp;
931 const UINT32 ColorDepth =
933 if ((bpp == 16) && (ColorDepth == 15))
936 brushFormat = gdi_get_pixel_format(bpp);
938 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
939 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
943 winpr_aligned_free(data);
949 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
950 8, brush->data, backColor, foreColor,
954 winpr_aligned_free(data);
959 hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->format, data);
964 winpr_aligned_free(data);
968 originalBrush = gdi->drawing->hdc->brush;
969 gdi->drawing->hdc->brush = gdi_CreatePatternBrush(hBmp);
971 if (!gdi->drawing->hdc->brush)
977 gdi->drawing->hdc->brush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
978 gdi->drawing->hdc->brush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
979 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
980 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
981 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
982 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
984 gdi->drawing->hdc->brush = originalBrush;
989 WLog_ERR(TAG,
"Mem3Blt unimplemented brush style:%" PRIu32
"", brush->style);
994 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
998static BOOL gdi_polygon_sc(WINPR_ATTR_UNUSED rdpContext* context,
1001 WLog_WARN(TAG,
"not implemented");
1005static BOOL gdi_polygon_cb(WINPR_ATTR_UNUSED rdpContext* context,
1008 WLog_WARN(TAG,
"not implemented");
1012static BOOL gdi_ellipse_sc(WINPR_ATTR_UNUSED rdpContext* context,
1015 WLog_WARN(TAG,
"not implemented");
1019static BOOL gdi_ellipse_cb(WINPR_ATTR_UNUSED rdpContext* context,
1022 WLog_WARN(TAG,
"not implemented");
1026static BOOL gdi_frame_marker(WINPR_ATTR_UNUSED rdpContext* context,
1032static BOOL gdi_surface_frame_marker(rdpContext* context,
1035 WINPR_ASSERT(context);
1036 WINPR_ASSERT(context->gdi);
1037 WINPR_ASSERT(context->update);
1038 WINPR_ASSERT(surfaceFrameMarker);
1040 WLog_Print(context->gdi->log, WLOG_DEBUG,
"frameId %" PRIu32
" frameAction %" PRIu32
"",
1041 surfaceFrameMarker->frameId, surfaceFrameMarker->frameAction);
1043 switch (surfaceFrameMarker->frameAction)
1045 case SURFACECMD_FRAMEACTION_BEGIN:
1048 case SURFACECMD_FRAMEACTION_END:
1051 IFCALL(context->update->SurfaceFrameAcknowledge, context,
1052 surfaceFrameMarker->frameId);
1067 WINPR_ASSERT(prect);
1069 const UINT32 w = (
const UINT32)gdi->width;
1070 const UINT32 h = (
const UINT32)gdi->height;
1072 if (cmd->destLeft > w)
1074 if (cmd->destRight > w)
1076 if (cmd->destLeft > cmd->destRight)
1078 if (cmd->destRight > UINT16_MAX)
1081 if (cmd->destTop > h)
1083 if (cmd->destBottom > h)
1085 if (cmd->destTop > cmd->destBottom)
1087 if (cmd->destBottom > UINT16_MAX)
1090 prect->left = (
const UINT16)cmd->destLeft;
1091 prect->top = (
const UINT16)cmd->destTop;
1092 prect->right = MIN((UINT16)cmd->destRight, prect->left + cmd->bmp.width);
1093 prect->bottom = MIN((UINT16)cmd->destBottom, prect->top + cmd->bmp.height);
1099 BOOL result = FALSE;
1105 if (!context || !cmd)
1108 rdpGdi* gdi = context->gdi;
1112 WLog_Print(gdi->log, WLOG_DEBUG,
1113 "destLeft %" PRIu32
" destTop %" PRIu32
" destRight %" PRIu32
" destBottom %" PRIu32
1115 "bpp %" PRIu8
" flags %" PRIx8
" codecID %s [0x%04" PRIu16
"] width %" PRIu16
1116 " height %" PRIu16
" length %" PRIu32
"",
1117 cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bmp.bpp,
1118 cmd->bmp.flags, freerdp_codec_id_to_str(cmd->bmp.codecID), cmd->bmp.codecID,
1119 cmd->bmp.width, cmd->bmp.height, cmd->bmp.bitmapDataLength);
1120 region16_init(®ion);
1122 if (!intersect_rect(gdi, cmd, &cmdRect))
1125 switch (cmd->bmp.codecID)
1127 case RDP_CODEC_ID_REMOTEFX:
1128 case RDP_CODEC_ID_IMAGE_REMOTEFX:
1129 if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData,
1130 cmd->bmp.bitmapDataLength, cmdRect.left, cmdRect.top,
1131 gdi->primary_buffer, gdi->dstFormat, gdi->stride,
1132 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height), ®ion))
1134 WLog_ERR(TAG,
"Failed to process RemoteFX message");
1140 case RDP_CODEC_ID_NSCODEC:
1141 format = gdi->dstFormat;
1143 if (!nsc_process_message(
1144 context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, cmd->bmp.height,
1145 cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, format,
1146 gdi->stride, cmdRect.left, cmdRect.top, cmdRect.right - cmdRect.left,
1147 cmdRect.bottom - cmdRect.top, FREERDP_FLIP_VERTICAL))
1149 WLog_ERR(TAG,
"Failed to process NSCodec message");
1153 region16_union_rect(®ion, ®ion, &cmdRect);
1156 case RDP_CODEC_ID_NONE:
1157 format = gdi_get_pixel_format(cmd->bmp.bpp);
1158 size = 1ull * cmd->bmp.width * cmd->bmp.height * FreeRDPGetBytesPerPixel(format);
1159 if (size > cmd->bmp.bitmapDataLength)
1161 WLog_ERR(TAG,
"Short nocodec message: got %" PRIu32
" bytes, require %" PRIuz,
1162 cmd->bmp.bitmapDataLength, size);
1166 if (!freerdp_image_copy_no_overlap(
1167 gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmdRect.left, cmdRect.top,
1168 cmdRect.right - cmdRect.left, cmdRect.bottom - cmdRect.top, cmd->bmp.bitmapData,
1169 format, 0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))
1171 WLog_ERR(TAG,
"Failed to process nocodec message");
1175 region16_union_rect(®ion, ®ion, &cmdRect);
1179 WLog_ERR(TAG,
"Unsupported codecID %" PRIu32
"", cmd->bmp.codecID);
1185 const RECTANGLE_16* rects = region16_rects(®ion, &nbRects);
1186 if (!rects && (nbRects > 0))
1191 const int32_t w = cmdRect.right - cmdRect.left;
1192 const int32_t h = cmdRect.bottom - cmdRect.top;
1193 if (!gdi_InvalidateRegion(gdi->primary->hdc, cmdRect.left, cmdRect.top, w, h))
1196 for (UINT32 i = 0; i < nbRects; i++)
1200 UINT32 left = rect->left;
1201 UINT32 top = rect->top;
1202 UINT32 width = rect->right - rect->left;
1203 UINT32 height = rect->bottom - rect->top;
1205 if (!gdi_InvalidateRegion(gdi->primary->hdc, WINPR_ASSERTING_INT_CAST(int32_t, left),
1206 WINPR_ASSERTING_INT_CAST(int32_t, top),
1207 WINPR_ASSERTING_INT_CAST(int32_t, width),
1208 WINPR_ASSERTING_INT_CAST(int32_t, height)))
1210 WLog_ERR(TAG,
"Failed to update invalid region");
1217 region16_uninit(®ion);
1226static void gdi_register_update_callbacks(rdpUpdate* update)
1228 WINPR_ASSERT(update);
1229 WINPR_ASSERT(update->context);
1231 const rdpSettings* settings = update->context->settings;
1232 WINPR_ASSERT(settings);
1234 rdpPrimaryUpdate* primary = update->primary;
1235 WINPR_ASSERT(primary);
1239 update->Palette = gdi_palette_update;
1240 update->SetBounds = gdi_set_bounds;
1241 primary->DstBlt = gdi_dstblt;
1242 primary->PatBlt = gdi_patblt;
1243 primary->ScrBlt = gdi_scrblt;
1244 primary->OpaqueRect = gdi_opaque_rect;
1245 primary->DrawNineGrid = NULL;
1246 primary->MultiDstBlt = NULL;
1247 primary->MultiPatBlt = NULL;
1248 primary->MultiScrBlt = NULL;
1249 primary->MultiOpaqueRect = gdi_multi_opaque_rect;
1250 primary->MultiDrawNineGrid = NULL;
1251 primary->LineTo = gdi_line_to;
1252 primary->Polyline = gdi_polyline;
1253 primary->MemBlt = gdi_memblt;
1254 primary->Mem3Blt = gdi_mem3blt;
1255 primary->SaveBitmap = NULL;
1256 primary->GlyphIndex = NULL;
1257 primary->FastIndex = NULL;
1258 primary->FastGlyph = NULL;
1259 primary->PolygonSC = gdi_polygon_sc;
1260 primary->PolygonCB = gdi_polygon_cb;
1261 primary->EllipseSC = gdi_ellipse_sc;
1262 primary->EllipseCB = gdi_ellipse_cb;
1263 update->SurfaceBits = gdi_surface_bits;
1264 update->SurfaceFrameMarker = gdi_surface_frame_marker;
1265 update->altsec->FrameMarker = gdi_frame_marker;
1268static BOOL gdi_init_primary(rdpGdi* gdi, UINT32 stride, UINT32 format, BYTE* buffer,
1269 void (*pfree)(
void*), BOOL isLocked)
1272 WINPR_ASSERT(gdi->context);
1273 WINPR_ASSERT(gdi->context->update);
1275 rdp_update_lock(gdi->context->update);
1277 gdi->primary = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
1280 gdi->dstFormat = format;
1283 gdi->stride = stride;
1285 gdi->stride = WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width) *
1286 FreeRDPGetBytesPerPixel(gdi->dstFormat);
1291 if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
1296 gdi->primary->bitmap =
1297 gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1298 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height));
1302 gdi->primary->bitmap = gdi_CreateBitmapEx(WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1303 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height),
1304 gdi->dstFormat, gdi->stride, buffer, pfree);
1307 if (!gdi->primary->bitmap)
1310 gdi->stride = gdi->primary->bitmap->scanline;
1311 gdi_SelectObject(gdi->primary->hdc, (
HGDIOBJECT)gdi->primary->bitmap);
1312 gdi->primary->org_bitmap = NULL;
1313 gdi->primary_buffer = gdi->primary->bitmap->data;
1315 if (!(gdi->primary->hdc->hwnd = (
HGDI_WND)calloc(1,
sizeof(
GDI_WND))))
1318 if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0)))
1321 gdi->primary->hdc->hwnd->invalid->null = TRUE;
1322 gdi->primary->hdc->hwnd->count = 32;
1324 if (!(gdi->primary->hdc->hwnd->cinvalid =
1325 (
GDI_RGN*)calloc(gdi->primary->hdc->hwnd->count,
sizeof(
GDI_RGN))))
1328 gdi->primary->hdc->hwnd->ninvalid = 0;
1331 gdi->drawing = gdi->primary;
1333 rdp_update_unlock(gdi->context->update);
1336 gdi_DeleteObject((
HGDIOBJECT)gdi->primary->bitmap);
1338 gdi_DeleteDC(gdi->primary->hdc);
1341 gdi->primary = NULL;
1343 rdp_update_unlock(gdi->context->update);
1347BOOL gdi_resize(rdpGdi* gdi, UINT32 width, UINT32 height)
1349 return gdi_resize_ex(gdi, width, height, 0, 0, NULL, NULL);
1352BOOL gdi_resize_ex(rdpGdi* gdi, UINT32 width, UINT32 height, UINT32 stride, UINT32 format,
1353 BYTE* buffer,
void (*pfree)(
void*))
1355 if (!gdi || !gdi->primary)
1358 if ((width > INT32_MAX) || (height > INT32_MAX))
1361 if ((gdi->width == (INT32)width) && (gdi->height == (INT32)height) &&
1362 (!buffer || (gdi->primary_buffer == buffer)))
1365 WINPR_ASSERT(gdi->context);
1366 WINPR_ASSERT(gdi->context->update);
1369 if (!update_end_paint(gdi->context->update))
1371 rdp_update_lock(gdi->context->update);
1373 if (gdi->drawing == gdi->primary)
1374 gdi->drawing = NULL;
1376 gdi->width = (INT32)width;
1377 gdi->height = (INT32)height;
1378 gdi_bitmap_free_ex(gdi->primary);
1379 gdi->primary = NULL;
1380 gdi->primary_buffer = NULL;
1381 return gdi_init_primary(gdi, stride, format, buffer, pfree, TRUE);
1391BOOL gdi_init(freerdp* instance, UINT32 format)
1393 return gdi_init_ex(instance, format, 0, NULL, winpr_aligned_free);
1407BOOL gdi_init_ex(freerdp* instance, UINT32 format, UINT32 stride, BYTE* buffer,
1408 void (*pfree)(
void*))
1410 rdpContext* context = NULL;
1411 UINT32 SrcFormat = 0;
1414 WINPR_ASSERT(instance);
1416 context = instance->context;
1417 WINPR_ASSERT(context);
1418 WINPR_ASSERT(context->settings);
1421 SrcFormat = gdi_get_pixel_format(ColorDepth);
1422 gdi = (rdpGdi*)calloc(1,
sizeof(rdpGdi));
1428 gdi->log = WLog_Get(TAG);
1433 gdi->context = context;
1434 gdi->width = WINPR_ASSERTING_INT_CAST(
1436 gdi->height = WINPR_ASSERTING_INT_CAST(
1438 gdi->dstFormat = format;
1440 WLog_Print(gdi->log, WLOG_INFO,
"Local framebuffer format %s",
1441 FreeRDPGetColorFormatName(gdi->dstFormat));
1442 WLog_Print(gdi->log, WLOG_INFO,
"Remote framebuffer format %s",
1443 FreeRDPGetColorFormatName(SrcFormat));
1445 if (!(gdi->hdc = gdi_GetDC()))
1448 gdi->hdc->format = gdi->dstFormat;
1450 if (!gdi_init_primary(gdi, stride, gdi->dstFormat, buffer, pfree, FALSE))
1453 if (!(context->cache = cache_new(context)))
1456 gdi_register_update_callbacks(context->update);
1457 brush_cache_register_callbacks(context->update);
1458 glyph_cache_register_callbacks(context->update);
1459 bitmap_cache_register_callbacks(context->update);
1460 offscreen_cache_register_callbacks(context->update);
1461 palette_cache_register_callbacks(context->update);
1463 if (!gdi_register_graphics(context->graphics))
1469 WLog_ERR(TAG,
"failed to initialize gdi");
1473void gdi_free(freerdp* instance)
1476 rdpContext* context = NULL;
1478 if (!instance || !instance->context)
1481 gdi = instance->context->gdi;
1485 gdi_bitmap_free_ex(gdi->primary);
1486 gdi_DeleteDC(gdi->hdc);
1490 context = instance->context;
1491 cache_free(context->cache);
1492 context->cache = NULL;
1493 instance->context->gdi = (rdpGdi*)NULL;
1496BOOL gdi_send_suppress_output(rdpGdi* gdi, BOOL suppress)
1498 if (!gdi || !gdi->context)
1501 if (gdi->suppressOutput == suppress)
1504 gdi->suppressOutput = suppress;
1506 rdpContext* context = gdi->context;
1507 rdpSettings* settings = context->settings;
1508 WINPR_ASSERT(settings);
1510 rdpUpdate* update = context->update;
1511 WINPR_ASSERT(update);
1518 .right = WINPR_ASSERTING_INT_CAST(UINT16, w),
1519 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, h) };
1521 WINPR_ASSERT(update->SuppressOutput);
1522 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.