diff --git a/libfreerdp/codec/CMakeLists.txt b/libfreerdp/codec/CMakeLists.txt index 10dac8c5c..9b78f1816 100644 --- a/libfreerdp/codec/CMakeLists.txt +++ b/libfreerdp/codec/CMakeLists.txt @@ -1,5 +1,11 @@ # codec +option(WITH_CURSOR_DUMP "Dump mouse cursor data to binary directory" OFF) +if(WITH_CURSOR_DUMP) + add_compile_definitions(WITH_CURSOR_DUMP) + add_compile_definitions(CURSOR_DUMP_DIR="${CMAKE_CURRENT_BINARY_DIR}") +endif() + set(CODEC_SRCS bulk.c bulk.h diff --git a/libfreerdp/codec/color.c b/libfreerdp/codec/color.c index 0d99fd1e0..609d20df4 100644 --- a/libfreerdp/codec/color.c +++ b/libfreerdp/codec/color.c @@ -43,6 +43,205 @@ #define TAG FREERDP_TAG("color") +static BOOL freerdp_image_copy_from_pointer_data_int( + BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, + UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength, + const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, UINT32 xorBpp, + const gdiPalette* WINPR_RESTRICT palette); + +#if defined(WITH_CURSOR_DUMP) +#include +#include +static char* get_dump_name(char* prefix, size_t len) +{ + static uint64_t count = 0; + _snprintf(prefix, len, "cursor_dump_%08" PRIx64, count++); + + return GetCombinedPath(CURSOR_DUMP_DIR, prefix); +} + +static void dump_binary_data(FILE* fp, const uint8_t* data, size_t len) +{ + if (len > 0) + (void)fprintf(fp, "0x%02" PRIx8, data[0]); + for (size_t x = 1; x < len; x++) + { + (void)fprintf(fp, ", 0x%02" PRIx8, data[x]); + } +} + +static void dump_uint_data(FILE* fp, const uint32_t* data, size_t len) +{ + if (len > 0) + (void)fprintf(fp, "0x%08" PRIx32, data[0]); + for (size_t x = 1; x < len; x++) + { + (void)fprintf(fp, ", 0x%08" PRIx32, data[x]); + } +} + +static void dump_write_header(const char* path, const char* prefix) +{ + char* header = NULL; + size_t headerlen = 0; + winpr_asprintf(&header, &headerlen, "%s.h", path); + if (!header) + return; + FILE* fp = fopen(header, "w"); + free(header); + + if (!fp) + return; + + (void)fprintf(fp, "/* FreeRDP cursor dump to use for unit tests\n"); + (void)fprintf(fp, " * this file was auto generated by %s\n", __func__); + (void)fprintf(fp, " * do not modify manually\n"); + (void)fprintf(fp, " */\n"); + (void)fprintf(fp, "\n"); + (void)fprintf(fp, "#pragma once\n"); + (void)fprintf(fp, "\n"); + (void)fprintf(fp, "#include \n"); + (void)fprintf(fp, "#include \n"); + (void)fprintf(fp, "\n"); + (void)fprintf(fp, "extern const gdiPalette %s_palette;\n", prefix); + (void)fprintf(fp, "extern const rdpPointer %s_pointer;\n", prefix); + (void)fprintf(fp, "extern const uint8_t %s_image_bgra32[];\n", prefix); + fclose(fp); +} + +static void dump_write_c_file(const char* path, const char* prefix, UINT32 nXDst, UINT32 nYDst, + UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT xorMask, + UINT32 xorMaskLength, const BYTE* WINPR_RESTRICT andMask, + UINT32 andMaskLength, UINT32 xorBpp, const gdiPalette* palette, + const uint8_t* bmp) +{ + const uint32_t format = PIXEL_FORMAT_BGRA32; + const uint32_t bpp = FreeRDPGetBytesPerPixel(format); + const uint32_t step = nWidth * bpp; + + char* header = NULL; + size_t headerlen = 0; + winpr_asprintf(&header, &headerlen, "%s.c", path); + if (!header) + return; + FILE* fp = fopen(header, "w"); + free(header); + + if (fp) + { + (void)fprintf(fp, "/* FreeRDP cursor dump to use for unit tests\n"); + (void)fprintf(fp, " * this file was auto generated by %s\n", __func__); + (void)fprintf(fp, " * do not modify manually\n"); + (void)fprintf(fp, " */\n"); + (void)fprintf(fp, "\n"); + (void)fprintf(fp, "#include \"%s.h\"\n", prefix); + (void)fprintf(fp, "\n"); + + (void)fprintf(fp, "static const uint8_t andmask[] = {\n"); + dump_binary_data(fp, andMask, andMaskLength); + (void)fprintf(fp, "};\n"); + (void)fprintf(fp, "\n"); + + (void)fprintf(fp, "static const uint8_t xormask[] = {\n"); + dump_binary_data(fp, xorMask, xorMaskLength); + (void)fprintf(fp, "};\n"); + (void)fprintf(fp, "\n"); + (void)fprintf(fp, "const gdiPalette %s_palette = {\n", prefix); + if (palette) + { + (void)fprintf(fp, ".format=%" PRIu32 ",", palette->format); + (void)fprintf(fp, ".palette={"); + dump_uint_data(fp, palette->palette, ARRAYSIZE(palette->palette)); + (void)fprintf(fp, "}\n"); + } + else + (void)fprintf(fp, "0"); + + (void)fprintf(fp, "};\n"); + + (void)fprintf(fp, "\n"); + (void)fprintf(fp, "const rdpPointer %s_pointer = {\n", prefix); + (void)fprintf(fp, ".size = 0,\n"); + (void)fprintf(fp, ".New = NULL,\n"); + (void)fprintf(fp, ".Free = NULL,\n"); + (void)fprintf(fp, ".Set = NULL,\n"); + (void)fprintf(fp, ".SetNull = NULL,\n"); + (void)fprintf(fp, ".SetDefault = NULL,\n"); + (void)fprintf(fp, ".SetPosition = NULL,\n"); + (void)fprintf(fp, ".paddingA = {0},\n"); + (void)fprintf(fp, ".xPos = %" PRIu32 ",\n", nXDst); + (void)fprintf(fp, ".yPos = %" PRIu32 ",\n", nYDst); + (void)fprintf(fp, ".width = %" PRIu32 ",\n", nWidth); + (void)fprintf(fp, ".height = %" PRIu32 ",\n", nHeight); + (void)fprintf(fp, ".xorBpp = %" PRIu32 ",\n", xorBpp); + (void)fprintf(fp, ".lengthAndMask = ARRAYSIZE(andmask),\n"); + (void)fprintf(fp, ".lengthXorMask = ARRAYSIZE(xormask),\n"); + (void)fprintf(fp, ".xorMaskData = xormask,\n"); + (void)fprintf(fp, ".andMaskData = andmask,\n"); + (void)fprintf(fp, ".paddingB = {0}\n"); + (void)fprintf(fp, "};\n"); + (void)fprintf(fp, "\n"); + (void)fprintf(fp, "const uint8_t %s_image_bgra32[]={\n", prefix); + dump_binary_data(fp, bmp, step * nHeight); + (void)fprintf(fp, "};\n"); + fclose(fp); + } + + wImage* img = winpr_image_new(); + if (img) + { + img->data = WINPR_CAST_CONST_PTR_AWAY(bmp, BYTE*); + img->bitsPerPixel = 32; + img->bytesPerPixel = 4; + img->height = nHeight; + img->width = nWidth; + img->scanline = step; + img->type = WINPR_IMAGE_PNG; + char* imgname = NULL; + size_t imgnamesize = 0; + winpr_asprintf(&imgname, &imgnamesize, "%s.png", path); + if (imgname) + winpr_image_write(img, imgname); + free(imgname); + winpr_image_free(img, FALSE); + } +} + +/** @brief dump a mouse cursor raw data and resulting image. + * + * The whole data is dumped into current binary directory as .c and .h files ready to use + * as unit test. The image data is also stored as png + */ +static void dump_pointer_data(UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, + const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength, + const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, + UINT32 xorBpp, const gdiPalette* palette) +{ + const uint32_t format = PIXEL_FORMAT_BGRA32; + const uint32_t bpp = FreeRDPGetBytesPerPixel(format); + const uint32_t step = nWidth * bpp; + BYTE* bmp = calloc(step * 2, nHeight); + char prefix[64] = { 0 }; + char* path = get_dump_name(prefix, sizeof(prefix)); + + if (!bmp || !path) + goto fail; + + if (!freerdp_image_copy_from_pointer_data_int(bmp, format, step, 0, 0, nWidth, nHeight, xorMask, + xorMaskLength, andMask, andMaskLength, xorBpp, + palette)) + goto fail; + + dump_write_header(path, prefix); + dump_write_c_file(path, prefix, nXDst, nYDst, nWidth, nHeight, xorMask, xorMaskLength, andMask, + andMaskLength, xorBpp, palette, bmp); + +fail: + free(bmp); + free(path); +} +#endif + BYTE* freerdp_glyph_convert(UINT32 width, UINT32 height, const BYTE* WINPR_RESTRICT data) { /* @@ -520,12 +719,11 @@ static BOOL freerdp_image_copy_from_pointer_data_xbpp( * http://msdn.microsoft.com/en-us/library/windows/hardware/ff556138/ */ -BOOL freerdp_image_copy_from_pointer_data(BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, - UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, - UINT32 nWidth, UINT32 nHeight, - const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength, - const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, - UINT32 xorBpp, const gdiPalette* WINPR_RESTRICT palette) +BOOL freerdp_image_copy_from_pointer_data_int( + BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, + UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength, + const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, UINT32 xorBpp, + const gdiPalette* WINPR_RESTRICT palette) { UINT32 dstBitsPerPixel = 0; UINT32 dstBytesPerPixel = 0; @@ -563,6 +761,22 @@ BOOL freerdp_image_copy_from_pointer_data(BYTE* WINPR_RESTRICT pDstData, UINT32 } } +BOOL freerdp_image_copy_from_pointer_data(BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, + UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, + UINT32 nWidth, UINT32 nHeight, + const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength, + const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, + UINT32 xorBpp, const gdiPalette* WINPR_RESTRICT palette) +{ +#if defined(WITH_CURSOR_DUMP) + dump_pointer_data(nXDst, nYDst, nWidth, nHeight, xorMask, xorMaskLength, andMask, andMaskLength, + xorBpp, palette); +#endif + return freerdp_image_copy_from_pointer_data_int(pDstData, DstFormat, nDstStep, nXDst, nYDst, + nWidth, nHeight, xorMask, xorMaskLength, + andMask, andMaskLength, xorBpp, palette); +} + static INLINE BOOL overlapping(const BYTE* pDstData, UINT32 nYDst, UINT32 nDstStep, const BYTE* pSrcData, UINT32 nYSrc, UINT32 nSrcStep, UINT32 nHeight) {