22#include <freerdp/config.h>
26#include <freerdp/log.h>
27#include <freerdp/freerdp.h>
28#include <freerdp/gdi/dc.h>
29#include <freerdp/gdi/shape.h>
30#include <freerdp/gdi/region.h>
31#include <freerdp/gdi/bitmap.h>
38#define TAG FREERDP_TAG("gdi")
41HGDI_BITMAP gdi_create_bitmap(rdpGdi* gdi, UINT32 nWidth, UINT32 nHeight, UINT32 SrcFormat,
46 BYTE* pSrcData =
nullptr;
47 BYTE* pDstData =
nullptr;
53 nDstStep = nWidth * FreeRDPGetBytesPerPixel(gdi->dstFormat);
54 pDstData = winpr_aligned_malloc(1ull * nHeight * nDstStep, 16);
60 nSrcStep = nWidth * FreeRDPGetBytesPerPixel(SrcFormat);
62 if (!freerdp_image_copy_no_overlap(pDstData, gdi->dstFormat, nDstStep, 0, 0, nWidth, nHeight,
63 pSrcData, SrcFormat, nSrcStep, 0, 0, &gdi->palette,
66 winpr_aligned_free(pDstData);
70 bitmap = gdi_CreateBitmap(nWidth, nHeight, gdi->dstFormat, pDstData);
72 winpr_aligned_free(pDstData);
76static BOOL gdi_Bitmap_New(rdpContext* context, rdpBitmap* bitmap)
79 rdpGdi* gdi = context->gdi;
81 gdi_bitmap->hdc = gdi_CreateCompatibleDC(gdi->hdc);
87 gdi_bitmap->bitmap = gdi_CreateCompatibleBitmap(gdi->hdc, bitmap->width, bitmap->height);
90 UINT32 format = bitmap->format;
92 gdi_create_bitmap(gdi, bitmap->width, bitmap->height, format, bitmap->data);
108static void gdi_Bitmap_Free(WINPR_ATTR_UNUSED rdpContext* context, rdpBitmap* bitmap)
119 winpr_aligned_free(bitmap->data);
125static BOOL gdi_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap)
128 UINT32 width = bitmap->right - bitmap->left + 1;
129 UINT32 height = bitmap->bottom - bitmap->top + 1;
130 return gdi_BitBlt(context->gdi->primary->hdc, WINPR_ASSERTING_INT_CAST(
int, bitmap->left),
131 WINPR_ASSERTING_INT_CAST(
int, bitmap->top),
132 WINPR_ASSERTING_INT_CAST(
int, width), WINPR_ASSERTING_INT_CAST(
int, height),
133 gdi_bitmap->hdc, 0, 0, GDI_SRCCOPY, &context->gdi->palette);
137static BOOL gdi_Bitmap_Rfx(rdpContext* context, rdpBitmap* bitmap,
const BYTE* pSrcData,
140 WINPR_ASSERT(context);
141 WINPR_ASSERT(bitmap);
142 WINPR_ASSERT(pSrcData || (SrcSize == 0));
144 REGION16 invalidRegion = WINPR_C_ARRAY_INIT;
145 region16_init(&invalidRegion);
147 const UINT32 stride = bitmap->width * FreeRDPGetBytesPerPixel(bitmap->format);
150 rfx_process_message(context->codecs->rfx, pSrcData, SrcSize, bitmap->left, bitmap->top,
151 bitmap->data, bitmap->format, stride, bitmap->height, &invalidRegion);
152 region16_uninit(&invalidRegion);
156 WLog_ERR(TAG,
"rfx_process_message failed");
162static BOOL gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap,
const BYTE* pSrcData,
163 UINT32 DstWidth, UINT32 DstHeight, UINT32 bpp, UINT32 length,
164 BOOL compressed, UINT32 codecId)
166 WINPR_ASSERT(context);
167 WINPR_ASSERT(bitmap);
169 UINT32 SrcSize = length;
170 rdpGdi* gdi = context->gdi;
173 bitmap->compressed = FALSE;
174 bitmap->format = gdi->dstFormat;
176 if ((FreeRDPGetBytesPerPixel(bitmap->format) == 0) || (DstWidth == 0) || (DstHeight == 0) ||
177 (DstWidth > UINT32_MAX / DstHeight) ||
178 ((DstWidth * DstHeight) > (UINT32_MAX / FreeRDPGetBytesPerPixel(bitmap->format))))
180 WLog_ERR(TAG,
"invalid input data");
184 const UINT32 stride = DstWidth * FreeRDPGetBytesPerPixel(bitmap->format);
185 bitmap->length = stride * DstHeight;
186 bitmap->data = (BYTE*)winpr_aligned_malloc(bitmap->length, 16);
193 WINPR_ASSERT(context->codecs);
196 case RDP_CODEC_ID_REMOTEFX:
197 case RDP_CODEC_ID_IMAGE_REMOTEFX:
198 if (!gdi_Bitmap_Rfx(context, bitmap, pSrcData, SrcSize))
201 case RDP_CODEC_ID_NSCODEC:
203 const int status = nsc_process_message(
204 context->codecs->nsc, 32, DstWidth, DstHeight, pSrcData, SrcSize, bitmap->data,
205 bitmap->format, stride, 0, 0, DstWidth, DstHeight, FREERDP_FLIP_VERTICAL);
209 WLog_ERR(TAG,
"nsc_process_message failed");
217 if (!interleaved_decompress(context->codecs->interleaved, pSrcData, SrcSize,
218 DstWidth, DstHeight, bpp, bitmap->data,
219 bitmap->format, stride, 0, 0, DstWidth, DstHeight,
222 WLog_ERR(TAG,
"interleaved_decompress failed");
229 context->settings, FreeRDP_DrawAllowDynamicColorFidelity);
230 freerdp_planar_switch_bgr(context->codecs->planar, fidelity);
231 if (!freerdp_bitmap_decompress_planar(
232 context->codecs->planar, pSrcData, SrcSize, DstWidth, DstHeight,
233 bitmap->data, bitmap->format, stride, 0, 0, DstWidth, DstHeight, TRUE))
235 WLog_ERR(TAG,
"freerdp_bitmap_decompress_planar failed");
244 const UINT32 SrcFormat = gdi_get_pixel_format(bpp);
245 const size_t sbpp = FreeRDPGetBytesPerPixel(SrcFormat);
246 const size_t dbpp = FreeRDPGetBytesPerPixel(bitmap->format);
248 if ((sbpp == 0) || (dbpp == 0))
252 const size_t dstSize = SrcSize * dbpp / sbpp;
254 if (dstSize < bitmap->length)
256 WLog_ERR(TAG,
"dstSize %" PRIuz
" < bitmap->length %" PRIu32, dstSize,
262 if (!freerdp_image_copy_no_overlap(bitmap->data, bitmap->format, stride, 0, 0, DstWidth,
263 DstHeight, pSrcData, SrcFormat, 0, 0, 0, &gdi->palette,
264 FREERDP_FLIP_VERTICAL))
266 WLog_ERR(TAG,
"freerdp_image_copy failed");
274static BOOL gdi_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary)
276 rdpGdi* gdi =
nullptr;
287 gdi->drawing = gdi->primary;
289 gdi->drawing = (gdiBitmap*)bitmap;
295static BOOL gdi_Glyph_New(rdpContext* context, rdpGlyph* glyph)
297 if (!context || !glyph)
306 gdi_glyph->hdc->format = PIXEL_FORMAT_MONO;
307 BYTE* data = freerdp_glyph_convert_ex(glyph->cx, glyph->cy, glyph->aj, glyph->cb);
315 gdi_glyph->bitmap = gdi_CreateBitmap(glyph->cx, glyph->cy, PIXEL_FORMAT_MONO, data);
320 winpr_aligned_free(data);
329static void gdi_Glyph_Free(WINPR_ATTR_UNUSED rdpContext* context, rdpGlyph* glyph)
344static BOOL gdi_Glyph_Draw(rdpContext* context,
const rdpGlyph* glyph, INT32 x, INT32 y, INT32 w,
345 INT32 h, INT32 sx, INT32 sy, BOOL fOpRedundant)
348 rdpGdi* gdi =
nullptr;
352 if (!context || !glyph)
369 rect.right = x + w - 1;
372 rect.bottom = y + h - 1;
374 if ((rect.left < rect.right) && (rect.top < rect.bottom))
376 brush = gdi_CreateSolidBrush(gdi->drawing->hdc->bkColor);
381 const BOOL res = gdi_FillRect(gdi->drawing->hdc, &rect, brush);
388 brush = gdi_CreateSolidBrush(gdi->drawing->hdc->textColor);
393 gdi_SelectObject(gdi->drawing->hdc, (
HGDIOBJECT)brush);
394 rc = gdi_BitBlt(gdi->drawing->hdc, x, y, w, h,
gdi_glyph->hdc, sx, sy, GDI_GLYPH_ORDER,
395 &context->gdi->palette);
400static BOOL gdi_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height,
401 UINT32 bgcolor, UINT32 fgcolor, BOOL fOpRedundant)
403 if (!context || !context->gdi)
406 rdpGdi* gdi = context->gdi;
408 if (!gdi->drawing || !gdi->drawing->hdc)
413 if (!gdi_decode_color(gdi, bgcolor, &bgcolor,
nullptr))
416 if (!gdi_decode_color(gdi, fgcolor, &fgcolor,
nullptr))
419 if (!gdi_SetClipRgn(gdi->drawing->hdc, x, y, width, height))
422 gdi_SetTextColor(gdi->drawing->hdc, bgcolor);
423 gdi_SetBkColor(gdi->drawing->hdc, fgcolor);
427 HGDI_BRUSH brush = gdi_CreateSolidBrush(fgcolor);
438 rect.right = x + width - 1;
439 rect.bottom = y + height - 1;
442 if ((x + width > rect.left) && (y + height > rect.top))
443 res = gdi_FillRect(gdi->drawing->hdc, &rect, brush);
450 return gdi_SetNullClipRgn(gdi->drawing->hdc);
456static BOOL gdi_Glyph_EndDraw(rdpContext* context, WINPR_ATTR_UNUSED INT32 x,
457 WINPR_ATTR_UNUSED INT32 y, WINPR_ATTR_UNUSED INT32 width,
458 WINPR_ATTR_UNUSED INT32 height, WINPR_ATTR_UNUSED UINT32 bgcolor,
459 WINPR_ATTR_UNUSED UINT32 fgcolor)
461 rdpGdi* gdi =
nullptr;
463 if (!context || !context->gdi)
468 if (!gdi->drawing || !gdi->drawing->hdc)
471 return gdi_SetNullClipRgn(gdi->drawing->hdc);
475BOOL gdi_register_graphics(rdpGraphics* graphics)
477 rdpBitmap bitmap = WINPR_C_ARRAY_INIT;
478 rdpGlyph glyph = WINPR_C_ARRAY_INIT;
479 bitmap.size =
sizeof(gdiBitmap);
480 bitmap.New = gdi_Bitmap_New;
481 bitmap.Free = gdi_Bitmap_Free;
482 bitmap.Paint = gdi_Bitmap_Paint;
483 bitmap.Decompress = gdi_Bitmap_Decompress;
484 bitmap.SetSurface = gdi_Bitmap_SetSurface;
485 graphics_register_bitmap(graphics, &bitmap);
486 glyph.size =
sizeof(gdiGlyph);
487 glyph.New = gdi_Glyph_New;
488 glyph.Free = gdi_Glyph_Free;
489 glyph.Draw = gdi_Glyph_Draw;
490 glyph.BeginDraw = gdi_Glyph_BeginDraw;
491 glyph.EndDraw = gdi_Glyph_EndDraw;
492 graphics_register_glyph(graphics, &glyph);
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.