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 if (brush->hatch >= ARRAYSIZE(GDI_BS_HATCHED_PATTERNS) / 8)
628 WLog_ERR(TAG,
"invalid brush hatch:%" PRIu32
"", brush->hatch);
632 const BYTE* hatched = &GDI_BS_HATCHED_PATTERNS[8ULL * brush->hatch];
634 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
635 hatched, backColor, foreColor, &gdi->palette))
638 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data,
nullptr);
643 hbrush = gdi_CreateHatchBrush(hBmp);
649 UINT32 brushFormat = 0;
653 UINT32 bpp = brush->bpp;
659 brushFormat = gdi_get_pixel_format(bpp);
661 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
662 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
668 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
669 8, brush->data, backColor, foreColor,
674 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data,
nullptr);
679 hbrush = gdi_CreatePatternBrush(hBmp);
684 WLog_ERR(TAG,
"unimplemented brush style:%" PRIu32
"", brush->style);
690 hbrush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
691 hbrush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
692 gdi->drawing->hdc->brush = hbrush;
693 ret = gdi_BitBlt(gdi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
694 patblt->nHeight, gdi->primary->hdc, nXSrc, nYSrc, rop, &gdi->palette);
700 gdi->drawing->hdc->brush = originalBrush;
701 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
705static BOOL gdi_scrblt(rdpContext* context,
const SCRBLT_ORDER* scrblt)
707 if (!context || !context->gdi)
710 rdpGdi* gdi = context->gdi;
711 if (!gdi->drawing || !gdi->primary)
714 return gdi_BitBlt(gdi->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth,
715 scrblt->nHeight, gdi->primary->hdc, scrblt->nXSrc, scrblt->nYSrc,
716 gdi_rop3_code_checked(scrblt->bRop), &gdi->palette);
719static BOOL gdi_opaque_rect(rdpContext* context,
const OPAQUE_RECT_ORDER* opaque_rect)
721 WINPR_ASSERT(context);
722 WINPR_ASSERT(opaque_rect);
726 UINT32 brush_color = 0;
727 rdpGdi* gdi = context->gdi;
729 INT32 x = opaque_rect->nLeftRect;
730 INT32 y = opaque_rect->nTopRect;
731 INT32 w = opaque_rect->nWidth;
732 INT32 h = opaque_rect->nHeight;
733 if (!gdi || !gdi->drawing)
739 if (!gdi_CRgnToRect(x, y, w, h, &rect))
742 if (!gdi_decode_color(gdi, opaque_rect->color, &brush_color,
nullptr))
745 if (!(hBrush = gdi_CreateSolidBrush(brush_color)))
748 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
753static BOOL gdi_multi_opaque_rect(rdpContext* context,
756 WINPR_ASSERT(context);
757 WINPR_ASSERT(multi_opaque_rect);
760 UINT32 brush_color = 0;
761 rdpGdi* gdi = context->gdi;
764 if (!gdi || !gdi->drawing)
767 if (!gdi_decode_color(gdi, multi_opaque_rect->color, &brush_color,
nullptr))
770 HGDI_BRUSH hBrush = gdi_CreateSolidBrush(brush_color);
775 for (UINT32 i = 0; i < multi_opaque_rect->numRectangles; i++)
777 const DELTA_RECT* rectangle = &multi_opaque_rect->rectangles[i];
778 const INT32 x = rectangle->left;
779 const INT32 y = rectangle->top;
780 const INT32 w = rectangle->width;
781 const INT32 h = rectangle->height;
786 if (!gdi_CRgnToRect(x, y, w, h, &rect))
789 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
799static BOOL gdi_line_to(rdpContext* context,
const LINE_TO_ORDER* lineTo)
803 WINPR_ASSERT(context);
804 WINPR_ASSERT(lineTo);
806 rdpGdi* gdi = context->gdi;
807 if (!gdi || !gdi->drawing || !gdi->drawing->hdc)
810 if (!gdi_decode_color(gdi, lineTo->penColor, &color,
nullptr))
813 HGDI_PEN hPen = gdi_CreatePen(lineTo->penStyle, lineTo->penWidth, color,
814 gdi->drawing->hdc->format, &gdi->palette);
818 WINPR_ASSERT(gdi->drawing);
820 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)hPen);
821 gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, lineTo->bRop2));
822 if (!gdi_MoveToEx(gdi->drawing->hdc, lineTo->nXStart, lineTo->nYStart,
nullptr))
824 if (!gdi_LineTo(gdi->drawing->hdc, lineTo->nXEnd, lineTo->nYEnd))
833static BOOL gdi_polyline(rdpContext* context,
const POLYLINE_ORDER* polyline)
836 WINPR_ASSERT(context);
837 WINPR_ASSERT(polyline);
839 rdpGdi* gdi = context->gdi;
840 if (!gdi || !gdi->drawing || !gdi->drawing->hdc)
844 if (!gdi_decode_color(gdi, polyline->penColor, &color,
nullptr))
847 WINPR_ASSERT(gdi->drawing);
848 WINPR_ASSERT(gdi->drawing->hdc);
850 HGDI_PEN hPen = gdi_CreatePen(GDI_PS_SOLID, 1, color, gdi->drawing->hdc->format, &gdi->palette);
854 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)hPen);
855 gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, polyline->bRop2));
856 INT32 x = polyline->xStart;
857 INT32 y = polyline->yStart;
858 if (!gdi_MoveToEx(gdi->drawing->hdc, x, y,
nullptr))
862 for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
866 if (!gdi_LineTo(gdi->drawing->hdc, x, y))
868 if (!gdi_MoveToEx(gdi->drawing->hdc, x, y,
nullptr))
878static BOOL gdi_memblt(rdpContext* context,
MEMBLT_ORDER* memblt)
880 if (!context || !memblt || !memblt->bitmap)
883 gdiBitmap* bitmap = (gdiBitmap*)memblt->bitmap;
884 rdpGdi* gdi = context->gdi;
885 if (!gdi || !gdi->drawing)
887 return gdi_BitBlt(gdi->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
888 memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc,
889 gdi_rop3_code_checked(memblt->bRop), &gdi->palette);
892static BOOL gdi_mem3blt(rdpContext* context,
MEM3BLT_ORDER* mem3blt)
894 WINPR_ASSERT(context);
895 WINPR_ASSERT(mem3blt);
898 rdpGdi* gdi = context->gdi;
899 if (!gdi || !gdi->drawing)
903 const rdpBrush* brush = &mem3blt->brush;
904 gdiBitmap* bitmap = (gdiBitmap*)mem3blt->bitmap;
905 UINT32 foreColor = 0;
906 UINT32 backColor = 0;
907 UINT32 originalColor = 0;
909 if (!gdi_decode_color(gdi, mem3blt->foreColor, &foreColor,
nullptr))
912 if (!gdi_decode_color(gdi, mem3blt->backColor, &backColor,
nullptr))
915 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
917 switch (brush->style)
920 originalBrush = gdi->drawing->hdc->brush;
921 gdi->drawing->hdc->brush = gdi_CreateSolidBrush(foreColor);
923 if (!gdi->drawing->hdc->brush)
929 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
930 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
931 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
932 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
933 gdi->drawing->hdc->brush = originalBrush;
939 UINT32 brushFormat = 0;
940 BYTE* data = (BYTE*)winpr_aligned_malloc(
941 8ULL * 8ULL * FreeRDPGetBytesPerPixel(gdi->drawing->hdc->format), 16);
951 UINT32 bpp = brush->bpp;
953 const UINT32 ColorDepth =
955 if ((bpp == 16) && (ColorDepth == 15))
958 brushFormat = gdi_get_pixel_format(bpp);
960 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
961 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
965 winpr_aligned_free(data);
971 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
972 8, brush->data, backColor, foreColor,
976 winpr_aligned_free(data);
981 hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->format, data);
986 winpr_aligned_free(data);
990 originalBrush = gdi->drawing->hdc->brush;
991 gdi->drawing->hdc->brush = gdi_CreatePatternBrush(hBmp);
993 if (!gdi->drawing->hdc->brush)
999 gdi->drawing->hdc->brush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
1000 gdi->drawing->hdc->brush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
1001 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
1002 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
1003 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
1004 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
1006 gdi->drawing->hdc->brush = originalBrush;
1011 WLog_ERR(TAG,
"Mem3Blt unimplemented brush style:%" PRIu32
"", brush->style);
1016 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
1020static BOOL gdi_polygon_sc(WINPR_ATTR_UNUSED rdpContext* context,
1023 WLog_WARN(TAG,
"not implemented");
1027static BOOL gdi_polygon_cb(WINPR_ATTR_UNUSED rdpContext* context,
1030 WLog_WARN(TAG,
"not implemented");
1034static BOOL gdi_ellipse_sc(WINPR_ATTR_UNUSED rdpContext* context,
1037 WLog_WARN(TAG,
"not implemented");
1041static BOOL gdi_ellipse_cb(WINPR_ATTR_UNUSED rdpContext* context,
1044 WLog_WARN(TAG,
"not implemented");
1048static BOOL gdi_frame_marker(WINPR_ATTR_UNUSED rdpContext* context,
1054static BOOL gdi_surface_frame_marker(rdpContext* context,
1057 WINPR_ASSERT(context);
1058 WINPR_ASSERT(context->gdi);
1059 WINPR_ASSERT(context->update);
1060 WINPR_ASSERT(surfaceFrameMarker);
1062 WLog_Print(context->gdi->log, WLOG_DEBUG,
"frameId %" PRIu32
" frameAction %" PRIu32
"",
1063 surfaceFrameMarker->frameId, surfaceFrameMarker->frameAction);
1065 switch (surfaceFrameMarker->frameAction)
1067 case SURFACECMD_FRAMEACTION_BEGIN:
1070 case SURFACECMD_FRAMEACTION_END:
1073 if (!IFCALLRESULT(TRUE, context->update->SurfaceFrameAcknowledge, context,
1074 surfaceFrameMarker->frameId))
1090 WINPR_ASSERT(prect);
1092 const UINT32 w = (
const UINT32)gdi->width;
1093 const UINT32 h = (
const UINT32)gdi->height;
1095 if (cmd->destLeft > w)
1097 if (cmd->destRight > w)
1099 if (cmd->destLeft > cmd->destRight)
1101 if (cmd->destRight > UINT16_MAX)
1104 if (cmd->destTop > h)
1106 if (cmd->destBottom > h)
1108 if (cmd->destTop > cmd->destBottom)
1110 if (cmd->destBottom > UINT16_MAX)
1113 prect->left = (
const UINT16)cmd->destLeft;
1114 prect->top = (
const UINT16)cmd->destTop;
1115 prect->right = MIN((UINT16)cmd->destRight, prect->left + cmd->bmp.width);
1116 prect->bottom = MIN((UINT16)cmd->destBottom, prect->top + cmd->bmp.height);
1122 BOOL result = FALSE;
1128 if (!context || !cmd)
1131 rdpGdi* gdi = context->gdi;
1135 WLog_Print(gdi->log, WLOG_DEBUG,
1136 "destLeft %" PRIu32
" destTop %" PRIu32
" destRight %" PRIu32
" destBottom %" PRIu32
1138 "bpp %" PRIu8
" flags %" PRIx8
" codecID %s [0x%04" PRIu16
"] width %" PRIu16
1139 " height %" PRIu16
" length %" PRIu32
"",
1140 cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bmp.bpp,
1141 cmd->bmp.flags, freerdp_codec_id_to_str(cmd->bmp.codecID), cmd->bmp.codecID,
1142 cmd->bmp.width, cmd->bmp.height, cmd->bmp.bitmapDataLength);
1143 region16_init(®ion);
1145 if (!intersect_rect(gdi, cmd, &cmdRect))
1148 switch (cmd->bmp.codecID)
1150 case RDP_CODEC_ID_REMOTEFX:
1151 case RDP_CODEC_ID_IMAGE_REMOTEFX:
1152 if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData,
1153 cmd->bmp.bitmapDataLength, cmdRect.left, cmdRect.top,
1154 gdi->primary_buffer, gdi->dstFormat, gdi->stride,
1155 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height), ®ion))
1157 WLog_ERR(TAG,
"Failed to process RemoteFX message");
1163 case RDP_CODEC_ID_NSCODEC:
1164 format = gdi->dstFormat;
1166 if (!nsc_process_message(
1167 context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, cmd->bmp.height,
1168 cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, format,
1169 gdi->stride, cmdRect.left, cmdRect.top,
1170 WINPR_ASSERTING_INT_CAST(UINT32, gdi->width),
1171 WINPR_ASSERTING_INT_CAST(UINT32, gdi->height), FREERDP_FLIP_VERTICAL))
1173 WLog_ERR(TAG,
"Failed to process NSCodec message");
1177 if (!region16_union_rect(®ion, ®ion, &cmdRect))
1181 case RDP_CODEC_ID_NONE:
1182 format = gdi_get_pixel_format(cmd->bmp.bpp);
1183 size = 1ull * cmd->bmp.width * cmd->bmp.height * FreeRDPGetBytesPerPixel(format);
1184 if (size > cmd->bmp.bitmapDataLength)
1186 WLog_ERR(TAG,
"Short nocodec message: got %" PRIu32
" bytes, require %" PRIuz,
1187 cmd->bmp.bitmapDataLength, size);
1191 if (!freerdp_image_copy_no_overlap(
1192 gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmdRect.left, cmdRect.top,
1193 cmdRect.right - cmdRect.left, cmdRect.bottom - cmdRect.top, cmd->bmp.bitmapData,
1194 format, 0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))
1196 WLog_ERR(TAG,
"Failed to process nocodec message");
1200 if (!region16_union_rect(®ion, ®ion, &cmdRect))
1205 WLog_ERR(TAG,
"Unsupported codecID %" PRIu32
"", cmd->bmp.codecID);
1211 const RECTANGLE_16* rects = region16_rects(®ion, &nbRects);
1212 if (!rects && (nbRects > 0))
1217 const int32_t w = cmdRect.right - cmdRect.left;
1218 const int32_t h = cmdRect.bottom - cmdRect.top;
1219 if (!gdi_InvalidateRegion(gdi->primary->hdc, cmdRect.left, cmdRect.top, w, h))
1222 for (UINT32 i = 0; i < nbRects; i++)
1226 UINT32 left = rect->left;
1227 UINT32 top = rect->top;
1228 UINT32 width = rect->right - rect->left;
1229 UINT32 height = rect->bottom - rect->top;
1231 if (!gdi_InvalidateRegion(gdi->primary->hdc, WINPR_ASSERTING_INT_CAST(int32_t, left),
1232 WINPR_ASSERTING_INT_CAST(int32_t, top),
1233 WINPR_ASSERTING_INT_CAST(int32_t, width),
1234 WINPR_ASSERTING_INT_CAST(int32_t, height)))
1236 WLog_ERR(TAG,
"Failed to update invalid region");
1243 region16_uninit(®ion);
1252static void gdi_register_update_callbacks(rdpUpdate* update)
1254 WINPR_ASSERT(update);
1255 WINPR_ASSERT(update->context);
1257 const rdpSettings* settings = update->context->settings;
1258 WINPR_ASSERT(settings);
1260 rdpPrimaryUpdate* primary = update->primary;
1261 WINPR_ASSERT(primary);
1265 update->Palette = gdi_palette_update;
1266 update->SetBounds = gdi_set_bounds;
1267 primary->DstBlt = gdi_dstblt;
1268 primary->PatBlt = gdi_patblt;
1269 primary->ScrBlt = gdi_scrblt;
1270 primary->OpaqueRect = gdi_opaque_rect;
1271 primary->DrawNineGrid =
nullptr;
1272 primary->MultiDstBlt =
nullptr;
1273 primary->MultiPatBlt =
nullptr;
1274 primary->MultiScrBlt =
nullptr;
1275 primary->MultiOpaqueRect = gdi_multi_opaque_rect;
1276 primary->MultiDrawNineGrid =
nullptr;
1277 primary->LineTo = gdi_line_to;
1278 primary->Polyline = gdi_polyline;
1279 primary->MemBlt = gdi_memblt;
1280 primary->Mem3Blt = gdi_mem3blt;
1281 primary->SaveBitmap =
nullptr;
1282 primary->GlyphIndex =
nullptr;
1283 primary->FastIndex =
nullptr;
1284 primary->FastGlyph =
nullptr;
1285 primary->PolygonSC = gdi_polygon_sc;
1286 primary->PolygonCB = gdi_polygon_cb;
1287 primary->EllipseSC = gdi_ellipse_sc;
1288 primary->EllipseCB = gdi_ellipse_cb;
1289 update->SurfaceBits = gdi_surface_bits;
1290 update->SurfaceFrameMarker = gdi_surface_frame_marker;
1291 update->altsec->FrameMarker = gdi_frame_marker;
1294static BOOL gdi_init_primary(rdpGdi* gdi, UINT32 stride, UINT32 format, BYTE* buffer,
1295 void (*pfree)(
void*), BOOL isLocked)
1298 WINPR_ASSERT(gdi->context);
1299 WINPR_ASSERT(gdi->context->update);
1301 rdp_update_lock(gdi->context->update);
1303 gdi->primary = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
1306 gdi->dstFormat = format;
1309 gdi->stride = stride;
1311 gdi->stride = WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width) *
1312 FreeRDPGetBytesPerPixel(gdi->dstFormat);
1317 if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
1322 gdi->primary->bitmap =
1323 gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1324 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height));
1328 gdi->primary->bitmap = gdi_CreateBitmapEx(WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1329 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height),
1330 gdi->dstFormat, gdi->stride, buffer, pfree);
1333 if (!gdi->primary->bitmap)
1336 gdi->stride = gdi->primary->bitmap->scanline;
1337 gdi_SelectObject(gdi->primary->hdc, (
HGDIOBJECT)gdi->primary->bitmap);
1338 gdi->primary->org_bitmap =
nullptr;
1339 gdi->primary_buffer = gdi->primary->bitmap->data;
1341 if (!(gdi->primary->hdc->hwnd = (
HGDI_WND)calloc(1,
sizeof(
GDI_WND))))
1344 if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0)))
1347 gdi->primary->hdc->hwnd->invalid->null = TRUE;
1348 gdi->primary->hdc->hwnd->count = 32;
1350 if (!(gdi->primary->hdc->hwnd->cinvalid =
1351 (
GDI_RGN*)calloc(gdi->primary->hdc->hwnd->count,
sizeof(
GDI_RGN))))
1354 gdi->primary->hdc->hwnd->ninvalid = 0;
1357 gdi->drawing = gdi->primary;
1359 rdp_update_unlock(gdi->context->update);
1362 gdi_DeleteObject((
HGDIOBJECT)gdi->primary->bitmap);
1364 gdi_DeleteDC(gdi->primary->hdc);
1367 gdi->primary =
nullptr;
1369 rdp_update_unlock(gdi->context->update);
1373BOOL gdi_resize(rdpGdi* gdi, UINT32 width, UINT32 height)
1375 return gdi_resize_ex(gdi, width, height, 0, 0,
nullptr,
nullptr);
1378BOOL gdi_resize_ex(rdpGdi* gdi, UINT32 width, UINT32 height, UINT32 stride, UINT32 format,
1379 BYTE* buffer,
void (*pfree)(
void*))
1381 if (!gdi || !gdi->primary)
1384 if ((width > INT32_MAX) || (height > INT32_MAX))
1387 if ((gdi->width == (INT32)width) && (gdi->height == (INT32)height) &&
1388 (!buffer || (gdi->primary_buffer == buffer)))
1391 WINPR_ASSERT(gdi->context);
1392 WINPR_ASSERT(gdi->context->update);
1395 if (!update_end_paint(gdi->context->update))
1397 rdp_update_lock(gdi->context->update);
1399 if (gdi->drawing == gdi->primary)
1400 gdi->drawing =
nullptr;
1402 gdi->width = (INT32)width;
1403 gdi->height = (INT32)height;
1404 gdi_bitmap_free_ex(gdi->primary);
1405 gdi->primary =
nullptr;
1406 gdi->primary_buffer =
nullptr;
1407 return gdi_init_primary(gdi, stride, format, buffer, pfree, TRUE);
1417BOOL gdi_init(freerdp* instance, UINT32 format)
1419 return gdi_init_ex(instance, format, 0,
nullptr, winpr_aligned_free);
1433BOOL gdi_init_ex(freerdp* instance, UINT32 format, UINT32 stride, BYTE* buffer,
1434 void (*pfree)(
void*))
1436 rdpContext* context =
nullptr;
1437 UINT32 SrcFormat = 0;
1438 rdpGdi* gdi =
nullptr;
1440 WINPR_ASSERT(instance);
1442 context = instance->context;
1443 WINPR_ASSERT(context);
1444 WINPR_ASSERT(context->settings);
1447 SrcFormat = gdi_get_pixel_format(ColorDepth);
1448 gdi = (rdpGdi*)calloc(1,
sizeof(rdpGdi));
1454 gdi->log = WLog_Get(TAG);
1459 gdi->context = context;
1460 gdi->width = WINPR_ASSERTING_INT_CAST(
1462 gdi->height = WINPR_ASSERTING_INT_CAST(
1464 gdi->dstFormat = format;
1466 WLog_Print(gdi->log, WLOG_INFO,
"Local framebuffer format %s",
1467 FreeRDPGetColorFormatName(gdi->dstFormat));
1468 WLog_Print(gdi->log, WLOG_INFO,
"Remote framebuffer format %s",
1469 FreeRDPGetColorFormatName(SrcFormat));
1471 if (!(gdi->hdc = gdi_GetDC()))
1474 gdi->hdc->format = gdi->dstFormat;
1476 if (!gdi_init_primary(gdi, stride, gdi->dstFormat, buffer, pfree, FALSE))
1479 if (!(context->cache = cache_new(context)))
1482 gdi_register_update_callbacks(context->update);
1483 brush_cache_register_callbacks(context->update);
1484 glyph_cache_register_callbacks(context->update);
1485 bitmap_cache_register_callbacks(context->update);
1486 offscreen_cache_register_callbacks(context->update);
1487 palette_cache_register_callbacks(context->update);
1489 if (!gdi_register_graphics(context->graphics))
1495 WLog_ERR(TAG,
"failed to initialize gdi");
1499void gdi_free(freerdp* instance)
1501 rdpGdi* gdi =
nullptr;
1502 rdpContext* context =
nullptr;
1504 if (!instance || !instance->context)
1507 gdi = instance->context->gdi;
1511 gdi_bitmap_free_ex(gdi->primary);
1512 gdi_DeleteDC(gdi->hdc);
1516 context = instance->context;
1517 cache_free(context->cache);
1518 context->cache =
nullptr;
1519 instance->context->gdi = (rdpGdi*)
nullptr;
1522BOOL gdi_send_suppress_output(rdpGdi* gdi, BOOL suppress)
1524 if (!gdi || !gdi->context)
1527 if (gdi->suppressOutput == suppress)
1530 gdi->suppressOutput = suppress;
1532 rdpContext* context = gdi->context;
1533 rdpSettings* settings = context->settings;
1534 WINPR_ASSERT(settings);
1536 rdpUpdate* update = context->update;
1537 WINPR_ASSERT(update);
1544 .right = WINPR_ASSERTING_INT_CAST(UINT16, w),
1545 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, h) };
1547 WINPR_ASSERT(update->SuppressOutput);
1548 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.