FreeRDP
Loading...
Searching...
No Matches
color.c
1
22#include <freerdp/config.h>
23
24#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27
28#include <winpr/crt.h>
29
30#include <freerdp/log.h>
31#include <freerdp/freerdp.h>
32#include <freerdp/primitives.h>
33
34#if defined(WITH_CAIRO)
35#include <cairo.h>
36#endif
37
38#if defined(WITH_SWSCALE)
39#include "image_ffmpeg.h"
40#endif
41
42#include "color.h"
43
44#define TAG FREERDP_TAG("color")
45
46static BOOL freerdp_image_copy_from_pointer_data_int(
47 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
48 UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
49 const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, UINT32 xorBpp,
50 const gdiPalette* WINPR_RESTRICT palette);
51
52#if defined(WITH_CURSOR_DUMP)
53#include <winpr/path.h>
54#include <winpr/image.h>
55
56WINPR_ATTR_MALLOC(free, 1)
57static char* get_dump_name(char* prefix, size_t len)
58{
59 static uint64_t count = 0;
60 if (_snprintf(prefix, len, "cursor_dump_%08" PRIx64, count++) < 0)
61 return nullptr;
62
63 return GetCombinedPath(CURSOR_DUMP_DIR, prefix);
64}
65
66static void dump_binary_data(FILE* fp, const uint8_t* data, size_t len)
67{
68 if (len > 0)
69 (void)fprintf(fp, "0x%02" PRIx8, data[0]);
70 for (size_t x = 1; x < len; x++)
71 {
72 (void)fprintf(fp, ", 0x%02" PRIx8, data[x]);
73 }
74}
75
76static void dump_uint_data(FILE* fp, const uint32_t* data, size_t len)
77{
78 if (len > 0)
79 (void)fprintf(fp, "0x%08" PRIx32, data[0]);
80 for (size_t x = 1; x < len; x++)
81 {
82 (void)fprintf(fp, ", 0x%08" PRIx32, data[x]);
83 }
84}
85
86static void dump_write_header(const char* path, const char* prefix)
87{
88 char* header = nullptr;
89 size_t headerlen = 0;
90 winpr_asprintf(&header, &headerlen, "%s.h", path);
91 if (!header)
92 return;
93 FILE* fp = fopen(header, "w");
94 free(header);
95
96 if (!fp)
97 return;
98
99 (void)fprintf(fp, "/* FreeRDP cursor dump to use for unit tests\n");
100 (void)fprintf(fp, " * this file was auto generated by %s\n", __func__);
101 (void)fprintf(fp, " * do not modify manually\n");
102 (void)fprintf(fp, " */\n");
103 (void)fprintf(fp, "\n");
104 (void)fprintf(fp, "#pragma once\n");
105 (void)fprintf(fp, "\n");
106 (void)fprintf(fp, "#include <freerdp/codec/color.h>\n");
107 (void)fprintf(fp, "#include <freerdp/graphics.h>\n");
108 (void)fprintf(fp, "\n");
109 (void)fprintf(fp, "extern const gdiPalette %s_palette;\n", prefix);
110 (void)fprintf(fp, "extern const rdpPointer %s_pointer;\n", prefix);
111 (void)fprintf(fp, "extern const uint8_t %s_image_bgra32[];\n", prefix);
112 fclose(fp);
113}
114
115static void dump_write_c_file(const char* path, const char* prefix, UINT32 nXDst, UINT32 nYDst,
116 UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT xorMask,
117 UINT32 xorMaskLength, const BYTE* WINPR_RESTRICT andMask,
118 UINT32 andMaskLength, UINT32 xorBpp, const gdiPalette* palette,
119 const uint8_t* bmp)
120{
121 const uint32_t format = PIXEL_FORMAT_BGRA32;
122 const uint32_t bpp = FreeRDPGetBytesPerPixel(format);
123 const uint32_t step = nWidth * bpp;
124
125 char* header = nullptr;
126 size_t headerlen = 0;
127 winpr_asprintf(&header, &headerlen, "%s.c", path);
128 if (!header)
129 return;
130 FILE* fp = fopen(header, "w");
131 free(header);
132
133 if (fp)
134 {
135 (void)fprintf(fp, "/* FreeRDP cursor dump to use for unit tests\n");
136 (void)fprintf(fp, " * this file was auto generated by %s\n", __func__);
137 (void)fprintf(fp, " * do not modify manually\n");
138 (void)fprintf(fp, " */\n");
139 (void)fprintf(fp, "\n");
140 (void)fprintf(fp, "#include \"%s.h\"\n", prefix);
141 (void)fprintf(fp, "\n");
142
143 (void)fprintf(fp, "static const uint8_t andmask[] = {\n");
144 dump_binary_data(fp, andMask, andMaskLength);
145 (void)fprintf(fp, "};\n");
146 (void)fprintf(fp, "\n");
147
148 (void)fprintf(fp, "static const uint8_t xormask[] = {\n");
149 dump_binary_data(fp, xorMask, xorMaskLength);
150 (void)fprintf(fp, "};\n");
151 (void)fprintf(fp, "\n");
152 (void)fprintf(fp, "const gdiPalette %s_palette = {\n", prefix);
153 if (palette)
154 {
155 (void)fprintf(fp, ".format=%" PRIu32 ",", palette->format);
156 (void)fprintf(fp, ".palette={");
157 dump_uint_data(fp, palette->palette, ARRAYSIZE(palette->palette));
158 (void)fprintf(fp, "}\n");
159 }
160 else
161 (void)fprintf(fp, "0");
162
163 (void)fprintf(fp, "};\n");
164
165 (void)fprintf(fp, "\n");
166 (void)fprintf(fp, "const rdpPointer %s_pointer = {\n", prefix);
167 (void)fprintf(fp, ".size = 0,\n");
168 (void)fprintf(fp, ".New = nullptr,\n");
169 (void)fprintf(fp, ".Free = nullptr,\n");
170 (void)fprintf(fp, ".Set = nullptr,\n");
171 (void)fprintf(fp, ".SetNull = nullptr,\n");
172 (void)fprintf(fp, ".SetDefault = nullptr,\n");
173 (void)fprintf(fp, ".SetPosition = nullptr,\n");
174 (void)fprintf(fp, ".paddingA = {0},\n");
175 (void)fprintf(fp, ".xPos = %" PRIu32 ",\n", nXDst);
176 (void)fprintf(fp, ".yPos = %" PRIu32 ",\n", nYDst);
177 (void)fprintf(fp, ".width = %" PRIu32 ",\n", nWidth);
178 (void)fprintf(fp, ".height = %" PRIu32 ",\n", nHeight);
179 (void)fprintf(fp, ".xorBpp = %" PRIu32 ",\n", xorBpp);
180 (void)fprintf(fp, ".lengthAndMask = ARRAYSIZE(andmask),\n");
181 (void)fprintf(fp, ".lengthXorMask = ARRAYSIZE(xormask),\n");
182 (void)fprintf(fp, ".xorMaskData = xormask,\n");
183 (void)fprintf(fp, ".andMaskData = andmask,\n");
184 (void)fprintf(fp, ".paddingB = {0}\n");
185 (void)fprintf(fp, "};\n");
186 (void)fprintf(fp, "\n");
187 (void)fprintf(fp, "const uint8_t %s_image_bgra32[]={\n", prefix);
188 dump_binary_data(fp, bmp, step * nHeight);
189 (void)fprintf(fp, "};\n");
190 fclose(fp);
191 }
192
193 wImage* img = winpr_image_new();
194 if (img)
195 {
196 img->data = WINPR_CAST_CONST_PTR_AWAY(bmp, BYTE*);
197 img->bitsPerPixel = 32;
198 img->bytesPerPixel = 4;
199 img->height = nHeight;
200 img->width = nWidth;
201 img->scanline = step;
202 img->type = WINPR_IMAGE_PNG;
203 char* imgname = nullptr;
204 size_t imgnamesize = 0;
205 winpr_asprintf(&imgname, &imgnamesize, "%s.png", path);
206 if (imgname)
207 winpr_image_write(img, imgname);
208 free(imgname);
209 winpr_image_free(img, FALSE);
210 }
211}
212
218static void dump_pointer_data(UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight,
219 const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
220 const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength,
221 UINT32 xorBpp, const gdiPalette* palette)
222{
223 const uint32_t format = PIXEL_FORMAT_BGRA32;
224 const uint32_t bpp = FreeRDPGetBytesPerPixel(format);
225 const uint32_t step = nWidth * bpp;
226 BYTE* bmp = calloc(step * 2, nHeight);
227 char prefix[64] = WINPR_C_ARRAY_INIT;
228 char* path = get_dump_name(prefix, sizeof(prefix));
229
230 if (!bmp || !path)
231 goto fail;
232
233 if (!freerdp_image_copy_from_pointer_data_int(bmp, format, step, 0, 0, nWidth, nHeight, xorMask,
234 xorMaskLength, andMask, andMaskLength, xorBpp,
235 palette))
236 goto fail;
237
238 dump_write_header(path, prefix);
239 dump_write_c_file(path, prefix, nXDst, nYDst, nWidth, nHeight, xorMask, xorMaskLength, andMask,
240 andMaskLength, xorBpp, palette, bmp);
241
242fail:
243 free(bmp);
244 free(path);
245}
246#endif
247
248#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
249BYTE* freerdp_glyph_convert(UINT32 width, UINT32 height, const BYTE* WINPR_RESTRICT data)
250{
251 const size_t scanline = (width + 7ull) / 8ull;
252 const size_t required = scanline * height;
253 return freerdp_glyph_convert_ex(width, height, data, required);
254}
255#endif
256
257BYTE* freerdp_glyph_convert_ex(UINT32 width, UINT32 height, const BYTE* WINPR_RESTRICT data,
258 size_t len)
259{
260 /*
261 * converts a 1-bit-per-pixel glyph to a one-byte-per-pixel glyph:
262 * this approach uses a little more memory, but provides faster
263 * means of accessing individual pixels in blitting operations
264 */
265 const size_t scanline = (width + 7ull) / 8ull;
266 const size_t required = scanline * height;
267 if (len < required)
268 return nullptr;
269
270 if ((len == 0) || (width == 0) || (height == 0))
271 return nullptr;
272
273 WINPR_ASSERT(data);
274
275 BYTE* dstData = (BYTE*)winpr_aligned_malloc(1ull * width * height, 16);
276
277 if (!dstData)
278 return nullptr;
279
280 ZeroMemory(dstData, 1ULL * width * height);
281 BYTE* dstp = dstData;
282
283 for (UINT32 y = 0; y < height; y++)
284 {
285 const BYTE* srcp = &data[1ull * y * scanline];
286
287 for (UINT32 x = 0; x < width; x++)
288 {
289 if ((*srcp & (0x80 >> (x % 8))) != 0)
290 *dstp = 0xFF;
291
292 dstp++;
293
294 if (((x + 1) % 8 == 0) && x != 0)
295 srcp++;
296 }
297 }
298
299 return dstData;
300}
301
302BOOL freerdp_image_copy_from_monochrome(BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
303 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
304 UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData,
305 UINT32 backColor, UINT32 foreColor,
306 const gdiPalette* WINPR_RESTRICT palette)
307{
308 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
309 return FALSE;
310 const UINT32 dstBytesPerPixel = FreeRDPGetBytesPerPixel(DstFormat);
311
312 if (!pDstData || !pSrcData || !palette)
313 return FALSE;
314
315 if (nDstStep == 0)
316 nDstStep = dstBytesPerPixel * nWidth;
317
318 WINPR_ASSERT(1ull * nXDst + nWidth <= UINT32_MAX);
319 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nXDst + nWidth);
320
321 const UINT32 monoStep = (nWidth + 7) / 8;
322
323 for (size_t y = 0; y < nHeight; y++)
324 {
325 BYTE* pDstLine = &pDstData[((nYDst + y) * nDstStep)];
326 UINT32 monoBit = 0x80;
327 const BYTE* monoBits = &pSrcData[monoStep * y];
328
329 for (size_t x = 0; x < nWidth; x++)
330 {
331 BYTE* pDstPixel = &pDstLine[((nXDst + x) * FreeRDPGetBytesPerPixel(DstFormat))];
332 BOOL monoPixel = (*monoBits & monoBit) != 0;
333
334 if (!(monoBit >>= 1))
335 {
336 monoBits++;
337 monoBit = 0x80;
338 }
339
340 if (monoPixel)
341 {
342 if (!FreeRDPWriteColor_int(pDstPixel, DstFormat, backColor))
343 return FALSE;
344 }
345 else if (!FreeRDPWriteColor_int(pDstPixel, DstFormat, foreColor))
346 return FALSE;
347 }
348 }
349
350 return TRUE;
351}
352
353static inline UINT32 freerdp_image_inverted_pointer_color(UINT32 x, UINT32 y, UINT32 format)
354{
364 BYTE fill = (x + y) & 1 ? 0x00 : 0xFF;
365 return FreeRDPGetColor(format, fill, fill, fill, 0xFF);
366}
367
368/*
369 * DIB color palettes are arrays of RGBQUAD structs with colors in BGRX format.
370 * They are used only by 1, 2, 4, and 8-bit bitmaps.
371 */
372static void fill_gdi_palette_for_icon(const BYTE* colorTable, UINT16 cbColorTable,
373 gdiPalette* palette)
374{
375 WINPR_ASSERT(palette);
376
377 palette->format = PIXEL_FORMAT_BGRX32;
378 ZeroMemory(palette->palette, sizeof(palette->palette));
379
380 if (!cbColorTable)
381 return;
382
383 if ((cbColorTable % 4 != 0) || (cbColorTable / 4 > 256))
384 {
385 WLog_WARN(TAG, "weird palette size: %u", cbColorTable);
386 return;
387 }
388
389 for (UINT16 i = 0; i < cbColorTable / 4; i++)
390 {
391 palette->palette[i] = FreeRDPReadColor_int(&colorTable[4ULL * i], palette->format);
392 }
393}
394
395static inline UINT32 div_ceil(UINT32 a, UINT32 b)
396{
397 return (a + (b - 1)) / b;
398}
399
400static inline UINT32 round_up(UINT32 a, UINT32 b)
401{
402 return b * div_ceil(a, b);
403}
404
405BOOL freerdp_image_copy_from_icon_data(BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
406 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT16 nWidth,
407 UINT16 nHeight, const BYTE* WINPR_RESTRICT bitsColor,
408 UINT16 cbBitsColor, const BYTE* WINPR_RESTRICT bitsMask,
409 UINT16 cbBitsMask, const BYTE* WINPR_RESTRICT colorTable,
410 UINT16 cbColorTable, UINT32 bpp)
411{
412 DWORD format = 0;
413 gdiPalette palette;
414
415 if (!pDstData || !bitsColor)
416 return FALSE;
417
418 if ((nWidth == 0) || (nHeight == 0))
419 return TRUE;
420 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
421 return FALSE;
422
423 WINPR_ASSERT((nDstStep == 0) || (nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nWidth));
424
425 /*
426 * Color formats used by icons are DIB bitmap formats (2-bit format
427 * is not used by MS-RDPERP). Note that 16-bit is RGB555, not RGB565,
428 * and that 32-bit format uses BGRA order.
429 */
430 switch (bpp)
431 {
432 case 1:
433 case 4:
434 /*
435 * These formats are not supported by freerdp_image_copy().
436 * PIXEL_FORMAT_MONO and PIXEL_FORMAT_A4 are *not* correct
437 * color formats for this. Please fix freerdp_image_copy()
438 * if you came here to fix a broken icon of some weird app
439 * that still uses 1 or 4bpp format in the 21st century.
440 */
441 WLog_WARN(TAG, "1bpp and 4bpp icons are not supported");
442 return FALSE;
443
444 case 8:
445 format = PIXEL_FORMAT_RGB8;
446 break;
447
448 case 16:
449 format = PIXEL_FORMAT_RGB15;
450 break;
451
452 case 24:
453 format = PIXEL_FORMAT_RGB24;
454 break;
455
456 case 32:
457 format = PIXEL_FORMAT_BGRA32;
458 break;
459
460 default:
461 WLog_WARN(TAG, "invalid icon bpp: %" PRIu32, bpp);
462 return FALSE;
463 }
464
465 /* Ensure we have enough source data bytes for image copy. */
466 if ((1ul * cbBitsColor) / nHeight < (1ul * FreeRDPGetBytesPerPixel(format) * nWidth))
467 {
468 WLog_ERR(TAG,
469 "cbBitsColor{%" PRIu16 "} < nWidth{%" PRIu16 "} * nHeight{%" PRIu16
470 "} * bpp{%" PRIu32 "}",
471 cbBitsColor, nWidth, nHeight, FreeRDPGetBytesPerPixel(format));
472 return FALSE;
473 }
474
475 fill_gdi_palette_for_icon(colorTable, cbColorTable, &palette);
476 if (!freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
477 bitsColor, format, 0, 0, 0, &palette, FREERDP_FLIP_VERTICAL))
478 return FALSE;
479
480 /* apply alpha mask */
481 if (FreeRDPColorHasAlpha(DstFormat) && (cbBitsMask > 0))
482 {
483 BYTE* dstBuf = pDstData;
484 UINT32 dstBpp = FreeRDPGetBytesPerPixel(DstFormat);
485
486 /*
487 * Each byte encodes 8 adjacent pixels (with LSB padding as needed).
488 * And due to hysterical raisins, stride of DIB bitmaps must be
489 * a multiple of 4 bytes.
490 */
491 const size_t stride = round_up(div_ceil(nWidth, 8), 4);
492 const size_t maskSize = stride * (nHeight - 1ULL) + div_ceil(nWidth, 8);
493 if (cbBitsMask < maskSize)
494 {
495 WLog_ERR(TAG, "cbBitsMask{%" PRIu32 "} < required mask size{%" PRIuz "}", cbBitsMask,
496 maskSize);
497 return FALSE;
498 }
499
500 for (UINT32 y = 0; y < nHeight; y++)
501 {
502 const BYTE* maskByte = &bitsMask[stride * (nHeight - 1ULL - y)];
503 BYTE nextBit = 0x80;
504
505 for (UINT32 x = 0; x < nWidth; x++)
506 {
507 BYTE r = 0;
508 BYTE g = 0;
509 BYTE b = 0;
510 BYTE alpha = (*maskByte & nextBit) ? 0x00 : 0xFF;
511
512 /* read color back, add alpha and write it back */
513 UINT32 color = FreeRDPReadColor_int(dstBuf, DstFormat);
514 FreeRDPSplitColor(color, DstFormat, &r, &g, &b, nullptr, &palette);
515 color = FreeRDPGetColor(DstFormat, r, g, b, alpha);
516 if (!FreeRDPWriteColor_int(dstBuf, DstFormat, color))
517 return FALSE;
518
519 nextBit >>= 1;
520 dstBuf += dstBpp;
521 if (!nextBit)
522 {
523 nextBit = 0x80;
524 maskByte++;
525 }
526 }
527 }
528 }
529
530 return TRUE;
531}
532
533static BOOL freerdp_image_copy_from_pointer_data_1bpp(
534 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
535 UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
536 const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, UINT32 xorBpp)
537{
538 BOOL vFlip = 0;
539 UINT32 xorStep = 0;
540 UINT32 andStep = 0;
541 UINT32 xorBit = 0;
542 UINT32 andBit = 0;
543 UINT32 xorPixel = 0;
544 UINT32 andPixel = 0;
545
546 vFlip = (xorBpp != 1);
547 andStep = (nWidth + 7) / 8;
548 andStep += (andStep % 2);
549
550 if (!xorMask || (xorMaskLength == 0))
551 return FALSE;
552 if (!andMask || (andMaskLength == 0))
553 return FALSE;
554
555 xorStep = (nWidth + 7) / 8;
556 xorStep += (xorStep % 2);
557
558 if (xorStep * nHeight > xorMaskLength)
559 return FALSE;
560
561 if (andStep * nHeight > andMaskLength)
562 return FALSE;
563
564 for (UINT32 y = 0; y < nHeight; y++)
565 {
566 const BYTE* andBits = nullptr;
567 const BYTE* xorBits = nullptr;
568 BYTE* pDstPixel = &pDstData[((1ULL * nYDst + y) * nDstStep) +
569 (1ULL * nXDst * FreeRDPGetBytesPerPixel(DstFormat))];
570 xorBit = andBit = 0x80;
571
572 if (!vFlip)
573 {
574 xorBits = &xorMask[1ULL * xorStep * y];
575 andBits = &andMask[1ULL * andStep * y];
576 }
577 else
578 {
579 xorBits = &xorMask[1ULL * xorStep * (nHeight - y - 1)];
580 andBits = &andMask[1ULL * andStep * (nHeight - y - 1)];
581 }
582
583 for (UINT32 x = 0; x < nWidth; x++)
584 {
585 UINT32 color = 0;
586 xorPixel = (*xorBits & xorBit) ? 1 : 0;
587
588 if (!(xorBit >>= 1))
589 {
590 xorBits++;
591 xorBit = 0x80;
592 }
593
594 andPixel = (*andBits & andBit) ? 1 : 0;
595
596 if (!(andBit >>= 1))
597 {
598 andBits++;
599 andBit = 0x80;
600 }
601
602 if (!andPixel && !xorPixel)
603 color = FreeRDPGetColor(DstFormat, 0, 0, 0, 0xFF); /* black */
604 else if (!andPixel && xorPixel)
605 color = FreeRDPGetColor(DstFormat, 0xFF, 0xFF, 0xFF, 0xFF); /* white */
606 else if (andPixel && !xorPixel)
607 color = FreeRDPGetColor(DstFormat, 0, 0, 0, 0); /* transparent */
608 else if (andPixel && xorPixel)
609 color = freerdp_image_inverted_pointer_color(x, y, DstFormat); /* inverted */
610
611 if (!FreeRDPWriteColor_int(pDstPixel, DstFormat, color))
612 return FALSE;
613 pDstPixel += FreeRDPGetBytesPerPixel(DstFormat);
614 }
615 }
616
617 return TRUE;
618}
619
620static BOOL freerdp_image_copy_from_pointer_data_xbpp(
621 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
622 UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
623 const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, UINT32 xorBpp,
624 const gdiPalette* palette)
625{
626 BOOL vFlip = 0;
627 size_t xorStep = 0;
628 size_t andStep = 0;
629 UINT32 andBit = 0;
630 UINT32 xorPixel = 0;
631 UINT32 andPixel = 0;
632 UINT32 dstBitsPerPixel = 0;
633 UINT32 xorBytesPerPixel = 0;
634 dstBitsPerPixel = FreeRDPGetBitsPerPixel(DstFormat);
635
636 vFlip = (xorBpp != 1);
637 andStep = (nWidth + 7) / 8;
638 andStep += (andStep % 2);
639
640 if (!xorMask || (xorMaskLength == 0))
641 return FALSE;
642
643 xorBytesPerPixel = xorBpp >> 3;
644 xorStep = 1ULL * nWidth * xorBytesPerPixel;
645 xorStep += (xorStep % 2);
646
647 if (xorBpp == 8 && !palette)
648 {
649 WLog_ERR(TAG, "null palette in conversion from %" PRIu32 " bpp to %" PRIu32 " bpp", xorBpp,
650 dstBitsPerPixel);
651 return FALSE;
652 }
653
654 if (xorStep * nHeight > xorMaskLength)
655 return FALSE;
656
657 if (andMask)
658 {
659 if (andStep * nHeight > andMaskLength)
660 return FALSE;
661 }
662
663 for (UINT32 y = 0; y < nHeight; y++)
664 {
665 const BYTE* xorBits = nullptr;
666 const BYTE* andBits = nullptr;
667 BYTE* pDstPixel = &pDstData[((1ULL * nYDst + y) * nDstStep) +
668 (1ULL * nXDst * FreeRDPGetBytesPerPixel(DstFormat))];
669 andBit = 0x80;
670
671 if (!vFlip)
672 {
673 if (andMask)
674 andBits = &andMask[andStep * y];
675
676 xorBits = &xorMask[xorStep * y];
677 }
678 else
679 {
680 if (andMask)
681 andBits = &andMask[1ULL * andStep * (nHeight - y - 1)];
682
683 xorBits = &xorMask[1ULL * xorStep * (nHeight - y - 1)];
684 }
685
686 for (UINT32 x = 0; x < nWidth; x++)
687 {
688 UINT32 pixelFormat = 0;
689 UINT32 color = 0;
690
691 andPixel = 0;
692
693 if (andMask)
694 {
695 andPixel = (*andBits & andBit) ? 1 : 0;
696
697 if (!(andBit >>= 1))
698 {
699 andBits++;
700 andBit = 0x80;
701 }
702 }
703
704 if (xorBpp == 32)
705 {
706 pixelFormat = PIXEL_FORMAT_BGRA32;
707 xorPixel = FreeRDPReadColor_int(xorBits, pixelFormat);
708 }
709 else if (xorBpp == 16)
710 {
711 pixelFormat = PIXEL_FORMAT_RGB15;
712 xorPixel = FreeRDPReadColor_int(xorBits, pixelFormat);
713 }
714 else if (xorBpp == 8)
715 {
716 pixelFormat = palette->format;
717 xorPixel = palette->palette[xorBits[0]];
718 }
719 else
720 {
721 pixelFormat = PIXEL_FORMAT_BGR24;
722 xorPixel = FreeRDPReadColor_int(xorBits, pixelFormat);
723
724 if (andPixel)
725 {
726 if (xorPixel == 0x00FFFFFFUL)
727 xorPixel |= 0xFF000000UL;
728 else
729 xorPixel = 0;
730 }
731 else
732 xorPixel |= 0xFF000000UL;
733
734 // We need a transparent default alpha value, so use a different format here
735 pixelFormat = PIXEL_FORMAT_ABGR32;
736 }
737
738 xorPixel = FreeRDPConvertColor(xorPixel, pixelFormat, PIXEL_FORMAT_ARGB32, palette);
739 xorBits += xorBytesPerPixel;
740
741 if (andPixel)
742 {
743 if (xorPixel == 0xFF000000UL) /* black -> transparent */
744 xorPixel = 0x00000000;
745 else if (xorPixel == 0xFFFFFFFFUL) /* white -> inverted */
746 xorPixel = freerdp_image_inverted_pointer_color(x, y, PIXEL_FORMAT_ARGB32);
747 }
748
749 color = FreeRDPConvertColor(xorPixel, PIXEL_FORMAT_ARGB32, DstFormat, palette);
750 if (!FreeRDPWriteColor_int(pDstPixel, DstFormat, color))
751 return FALSE;
752 pDstPixel += FreeRDPGetBytesPerPixel(DstFormat);
753 }
754 }
755
756 return TRUE;
757}
758
767BOOL freerdp_image_copy_from_pointer_data_int(
768 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
769 UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
770 const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength, UINT32 xorBpp,
771 const gdiPalette* WINPR_RESTRICT palette)
772{
773 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
774 return FALSE;
775
776 UINT32 dstBitsPerPixel = FreeRDPGetBitsPerPixel(DstFormat);
777 UINT32 dstBytesPerPixel = FreeRDPGetBytesPerPixel(DstFormat);
778
779 WINPR_ASSERT(1ull * nXDst + nWidth <= UINT32_MAX);
780 if (nDstStep <= 0)
781 nDstStep = dstBytesPerPixel * (1ull * nXDst + nWidth);
782
783 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= (1ull * nXDst + nWidth));
784
785 for (UINT32 y = nYDst; y < nHeight; y++)
786 {
787 BYTE* WINPR_RESTRICT pDstLine = &pDstData[y * nDstStep + nXDst * dstBytesPerPixel];
788 memset(pDstLine, 0, 1ull * dstBytesPerPixel * (nWidth - nXDst));
789 }
790
791 switch (xorBpp)
792 {
793 case 1:
794 return freerdp_image_copy_from_pointer_data_1bpp(
795 pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, xorMask,
796 xorMaskLength, andMask, andMaskLength, xorBpp);
797
798 case 8:
799 case 16:
800 case 24:
801 case 32:
802 return freerdp_image_copy_from_pointer_data_xbpp(
803 pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, xorMask,
804 xorMaskLength, andMask, andMaskLength, xorBpp, palette);
805
806 default:
807 WLog_ERR(TAG, "failed to convert from %" PRIu32 " bpp to %" PRIu32 " bpp", xorBpp,
808 dstBitsPerPixel);
809 return FALSE;
810 }
811}
812
813BOOL freerdp_image_copy_from_pointer_data(BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat,
814 UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
815 UINT32 nWidth, UINT32 nHeight,
816 const BYTE* WINPR_RESTRICT xorMask, UINT32 xorMaskLength,
817 const BYTE* WINPR_RESTRICT andMask, UINT32 andMaskLength,
818 UINT32 xorBpp, const gdiPalette* WINPR_RESTRICT palette)
819{
820#if defined(WITH_CURSOR_DUMP)
821 dump_pointer_data(nXDst, nYDst, nWidth, nHeight, xorMask, xorMaskLength, andMask, andMaskLength,
822 xorBpp, palette);
823#endif
824 return freerdp_image_copy_from_pointer_data_int(pDstData, DstFormat, nDstStep, nXDst, nYDst,
825 nWidth, nHeight, xorMask, xorMaskLength,
826 andMask, andMaskLength, xorBpp, palette);
827}
828
829static inline BOOL overlapping(const BYTE* pDstData, UINT32 nYDst, UINT32 nDstStep,
830 const BYTE* pSrcData, UINT32 nYSrc, UINT32 nSrcStep, UINT32 nHeight)
831{
832 const uintptr_t src = (uintptr_t)pSrcData;
833 const uintptr_t srcstart = src + 1ULL * nSrcStep * nYSrc;
834 const uintptr_t srcend = srcstart + 1ULL * nSrcStep * nHeight;
835 const uintptr_t dst = (uintptr_t)pDstData;
836 const uintptr_t dststart = dst + 1ULL * nDstStep * nYDst;
837 const uintptr_t dstend = dststart + 1ULL * nDstStep * nHeight;
838
839 WINPR_ASSERT(nDstStep > 0);
840 WINPR_ASSERT(nSrcStep > 0);
841 if ((dststart >= srcstart) && (dststart < srcend))
842 return TRUE;
843
844 if ((dstend > srcstart) && (dstend <= srcend))
845 return TRUE;
846
847 return FALSE;
848}
849
850static inline BOOL freerdp_image_copy_bgr24_bgrx32(BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep,
851 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
852 UINT32 nHeight,
853 const BYTE* WINPR_RESTRICT pSrcData,
854 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
855 int64_t srcVMultiplier, int64_t srcVOffset,
856 int64_t dstVMultiplier, int64_t dstVOffset)
857{
858
859 const int64_t srcByte = 3;
860 const int64_t dstByte = 4;
861
862 for (int64_t y = 0; y < nHeight; y++)
863 {
864 const BYTE* WINPR_RESTRICT srcLine =
865 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
866 BYTE* WINPR_RESTRICT dstLine =
867 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
868
869 for (int64_t x = 0; x < nWidth; x++)
870 {
871 dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
872 dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
873 dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
874 }
875 }
876
877 return TRUE;
878}
879
880static inline BOOL freerdp_image_copy_bgrx32_bgrx32(BYTE* WINPR_RESTRICT pDstData, UINT32 nDstStep,
881 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
882 UINT32 nHeight,
883 const BYTE* WINPR_RESTRICT pSrcData,
884 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
885 int64_t srcVMultiplier, int64_t srcVOffset,
886 int64_t dstVMultiplier, int64_t dstVOffset)
887{
888
889 const int64_t srcByte = 4;
890 const int64_t dstByte = 4;
891
892 for (int64_t y = 0; y < nHeight; y++)
893 {
894 const BYTE* WINPR_RESTRICT srcLine =
895 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
896 BYTE* WINPR_RESTRICT dstLine =
897 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
898
899 for (int64_t x = 0; x < nWidth; x++)
900 {
901 dstLine[(x + nXDst) * dstByte + 0] = srcLine[(x + nXSrc) * srcByte + 0];
902 dstLine[(x + nXDst) * dstByte + 1] = srcLine[(x + nXSrc) * srcByte + 1];
903 dstLine[(x + nXDst) * dstByte + 2] = srcLine[(x + nXSrc) * srcByte + 2];
904 }
905 }
906
907 return TRUE;
908}
909
910static inline BOOL freerdp_image_copy_generic(
911 BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
912 UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcFormat,
913 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* WINPR_RESTRICT palette,
914 int64_t srcVMultiplier, int64_t srcVOffset, int64_t dstVMultiplier, int64_t dstVOffset)
915{
916
917 const int64_t srcByte = 4;
918 const int64_t dstByte = 4;
919
920 for (int64_t y = 0; y < nHeight; y++)
921 {
922 const BYTE* WINPR_RESTRICT srcLine =
923 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
924 BYTE* WINPR_RESTRICT dstLine =
925 &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
926
927 UINT32 color = FreeRDPReadColor_int(&srcLine[nXSrc * srcByte], SrcFormat);
928 UINT32 oldColor = color;
929 UINT32 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
930 if (!FreeRDPWriteColorIgnoreAlpha_int(&dstLine[nXDst * dstByte], DstFormat, dstColor))
931 return FALSE;
932
933 for (int64_t x = 1; x < nWidth; x++)
934 {
935 color = FreeRDPReadColor_int(&srcLine[(x + nXSrc) * srcByte], SrcFormat);
936 if (color == oldColor)
937 {
938 if (!FreeRDPWriteColorIgnoreAlpha_int(&dstLine[(x + nXDst) * dstByte], DstFormat,
939 dstColor))
940 return FALSE;
941 }
942 else
943 {
944 oldColor = color;
945 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
946 if (!FreeRDPWriteColorIgnoreAlpha_int(&dstLine[(x + nXDst) * dstByte], DstFormat,
947 dstColor))
948 return FALSE;
949 }
950 }
951 }
952
953 return TRUE;
954}
955
956static inline BOOL freerdp_image_copy_no_overlap_dst_alpha(
957 BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
958 UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
959 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* WINPR_RESTRICT palette,
960 int64_t srcVMultiplier, int64_t srcVOffset, int64_t dstVMultiplier, int64_t dstVOffset)
961{
962 WINPR_ASSERT(pDstData);
963 WINPR_ASSERT(pSrcData);
964
965 switch (SrcFormat)
966 {
967 case PIXEL_FORMAT_BGR24:
968 switch (DstFormat)
969 {
970 case PIXEL_FORMAT_BGRX32:
971 case PIXEL_FORMAT_BGRA32:
972 return freerdp_image_copy_bgr24_bgrx32(
973 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
974 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
975 default:
976 break;
977 }
978 break;
979 case PIXEL_FORMAT_BGRX32:
980 case PIXEL_FORMAT_BGRA32:
981 switch (DstFormat)
982 {
983 case PIXEL_FORMAT_BGRX32:
984 case PIXEL_FORMAT_BGRA32:
985 return freerdp_image_copy_bgrx32_bgrx32(
986 pDstData, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, nSrcStep,
987 nXSrc, nYSrc, srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
988 default:
989 break;
990 }
991 break;
992 default:
993 break;
994 }
995
996 return freerdp_image_copy_generic(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
997 pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette,
998 srcVMultiplier, srcVOffset, dstVMultiplier, dstVOffset);
999}
1000
1001BOOL freerdp_image_copy_overlap(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst,
1002 UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, const BYTE* pSrcData,
1003 DWORD SrcFormat, UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
1004 const gdiPalette* WINPR_RESTRICT palette, UINT32 flags)
1005{
1006 const UINT32 dstByte = FreeRDPGetBytesPerPixel(DstFormat);
1007 const UINT32 srcByte = FreeRDPGetBytesPerPixel(SrcFormat);
1008 const UINT32 copyDstWidth = nWidth * dstByte;
1009 const UINT32 xSrcOffset = nXSrc * srcByte;
1010 const UINT32 xDstOffset = nXDst * dstByte;
1011 const BOOL vSrcVFlip = (flags & FREERDP_FLIP_VERTICAL) != 0;
1012 int64_t srcVOffset = 0;
1013 int64_t srcVMultiplier = 1;
1014 int64_t dstVOffset = 0;
1015 int64_t dstVMultiplier = 1;
1016
1017 if ((nWidth == 0) || (nHeight == 0))
1018 return TRUE;
1019
1020 if (FreeRDPGetBitsPerPixel(SrcFormat) == 0)
1021 return FALSE;
1022 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
1023 return FALSE;
1024
1025 WINPR_ASSERT(1ull * nXDst + nWidth <= UINT32_MAX);
1026 WINPR_ASSERT(1ull * nXSrc + nWidth <= UINT32_MAX);
1027 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nXDst + nWidth);
1028 WINPR_ASSERT(nSrcStep / FreeRDPGetBytesPerPixel(SrcFormat) >= nXSrc + nWidth);
1029 WINPR_ASSERT(overlapping(pDstData, nYDst, nDstStep, pSrcData, nYSrc, nSrcStep, nHeight));
1030
1031 if ((nWidth == 0) || (nHeight == 0))
1032 return TRUE;
1033
1034 if ((nHeight > INT32_MAX) || (nWidth > INT32_MAX))
1035 return FALSE;
1036
1037 if (!pDstData || !pSrcData)
1038 return FALSE;
1039
1040 if (nDstStep == 0)
1041 nDstStep = (nXDst + nWidth) * FreeRDPGetBytesPerPixel(DstFormat);
1042
1043 if (nSrcStep == 0)
1044 nSrcStep = (nXSrc + nWidth) * FreeRDPGetBytesPerPixel(SrcFormat);
1045
1046 if (vSrcVFlip)
1047 {
1048 srcVOffset = (nHeight - 1ll) * nSrcStep;
1049 srcVMultiplier = -1;
1050 }
1051
1052 if (((flags & FREERDP_KEEP_DST_ALPHA) != 0) && FreeRDPColorHasAlpha(DstFormat))
1053 {
1054 return freerdp_image_copy_no_overlap_dst_alpha(
1055 pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, pSrcData, SrcFormat,
1056 nSrcStep, nXSrc, nYSrc, palette, srcVMultiplier, srcVOffset, dstVMultiplier,
1057 dstVOffset);
1058 }
1059 else if (FreeRDPAreColorFormatsEqualNoAlpha_int(SrcFormat, DstFormat))
1060 {
1061 /* Copy down */
1062 if (nYDst < nYSrc)
1063 {
1064 for (int64_t y = 0; y < nHeight; y++)
1065 {
1066 const BYTE* srcLine =
1067 &pSrcData[(y + nYSrc) * nSrcStep * srcVMultiplier + srcVOffset];
1068 BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
1069 memcpy(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
1070 }
1071 }
1072 /* Copy up */
1073 else if (nYDst > nYSrc)
1074 {
1075 for (int64_t y = nHeight - 1; y >= 0; y--)
1076 {
1077 const BYTE* srcLine =
1078 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
1079 BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
1080 memcpy(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
1081 }
1082 }
1083 /* Copy left */
1084 else if (nXSrc > nXDst)
1085 {
1086 for (int64_t y = 0; y < nHeight; y++)
1087 {
1088 const BYTE* srcLine =
1089 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
1090 BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
1091 memmove(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
1092 }
1093 }
1094 /* Copy right */
1095 else if (nXSrc < nXDst)
1096 {
1097 for (int64_t y = nHeight - 1; y >= 0; y--)
1098 {
1099 const BYTE* srcLine =
1100 &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
1101 BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
1102 memmove(&dstLine[xDstOffset], &srcLine[xSrcOffset], copyDstWidth);
1103 }
1104 }
1105 /* Source and destination are equal... */
1106 else
1107 {
1108 }
1109 }
1110 else
1111 {
1112 for (int64_t y = 0; y < nHeight; y++)
1113 {
1114 const BYTE* srcLine = &pSrcData[srcVMultiplier * (y + nYSrc) * nSrcStep + srcVOffset];
1115 BYTE* dstLine = &pDstData[dstVMultiplier * (y + nYDst) * nDstStep + dstVOffset];
1116
1117 UINT32 color = FreeRDPReadColor_int(&srcLine[1ULL * nXSrc * srcByte], SrcFormat);
1118 UINT32 oldColor = color;
1119 UINT32 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
1120 if (!FreeRDPWriteColor_int(&dstLine[1ULL * nXDst * dstByte], DstFormat, dstColor))
1121 return FALSE;
1122
1123 for (int64_t x = 1; x < nWidth; x++)
1124 {
1125 color = FreeRDPReadColor_int(&srcLine[(x + nXSrc) * srcByte], SrcFormat);
1126 if (color == oldColor)
1127 {
1128 if (!FreeRDPWriteColor_int(&dstLine[(x + nXDst) * dstByte], DstFormat,
1129 dstColor))
1130 return FALSE;
1131 }
1132 else
1133 {
1134 oldColor = color;
1135 dstColor = FreeRDPConvertColor(color, SrcFormat, DstFormat, palette);
1136 if (!FreeRDPWriteColor_int(&dstLine[(x + nXDst) * dstByte], DstFormat,
1137 dstColor))
1138 return FALSE;
1139 }
1140 }
1141 }
1142 }
1143
1144 return TRUE;
1145}
1146
1147BOOL freerdp_image_copy(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst,
1148 UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, const BYTE* pSrcData,
1149 DWORD SrcFormat, UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
1150 const gdiPalette* WINPR_RESTRICT palette, UINT32 flags)
1151{
1152 if ((nHeight > INT32_MAX) || (nWidth > INT32_MAX))
1153 return FALSE;
1154
1155 if (!pDstData || !pSrcData)
1156 return FALSE;
1157
1158 if ((nWidth == 0) || (nHeight == 0))
1159 return TRUE;
1160
1161 if (FreeRDPGetBitsPerPixel(SrcFormat) == 0)
1162 return FALSE;
1163 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
1164 return FALSE;
1165
1166 WINPR_ASSERT(1ull * nXDst + nWidth <= UINT32_MAX);
1167 WINPR_ASSERT(1ull * nXSrc + nWidth <= UINT32_MAX);
1168 if (nDstStep == 0)
1169 nDstStep = (nXDst + nWidth) * FreeRDPGetBytesPerPixel(DstFormat);
1170
1171 if (nSrcStep == 0)
1172 nSrcStep = (nXSrc + nWidth) * FreeRDPGetBytesPerPixel(SrcFormat);
1173
1174 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nXDst + nWidth);
1175 WINPR_ASSERT(nSrcStep / FreeRDPGetBytesPerPixel(SrcFormat) >= nXSrc + nWidth);
1176
1177 const BOOL ovl = overlapping(pDstData, nYDst, nDstStep, pSrcData, nYSrc, nSrcStep, nHeight);
1178 if (ovl)
1179 return freerdp_image_copy_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth,
1180 nHeight, pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc,
1181 palette, flags);
1182 return freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth,
1183 nHeight, pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc,
1184 palette, flags);
1185}
1186
1187BOOL freerdp_image_fill(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep,
1188 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, UINT32 color)
1189{
1190 if ((nWidth == 0) || (nHeight == 0))
1191 return TRUE;
1192
1193 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
1194 return FALSE;
1195
1196 const UINT32 bpp = FreeRDPGetBytesPerPixel(DstFormat);
1197 BYTE* WINPR_RESTRICT pFirstDstLine = nullptr;
1198 BYTE* WINPR_RESTRICT pFirstDstLineXOffset = nullptr;
1199
1200 WINPR_ASSERT(1ull * nXDst + nWidth <= UINT32_MAX);
1201 if (nDstStep == 0)
1202 nDstStep = (nXDst + nWidth) * FreeRDPGetBytesPerPixel(DstFormat);
1203
1204 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nXDst + nWidth);
1205 pFirstDstLine = &pDstData[1ULL * nYDst * nDstStep];
1206 pFirstDstLineXOffset = &pFirstDstLine[1ULL * nXDst * bpp];
1207
1208 for (size_t x = 0; x < nWidth; x++)
1209 {
1210 BYTE* pDst = &pFirstDstLine[(x + nXDst) * bpp];
1211 if (!FreeRDPWriteColor_int(pDst, DstFormat, color))
1212 return FALSE;
1213 }
1214
1215 for (size_t y = 1; y < nHeight; y++)
1216 {
1217 BYTE* pDstLine = &pDstData[(y + nYDst) * nDstStep + 1ULL * nXDst * bpp];
1218 memcpy(pDstLine, pFirstDstLineXOffset, 1ull * nWidth * bpp);
1219 }
1220
1221 return TRUE;
1222}
1223
1224BOOL freerdp_image_fill_ex(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep,
1225 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, UINT32 color,
1226 UINT32 flags)
1227{
1228 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
1229 return FALSE;
1230
1231 WINPR_ASSERT(pDstData);
1232 WINPR_ASSERT(1ull * nXDst + nWidth <= UINT32_MAX);
1233 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nXDst + nWidth);
1234
1235 if (FreeRDPColorHasAlpha(DstFormat) && ((flags & FREERDP_IMAGE_FILL_IGNORE_ALPHA) != 0))
1236 {
1237 const UINT32 bpp = FreeRDPGetBytesPerPixel(DstFormat);
1238 BYTE r = 0;
1239 BYTE g = 0;
1240 BYTE b = 0;
1241 FreeRDPSplitColor(color, DstFormat, &r, &g, &b, nullptr, nullptr);
1242
1243 for (size_t y = 0; y < nHeight; y++)
1244 {
1245 BYTE* WINPR_RESTRICT line = &pDstData[(y + nYDst) * nDstStep];
1246
1247 for (size_t x = 0; x < nWidth; x++)
1248 {
1249 BYTE* WINPR_RESTRICT dst = &line[x * bpp];
1250 const UINT32 dcolor = FreeRDPReadColor_int(dst, DstFormat);
1251 BYTE a = 0;
1252 FreeRDPSplitColor(dcolor, DstFormat, nullptr, nullptr, nullptr, &a, nullptr);
1253 const UINT32 scolor = FreeRDPGetColor(DstFormat, r, g, b, a);
1254 if (!FreeRDPWriteColor_int(dst, DstFormat, scolor))
1255 return FALSE;
1256 }
1257 }
1258 return TRUE;
1259 }
1260 return freerdp_image_fill(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, color);
1261}
1262
1263#if defined(WITH_SWSCALE)
1264static enum AVPixelFormat av_format_for_buffer(UINT32 format)
1265{
1266 switch (format)
1267 {
1268 case PIXEL_FORMAT_ARGB32:
1269 return AV_PIX_FMT_BGRA;
1270
1271 case PIXEL_FORMAT_XRGB32:
1272 return AV_PIX_FMT_BGR0;
1273
1274 case PIXEL_FORMAT_BGRA32:
1275 return AV_PIX_FMT_RGBA;
1276
1277 case PIXEL_FORMAT_BGRX32:
1278 return AV_PIX_FMT_RGB0;
1279
1280 default:
1281 return AV_PIX_FMT_NONE;
1282 }
1283}
1284#endif
1285
1286BOOL freerdp_image_scale(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep,
1287 UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight,
1288 const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat, UINT32 nSrcStep,
1289 UINT32 nXSrc, UINT32 nYSrc, UINT32 nSrcWidth, UINT32 nSrcHeight)
1290{
1291 BOOL rc = FALSE;
1292 if (FreeRDPGetBitsPerPixel(SrcFormat) == 0)
1293 return FALSE;
1294 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
1295 return FALSE;
1296
1297 WINPR_ASSERT(1ull * nXDst + nDstWidth <= UINT32_MAX);
1298 WINPR_ASSERT(1ull * nXSrc + nSrcWidth <= UINT32_MAX);
1299 if (nDstStep == 0)
1300 nDstStep = (nXDst + nDstWidth) * FreeRDPGetBytesPerPixel(DstFormat);
1301
1302 if (nSrcStep == 0)
1303 nSrcStep = (nXSrc + nSrcWidth) * FreeRDPGetBytesPerPixel(SrcFormat);
1304
1305 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nXDst + nDstWidth);
1306 WINPR_ASSERT(nSrcStep / FreeRDPGetBytesPerPixel(SrcFormat) >= nXSrc + nSrcWidth);
1307
1308#if defined(WITH_SWSCALE) || defined(WITH_CAIRO)
1309 const BYTE* src = &pSrcData[nXSrc * FreeRDPGetBytesPerPixel(SrcFormat) + nYSrc * nSrcStep];
1310 BYTE* dst = &pDstData[nXDst * FreeRDPGetBytesPerPixel(DstFormat) + nYDst * nDstStep];
1311#endif
1312
1313 /* direct copy is much faster than scaling, so check if we can simply copy... */
1314 if ((nDstWidth == nSrcWidth) && (nDstHeight == nSrcHeight))
1315 {
1316 return freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth,
1317 nDstHeight, pSrcData, SrcFormat, nSrcStep, nXSrc,
1318 nYSrc, nullptr, FREERDP_FLIP_NONE);
1319 }
1320 else
1321#if defined(WITH_SWSCALE)
1322 {
1323 int res = 0;
1324 struct SwsContext* resize = nullptr;
1325 enum AVPixelFormat srcFormat = av_format_for_buffer(SrcFormat);
1326 enum AVPixelFormat dstFormat = av_format_for_buffer(DstFormat);
1327 const int srcStep[1] = { (int)nSrcStep };
1328 const int dstStep[1] = { (int)nDstStep };
1329
1330 if ((srcFormat == AV_PIX_FMT_NONE) || (dstFormat == AV_PIX_FMT_NONE))
1331 return FALSE;
1332
1333 if (!freerdp_swscale_available())
1334 {
1335 WLog_WARN(TAG, "swscale not available");
1336 return FALSE;
1337 }
1338
1339 resize = freerdp_sws_getContext((int)nSrcWidth, (int)nSrcHeight, srcFormat, (int)nDstWidth,
1340 (int)nDstHeight, dstFormat, SWS_BILINEAR, nullptr, nullptr,
1341 nullptr);
1342
1343 if (!resize)
1344 goto fail;
1345
1346 /* sws_scale expects arrays of pointers, not pointer-to-pointer */
1347 const BYTE* srcSlice[4] = { src, nullptr, nullptr, nullptr };
1348 BYTE* dstSlice[4] = { dst, nullptr, nullptr, nullptr };
1349 const int srcSteps[4] = { srcStep[0], 0, 0, 0 };
1350 const int dstSteps[4] = { dstStep[0], 0, 0, 0 };
1351
1352 res = freerdp_sws_scale(resize, srcSlice, srcSteps, 0, (int)nSrcHeight, dstSlice, dstSteps);
1353 rc = (res == ((int)nDstHeight));
1354 fail:
1355 freerdp_sws_freeContext(resize);
1356 }
1357
1358#elif defined(WITH_CAIRO)
1359 {
1360 const double sx = (double)nDstWidth / (double)nSrcWidth;
1361 const double sy = (double)nDstHeight / (double)nSrcHeight;
1362 cairo_t* cairo_context;
1363 cairo_surface_t *csrc, *cdst;
1364
1365 if ((nSrcWidth > INT_MAX) || (nSrcHeight > INT_MAX) || (nSrcStep > INT_MAX))
1366 return FALSE;
1367
1368 if ((nDstWidth > INT_MAX) || (nDstHeight > INT_MAX) || (nDstStep > INT_MAX))
1369 return FALSE;
1370
1371 csrc = cairo_image_surface_create_for_data((void*)src, CAIRO_FORMAT_ARGB32, (int)nSrcWidth,
1372 (int)nSrcHeight, (int)nSrcStep);
1373 cdst = cairo_image_surface_create_for_data(dst, CAIRO_FORMAT_ARGB32, (int)nDstWidth,
1374 (int)nDstHeight, (int)nDstStep);
1375
1376 if (!csrc || !cdst)
1377 goto fail;
1378
1379 cairo_context = cairo_create(cdst);
1380
1381 if (!cairo_context)
1382 goto fail2;
1383
1384 cairo_scale(cairo_context, sx, sy);
1385 cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE);
1386 cairo_set_source_surface(cairo_context, csrc, 0, 0);
1387 cairo_paint(cairo_context);
1388 rc = TRUE;
1389 fail2:
1390 cairo_destroy(cairo_context);
1391 fail:
1392 cairo_surface_destroy(csrc);
1393 cairo_surface_destroy(cdst);
1394 }
1395#else
1396 {
1397 WLog_WARN(TAG, "SmartScaling requested but compiled without libcairo support!");
1398 }
1399#endif
1400 return rc;
1401}
1402
1403DWORD FreeRDPAreColorFormatsEqualNoAlpha(DWORD first, DWORD second)
1404{
1405 return FreeRDPAreColorFormatsEqualNoAlpha_int(first, second);
1406}
1407
1408const char* FreeRDPGetColorFormatName(UINT32 format)
1409{
1410#define ENTRY(x) \
1411 case x: \
1412 return #x;
1413
1414 switch (format)
1415 {
1416 ENTRY(PIXEL_FORMAT_ARGB32)
1417 ENTRY(PIXEL_FORMAT_XRGB32)
1418 ENTRY(PIXEL_FORMAT_ABGR32)
1419 ENTRY(PIXEL_FORMAT_XBGR32)
1420 ENTRY(PIXEL_FORMAT_BGRA32)
1421 ENTRY(PIXEL_FORMAT_BGRX32)
1422 ENTRY(PIXEL_FORMAT_RGBA32)
1423 ENTRY(PIXEL_FORMAT_RGBX32)
1424 ENTRY(PIXEL_FORMAT_BGRX32_DEPTH30)
1425 ENTRY(PIXEL_FORMAT_RGBX32_DEPTH30)
1426 ENTRY(PIXEL_FORMAT_RGB24)
1427 ENTRY(PIXEL_FORMAT_BGR24)
1428 ENTRY(PIXEL_FORMAT_RGB16)
1429 ENTRY(PIXEL_FORMAT_BGR16)
1430 ENTRY(PIXEL_FORMAT_ARGB15)
1431 ENTRY(PIXEL_FORMAT_RGB15)
1432 ENTRY(PIXEL_FORMAT_ABGR15)
1433 ENTRY(PIXEL_FORMAT_BGR15)
1434 ENTRY(PIXEL_FORMAT_RGB8)
1435 ENTRY(PIXEL_FORMAT_A4)
1436 ENTRY(PIXEL_FORMAT_MONO)
1437
1438 default:
1439 return "UNKNOWN";
1440 }
1441#undef ENTRY
1442}
1443
1444uint32_t FreeRDPGetColorFromatFromName(const char* name)
1445{
1446#define ENTRY(x) \
1447 if (strcmp(name, #x) == 0) \
1448 return x;
1449
1450 if (!name)
1451 return 0;
1452
1453 ENTRY(PIXEL_FORMAT_ARGB32)
1454 ENTRY(PIXEL_FORMAT_XRGB32)
1455 ENTRY(PIXEL_FORMAT_ABGR32)
1456 ENTRY(PIXEL_FORMAT_XBGR32)
1457 ENTRY(PIXEL_FORMAT_BGRA32)
1458 ENTRY(PIXEL_FORMAT_BGRX32)
1459 ENTRY(PIXEL_FORMAT_RGBA32)
1460 ENTRY(PIXEL_FORMAT_RGBX32)
1461 ENTRY(PIXEL_FORMAT_BGRX32_DEPTH30)
1462 ENTRY(PIXEL_FORMAT_RGBX32_DEPTH30)
1463 ENTRY(PIXEL_FORMAT_RGB24)
1464 ENTRY(PIXEL_FORMAT_BGR24)
1465 ENTRY(PIXEL_FORMAT_RGB16)
1466 ENTRY(PIXEL_FORMAT_BGR16)
1467 ENTRY(PIXEL_FORMAT_ARGB15)
1468 ENTRY(PIXEL_FORMAT_RGB15)
1469 ENTRY(PIXEL_FORMAT_ABGR15)
1470 ENTRY(PIXEL_FORMAT_BGR15)
1471 ENTRY(PIXEL_FORMAT_RGB8)
1472 ENTRY(PIXEL_FORMAT_A4)
1473 ENTRY(PIXEL_FORMAT_MONO)
1474
1475 return 0;
1476#undef ENTRY
1477}
1478
1479void FreeRDPSplitColor(UINT32 color, UINT32 format, BYTE* _r, BYTE* _g, BYTE* _b, BYTE* _a,
1480 const gdiPalette* palette)
1481{
1482 UINT32 tmp = 0;
1483
1484 switch (format)
1485 {
1486 /* 32bpp formats */
1487 case PIXEL_FORMAT_ARGB32:
1488 if (_a)
1489 *_a = (BYTE)(color >> 24);
1490
1491 if (_r)
1492 *_r = (BYTE)(color >> 16);
1493
1494 if (_g)
1495 *_g = (BYTE)(color >> 8);
1496
1497 if (_b)
1498 *_b = (BYTE)color;
1499
1500 break;
1501
1502 case PIXEL_FORMAT_XRGB32:
1503 if (_r)
1504 *_r = (BYTE)(color >> 16);
1505
1506 if (_g)
1507 *_g = (BYTE)(color >> 8);
1508
1509 if (_b)
1510 *_b = (BYTE)color;
1511
1512 if (_a)
1513 *_a = 0xFF;
1514
1515 break;
1516
1517 case PIXEL_FORMAT_ABGR32:
1518 if (_a)
1519 *_a = (BYTE)(color >> 24);
1520
1521 if (_b)
1522 *_b = (BYTE)(color >> 16);
1523
1524 if (_g)
1525 *_g = (BYTE)(color >> 8);
1526
1527 if (_r)
1528 *_r = (BYTE)color;
1529
1530 break;
1531
1532 case PIXEL_FORMAT_XBGR32:
1533 if (_b)
1534 *_b = (BYTE)(color >> 16);
1535
1536 if (_g)
1537 *_g = (BYTE)(color >> 8);
1538
1539 if (_r)
1540 *_r = (BYTE)color;
1541
1542 if (_a)
1543 *_a = 0xFF;
1544
1545 break;
1546
1547 case PIXEL_FORMAT_RGBA32:
1548 if (_r)
1549 *_r = (BYTE)(color >> 24);
1550
1551 if (_g)
1552 *_g = (BYTE)(color >> 16);
1553
1554 if (_b)
1555 *_b = (BYTE)(color >> 8);
1556
1557 if (_a)
1558 *_a = (BYTE)color;
1559
1560 break;
1561
1562 case PIXEL_FORMAT_RGBX32:
1563 if (_r)
1564 *_r = (BYTE)(color >> 24);
1565
1566 if (_g)
1567 *_g = (BYTE)(color >> 16);
1568
1569 if (_b)
1570 *_b = (BYTE)(color >> 8);
1571
1572 if (_a)
1573 *_a = 0xFF;
1574
1575 break;
1576
1577 case PIXEL_FORMAT_BGRA32:
1578 if (_b)
1579 *_b = (BYTE)(color >> 24);
1580
1581 if (_g)
1582 *_g = (BYTE)(color >> 16);
1583
1584 if (_r)
1585 *_r = (BYTE)(color >> 8);
1586
1587 if (_a)
1588 *_a = (BYTE)color;
1589
1590 break;
1591
1592 case PIXEL_FORMAT_BGRX32:
1593 if (_b)
1594 *_b = (BYTE)(color >> 24);
1595
1596 if (_g)
1597 *_g = (BYTE)(color >> 16);
1598
1599 if (_r)
1600 *_r = (BYTE)(color >> 8);
1601
1602 if (_a)
1603 *_a = 0xFF;
1604
1605 break;
1606
1607 /* 24bpp formats */
1608 case PIXEL_FORMAT_RGB24:
1609 if (_r)
1610 *_r = (BYTE)(color >> 16);
1611
1612 if (_g)
1613 *_g = (BYTE)(color >> 8);
1614
1615 if (_b)
1616 *_b = (BYTE)color;
1617
1618 if (_a)
1619 *_a = 0xFF;
1620
1621 break;
1622
1623 case PIXEL_FORMAT_BGR24:
1624 if (_b)
1625 *_b = (BYTE)(color >> 16);
1626
1627 if (_g)
1628 *_g = (BYTE)(color >> 8);
1629
1630 if (_r)
1631 *_r = (BYTE)color;
1632
1633 if (_a)
1634 *_a = 0xFF;
1635
1636 break;
1637
1638 /* 16bpp formats */
1639 case PIXEL_FORMAT_RGB16:
1640 if (_r)
1641 {
1642 const UINT32 c = (color >> 11) & 0x1F;
1643 const UINT32 val = (c << 3) + c / 4;
1644 *_r = (BYTE)(val > 255 ? 255 : val);
1645 }
1646
1647 if (_g)
1648 {
1649 const UINT32 c = (color >> 5) & 0x3F;
1650 const UINT32 val = (c << 2) + c / 4 / 2;
1651 *_g = (BYTE)(val > 255 ? 255 : val);
1652 }
1653
1654 if (_b)
1655 {
1656 const UINT32 c = (color)&0x1F;
1657 const UINT32 val = (c << 3) + c / 4;
1658 *_b = (BYTE)(val > 255 ? 255 : val);
1659 }
1660
1661 if (_a)
1662 *_a = 0xFF;
1663
1664 break;
1665
1666 case PIXEL_FORMAT_BGR16:
1667 if (_r)
1668 {
1669 const UINT32 c = (color)&0x1F;
1670 const UINT32 val = (c << 3) + c / 4;
1671 *_r = (BYTE)(val > 255 ? 255 : val);
1672 }
1673
1674 if (_g)
1675 {
1676 const UINT32 c = (color >> 5) & 0x3F;
1677 const UINT32 val = (c << 2) + c / 4 / 2;
1678 *_g = (BYTE)(val > 255 ? 255 : val);
1679 }
1680
1681 if (_b)
1682 {
1683 const UINT32 c = (color >> 11) & 0x1F;
1684 const UINT32 val = (c << 3) + c / 4;
1685 *_b = (BYTE)(val > 255 ? 255 : val);
1686 }
1687
1688 if (_a)
1689 *_a = 0xFF;
1690
1691 break;
1692
1693 case PIXEL_FORMAT_ARGB15:
1694 if (_r)
1695 {
1696 const UINT32 c = (color >> 10) & 0x1F;
1697 const UINT32 val = (c << 3) + c / 4;
1698 *_r = (BYTE)(val > 255 ? 255 : val);
1699 }
1700
1701 if (_g)
1702 {
1703 const UINT32 c = (color >> 5) & 0x1F;
1704 const UINT32 val = (c << 3) + c / 4;
1705 *_g = (BYTE)(val > 255 ? 255 : val);
1706 }
1707
1708 if (_b)
1709 {
1710 const UINT32 c = (color)&0x1F;
1711 const UINT32 val = (c << 3) + c / 4;
1712 *_b = (BYTE)(val > 255 ? 255 : val);
1713 }
1714
1715 if (_a)
1716 *_a = color & 0x8000 ? 0xFF : 0x00;
1717
1718 break;
1719
1720 case PIXEL_FORMAT_ABGR15:
1721 if (_r)
1722 {
1723 const UINT32 c = (color)&0x1F;
1724 const UINT32 val = (c << 3) + c / 4;
1725 *_r = (BYTE)(val > 255 ? 255 : val);
1726 }
1727
1728 if (_g)
1729 {
1730 const UINT32 c = (color >> 5) & 0x1F;
1731 const UINT32 val = (c << 3) + c / 4;
1732 *_g = (BYTE)(val > 255 ? 255 : val);
1733 }
1734
1735 if (_b)
1736 {
1737 const UINT32 c = (color >> 10) & 0x1F;
1738 const UINT32 val = (c << 3) + c / 4;
1739 *_b = (BYTE)(val > 255 ? 255 : val);
1740 }
1741
1742 if (_a)
1743 *_a = color & 0x8000 ? 0xFF : 0x00;
1744
1745 break;
1746
1747 /* 15bpp formats */
1748 case PIXEL_FORMAT_RGB15:
1749 if (_r)
1750 {
1751 const UINT32 c = (color >> 10) & 0x1F;
1752 const UINT32 val = (c << 3) + c / 4;
1753 *_r = (BYTE)(val > 255 ? 255 : val);
1754 }
1755
1756 if (_g)
1757 {
1758 const UINT32 c = (color >> 5) & 0x1F;
1759 const UINT32 val = (c << 3) + c / 4;
1760 *_g = (BYTE)(val > 255 ? 255 : val);
1761 }
1762
1763 if (_b)
1764 {
1765 const UINT32 c = (color)&0x1F;
1766 const UINT32 val = (c << 3) + c / 4;
1767 *_b = (BYTE)(val > 255 ? 255 : val);
1768 }
1769
1770 if (_a)
1771 *_a = 0xFF;
1772
1773 break;
1774
1775 case PIXEL_FORMAT_BGR15:
1776 if (_r)
1777 {
1778 const UINT32 c = (color)&0x1F;
1779 const UINT32 val = (c << 3) + c / 4;
1780 *_r = (BYTE)(val > 255 ? 255 : val);
1781 }
1782
1783 if (_g)
1784 {
1785 const UINT32 c = (color >> 5) & 0x1F;
1786 const UINT32 val = (c << 3) + c / 4;
1787 *_g = (BYTE)(val > 255 ? 255 : val);
1788 }
1789
1790 if (_b)
1791 {
1792 const UINT32 c = (color >> 10) & 0x1F;
1793 const UINT32 val = (c << 3) + c / 4;
1794 *_b = (BYTE)(val > 255 ? 255 : val);
1795 }
1796
1797 if (_a)
1798 *_a = 0xFF;
1799
1800 break;
1801
1802 /* 8bpp formats */
1803 case PIXEL_FORMAT_RGB8:
1804 if (color <= 0xFF)
1805 {
1806 tmp = palette->palette[color];
1807 FreeRDPSplitColor(tmp, palette->format, _r, _g, _b, _a, nullptr);
1808 }
1809 else
1810 {
1811 if (_r)
1812 *_r = 0x00;
1813
1814 if (_g)
1815 *_g = 0x00;
1816
1817 if (_b)
1818 *_b = 0x00;
1819
1820 if (_a)
1821 *_a = 0x00;
1822 }
1823
1824 break;
1825
1826 /* 1bpp formats */
1827 case PIXEL_FORMAT_MONO:
1828 if (_r)
1829 *_r = (color) ? 0xFF : 0x00;
1830
1831 if (_g)
1832 *_g = (color) ? 0xFF : 0x00;
1833
1834 if (_b)
1835 *_b = (color) ? 0xFF : 0x00;
1836
1837 if (_a)
1838 *_a = (color) ? 0xFF : 0x00;
1839
1840 break;
1841
1842 /* 4 bpp formats */
1843 case PIXEL_FORMAT_A4:
1844 default:
1845 if (_r)
1846 *_r = 0x00;
1847
1848 if (_g)
1849 *_g = 0x00;
1850
1851 if (_b)
1852 *_b = 0x00;
1853
1854 if (_a)
1855 *_a = 0x00;
1856
1857 WLog_ERR(TAG, "Unsupported format %s", FreeRDPGetColorFormatName(format));
1858 break;
1859 }
1860}
1861
1862BOOL FreeRDPWriteColorIgnoreAlpha(BYTE* WINPR_RESTRICT dst, UINT32 format, UINT32 color)
1863{
1864 return FreeRDPWriteColorIgnoreAlpha_int(dst, format, color);
1865}
1866
1867BOOL FreeRDPWriteColor(BYTE* WINPR_RESTRICT dst, UINT32 format, UINT32 color)
1868{
1869 return FreeRDPWriteColor_int(dst, format, color);
1870}
1871
1872UINT32 FreeRDPReadColor(const BYTE* WINPR_RESTRICT src, UINT32 format)
1873{
1874 return FreeRDPReadColor_int(src, format);
1875}
1876
1877UINT32 FreeRDPGetColor(UINT32 format, BYTE r, BYTE g, BYTE b, BYTE a)
1878{
1879 UINT32 _r = r;
1880 UINT32 _g = g;
1881 UINT32 _b = b;
1882 UINT32 _a = a;
1883 UINT32 t = 0;
1884
1885 switch (format)
1886 {
1887 /* 32bpp formats */
1888 case PIXEL_FORMAT_ARGB32:
1889 return (_a << 24) | (_r << 16) | (_g << 8) | _b;
1890
1891 case PIXEL_FORMAT_XRGB32:
1892 return (_r << 16) | (_g << 8) | _b;
1893
1894 case PIXEL_FORMAT_ABGR32:
1895 return (_a << 24) | (_b << 16) | (_g << 8) | _r;
1896
1897 case PIXEL_FORMAT_XBGR32:
1898 return (_b << 16) | (_g << 8) | _r;
1899
1900 case PIXEL_FORMAT_RGBA32:
1901 return (_r << 24) | (_g << 16) | (_b << 8) | _a;
1902
1903 case PIXEL_FORMAT_RGBX32:
1904 return (_r << 24) | (_g << 16) | (_b << 8) | _a;
1905
1906 case PIXEL_FORMAT_BGRA32:
1907 return (_b << 24) | (_g << 16) | (_r << 8) | _a;
1908
1909 case PIXEL_FORMAT_BGRX32:
1910 return (_b << 24) | (_g << 16) | (_r << 8) | _a;
1911
1912 case PIXEL_FORMAT_RGBX32_DEPTH30:
1913 // TODO: Not tested
1914 t = (_r << 22) | (_g << 12) | (_b << 2);
1915 // NOTE: Swapping byte-order because FreeRDPWriteColor written UINT32 in big-endian
1916 return ((t & 0xff) << 24) | (((t >> 8) & 0xff) << 16) | (((t >> 16) & 0xff) << 8) |
1917 (t >> 24);
1918
1919 case PIXEL_FORMAT_BGRX32_DEPTH30:
1920 // NOTE: Swapping b and r channel (unknown reason)
1921 t = (_r << 22) | (_g << 12) | (_b << 2);
1922 // NOTE: Swapping byte-order because FreeRDPWriteColor written UINT32 in big-endian
1923 return ((t & 0xff) << 24) | (((t >> 8) & 0xff) << 16) | (((t >> 16) & 0xff) << 8) |
1924 (t >> 24);
1925
1926 /* 24bpp formats */
1927 case PIXEL_FORMAT_RGB24:
1928 return (_r << 16) | (_g << 8) | _b;
1929
1930 case PIXEL_FORMAT_BGR24:
1931 return (_b << 16) | (_g << 8) | _r;
1932
1933 /* 16bpp formats */
1934 case PIXEL_FORMAT_RGB16:
1935 return (((_r >> 3) & 0x1F) << 11) | (((_g >> 2) & 0x3F) << 5) | ((_b >> 3) & 0x1F);
1936
1937 case PIXEL_FORMAT_BGR16:
1938 return (((_b >> 3) & 0x1F) << 11) | (((_g >> 2) & 0x3F) << 5) | ((_r >> 3) & 0x1F);
1939
1940 case PIXEL_FORMAT_ARGB15:
1941 return (((_r >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_b >> 3) & 0x1F) |
1942 (_a ? 0x8000 : 0x0000);
1943
1944 case PIXEL_FORMAT_ABGR15:
1945 return (((_b >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_r >> 3) & 0x1F) |
1946 (_a ? 0x8000 : 0x0000);
1947
1948 /* 15bpp formats */
1949 case PIXEL_FORMAT_RGB15:
1950 return (((_r >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_b >> 3) & 0x1F);
1951
1952 case PIXEL_FORMAT_BGR15:
1953 return (((_b >> 3) & 0x1F) << 10) | (((_g >> 3) & 0x1F) << 5) | ((_r >> 3) & 0x1F);
1954
1955 /* 8bpp formats */
1956 case PIXEL_FORMAT_RGB8:
1957
1958 /* 4 bpp formats */
1959 case PIXEL_FORMAT_A4:
1960
1961 /* 1bpp formats */
1962 case PIXEL_FORMAT_MONO:
1963 default:
1964 WLog_ERR(TAG, "Unsupported format %s", FreeRDPGetColorFormatName(format));
1965 return 0;
1966 }
1967}
1968
1969BOOL freerdp_image_copy_no_overlap(BYTE* WINPR_RESTRICT pDstData, DWORD DstFormat, UINT32 nDstStep,
1970 UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight,
1971 const BYTE* WINPR_RESTRICT pSrcData, DWORD SrcFormat,
1972 UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
1973 const gdiPalette* WINPR_RESTRICT palette, UINT32 flags)
1974{
1975 static primitives_t* prims = nullptr;
1976 if (!prims)
1977 prims = primitives_get();
1978
1979 if (FreeRDPGetBitsPerPixel(SrcFormat) == 0)
1980 return FALSE;
1981 if (FreeRDPGetBitsPerPixel(DstFormat) == 0)
1982 return FALSE;
1983
1984 if ((nWidth == 0) || (nHeight == 0))
1985 return TRUE;
1986
1987 WINPR_ASSERT(1ull * nXDst + nWidth <= UINT32_MAX);
1988 WINPR_ASSERT(1ull * nXSrc + nWidth <= UINT32_MAX);
1989 if (nDstStep == 0)
1990 nDstStep = (nXDst + nWidth) * FreeRDPGetBytesPerPixel(DstFormat);
1991 if (nSrcStep == 0)
1992 nSrcStep = (nXSrc + nWidth) * FreeRDPGetBytesPerPixel(SrcFormat);
1993
1994 WINPR_ASSERT(nDstStep / FreeRDPGetBytesPerPixel(DstFormat) >= nXDst + nWidth);
1995 WINPR_ASSERT(nSrcStep / FreeRDPGetBytesPerPixel(SrcFormat) >= nXSrc + nWidth);
1996 WINPR_ASSERT(!overlapping(pDstData, nYDst, nDstStep, pSrcData, nYSrc, nSrcStep, nHeight));
1997 WINPR_ASSERT(prims);
1998 WINPR_ASSERT(prims->copy_no_overlap);
1999 return prims->copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight,
2000 pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette,
2001 flags) == PRIMITIVES_SUCCESS;
2002}
WINPR_ATTR_NODISCARD fn_copy_no_overlap_t copy_no_overlap
Definition primitives.h:304