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 HGDI_PEN originalPen = gdi->drawing->hdc->pen;
821 gdi->drawing->hdc->pen = hPen;
822 gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, lineTo->bRop2));
823 if (!gdi_MoveToEx(gdi->drawing->hdc, lineTo->nXStart, lineTo->nYStart,
nullptr))
825 if (!gdi_LineTo(gdi->drawing->hdc, lineTo->nXEnd, lineTo->nYEnd))
830 gdi->drawing->hdc->pen = originalPen;
835static BOOL gdi_polyline(rdpContext* context,
const POLYLINE_ORDER* polyline)
838 WINPR_ASSERT(context);
839 WINPR_ASSERT(polyline);
841 rdpGdi* gdi = context->gdi;
842 if (!gdi || !gdi->drawing || !gdi->drawing->hdc)
846 if (!gdi_decode_color(gdi, polyline->penColor, &color,
nullptr))
849 WINPR_ASSERT(gdi->drawing);
850 WINPR_ASSERT(gdi->drawing->hdc);
852 HGDI_PEN hPen = gdi_CreatePen(GDI_PS_SOLID, 1, color, gdi->drawing->hdc->format, &gdi->palette);
856 HGDI_PEN originalPen = gdi->drawing->hdc->pen;
857 gdi->drawing->hdc->pen = hPen;
858 gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, polyline->bRop2));
859 INT32 x = polyline->xStart;
860 INT32 y = polyline->yStart;
861 if (!gdi_MoveToEx(gdi->drawing->hdc, x, y,
nullptr))
865 for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
869 if (!gdi_LineTo(gdi->drawing->hdc, x, y))
871 if (!gdi_MoveToEx(gdi->drawing->hdc, x, y,
nullptr))
877 gdi->drawing->hdc->pen = originalPen;
882static BOOL gdi_memblt(rdpContext* context,
MEMBLT_ORDER* memblt)
884 if (!context || !memblt || !memblt->bitmap)
887 gdiBitmap* bitmap = (gdiBitmap*)memblt->bitmap;
888 rdpGdi* gdi = context->gdi;
889 if (!gdi || !gdi->drawing)
891 return gdi_BitBlt(gdi->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
892 memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc,
893 gdi_rop3_code_checked(memblt->bRop), &gdi->palette);
896static BOOL gdi_mem3blt(rdpContext* context,
MEM3BLT_ORDER* mem3blt)
898 WINPR_ASSERT(context);
899 WINPR_ASSERT(mem3blt);
902 rdpGdi* gdi = context->gdi;
903 if (!gdi || !gdi->drawing)
907 const rdpBrush* brush = &mem3blt->brush;
908 gdiBitmap* bitmap = (gdiBitmap*)mem3blt->bitmap;
909 UINT32 foreColor = 0;
910 UINT32 backColor = 0;
911 UINT32 originalColor = 0;
913 if (!gdi_decode_color(gdi, mem3blt->foreColor, &foreColor,
nullptr))
916 if (!gdi_decode_color(gdi, mem3blt->backColor, &backColor,
nullptr))
919 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
921 switch (brush->style)
924 originalBrush = gdi->drawing->hdc->brush;
925 gdi->drawing->hdc->brush = gdi_CreateSolidBrush(foreColor);
927 if (!gdi->drawing->hdc->brush)
933 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
934 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
935 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
936 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
937 gdi->drawing->hdc->brush = originalBrush;
943 UINT32 brushFormat = 0;
944 BYTE* data = (BYTE*)winpr_aligned_calloc(
945 8ULL * 8ULL, FreeRDPGetBytesPerPixel(gdi->drawing->hdc->format), 16);
955 UINT32 bpp = brush->bpp;
957 const UINT32 ColorDepth =
959 if ((bpp == 16) && (ColorDepth == 15))
962 brushFormat = gdi_get_pixel_format(bpp);
964 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
965 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
969 winpr_aligned_free(data);
975 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
976 8, brush->data, backColor, foreColor,
980 winpr_aligned_free(data);
985 hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->format, data);
990 winpr_aligned_free(data);
994 originalBrush = gdi->drawing->hdc->brush;
995 gdi->drawing->hdc->brush = gdi_CreatePatternBrush(hBmp);
997 if (!gdi->drawing->hdc->brush)
1003 gdi->drawing->hdc->brush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
1004 gdi->drawing->hdc->brush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
1005 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
1006 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
1007 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
1008 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
1010 gdi->drawing->hdc->brush = originalBrush;
1015 WLog_ERR(TAG,
"Mem3Blt unimplemented brush style:%" PRIu32
"", brush->style);
1020 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
1024static BOOL gdi_polygon_sc(WINPR_ATTR_UNUSED rdpContext* context,
1027 WLog_WARN(TAG,
"not implemented");
1031static BOOL gdi_polygon_cb(WINPR_ATTR_UNUSED rdpContext* context,
1034 WLog_WARN(TAG,
"not implemented");
1038static BOOL gdi_ellipse_sc(WINPR_ATTR_UNUSED rdpContext* context,
1041 WLog_WARN(TAG,
"not implemented");
1045static BOOL gdi_ellipse_cb(WINPR_ATTR_UNUSED rdpContext* context,
1048 WLog_WARN(TAG,
"not implemented");
1052static BOOL gdi_frame_marker(WINPR_ATTR_UNUSED rdpContext* context,
1058static BOOL gdi_surface_frame_marker(rdpContext* context,
1061 WINPR_ASSERT(context);
1062 WINPR_ASSERT(context->gdi);
1063 WINPR_ASSERT(context->update);
1064 WINPR_ASSERT(surfaceFrameMarker);
1066 WLog_Print(context->gdi->log, WLOG_DEBUG,
"frameId %" PRIu32
" frameAction %" PRIu32
"",
1067 surfaceFrameMarker->frameId, surfaceFrameMarker->frameAction);
1069 switch (surfaceFrameMarker->frameAction)
1071 case SURFACECMD_FRAMEACTION_BEGIN:
1074 case SURFACECMD_FRAMEACTION_END:
1077 if (!IFCALLRESULT(TRUE, context->update->SurfaceFrameAcknowledge, context,
1078 surfaceFrameMarker->frameId))
1094 WINPR_ASSERT(prect);
1096 const UINT32 w = (
const UINT32)gdi->width;
1097 const UINT32 h = (
const UINT32)gdi->height;
1099 if (cmd->destLeft > w)
1101 if (cmd->destRight > w)
1103 if (cmd->destLeft > cmd->destRight)
1105 if (cmd->destRight > UINT16_MAX)
1108 if (cmd->destTop > h)
1110 if (cmd->destBottom > h)
1112 if (cmd->destTop > cmd->destBottom)
1114 if (cmd->destBottom > UINT16_MAX)
1117 prect->left = (
const UINT16)cmd->destLeft;
1118 prect->top = (
const UINT16)cmd->destTop;
1119 prect->right = MIN((UINT16)cmd->destRight, prect->left + cmd->bmp.width);
1120 prect->bottom = MIN((UINT16)cmd->destBottom, prect->top + cmd->bmp.height);
1126 BOOL result = FALSE;
1132 if (!context || !cmd)
1135 rdpGdi* gdi = context->gdi;
1139 WLog_Print(gdi->log, WLOG_DEBUG,
1140 "destLeft %" PRIu32
" destTop %" PRIu32
" destRight %" PRIu32
" destBottom %" PRIu32
1142 "bpp %" PRIu8
" flags %" PRIx8
" codecID %s [0x%04" PRIu16
"] width %" PRIu16
1143 " height %" PRIu16
" length %" PRIu32
"",
1144 cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bmp.bpp,
1145 cmd->bmp.flags, freerdp_codec_id_to_str(cmd->bmp.codecID), cmd->bmp.codecID,
1146 cmd->bmp.width, cmd->bmp.height, cmd->bmp.bitmapDataLength);
1147 region16_init(®ion);
1149 if (!intersect_rect(gdi, cmd, &cmdRect))
1152 switch (cmd->bmp.codecID)
1154 case RDP_CODEC_ID_REMOTEFX:
1155 case RDP_CODEC_ID_IMAGE_REMOTEFX:
1156 if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData,
1157 cmd->bmp.bitmapDataLength, cmdRect.left, cmdRect.top,
1158 gdi->primary_buffer, gdi->dstFormat, gdi->stride,
1159 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height), ®ion))
1161 WLog_ERR(TAG,
"Failed to process RemoteFX message");
1167 case RDP_CODEC_ID_NSCODEC:
1168 format = gdi->dstFormat;
1170 if (!nsc_process_message(
1171 context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, cmd->bmp.height,
1172 cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, format,
1173 gdi->stride, cmdRect.left, cmdRect.top,
1174 WINPR_ASSERTING_INT_CAST(UINT32, gdi->width),
1175 WINPR_ASSERTING_INT_CAST(UINT32, gdi->height), FREERDP_FLIP_VERTICAL))
1177 WLog_ERR(TAG,
"Failed to process NSCodec message");
1181 if (!region16_union_rect(®ion, ®ion, &cmdRect))
1185 case RDP_CODEC_ID_NONE:
1186 format = gdi_get_pixel_format(cmd->bmp.bpp);
1187 size = 1ull * cmd->bmp.width * cmd->bmp.height * FreeRDPGetBytesPerPixel(format);
1188 if (size > cmd->bmp.bitmapDataLength)
1190 WLog_ERR(TAG,
"Short nocodec message: got %" PRIu32
" bytes, require %" PRIuz,
1191 cmd->bmp.bitmapDataLength, size);
1195 if (!freerdp_image_copy_no_overlap(
1196 gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmdRect.left, cmdRect.top,
1197 cmdRect.right - cmdRect.left, cmdRect.bottom - cmdRect.top, cmd->bmp.bitmapData,
1198 format, 0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))
1200 WLog_ERR(TAG,
"Failed to process nocodec message");
1204 if (!region16_union_rect(®ion, ®ion, &cmdRect))
1209 WLog_ERR(TAG,
"Unsupported codecID %" PRIu32
"", cmd->bmp.codecID);
1215 const RECTANGLE_16* rects = region16_rects(®ion, &nbRects);
1216 if (!rects && (nbRects > 0))
1221 const int32_t w = cmdRect.right - cmdRect.left;
1222 const int32_t h = cmdRect.bottom - cmdRect.top;
1223 if (!gdi_InvalidateRegion(gdi->primary->hdc, cmdRect.left, cmdRect.top, w, h))
1226 for (UINT32 i = 0; i < nbRects; i++)
1230 UINT32 left = rect->left;
1231 UINT32 top = rect->top;
1232 UINT32 width = rect->right - rect->left;
1233 UINT32 height = rect->bottom - rect->top;
1235 if (!gdi_InvalidateRegion(gdi->primary->hdc, WINPR_ASSERTING_INT_CAST(int32_t, left),
1236 WINPR_ASSERTING_INT_CAST(int32_t, top),
1237 WINPR_ASSERTING_INT_CAST(int32_t, width),
1238 WINPR_ASSERTING_INT_CAST(int32_t, height)))
1240 WLog_ERR(TAG,
"Failed to update invalid region");
1247 region16_uninit(®ion);
1256static void gdi_register_update_callbacks(rdpUpdate* update)
1258 WINPR_ASSERT(update);
1259 WINPR_ASSERT(update->context);
1261 const rdpSettings* settings = update->context->settings;
1262 WINPR_ASSERT(settings);
1264 rdpPrimaryUpdate* primary = update->primary;
1265 WINPR_ASSERT(primary);
1269 update->Palette = gdi_palette_update;
1270 update->SetBounds = gdi_set_bounds;
1271 primary->DstBlt = gdi_dstblt;
1272 primary->PatBlt = gdi_patblt;
1273 primary->ScrBlt = gdi_scrblt;
1274 primary->OpaqueRect = gdi_opaque_rect;
1275 primary->DrawNineGrid =
nullptr;
1276 primary->MultiDstBlt =
nullptr;
1277 primary->MultiPatBlt =
nullptr;
1278 primary->MultiScrBlt =
nullptr;
1279 primary->MultiOpaqueRect = gdi_multi_opaque_rect;
1280 primary->MultiDrawNineGrid =
nullptr;
1281 primary->LineTo = gdi_line_to;
1282 primary->Polyline = gdi_polyline;
1283 primary->MemBlt = gdi_memblt;
1284 primary->Mem3Blt = gdi_mem3blt;
1285 primary->SaveBitmap =
nullptr;
1286 primary->GlyphIndex =
nullptr;
1287 primary->FastIndex =
nullptr;
1288 primary->FastGlyph =
nullptr;
1289 primary->PolygonSC = gdi_polygon_sc;
1290 primary->PolygonCB = gdi_polygon_cb;
1291 primary->EllipseSC = gdi_ellipse_sc;
1292 primary->EllipseCB = gdi_ellipse_cb;
1293 update->SurfaceBits = gdi_surface_bits;
1294 update->SurfaceFrameMarker = gdi_surface_frame_marker;
1295 update->altsec->FrameMarker = gdi_frame_marker;
1298static BOOL gdi_init_primary(rdpGdi* gdi, UINT32 stride, UINT32 format, BYTE* buffer,
1299 void (*pfree)(
void*), BOOL isLocked)
1302 WINPR_ASSERT(gdi->context);
1303 WINPR_ASSERT(gdi->context->update);
1305 rdp_update_lock(gdi->context->update);
1307 gdi->primary = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
1310 gdi->dstFormat = format;
1313 gdi->stride = stride;
1315 gdi->stride = WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width) *
1316 FreeRDPGetBytesPerPixel(gdi->dstFormat);
1321 if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
1326 gdi->primary->bitmap =
1327 gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1328 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height));
1332 gdi->primary->bitmap = gdi_CreateBitmapEx(WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1333 WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height),
1334 gdi->dstFormat, gdi->stride, buffer, pfree);
1337 if (!gdi->primary->bitmap)
1340 gdi->stride = gdi->primary->bitmap->scanline;
1341 gdi_SelectObject(gdi->primary->hdc, (
HGDIOBJECT)gdi->primary->bitmap);
1342 gdi->primary->org_bitmap =
nullptr;
1343 gdi->primary_buffer = gdi->primary->bitmap->data;
1345 if (!(gdi->primary->hdc->hwnd = (
HGDI_WND)calloc(1,
sizeof(
GDI_WND))))
1348 if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0)))
1351 gdi->primary->hdc->hwnd->invalid->null = TRUE;
1352 gdi->primary->hdc->hwnd->count = 32;
1354 if (!(gdi->primary->hdc->hwnd->cinvalid =
1355 (
GDI_RGN*)calloc(gdi->primary->hdc->hwnd->count,
sizeof(
GDI_RGN))))
1358 gdi->primary->hdc->hwnd->ninvalid = 0;
1361 gdi->drawing = gdi->primary;
1363 rdp_update_unlock(gdi->context->update);
1366 gdi_DeleteObject((
HGDIOBJECT)gdi->primary->bitmap);
1368 gdi_DeleteDC(gdi->primary->hdc);
1371 gdi->primary =
nullptr;
1373 rdp_update_unlock(gdi->context->update);
1377BOOL gdi_resize(rdpGdi* gdi, UINT32 width, UINT32 height)
1379 return gdi_resize_ex(gdi, width, height, 0, 0,
nullptr,
nullptr);
1382BOOL gdi_resize_ex(rdpGdi* gdi, UINT32 width, UINT32 height, UINT32 stride, UINT32 format,
1383 BYTE* buffer,
void (*pfree)(
void*))
1385 if (!gdi || !gdi->primary)
1388 if ((width > INT32_MAX) || (height > INT32_MAX))
1391 if ((gdi->width == (INT32)width) && (gdi->height == (INT32)height) &&
1392 (!buffer || (gdi->primary_buffer == buffer)))
1395 WINPR_ASSERT(gdi->context);
1396 WINPR_ASSERT(gdi->context->update);
1401 rdp_update_lock(gdi->context->update);
1402 if (!update_end_paint(gdi->context->update))
1404 rdp_update_unlock(gdi->context->update);
1408 if (gdi->drawing == gdi->primary)
1409 gdi->drawing =
nullptr;
1411 gdi->width = (INT32)width;
1412 gdi->height = (INT32)height;
1413 gdi_bitmap_free_ex(gdi->primary);
1414 gdi->primary =
nullptr;
1415 gdi->primary_buffer =
nullptr;
1416 return gdi_init_primary(gdi, stride, format, buffer, pfree, TRUE);
1430BOOL gdi_init(freerdp* instance, UINT32 format)
1432 return gdi_init_ex(instance, format, 0,
nullptr, winpr_aligned_free);
1450BOOL gdi_init_ex(freerdp* instance, UINT32 format, UINT32 stride, BYTE* buffer,
1451 void (*pfree)(
void*))
1453 rdpContext* context =
nullptr;
1454 UINT32 SrcFormat = 0;
1455 rdpGdi* gdi =
nullptr;
1457 WINPR_ASSERT(instance);
1459 context = instance->context;
1460 WINPR_ASSERT(context);
1461 WINPR_ASSERT(context->settings);
1464 SrcFormat = gdi_get_pixel_format(ColorDepth);
1465 gdi = (rdpGdi*)calloc(1,
sizeof(rdpGdi));
1471 gdi->log = WLog_Get(TAG);
1476 gdi->context = context;
1477 gdi->width = WINPR_ASSERTING_INT_CAST(
1479 gdi->height = WINPR_ASSERTING_INT_CAST(
1481 gdi->dstFormat = format;
1483 WLog_Print(gdi->log, WLOG_INFO,
"Local framebuffer format %s",
1484 FreeRDPGetColorFormatName(gdi->dstFormat));
1485 WLog_Print(gdi->log, WLOG_INFO,
"Remote framebuffer format %s",
1486 FreeRDPGetColorFormatName(SrcFormat));
1488 if (!(gdi->hdc = gdi_GetDC()))
1491 gdi->hdc->format = gdi->dstFormat;
1493 if (!gdi_init_primary(gdi, stride, gdi->dstFormat, buffer, pfree, FALSE))
1496 gdi_register_update_callbacks(context->update);
1497 brush_cache_register_callbacks(context->update);
1498 glyph_cache_register_callbacks(context->update);
1499 bitmap_cache_register_callbacks(context->update);
1500 offscreen_cache_register_callbacks(context->update);
1501 palette_cache_register_callbacks(context->update);
1503 if (!gdi_register_graphics(context->graphics))
1509 WLog_ERR(TAG,
"failed to initialize gdi");
1513void gdi_free(freerdp* instance)
1515 if (!instance || !instance->context)
1518 rdpGdi* gdi = instance->context->gdi;
1522 gdi_bitmap_free_ex(gdi->primary);
1523 gdi_DeleteDC(gdi->hdc);
1527 instance->context->gdi = (rdpGdi*)
nullptr;
1530BOOL gdi_send_suppress_output(rdpGdi* gdi, BOOL suppress)
1532 if (!gdi || !gdi->context)
1535 if (gdi->suppressOutput == suppress)
1538 gdi->suppressOutput = suppress;
1540 rdpContext* context = gdi->context;
1541 rdpSettings* settings = context->settings;
1542 WINPR_ASSERT(settings);
1544 rdpUpdate* update = context->update;
1545 WINPR_ASSERT(update);
1552 .right = WINPR_ASSERTING_INT_CAST(UINT16, w),
1553 .bottom = WINPR_ASSERTING_INT_CAST(UINT16, h) };
1555 WINPR_ASSERT(update->SuppressOutput);
1556 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.