Coverage Report

Created: 2026-10-15 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/gdi/bitmap.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * GDI Bitmap Functions
4
 *
5
 * Copyright 2010-2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2016 Armin Novak <armin.novak@thincast.com>
7
 * Copyright 2016 Thincast Technologies GmbH
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21
22
#include <freerdp/config.h>
23
24
#include <stdio.h>
25
#include <string.h>
26
#include <stdlib.h>
27
28
#include <freerdp/api.h>
29
#include <freerdp/freerdp.h>
30
#include <freerdp/gdi/gdi.h>
31
#include <freerdp/codec/color.h>
32
33
#include <freerdp/gdi/region.h>
34
#include <freerdp/gdi/bitmap.h>
35
#include <freerdp/log.h>
36
#include <freerdp/gdi/shape.h>
37
38
#include "brush.h"
39
#include "clipping.h"
40
#include "../gdi/gdi.h"
41
42
#define TAG FREERDP_TAG("gdi.bitmap")
43
44
/**
45
 * Get pixel at the given coordinates. msdn{dd144909}
46
 * @param hdc device context
47
 * @param nXPos pixel x position
48
 * @param nYPos pixel y position
49
 * @return pixel color
50
 */
51
52
UINT32 gdi_GetPixel(HGDI_DC hdc, UINT32 nXPos, UINT32 nYPos)
53
0
{
54
0
  HGDI_BITMAP hBmp = WINPR_PACKED_ALIGN_CAST(HGDI_BITMAP, hdc->selectedObject);
55
0
  BYTE* data =
56
0
      &(hBmp->data[(nYPos * hBmp->scanline) + nXPos * FreeRDPGetBytesPerPixel(hBmp->format)]);
57
0
  return FreeRDPReadColor(data, hBmp->format);
58
0
}
59
60
BYTE* gdi_GetPointer(HGDI_BITMAP hBmp, UINT32 X, UINT32 Y)
61
0
{
62
0
  UINT32 bpp = FreeRDPGetBytesPerPixel(hBmp->format);
63
0
  return &hBmp->data[(Y * WINPR_ASSERTING_INT_CAST(uint32_t, hBmp->width) * bpp) + X * bpp];
64
0
}
65
66
/**
67
 * Set pixel at the given coordinates. msdn{dd145078}
68
 *
69
 * @param hBmp device context
70
 * @param X pixel x position
71
 * @param Y pixel y position
72
 * @param crColor new pixel color
73
 * @return the color written
74
 */
75
76
static inline UINT32 gdi_SetPixelBmp(HGDI_BITMAP hBmp, UINT32 X, UINT32 Y, UINT32 crColor)
77
0
{
78
0
  BYTE* p = &hBmp->data[(Y * hBmp->scanline) + X * FreeRDPGetBytesPerPixel(hBmp->format)];
79
0
  FreeRDPWriteColor(p, hBmp->format, crColor);
80
0
  return crColor;
81
0
}
82
83
UINT32 gdi_SetPixel(HGDI_DC hdc, UINT32 X, UINT32 Y, UINT32 crColor)
84
0
{
85
0
  HGDI_BITMAP hBmp = WINPR_PACKED_ALIGN_CAST(HGDI_BITMAP, hdc->selectedObject);
86
0
  return gdi_SetPixelBmp(hBmp, X, Y, crColor);
87
0
}
88
89
/**
90
 * Create a new bitmap with the given width, height, color format and pixel buffer. msdn{dd183485}
91
 *
92
 * @param nWidth width
93
 * @param nHeight height
94
 * @param format the color format used
95
 * @param data pixel buffer
96
 * @return new bitmap
97
 */
98
99
HGDI_BITMAP gdi_CreateBitmap(UINT32 nWidth, UINT32 nHeight, UINT32 format, BYTE* data)
100
0
{
101
0
  return gdi_CreateBitmapEx(nWidth, nHeight, format, 0, data, winpr_aligned_free);
102
0
}
103
104
/**
105
 * Create a new bitmap with the given width, height, color format and pixel buffer. msdn{dd183485}
106
 *
107
 * @param nWidth width
108
 * @param nHeight height
109
 * @param format the color format used
110
 * @param data pixel buffer
111
 * @param fkt_free The function used for deallocation of the buffer, nullptr for none.
112
 * @return new bitmap
113
 */
114
115
HGDI_BITMAP gdi_CreateBitmapEx(UINT32 nWidth, UINT32 nHeight, UINT32 format, UINT32 stride,
116
                               BYTE* data, void (*fkt_free)(void*))
117
0
{
118
0
  HGDI_BITMAP hBitmap = (HGDI_BITMAP)calloc(1, sizeof(GDI_BITMAP));
119
120
0
  if (!hBitmap)
121
0
    return nullptr;
122
123
0
  hBitmap->objectType = GDIOBJECT_BITMAP;
124
0
  hBitmap->format = format;
125
126
0
  if (stride > 0)
127
0
    hBitmap->scanline = stride;
128
0
  else
129
0
    hBitmap->scanline = nWidth * FreeRDPGetBytesPerPixel(hBitmap->format);
130
131
0
  hBitmap->width = WINPR_ASSERTING_INT_CAST(int, nWidth);
132
0
  hBitmap->height = WINPR_ASSERTING_INT_CAST(int, nHeight);
133
0
  hBitmap->data = data;
134
0
  hBitmap->free = fkt_free;
135
0
  return hBitmap;
136
0
}
137
138
/**
139
 * Create a new bitmap of the given width and height compatible with the current device context.
140
 * msdn{dd183488}
141
 *
142
 * @param hdc device context
143
 * @param nWidth width
144
 * @param nHeight height
145
 *
146
 * @return new bitmap
147
 */
148
149
HGDI_BITMAP gdi_CreateCompatibleBitmap(HGDI_DC hdc, UINT32 nWidth, UINT32 nHeight)
150
0
{
151
0
  HGDI_BITMAP hBitmap = (HGDI_BITMAP)calloc(1, sizeof(GDI_BITMAP));
152
153
0
  if (!hBitmap)
154
0
    return nullptr;
155
156
0
  hBitmap->objectType = GDIOBJECT_BITMAP;
157
0
  hBitmap->format = hdc->format;
158
0
  WINPR_ASSERT(nWidth <= INT32_MAX);
159
0
  hBitmap->width = (INT32)nWidth;
160
161
0
  WINPR_ASSERT(nHeight <= INT32_MAX);
162
0
  hBitmap->height = (INT32)nHeight;
163
164
0
  size_t size = 1ull * nWidth * nHeight * FreeRDPGetBytesPerPixel(hBitmap->format);
165
0
  hBitmap->data =
166
0
      winpr_aligned_calloc(1ull * nWidth * FreeRDPGetBytesPerPixel(hBitmap->format), nHeight, 16);
167
0
  hBitmap->free = winpr_aligned_free;
168
169
0
  if (!hBitmap->data)
170
0
  {
171
0
    free(hBitmap);
172
0
    return nullptr;
173
0
  }
174
175
  /* Initialize with 0xff */
176
0
  memset(hBitmap->data, 0xff, size);
177
0
  hBitmap->scanline = nWidth * FreeRDPGetBytesPerPixel(hBitmap->format);
178
0
  return hBitmap;
179
0
}
180
181
static BOOL op_not(UINT32* stack, const UINT32* stackp)
182
0
{
183
0
  if (!stack || !stackp)
184
0
    return FALSE;
185
186
0
  if (*stackp < 1)
187
0
    return FALSE;
188
189
0
  stack[(*stackp) - 1] = ~stack[(*stackp) - 1];
190
0
  return TRUE;
191
0
}
192
193
static BOOL op_and(UINT32* stack, UINT32* stackp)
194
0
{
195
0
  if (!stack || !stackp)
196
0
    return FALSE;
197
198
0
  if (*stackp < 2)
199
0
    return FALSE;
200
201
0
  (*stackp)--;
202
0
  stack[(*stackp) - 1] &= stack[(*stackp)];
203
0
  return TRUE;
204
0
}
205
206
static BOOL op_or(UINT32* stack, UINT32* stackp)
207
0
{
208
0
  if (!stack || !stackp)
209
0
    return FALSE;
210
211
0
  if (*stackp < 2)
212
0
    return FALSE;
213
214
0
  (*stackp)--;
215
0
  stack[(*stackp) - 1] |= stack[(*stackp)];
216
0
  return TRUE;
217
0
}
218
219
static BOOL op_xor(UINT32* stack, UINT32* stackp)
220
0
{
221
0
  if (!stack || !stackp)
222
0
    return FALSE;
223
224
0
  if (*stackp < 2)
225
0
    return FALSE;
226
227
0
  (*stackp)--;
228
0
  stack[(*stackp) - 1] ^= stack[(*stackp)];
229
0
  return TRUE;
230
0
}
231
232
static UINT32 process_rop(UINT32 src, UINT32 dst, UINT32 pat, const char* rop, UINT32 format)
233
0
{
234
0
  UINT32 stack[10] = WINPR_C_ARRAY_INIT;
235
0
  UINT32 stackp = 0;
236
237
0
  while (*rop != '\0')
238
0
  {
239
0
    char op = *rop++;
240
241
0
    switch (op)
242
0
    {
243
0
      case '0':
244
0
        stack[stackp++] = FreeRDPGetColor(format, 0, 0, 0, 0xFF);
245
0
        break;
246
247
0
      case '1':
248
0
        stack[stackp++] = FreeRDPGetColor(format, 0xFF, 0xFF, 0xFF, 0xFF);
249
0
        break;
250
251
0
      case 'D':
252
0
        stack[stackp++] = dst;
253
0
        break;
254
255
0
      case 'S':
256
0
        stack[stackp++] = src;
257
0
        break;
258
259
0
      case 'P':
260
0
        stack[stackp++] = pat;
261
0
        break;
262
263
0
      case 'x':
264
0
        op_xor(stack, &stackp);
265
0
        break;
266
267
0
      case 'a':
268
0
        op_and(stack, &stackp);
269
0
        break;
270
271
0
      case 'o':
272
0
        op_or(stack, &stackp);
273
0
        break;
274
275
0
      case 'n':
276
0
        op_not(stack, &stackp);
277
0
        break;
278
279
0
      default:
280
0
        break;
281
0
    }
282
0
  }
283
284
0
  return stack[0];
285
0
}
286
287
static inline BOOL BitBlt_write(HGDI_DC hdcDest, HGDI_DC hdcSrc, INT32 nXDest, INT32 nYDest,
288
                                INT32 nXSrc, INT32 nYSrc, INT32 x, INT32 y, BOOL useSrc,
289
                                BOOL usePat, UINT32 style, const char* rop,
290
                                const gdiPalette* palette)
291
0
{
292
0
  UINT32 dstColor = 0;
293
0
  UINT32 colorA = 0;
294
0
  UINT32 colorB = 0;
295
0
  UINT32 colorC = 0;
296
0
  const INT32 dstX = nXDest + x;
297
0
  const INT32 dstY = nYDest + y;
298
0
  BYTE* dstp = gdi_get_bitmap_pointer(hdcDest, dstX, dstY);
299
300
0
  if (!dstp)
301
0
  {
302
0
    WLog_ERR(TAG, "dstp=%p", (const void*)dstp);
303
0
    return FALSE;
304
0
  }
305
306
0
  colorA = FreeRDPReadColor(dstp, hdcDest->format);
307
308
0
  if (useSrc)
309
0
  {
310
0
    const BYTE* srcp = gdi_get_bitmap_pointer(hdcSrc, nXSrc + x, nYSrc + y);
311
312
0
    if (!srcp)
313
0
    {
314
0
      WLog_ERR(TAG, "srcp=%p", (const void*)srcp);
315
0
      return FALSE;
316
0
    }
317
318
0
    colorC = FreeRDPReadColor(srcp, hdcSrc->format);
319
0
    colorC = FreeRDPConvertColor(colorC, hdcSrc->format, hdcDest->format, palette);
320
0
  }
321
322
0
  if (usePat)
323
0
  {
324
0
    switch (style)
325
0
    {
326
0
      case GDI_BS_SOLID:
327
0
        colorB = hdcDest->brush->color;
328
0
        break;
329
330
0
      case GDI_BS_HATCHED:
331
0
      case GDI_BS_PATTERN:
332
0
      {
333
0
        const BYTE* patp =
334
0
            gdi_get_brush_pointer(hdcDest, WINPR_ASSERTING_INT_CAST(uint32_t, nXDest + x),
335
0
                                  WINPR_ASSERTING_INT_CAST(uint32_t, nYDest + y));
336
337
0
        if (!patp)
338
0
        {
339
0
          WLog_ERR(TAG, "patp=%p", (const void*)patp);
340
0
          return FALSE;
341
0
        }
342
343
0
        colorB = FreeRDPReadColor(patp, hdcDest->format);
344
0
      }
345
0
      break;
346
347
0
      default:
348
0
        break;
349
0
    }
350
0
  }
351
352
0
  dstColor = process_rop(colorC, colorA, colorB, rop, hdcDest->format);
353
0
  return FreeRDPWriteColor(dstp, hdcDest->format, dstColor);
354
0
}
355
356
static BOOL adjust_src_coordinates(HGDI_DC hdcSrc, INT32 nWidth, INT32 nHeight, INT32* px,
357
                                   INT32* py)
358
0
{
359
0
  HGDI_BITMAP hSrcBmp = nullptr;
360
0
  INT32 nXSrc = 0;
361
0
  INT32 nYSrc = 0;
362
363
0
  if (!hdcSrc || (nWidth < 0) || (nHeight < 0) || !px || !py)
364
0
    return FALSE;
365
366
0
  hSrcBmp = WINPR_PACKED_ALIGN_CAST(HGDI_BITMAP, hdcSrc->selectedObject);
367
0
  nXSrc = *px;
368
0
  nYSrc = *py;
369
370
0
  if (!hSrcBmp)
371
0
    return FALSE;
372
373
0
  if (nYSrc < 0)
374
0
  {
375
0
    nYSrc = 0;
376
0
    nHeight = nHeight + nYSrc;
377
0
  }
378
379
0
  if ((nXSrc) < 0)
380
0
  {
381
0
    nXSrc = 0;
382
0
    nWidth = nWidth + nXSrc;
383
0
  }
384
385
0
  if (hSrcBmp->width < (nXSrc + nWidth))
386
0
    nXSrc = hSrcBmp->width - nWidth;
387
388
0
  if (hSrcBmp->height < (nYSrc + nHeight))
389
0
    nYSrc = hSrcBmp->height - nHeight;
390
391
0
  if ((nXSrc < 0) || (nYSrc < 0))
392
0
    return FALSE;
393
394
0
  *px = nXSrc;
395
0
  *py = nYSrc;
396
0
  return TRUE;
397
0
}
398
399
static BOOL adjust_src_dst_coordinates(HGDI_DC hdcDest, INT32* pnXSrc, INT32* pnYSrc, INT32* pnXDst,
400
                                       INT32* pnYDst, INT32* pnWidth, INT32* pnHeight)
401
0
{
402
0
  HGDI_BITMAP hDstBmp = nullptr;
403
0
  volatile INT32 diffX = 0;
404
0
  volatile INT32 diffY = 0;
405
0
  volatile INT32 nXSrc = 0;
406
0
  volatile INT32 nYSrc = 0;
407
0
  volatile INT32 nXDst = 0;
408
0
  volatile INT32 nYDst = 0;
409
0
  volatile INT32 nWidth = 0;
410
0
  volatile INT32 nHeight = 0;
411
412
0
  if (!hdcDest || !pnXSrc || !pnYSrc || !pnXDst || !pnYDst || !pnWidth || !pnHeight)
413
0
    return FALSE;
414
415
0
  hDstBmp = WINPR_PACKED_ALIGN_CAST(HGDI_BITMAP, hdcDest->selectedObject);
416
0
  nXSrc = *pnXSrc;
417
0
  nYSrc = *pnYSrc;
418
0
  nXDst = *pnXDst;
419
0
  nYDst = *pnYDst;
420
0
  nWidth = *pnWidth;
421
0
  nHeight = *pnHeight;
422
423
0
  if (!hDstBmp)
424
0
    return FALSE;
425
426
0
  if (nXDst < 0)
427
0
  {
428
0
    nXSrc -= nXDst;
429
0
    nWidth += nXDst;
430
0
    nXDst = 0;
431
0
  }
432
433
0
  if (nYDst < 0)
434
0
  {
435
0
    nYSrc -= nYDst;
436
0
    nHeight += nYDst;
437
0
    nYDst = 0;
438
0
  }
439
440
0
  diffX = hDstBmp->width - nXDst - nWidth;
441
442
0
  if (diffX < 0)
443
0
    nWidth += diffX;
444
445
0
  diffY = hDstBmp->height - nYDst - nHeight;
446
447
0
  if (diffY < 0)
448
0
    nHeight += diffY;
449
450
0
  if ((nXDst < 0) || (nYDst < 0) || (nWidth < 0) || (nHeight < 0))
451
0
  {
452
0
    nXDst = 0;
453
0
    nYDst = 0;
454
0
    nWidth = 0;
455
0
    nHeight = 0;
456
0
  }
457
458
0
  *pnXSrc = nXSrc;
459
0
  *pnYSrc = nYSrc;
460
0
  *pnXDst = nXDst;
461
0
  *pnYDst = nYDst;
462
0
  *pnWidth = nWidth;
463
0
  *pnHeight = nHeight;
464
0
  return TRUE;
465
0
}
466
467
static BOOL BitBlt_process(HGDI_DC hdcDest, INT32 nXDest, INT32 nYDest, INT32 nWidth, INT32 nHeight,
468
                           HGDI_DC hdcSrc, INT32 nXSrc, INT32 nYSrc, const char* rop,
469
                           const gdiPalette* palette)
470
0
{
471
0
  UINT32 style = 0;
472
0
  BOOL useSrc = FALSE;
473
0
  BOOL usePat = FALSE;
474
0
  const char* iter = rop;
475
476
0
  while (*iter != '\0')
477
0
  {
478
0
    switch (*iter++)
479
0
    {
480
0
      case 'P':
481
0
        usePat = TRUE;
482
0
        break;
483
484
0
      case 'S':
485
0
        useSrc = TRUE;
486
0
        break;
487
488
0
      default:
489
0
        break;
490
0
    }
491
0
  }
492
493
0
  if (!hdcDest)
494
0
    return FALSE;
495
496
0
  if (!adjust_src_dst_coordinates(hdcDest, &nXSrc, &nYSrc, &nXDest, &nYDest, &nWidth, &nHeight))
497
0
    return FALSE;
498
499
0
  if (useSrc && !hdcSrc)
500
0
    return FALSE;
501
502
0
  if (useSrc)
503
0
  {
504
0
    if (!adjust_src_coordinates(hdcSrc, nWidth, nHeight, &nXSrc, &nYSrc))
505
0
      return FALSE;
506
0
  }
507
508
0
  if (usePat)
509
0
  {
510
0
    style = gdi_GetBrushStyle(hdcDest);
511
512
0
    switch (style)
513
0
    {
514
0
      case GDI_BS_SOLID:
515
0
      case GDI_BS_HATCHED:
516
0
      case GDI_BS_PATTERN:
517
0
        break;
518
519
0
      default:
520
0
        WLog_ERR(TAG, "Invalid brush!!");
521
0
        return FALSE;
522
0
    }
523
0
  }
524
525
0
  if ((nXDest > nXSrc) && (nYDest > nYSrc))
526
0
  {
527
0
    for (INT32 y = nHeight - 1; y >= 0; y--)
528
0
    {
529
0
      for (INT32 x = nWidth - 1; x >= 0; x--)
530
0
      {
531
0
        if (!BitBlt_write(hdcDest, hdcSrc, nXDest, nYDest, nXSrc, nYSrc, x, y, useSrc,
532
0
                          usePat, style, rop, palette))
533
0
          return FALSE;
534
0
      }
535
0
    }
536
0
  }
537
0
  else if (nXDest > nXSrc)
538
0
  {
539
0
    for (INT32 y = 0; y < nHeight; y++)
540
0
    {
541
0
      for (INT32 x = nWidth - 1; x >= 0; x--)
542
0
      {
543
0
        if (!BitBlt_write(hdcDest, hdcSrc, nXDest, nYDest, nXSrc, nYSrc, x, y, useSrc,
544
0
                          usePat, style, rop, palette))
545
0
          return FALSE;
546
0
      }
547
0
    }
548
0
  }
549
0
  else if (nYDest > nYSrc)
550
0
  {
551
0
    for (INT32 y = nHeight - 1; y >= 0; y--)
552
0
    {
553
0
      for (INT32 x = 0; x < nWidth; x++)
554
0
      {
555
0
        if (!BitBlt_write(hdcDest, hdcSrc, nXDest, nYDest, nXSrc, nYSrc, x, y, useSrc,
556
0
                          usePat, style, rop, palette))
557
0
          return FALSE;
558
0
      }
559
0
    }
560
0
  }
561
0
  else
562
0
  {
563
0
    for (INT32 y = 0; y < nHeight; y++)
564
0
    {
565
0
      for (INT32 x = 0; x < nWidth; x++)
566
0
      {
567
0
        if (!BitBlt_write(hdcDest, hdcSrc, nXDest, nYDest, nXSrc, nYSrc, x, y, useSrc,
568
0
                          usePat, style, rop, palette))
569
0
          return FALSE;
570
0
      }
571
0
    }
572
0
  }
573
574
0
  return TRUE;
575
0
}
576
577
/**
578
 * Perform a bit blit operation on the given pixel buffers.
579
 * msdn{dd183370}
580
 *
581
 * @param hdcDest destination device context
582
 * @param nXDest destination x1
583
 * @param nYDest destination y1
584
 * @param nWidth width
585
 * @param nHeight height
586
 * @param hdcSrc source device context
587
 * @param nXSrc source x1
588
 * @param nYSrc source y1
589
 * @param rop raster operation code
590
 * @return 0 on failure, non-zero otherwise
591
 */
592
BOOL gdi_BitBlt(HGDI_DC hdcDest, INT32 nXDest, INT32 nYDest, INT32 nWidth, INT32 nHeight,
593
                HGDI_DC hdcSrc, INT32 nXSrc, INT32 nYSrc, DWORD rop, const gdiPalette* palette)
594
0
{
595
0
  HGDI_BITMAP hSrcBmp = nullptr;
596
0
  HGDI_BITMAP hDstBmp = nullptr;
597
598
0
  if (!hdcDest)
599
0
    return FALSE;
600
601
0
  if (!gdi_ClipCoords(hdcDest, &nXDest, &nYDest, &nWidth, &nHeight, &nXSrc, &nYSrc))
602
0
    return TRUE;
603
604
  /* Check which ROP should be performed.
605
   * Some specific ROP are used heavily and are resource intensive,
606
   * add optimized versions for these here.
607
   *
608
   * For all others fall back to the generic implementation.
609
   */
610
0
  switch (rop)
611
0
  {
612
0
    case GDI_SRCCOPY:
613
0
      if (!hdcSrc)
614
0
        return FALSE;
615
616
0
      if (!adjust_src_dst_coordinates(hdcDest, &nXSrc, &nYSrc, &nXDest, &nYDest, &nWidth,
617
0
                                      &nHeight))
618
0
        return FALSE;
619
620
0
      if (!adjust_src_coordinates(hdcSrc, nWidth, nHeight, &nXSrc, &nYSrc))
621
0
        return FALSE;
622
623
0
      hSrcBmp = WINPR_PACKED_ALIGN_CAST(HGDI_BITMAP, hdcSrc->selectedObject);
624
0
      hDstBmp = WINPR_PACKED_ALIGN_CAST(HGDI_BITMAP, hdcDest->selectedObject);
625
626
0
      if (!hSrcBmp || !hDstBmp)
627
0
        return FALSE;
628
629
0
      if (!freerdp_image_copy(
630
0
              hDstBmp->data, hDstBmp->format, hDstBmp->scanline,
631
0
              WINPR_ASSERTING_INT_CAST(UINT32, nXDest),
632
0
              WINPR_ASSERTING_INT_CAST(UINT32, nYDest),
633
0
              WINPR_ASSERTING_INT_CAST(UINT32, nWidth),
634
0
              WINPR_ASSERTING_INT_CAST(UINT32, nHeight), hSrcBmp->data, hSrcBmp->format,
635
0
              hSrcBmp->scanline, WINPR_ASSERTING_INT_CAST(UINT32, nXSrc),
636
0
              WINPR_ASSERTING_INT_CAST(UINT32, nYSrc), palette, FREERDP_FLIP_NONE))
637
0
        return FALSE;
638
639
0
      break;
640
641
0
    case GDI_DSTCOPY:
642
0
      hSrcBmp = WINPR_PACKED_ALIGN_CAST(HGDI_BITMAP, hdcDest->selectedObject);
643
0
      hDstBmp = WINPR_PACKED_ALIGN_CAST(HGDI_BITMAP, hdcDest->selectedObject);
644
645
0
      if (!adjust_src_dst_coordinates(hdcDest, &nXSrc, &nYSrc, &nXDest, &nYDest, &nWidth,
646
0
                                      &nHeight))
647
0
        return FALSE;
648
649
0
      if (!adjust_src_coordinates(hdcDest, nWidth, nHeight, &nXSrc, &nYSrc))
650
0
        return FALSE;
651
652
0
      if (!hSrcBmp || !hDstBmp)
653
0
        return FALSE;
654
655
0
      if (!freerdp_image_copy(
656
0
              hDstBmp->data, hDstBmp->format, hDstBmp->scanline,
657
0
              WINPR_ASSERTING_INT_CAST(UINT32, nXDest),
658
0
              WINPR_ASSERTING_INT_CAST(UINT32, nYDest),
659
0
              WINPR_ASSERTING_INT_CAST(UINT32, nWidth),
660
0
              WINPR_ASSERTING_INT_CAST(UINT32, nHeight), hSrcBmp->data, hSrcBmp->format,
661
0
              hSrcBmp->scanline, WINPR_ASSERTING_INT_CAST(UINT32, nXSrc),
662
0
              WINPR_ASSERTING_INT_CAST(UINT32, nYSrc), palette, FREERDP_FLIP_NONE))
663
0
        return FALSE;
664
665
0
      break;
666
667
0
    default:
668
0
      if (!BitBlt_process(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc,
669
0
                          gdi_rop_to_string(rop), palette))
670
0
        return FALSE;
671
672
0
      break;
673
0
  }
674
675
0
  return gdi_InvalidateRegion(hdcDest, nXDest, nYDest, nWidth, nHeight);
676
0
}