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