22 #include <freerdp/config.h>
27 #include <winpr/crt.h>
28 #include <winpr/assert.h>
30 #include <freerdp/api.h>
31 #include <freerdp/log.h>
32 #include <freerdp/freerdp.h>
34 #include <freerdp/gdi/gdi.h>
35 #include <freerdp/gdi/dc.h>
36 #include <freerdp/gdi/pen.h>
37 #include <freerdp/gdi/shape.h>
38 #include <freerdp/gdi/region.h>
39 #include <freerdp/gdi/bitmap.h>
46 #include "../core/graphics.h"
47 #include "../core/update.h"
48 #include "../cache/cache.h"
50 #define TAG FREERDP_TAG("gdi")
59 static const rop_table_entry rop3_code_table[] = { { GDI_BLACKNESS,
"0" },
60 { GDI_DPSoon,
"DPSoon" },
61 { GDI_DPSona,
"DPSona" },
63 { GDI_SDPona,
"SDPona" },
65 { GDI_PDSxnon,
"PDSxnon" },
66 { GDI_PDSaon,
"PDSaon" },
67 { GDI_SDPnaa,
"SDPnaa" },
68 { GDI_PDSxon,
"PDSxon" },
70 { GDI_PSDnaon,
"PSDnaon" },
72 { GDI_PDSnaon,
"PDSnaon" },
73 { GDI_PDSonon,
"PDSonon" },
75 { GDI_PDSona,
"PDSona" },
76 { GDI_NOTSRCERASE,
"DSon" },
77 { GDI_SDPxnon,
"SDPxnon" },
78 { GDI_SDPaon,
"SDPaon" },
79 { GDI_DPSxnon,
"DPSxnon" },
80 { GDI_DPSaon,
"DPSaon" },
81 { GDI_PSDPSanaxx,
"PSDPSanaxx" },
82 { GDI_SSPxDSxaxn,
"SSPxDSxaxn" },
83 { GDI_SPxPDxa,
"SPxPDxa" },
84 { GDI_SDPSanaxn,
"SDPSanaxn" },
85 { GDI_PDSPaox,
"PDSPaox" },
86 { GDI_SDPSxaxn,
"SDPSxaxn" },
87 { GDI_PSDPaox,
"PSDPaox" },
88 { GDI_DSPDxaxn,
"DSPDxaxn" },
89 { GDI_PDSox,
"PDSox" },
90 { GDI_PDSoan,
"PDSoan" },
91 { GDI_DPSnaa,
"DPSnaa" },
92 { GDI_SDPxon,
"SDPxon" },
94 { GDI_SPDnaon,
"SPDnaon" },
95 { GDI_SPxDSxa,
"SPxDSxa" },
96 { GDI_PDSPanaxn,
"PDSPanaxn" },
97 { GDI_SDPSaox,
"SDPSaox" },
98 { GDI_SDPSxnox,
"SDPSxnox" },
99 { GDI_DPSxa,
"DPSxa" },
100 { GDI_PSDPSaoxxn,
"PSDPSaoxxn" },
101 { GDI_DPSana,
"DPSana" },
102 { GDI_SSPxPDxaxn,
"SSPxPDxaxn" },
103 { GDI_SPDSoax,
"SPDSoax" },
104 { GDI_PSDnox,
"PSDnox" },
105 { GDI_PSDPxox,
"PSDPxox" },
106 { GDI_PSDnoan,
"PSDnoan" },
107 { GDI_PSna,
"PSna" },
108 { GDI_SDPnaon,
"SDPnaon" },
109 { GDI_SDPSoox,
"SDPSoox" },
110 { GDI_NOTSRCCOPY,
"Sn" },
111 { GDI_SPDSaox,
"SPDSaox" },
112 { GDI_SPDSxnox,
"SPDSxnox" },
113 { GDI_SDPox,
"SDPox" },
114 { GDI_SDPoan,
"SDPoan" },
115 { GDI_PSDPoax,
"PSDPoax" },
116 { GDI_SPDnox,
"SPDnox" },
117 { GDI_SPDSxox,
"SPDSxox" },
118 { GDI_SPDnoan,
"SPDnoan" },
120 { GDI_SPDSonox,
"SPDSonox" },
121 { GDI_SPDSnaox,
"SPDSnaox" },
122 { GDI_PSan,
"PSan" },
123 { GDI_PSDnaa,
"PSDnaa" },
124 { GDI_DPSxon,
"DPSxon" },
125 { GDI_SDxPDxa,
"SDxPDxa" },
126 { GDI_SPDSanaxn,
"SPDSanaxn" },
127 { GDI_SRCERASE,
"SDna" },
128 { GDI_DPSnaon,
"DPSnaon" },
129 { GDI_DSPDaox,
"DSPDaox" },
130 { GDI_PSDPxaxn,
"PSDPxaxn" },
131 { GDI_SDPxa,
"SDPxa" },
132 { GDI_PDSPDaoxxn,
"PDSPDaoxxn" },
133 { GDI_DPSDoax,
"DPSDoax" },
134 { GDI_PDSnox,
"PDSnox" },
135 { GDI_SDPana,
"SDPana" },
136 { GDI_SSPxDSxoxn,
"SSPxDSxoxn" },
137 { GDI_PDSPxox,
"PDSPxox" },
138 { GDI_PDSnoan,
"PDSnoan" },
139 { GDI_PDna,
"PDna" },
140 { GDI_DSPnaon,
"DSPnaon" },
141 { GDI_DPSDaox,
"DPSDaox" },
142 { GDI_SPDSxaxn,
"SPDSxaxn" },
143 { GDI_DPSonon,
"DPSonon" },
144 { GDI_DSTINVERT,
"Dn" },
145 { GDI_DPSox,
"DPSox" },
146 { GDI_DPSoan,
"DPSoan" },
147 { GDI_PDSPoax,
"PDSPoax" },
148 { GDI_DPSnox,
"DPSnox" },
149 { GDI_PATINVERT,
"DPx" },
150 { GDI_DPSDonox,
"DPSDonox" },
151 { GDI_DPSDxox,
"DPSDxox" },
152 { GDI_DPSnoan,
"DPSnoan" },
153 { GDI_DPSDnaox,
"DPSDnaox" },
154 { GDI_DPan,
"DPan" },
155 { GDI_PDSxa,
"PDSxa" },
156 { GDI_DSPDSaoxxn,
"DSPDSaoxxn" },
157 { GDI_DSPDoax,
"DSPDoax" },
158 { GDI_SDPnox,
"SDPnox" },
159 { GDI_SDPSoax,
"SDPSoax" },
160 { GDI_DSPnox,
"DSPnox" },
161 { GDI_SRCINVERT,
"DSx" },
162 { GDI_SDPSonox,
"SDPSonox" },
163 { GDI_DSPDSonoxxn,
"DSPDSonoxxn" },
164 { GDI_PDSxxn,
"PDSxxn" },
165 { GDI_DPSax,
"DPSax" },
166 { GDI_PSDPSoaxxn,
"PSDPSoaxxn" },
167 { GDI_SDPax,
"SDPax" },
168 { GDI_PDSPDoaxxn,
"PDSPDoaxxn" },
169 { GDI_SDPSnoax,
"SDPSnoax" },
170 { GDI_PDSxnan,
"PDSxnan" },
171 { GDI_PDSana,
"PDSana" },
172 { GDI_SSDxPDxaxn,
"SSDxPDxaxn" },
173 { GDI_SDPSxox,
"SDPSxox" },
174 { GDI_SDPnoan,
"SDPnoan" },
175 { GDI_DSPDxox,
"DSPDxox" },
176 { GDI_DSPnoan,
"DSPnoan" },
177 { GDI_SDPSnaox,
"SDPSnaox" },
178 { GDI_DSan,
"DSan" },
179 { GDI_PDSax,
"PDSax" },
180 { GDI_DSPDSoaxxn,
"DSPDSoaxxn" },
181 { GDI_DPSDnoax,
"DPSDnoax" },
182 { GDI_SDPxnan,
"SDPxnan" },
183 { GDI_SPDSnoax,
"SPDSnoax" },
184 { GDI_DPSxnan,
"DPSxnan" },
185 { GDI_SPxDSxo,
"SPxDSxo" },
186 { GDI_DPSaan,
"DPSaan" },
187 { GDI_DPSaa,
"DPSaa" },
188 { GDI_SPxDSxon,
"SPxDSxon" },
189 { GDI_DPSxna,
"DPSxna" },
190 { GDI_SPDSnoaxn,
"SPDSnoaxn" },
191 { GDI_SDPxna,
"SDPxna" },
192 { GDI_PDSPnoaxn,
"PDSPnoaxn" },
193 { GDI_DSPDSoaxx,
"DSPDSoaxx" },
194 { GDI_PDSaxn,
"PDSaxn" },
195 { GDI_SRCAND,
"DSa" },
196 { GDI_SDPSnaoxn,
"SDPSnaoxn" },
197 { GDI_DSPnoa,
"DSPnoa" },
198 { GDI_DSPDxoxn,
"DSPDxoxn" },
199 { GDI_SDPnoa,
"SDPnoa" },
200 { GDI_SDPSxoxn,
"SDPSxoxn" },
201 { GDI_SSDxPDxax,
"SSDxPDxax" },
202 { GDI_PDSanan,
"PDSanan" },
203 { GDI_PDSxna,
"PDSxna" },
204 { GDI_SDPSnoaxn,
"SDPSnoaxn" },
205 { GDI_DPSDPoaxx,
"DPSDPoaxx" },
206 { GDI_SPDaxn,
"SPDaxn" },
207 { GDI_PSDPSoaxx,
"PSDPSoaxx" },
208 { GDI_DPSaxn,
"DPSaxn" },
209 { GDI_DPSxx,
"DPSxx" },
210 { GDI_PSDPSonoxx,
"PSDPSonoxx" },
211 { GDI_SDPSonoxn,
"SDPSonoxn" },
212 { GDI_DSxn,
"DSxn" },
213 { GDI_DPSnax,
"DPSnax" },
214 { GDI_SDPSoaxn,
"SDPSoaxn" },
215 { GDI_SPDnax,
"SPDnax" },
216 { GDI_DSPDoaxn,
"DSPDoaxn" },
217 { GDI_DSPDSaoxx,
"DSPDSaoxx" },
218 { GDI_PDSxan,
"PDSxan" },
220 { GDI_PDSPnaoxn,
"PDSPnaoxn" },
221 { GDI_DPSnoa,
"DPSnoa" },
222 { GDI_DPSDxoxn,
"DPSDxoxn" },
223 { GDI_PDSPonoxn,
"PDSPonoxn" },
224 { GDI_PDxn,
"PDxn" },
225 { GDI_DSPnax,
"DSPnax" },
226 { GDI_PDSPoaxn,
"PDSPoaxn" },
227 { GDI_DPSoa,
"DPSoa" },
228 { GDI_DPSoxn,
"DPSoxn" },
229 { GDI_DSTCOPY,
"D" },
230 { GDI_DPSono,
"DPSono" },
231 { GDI_SPDSxax,
"SPDSxax" },
232 { GDI_DPSDaoxn,
"DPSDaoxn" },
233 { GDI_DSPnao,
"DSPnao" },
234 { GDI_DPno,
"DPno" },
235 { GDI_PDSnoa,
"PDSnoa" },
236 { GDI_PDSPxoxn,
"PDSPxoxn" },
237 { GDI_SSPxDSxox,
"SSPxDSxox" },
238 { GDI_SDPanan,
"SDPanan" },
239 { GDI_PSDnax,
"PSDnax" },
240 { GDI_DPSDoaxn,
"DPSDoaxn" },
241 { GDI_DPSDPaoxx,
"DPSDPaoxx" },
242 { GDI_SDPxan,
"SDPxan" },
243 { GDI_PSDPxax,
"PSDPxax" },
244 { GDI_DSPDaoxn,
"DSPDaoxn" },
245 { GDI_DPSnao,
"DPSnao" },
246 { GDI_MERGEPAINT,
"DSno" },
247 { GDI_SPDSanax,
"SPDSanax" },
248 { GDI_SDxPDxan,
"SDxPDxan" },
249 { GDI_DPSxo,
"DPSxo" },
250 { GDI_DPSano,
"DPSano" },
251 { GDI_MERGECOPY,
"PSa" },
252 { GDI_SPDSnaoxn,
"SPDSnaoxn" },
253 { GDI_SPDSonoxn,
"SPDSonoxn" },
254 { GDI_PSxn,
"PSxn" },
255 { GDI_SPDnoa,
"SPDnoa" },
256 { GDI_SPDSxoxn,
"SPDSxoxn" },
257 { GDI_SDPnax,
"SDPnax" },
258 { GDI_PSDPoaxn,
"PSDPoaxn" },
259 { GDI_SDPoa,
"SDPoa" },
260 { GDI_SPDoxn,
"SPDoxn" },
261 { GDI_DPSDxax,
"DPSDxax" },
262 { GDI_SPDSaoxn,
"SPDSaoxn" },
263 { GDI_SRCCOPY,
"S" },
264 { GDI_SDPono,
"SDPono" },
265 { GDI_SDPnao,
"SDPnao" },
266 { GDI_SPno,
"SPno" },
267 { GDI_PSDnoa,
"PSDnoa" },
268 { GDI_PSDPxoxn,
"PSDPxoxn" },
269 { GDI_PDSnax,
"PDSnax" },
270 { GDI_SPDSoaxn,
"SPDSoaxn" },
271 { GDI_SSPxPDxax,
"SSPxPDxax" },
272 { GDI_DPSanan,
"DPSanan" },
273 { GDI_PSDPSaoxx,
"PSDPSaoxx" },
274 { GDI_DPSxan,
"DPSxan" },
275 { GDI_PDSPxax,
"PDSPxax" },
276 { GDI_SDPSaoxn,
"SDPSaoxn" },
277 { GDI_DPSDanax,
"DPSDanax" },
278 { GDI_SPxDSxan,
"SPxDSxan" },
279 { GDI_SPDnao,
"SPDnao" },
280 { GDI_SDno,
"SDno" },
281 { GDI_SDPxo,
"SDPxo" },
282 { GDI_SDPano,
"SDPano" },
283 { GDI_PDSoa,
"PDSoa" },
284 { GDI_PDSoxn,
"PDSoxn" },
285 { GDI_DSPDxax,
"DSPDxax" },
286 { GDI_PSDPaoxn,
"PSDPaoxn" },
287 { GDI_SDPSxax,
"SDPSxax" },
288 { GDI_PDSPaoxn,
"PDSPaoxn" },
289 { GDI_SDPSanax,
"SDPSanax" },
290 { GDI_SPxPDxan,
"SPxPDxan" },
291 { GDI_SSPxDSxax,
"SSPxDSxax" },
292 { GDI_DSPDSanaxxn,
"DSPDSanaxxn" },
293 { GDI_DPSao,
"DPSao" },
294 { GDI_DPSxno,
"DPSxno" },
295 { GDI_SDPao,
"SDPao" },
296 { GDI_SDPxno,
"SDPxno" },
297 { GDI_SRCPAINT,
"DSo" },
298 { GDI_SDPnoo,
"SDPnoo" },
299 { GDI_PATCOPY,
"P" },
300 { GDI_PDSono,
"PDSono" },
301 { GDI_PDSnao,
"PDSnao" },
302 { GDI_PSno,
"PSno" },
303 { GDI_PSDnao,
"PSDnao" },
304 { GDI_PDno,
"PDno" },
305 { GDI_PDSxo,
"PDSxo" },
306 { GDI_PDSano,
"PDSano" },
307 { GDI_PDSao,
"PDSao" },
308 { GDI_PDSxno,
"PDSxno" },
310 { GDI_PATPAINT,
"DPSnoo" },
312 { GDI_PSDnoo,
"PSDnoo" },
313 { GDI_DPSoo,
"DPSoo" },
314 { GDI_WHITENESS,
"1" } };
317 static const BYTE GDI_BS_HATCHED_PATTERNS[] = {
318 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
319 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7,
320 0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F,
321 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE,
322 0xF7, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0xF7, 0xF7,
323 0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E
326 static inline DWORD gdi_rop3_code_checked(UINT32 code)
328 WINPR_ASSERT(code <= UINT8_MAX);
329 return gdi_rop3_code((UINT8)code);
332 BOOL gdi_decode_color(rdpGdi* gdi,
const UINT32 srcColor, UINT32* color, UINT32* format)
334 UINT32 SrcFormat = 0;
336 if (!gdi || !color || !gdi->context || !gdi->context->settings)
339 const UINT32 ColorDepth =
346 SrcFormat = PIXEL_FORMAT_BGR24;
350 SrcFormat = PIXEL_FORMAT_RGB16;
354 SrcFormat = PIXEL_FORMAT_RGB15;
358 SrcFormat = PIXEL_FORMAT_RGB8;
366 *format = gdi->dstFormat;
368 *color = FreeRDPConvertColor(srcColor, SrcFormat, gdi->dstFormat, &gdi->palette);
373 DWORD gdi_rop3_code(BYTE code)
375 return rop3_code_table[code].code;
378 const char* gdi_rop3_code_string(BYTE code)
380 return rop3_code_table[code].name;
383 const char* gdi_rop3_string(DWORD rop)
385 const size_t count =
sizeof(rop3_code_table) /
sizeof(rop3_code_table[0]);
387 for (
size_t x = 0; x < count; x++)
389 if (rop3_code_table[x].code == rop)
390 return rop3_code_table[x].name;
396 UINT32 gdi_get_pixel_format(UINT32 bitsPerPixel)
400 switch (bitsPerPixel)
403 format = PIXEL_FORMAT_BGRA32;
407 format = PIXEL_FORMAT_BGR24;
411 format = PIXEL_FORMAT_RGB16;
415 format = PIXEL_FORMAT_RGB15;
419 format = PIXEL_FORMAT_RGB8;
423 WLog_ERR(TAG,
"Unsupported color depth %" PRIu32, bitsPerPixel);
431 gdiBitmap* gdi_bitmap_new_ex(rdpGdi* gdi,
int width,
int height,
int bpp, BYTE* data)
433 gdiBitmap* bitmap = NULL;
434 bitmap = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
439 if (!(bitmap->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
442 WLog_Print(gdi->log, WLOG_DEBUG,
"gdi_bitmap_new: width:%d height:%d bpp:%d", width, height,
446 bitmap->bitmap = gdi_CreateCompatibleBitmap(gdi->hdc, width, height);
448 bitmap->bitmap = gdi_create_bitmap(gdi, width, height, bpp, data);
451 goto fail_bitmap_bitmap;
453 gdi_SelectObject(bitmap->hdc, (
HGDIOBJECT)bitmap->bitmap);
454 bitmap->org_bitmap = NULL;
457 gdi_DeleteDC(bitmap->hdc);
464 void gdi_bitmap_free_ex(gdiBitmap* bitmap)
468 gdi_SelectObject(bitmap->hdc, (
HGDIOBJECT)bitmap->org_bitmap);
470 gdi_DeleteDC(bitmap->hdc);
475 BOOL gdi_bitmap_update(rdpContext* context,
const BITMAP_UPDATE* bitmapUpdate)
477 if (!context || !bitmapUpdate || !context->gdi || !context->codecs)
480 "Invalid arguments: context=%p, bitmapUpdate=%p, context->gdi=%p, "
481 "context->codecs=%p",
482 context, bitmapUpdate, context ? context->gdi : NULL,
483 context ? context->codecs : NULL);
487 for (UINT32 index = 0; index < bitmapUpdate->number; index++)
489 const BITMAP_DATA* bitmap = &(bitmapUpdate->rectangles[index]);
490 rdpBitmap* bmp = Bitmap_Alloc(context);
494 WLog_ERR(TAG,
"Bitmap_Alloc failed");
498 Bitmap_SetDimensions(bmp, bitmap->width, bitmap->height);
499 Bitmap_SetRectangle(bmp, bitmap->destLeft, bitmap->destTop, bitmap->destRight,
502 if (!bmp->Decompress(context, bmp, bitmap->bitmapDataStream, bitmap->width, bitmap->height,
503 bitmap->bitsPerPixel, bitmap->bitmapLength, bitmap->compressed,
506 WLog_ERR(TAG,
"bmp->Decompress failed");
507 Bitmap_Free(context, bmp);
511 if (!bmp->New(context, bmp))
513 WLog_ERR(TAG,
"bmp->New failed");
514 Bitmap_Free(context, bmp);
518 if (!bmp->Paint(context, bmp))
520 WLog_ERR(TAG,
"bmp->Paint failed");
521 Bitmap_Free(context, bmp);
525 Bitmap_Free(context, bmp);
531 static BOOL gdi_palette_update(rdpContext* context,
const PALETTE_UPDATE* palette)
535 if (!context || !palette)
539 gdi->palette.format = gdi->dstFormat;
541 for (UINT32 index = 0; index < palette->number; index++)
544 gdi->palette.palette[index] =
545 FreeRDPGetColor(gdi->dstFormat, pe->red, pe->green, pe->blue, 0xFF);
551 static BOOL gdi_set_bounds(rdpContext* context,
const rdpBounds* bounds)
562 gdi_SetClipRgn(gdi->drawing->hdc, bounds->left, bounds->top,
563 bounds->right - bounds->left + 1, bounds->bottom - bounds->top + 1);
566 gdi_SetNullClipRgn(gdi->drawing->hdc);
571 static BOOL gdi_dstblt(rdpContext* context,
const DSTBLT_ORDER* dstblt)
575 if (!context || !dstblt)
579 return gdi_BitBlt(gdi->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth,
580 dstblt->nHeight, NULL, 0, 0, gdi_rop3_code_checked(dstblt->bRop),
584 static BOOL gdi_patblt(rdpContext* context,
PATBLT_ORDER* patblt)
586 const rdpBrush* brush = &patblt->brush;
587 UINT32 foreColor = 0;
588 UINT32 backColor = 0;
589 UINT32 originalColor = 0;
592 rdpGdi* gdi = context->gdi;
594 const DWORD rop = gdi_rop3_code_checked(patblt->bRop);
597 BYTE data[8 * 8 * 4];
600 if (!gdi_decode_color(gdi, patblt->foreColor, &foreColor, NULL))
603 if (!gdi_decode_color(gdi, patblt->backColor, &backColor, NULL))
606 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
607 originalBrush = gdi->drawing->hdc->brush;
609 switch (brush->style)
612 hbrush = gdi_CreateSolidBrush(foreColor);
617 const BYTE* hatched = NULL;
618 hatched = GDI_BS_HATCHED_PATTERNS + (8ULL * brush->hatch);
620 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
621 hatched, backColor, foreColor, &gdi->palette))
624 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
629 hbrush = gdi_CreateHatchBrush(hBmp);
635 UINT32 brushFormat = 0;
639 UINT32 bpp = brush->bpp;
645 brushFormat = gdi_get_pixel_format(bpp);
647 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
648 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
654 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
655 8, brush->data, backColor, foreColor,
660 hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
665 hbrush = gdi_CreatePatternBrush(hBmp);
670 WLog_ERR(TAG,
"unimplemented brush style:%" PRIu32
"", brush->style);
676 hbrush->nXOrg = brush->x;
677 hbrush->nYOrg = brush->y;
678 gdi->drawing->hdc->brush = hbrush;
679 ret = gdi_BitBlt(gdi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
680 patblt->nHeight, gdi->primary->hdc, nXSrc, nYSrc, rop, &gdi->palette);
686 gdi->drawing->hdc->brush = originalBrush;
687 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
691 static BOOL gdi_scrblt(rdpContext* context,
const SCRBLT_ORDER* scrblt)
695 if (!context || !context->gdi)
699 return gdi_BitBlt(gdi->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth,
700 scrblt->nHeight, gdi->primary->hdc, scrblt->nXSrc, scrblt->nYSrc,
701 gdi_rop3_code_checked(scrblt->bRop), &gdi->palette);
704 static BOOL gdi_opaque_rect(rdpContext* context,
const OPAQUE_RECT_ORDER* opaque_rect)
708 UINT32 brush_color = 0;
709 rdpGdi* gdi = context->gdi;
711 INT32 x = opaque_rect->nLeftRect;
712 INT32 y = opaque_rect->nTopRect;
713 INT32 w = opaque_rect->nWidth;
714 INT32 h = opaque_rect->nHeight;
715 gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
716 gdi_CRgnToRect(x, y, w, h, &rect);
718 if (!gdi_decode_color(gdi, opaque_rect->color, &brush_color, NULL))
721 if (!(hBrush = gdi_CreateSolidBrush(brush_color)))
724 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
729 static BOOL gdi_multi_opaque_rect(rdpContext* context,
734 UINT32 brush_color = 0;
735 rdpGdi* gdi = context->gdi;
738 if (!gdi_decode_color(gdi, multi_opaque_rect->color, &brush_color, NULL))
741 hBrush = gdi_CreateSolidBrush(brush_color);
746 for (UINT32 i = 0; i < multi_opaque_rect->numRectangles; i++)
748 const DELTA_RECT* rectangle = &multi_opaque_rect->rectangles[i];
749 INT32 x = rectangle->left;
750 INT32 y = rectangle->top;
751 INT32 w = rectangle->width;
752 INT32 h = rectangle->height;
753 gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
754 gdi_CRgnToRect(x, y, w, h, &rect);
755 ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
765 static BOOL gdi_line_to(rdpContext* context,
const LINE_TO_ORDER* lineTo)
769 rdpGdi* gdi = context->gdi;
770 INT32 xStart = lineTo->nXStart;
771 INT32 yStart = lineTo->nYStart;
772 INT32 xEnd = lineTo->nXEnd;
773 INT32 yEnd = lineTo->nYEnd;
776 gdi_ClipCoords(gdi->drawing->hdc, &xStart, &yStart, &w, &h, NULL, NULL);
777 gdi_ClipCoords(gdi->drawing->hdc, &xEnd, &yEnd, &w, &h, NULL, NULL);
779 if (!gdi_decode_color(gdi, lineTo->penColor, &color, NULL))
782 if (!(hPen = gdi_CreatePen(lineTo->penStyle, lineTo->penWidth, color, gdi->drawing->hdc->format,
786 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)hPen);
787 gdi_SetROP2(gdi->drawing->hdc, lineTo->bRop2);
788 gdi_MoveToEx(gdi->drawing->hdc, lineTo->nXStart, lineTo->nYStart, NULL);
789 gdi_LineTo(gdi->drawing->hdc, lineTo->nXEnd, lineTo->nYEnd);
794 static BOOL gdi_polyline(rdpContext* context,
const POLYLINE_ORDER* polyline)
801 rdpGdi* gdi = context->gdi;
805 if (!gdi_decode_color(gdi, polyline->penColor, &color, NULL))
808 if (!(hPen = gdi_CreatePen(GDI_PS_SOLID, 1, color, gdi->drawing->hdc->format, &gdi->palette)))
811 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)hPen);
812 gdi_SetROP2(gdi->drawing->hdc, polyline->bRop2);
813 x = polyline->xStart;
814 y = polyline->yStart;
815 gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
816 gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL);
817 points = polyline->points;
819 for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
823 gdi_ClipCoords(gdi->drawing->hdc, &x, &y, &w, &h, NULL, NULL);
824 gdi_LineTo(gdi->drawing->hdc, x, y);
825 gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL);
832 static BOOL gdi_memblt(rdpContext* context,
MEMBLT_ORDER* memblt)
834 gdiBitmap* bitmap = NULL;
837 if (!context || !memblt || !context->gdi || !memblt->bitmap)
840 bitmap = (gdiBitmap*)memblt->bitmap;
842 return gdi_BitBlt(gdi->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
843 memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc,
844 gdi_rop3_code_checked(memblt->bRop), &gdi->palette);
847 static BOOL gdi_mem3blt(rdpContext* context,
MEM3BLT_ORDER* mem3blt)
850 rdpGdi* gdi = context->gdi;
852 const rdpBrush* brush = &mem3blt->brush;
853 gdiBitmap* bitmap = (gdiBitmap*)mem3blt->bitmap;
854 UINT32 foreColor = 0;
855 UINT32 backColor = 0;
856 UINT32 originalColor = 0;
858 if (!gdi_decode_color(gdi, mem3blt->foreColor, &foreColor, NULL))
861 if (!gdi_decode_color(gdi, mem3blt->backColor, &backColor, NULL))
864 originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
866 switch (brush->style)
869 originalBrush = gdi->drawing->hdc->brush;
870 gdi->drawing->hdc->brush = gdi_CreateSolidBrush(foreColor);
872 if (!gdi->drawing->hdc->brush)
878 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
879 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
880 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
881 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
882 gdi->drawing->hdc->brush = originalBrush;
888 UINT32 brushFormat = 0;
889 BYTE* data = (BYTE*)winpr_aligned_malloc(
890 8ULL * 8ULL * FreeRDPGetBytesPerPixel(gdi->drawing->hdc->format), 16);
900 UINT32 bpp = brush->bpp;
902 const UINT32 ColorDepth =
904 if ((bpp == 16) && (ColorDepth == 15))
907 brushFormat = gdi_get_pixel_format(bpp);
909 if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
910 brush->data, brushFormat, 0, 0, 0, &gdi->palette,
914 winpr_aligned_free(data);
920 if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
921 8, brush->data, backColor, foreColor,
925 winpr_aligned_free(data);
930 hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->format, data);
935 winpr_aligned_free(data);
939 originalBrush = gdi->drawing->hdc->brush;
940 gdi->drawing->hdc->brush = gdi_CreatePatternBrush(hBmp);
942 if (!gdi->drawing->hdc->brush)
948 gdi->drawing->hdc->brush->nXOrg = brush->x;
949 gdi->drawing->hdc->brush->nYOrg = brush->y;
950 ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
951 mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
952 mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
953 gdi_DeleteObject((
HGDIOBJECT)gdi->drawing->hdc->brush);
955 gdi->drawing->hdc->brush = originalBrush;
960 WLog_ERR(TAG,
"Mem3Blt unimplemented brush style:%" PRIu32
"", brush->style);
965 gdi_SetTextColor(gdi->drawing->hdc, originalColor);
969 static BOOL gdi_polygon_sc(rdpContext* context,
const POLYGON_SC_ORDER* polygon_sc)
971 WLog_WARN(TAG,
"not implemented");
975 static BOOL gdi_polygon_cb(rdpContext* context,
POLYGON_CB_ORDER* polygon_cb)
977 WLog_WARN(TAG,
"not implemented");
981 static BOOL gdi_ellipse_sc(rdpContext* context,
const ELLIPSE_SC_ORDER* ellipse_sc)
983 WLog_WARN(TAG,
"not implemented");
987 static BOOL gdi_ellipse_cb(rdpContext* context,
const ELLIPSE_CB_ORDER* ellipse_cb)
989 WLog_WARN(TAG,
"not implemented");
993 static BOOL gdi_frame_marker(rdpContext* context,
const FRAME_MARKER_ORDER* frameMarker)
998 static BOOL gdi_surface_frame_marker(rdpContext* context,
1001 WLog_Print(context->gdi->log, WLOG_DEBUG,
"frameId %" PRIu32
" frameAction %" PRIu32
"",
1002 surfaceFrameMarker->frameId, surfaceFrameMarker->frameAction);
1004 switch (surfaceFrameMarker->frameAction)
1006 case SURFACECMD_FRAMEACTION_BEGIN:
1009 case SURFACECMD_FRAMEACTION_END:
1012 IFCALL(context->update->SurfaceFrameAcknowledge, context,
1013 surfaceFrameMarker->frameId);
1026 const UINT32 w = (
const UINT32)gdi->width;
1027 const UINT32 h = (
const UINT32)gdi->height;
1029 if (cmd->destLeft > w)
1031 if (cmd->destRight > w)
1033 if (cmd->destLeft > cmd->destRight)
1035 if (cmd->destRight > UINT16_MAX)
1038 if (cmd->destTop > h)
1040 if (cmd->destBottom > h)
1042 if (cmd->destTop > cmd->destBottom)
1044 if (cmd->destBottom > UINT16_MAX)
1047 prect->left = (
const UINT16)cmd->destLeft;
1048 prect->top = (
const UINT16)cmd->destTop;
1049 prect->right = MIN((UINT16)cmd->destRight, prect->left + cmd->bmp.width);
1050 prect->bottom = MIN((UINT16)cmd->destBottom, prect->top + cmd->bmp.height);
1056 BOOL result = FALSE;
1065 if (!context || !cmd)
1070 gdi->log, WLOG_DEBUG,
1071 "destLeft %" PRIu32
" destTop %" PRIu32
" destRight %" PRIu32
" destBottom %" PRIu32
" "
1072 "bpp %" PRIu8
" flags %" PRIx8
" codecID %" PRIu16
" width %" PRIu16
" height %" PRIu16
1073 " length %" PRIu32
"",
1074 cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bmp.bpp, cmd->bmp.flags,
1075 cmd->bmp.codecID, cmd->bmp.width, cmd->bmp.height, cmd->bmp.bitmapDataLength);
1076 region16_init(®ion);
1078 if (!intersect_rect(gdi, cmd, &cmdRect))
1081 switch (cmd->bmp.codecID)
1083 case RDP_CODEC_ID_REMOTEFX:
1084 case RDP_CODEC_ID_IMAGE_REMOTEFX:
1085 if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData,
1086 cmd->bmp.bitmapDataLength, cmdRect.left, cmdRect.top,
1087 gdi->primary_buffer, gdi->dstFormat, gdi->stride, gdi->height,
1090 WLog_ERR(TAG,
"Failed to process RemoteFX message");
1096 case RDP_CODEC_ID_NSCODEC:
1097 format = gdi->dstFormat;
1099 if (!nsc_process_message(
1100 context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, cmd->bmp.height,
1101 cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, format,
1102 gdi->stride, cmdRect.left, cmdRect.top, cmdRect.right - cmdRect.left,
1103 cmdRect.bottom - cmdRect.top, FREERDP_FLIP_VERTICAL))
1105 WLog_ERR(TAG,
"Failed to process NSCodec message");
1109 region16_union_rect(®ion, ®ion, &cmdRect);
1112 case RDP_CODEC_ID_NONE:
1113 format = gdi_get_pixel_format(cmd->bmp.bpp);
1114 size = 1ull * cmd->bmp.width * cmd->bmp.height * FreeRDPGetBytesPerPixel(format);
1115 if (size > cmd->bmp.bitmapDataLength)
1117 WLog_ERR(TAG,
"Short nocodec message: got %" PRIu32
" bytes, require %" PRIuz,
1118 cmd->bmp.bitmapDataLength, size);
1122 if (!freerdp_image_copy_no_overlap(
1123 gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmdRect.left, cmdRect.top,
1124 cmdRect.right - cmdRect.left, cmdRect.bottom - cmdRect.top, cmd->bmp.bitmapData,
1125 format, 0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))
1127 WLog_ERR(TAG,
"Failed to process nocodec message");
1131 region16_union_rect(®ion, ®ion, &cmdRect);
1135 WLog_ERR(TAG,
"Unsupported codecID %" PRIu32
"", cmd->bmp.codecID);
1139 if (!(rects = region16_rects(®ion, &nbRects)))
1142 for (UINT32 i = 0; i < nbRects; i++)
1144 UINT32 left = rects[i].left;
1145 UINT32 top = rects[i].top;
1146 UINT32 width = rects[i].right - rects[i].left;
1147 UINT32 height = rects[i].bottom - rects[i].top;
1149 if (!gdi_InvalidateRegion(gdi->primary->hdc, left, top, width, height))
1151 WLog_ERR(TAG,
"Failed to update invalid region");
1158 region16_uninit(®ion);
1167 static void gdi_register_update_callbacks(rdpUpdate* update)
1169 rdpPrimaryUpdate* primary = NULL;
1170 const rdpSettings* settings = NULL;
1172 WINPR_ASSERT(update);
1173 WINPR_ASSERT(update->context);
1175 settings = update->context->settings;
1176 WINPR_ASSERT(settings);
1178 primary = update->primary;
1179 WINPR_ASSERT(primary);
1183 update->Palette = gdi_palette_update;
1184 update->SetBounds = gdi_set_bounds;
1185 primary->DstBlt = gdi_dstblt;
1186 primary->PatBlt = gdi_patblt;
1187 primary->ScrBlt = gdi_scrblt;
1188 primary->OpaqueRect = gdi_opaque_rect;
1189 primary->DrawNineGrid = NULL;
1190 primary->MultiDstBlt = NULL;
1191 primary->MultiPatBlt = NULL;
1192 primary->MultiScrBlt = NULL;
1193 primary->MultiOpaqueRect = gdi_multi_opaque_rect;
1194 primary->MultiDrawNineGrid = NULL;
1195 primary->LineTo = gdi_line_to;
1196 primary->Polyline = gdi_polyline;
1197 primary->MemBlt = gdi_memblt;
1198 primary->Mem3Blt = gdi_mem3blt;
1199 primary->SaveBitmap = NULL;
1200 primary->GlyphIndex = NULL;
1201 primary->FastIndex = NULL;
1202 primary->FastGlyph = NULL;
1203 primary->PolygonSC = gdi_polygon_sc;
1204 primary->PolygonCB = gdi_polygon_cb;
1205 primary->EllipseSC = gdi_ellipse_sc;
1206 primary->EllipseCB = gdi_ellipse_cb;
1207 update->SurfaceBits = gdi_surface_bits;
1208 update->SurfaceFrameMarker = gdi_surface_frame_marker;
1209 update->altsec->FrameMarker = gdi_frame_marker;
1212 static BOOL gdi_init_primary(rdpGdi* gdi, UINT32 stride, UINT32 format, BYTE* buffer,
1213 void (*pfree)(
void*), BOOL isLocked)
1216 WINPR_ASSERT(gdi->context);
1217 WINPR_ASSERT(gdi->context->update);
1219 rdp_update_lock(gdi->context->update);
1221 gdi->primary = (gdiBitmap*)calloc(1,
sizeof(gdiBitmap));
1224 gdi->dstFormat = format;
1227 gdi->stride = stride;
1229 gdi->stride = gdi->width * FreeRDPGetBytesPerPixel(gdi->dstFormat);
1234 if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
1239 gdi->primary->bitmap = gdi_CreateCompatibleBitmap(gdi->hdc, gdi->width, gdi->height);
1243 gdi->primary->bitmap =
1244 gdi_CreateBitmapEx(gdi->width, gdi->height, gdi->dstFormat, gdi->stride, buffer, pfree);
1247 if (!gdi->primary->bitmap)
1250 gdi->stride = gdi->primary->bitmap->scanline;
1251 gdi_SelectObject(gdi->primary->hdc, (
HGDIOBJECT)gdi->primary->bitmap);
1252 gdi->primary->org_bitmap = NULL;
1253 gdi->primary_buffer = gdi->primary->bitmap->data;
1255 if (!(gdi->primary->hdc->hwnd = (
HGDI_WND)calloc(1,
sizeof(
GDI_WND))))
1258 if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0)))
1261 gdi->primary->hdc->hwnd->invalid->null = TRUE;
1262 gdi->primary->hdc->hwnd->count = 32;
1264 if (!(gdi->primary->hdc->hwnd->cinvalid =
1268 gdi->primary->hdc->hwnd->ninvalid = 0;
1271 gdi->drawing = gdi->primary;
1273 rdp_update_unlock(gdi->context->update);
1276 gdi_DeleteObject((
HGDIOBJECT)gdi->primary->bitmap);
1278 gdi_DeleteDC(gdi->primary->hdc);
1281 gdi->primary = NULL;
1283 rdp_update_unlock(gdi->context->update);
1287 BOOL gdi_resize(rdpGdi* gdi, UINT32 width, UINT32 height)
1289 return gdi_resize_ex(gdi, width, height, 0, 0, NULL, NULL);
1292 BOOL gdi_resize_ex(rdpGdi* gdi, UINT32 width, UINT32 height, UINT32 stride, UINT32 format,
1293 BYTE* buffer,
void (*pfree)(
void*))
1295 if (!gdi || !gdi->primary)
1298 if ((width > INT32_MAX) || (height > INT32_MAX))
1301 if ((gdi->width == (INT32)width) && (gdi->height == (INT32)height) &&
1302 (!buffer || (gdi->primary_buffer == buffer)))
1305 WINPR_ASSERT(gdi->context);
1306 WINPR_ASSERT(gdi->context->update);
1309 update_end_paint(gdi->context->update);
1310 rdp_update_lock(gdi->context->update);
1312 if (gdi->drawing == gdi->primary)
1313 gdi->drawing = NULL;
1315 gdi->width = (INT32)width;
1316 gdi->height = (INT32)height;
1317 gdi_bitmap_free_ex(gdi->primary);
1318 gdi->primary = NULL;
1319 gdi->primary_buffer = NULL;
1320 return gdi_init_primary(gdi, stride, format, buffer, pfree, TRUE);
1330 BOOL gdi_init(freerdp* instance, UINT32 format)
1332 return gdi_init_ex(instance, format, 0, NULL, winpr_aligned_free);
1346 BOOL gdi_init_ex(freerdp* instance, UINT32 format, UINT32 stride, BYTE* buffer,
1347 void (*pfree)(
void*))
1349 rdpContext* context = NULL;
1350 UINT32 SrcFormat = 0;
1353 WINPR_ASSERT(instance);
1355 context = instance->context;
1356 WINPR_ASSERT(context);
1357 WINPR_ASSERT(context->settings);
1360 SrcFormat = gdi_get_pixel_format(ColorDepth);
1361 gdi = (rdpGdi*)calloc(1,
sizeof(rdpGdi));
1367 gdi->log = WLog_Get(TAG);
1372 gdi->context = context;
1375 gdi->dstFormat = format;
1377 WLog_Print(gdi->log, WLOG_INFO,
"Local framebuffer format %s",
1378 FreeRDPGetColorFormatName(gdi->dstFormat));
1379 WLog_Print(gdi->log, WLOG_INFO,
"Remote framebuffer format %s",
1380 FreeRDPGetColorFormatName(SrcFormat));
1382 if (!(gdi->hdc = gdi_GetDC()))
1385 gdi->hdc->format = gdi->dstFormat;
1387 if (!gdi_init_primary(gdi, stride, gdi->dstFormat, buffer, pfree, FALSE))
1390 if (!(context->cache = cache_new(context)))
1393 gdi_register_update_callbacks(context->update);
1394 brush_cache_register_callbacks(context->update);
1395 glyph_cache_register_callbacks(context->update);
1396 bitmap_cache_register_callbacks(context->update);
1397 offscreen_cache_register_callbacks(context->update);
1398 palette_cache_register_callbacks(context->update);
1400 if (!gdi_register_graphics(context->graphics))
1406 WLog_ERR(TAG,
"failed to initialize gdi");
1410 void gdi_free(freerdp* instance)
1413 rdpContext* context = NULL;
1415 if (!instance || !instance->context)
1418 gdi = instance->context->gdi;
1422 gdi_bitmap_free_ex(gdi->primary);
1423 gdi_DeleteDC(gdi->hdc);
1427 context = instance->context;
1428 cache_free(context->cache);
1429 context->cache = NULL;
1430 instance->context->gdi = (rdpGdi*)NULL;
1433 BOOL gdi_send_suppress_output(rdpGdi* gdi, BOOL suppress)
1436 rdpSettings* settings = NULL;
1437 rdpUpdate* update = NULL;
1439 if (!gdi || !gdi->context->settings || !gdi->context->update)
1442 if (gdi->suppressOutput == suppress)
1445 gdi->suppressOutput = suppress;
1446 settings = gdi->context->settings;
1447 update = gdi->context->update;
1452 return update->SuppressOutput(gdi->context, !suppress, &rect);
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.