Coverage Report

Created: 2026-02-26 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/gdi/gdi.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * GDI Library
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 <stdlib.h>
26
27
#include <winpr/crt.h>
28
#include <winpr/assert.h>
29
#include <winpr/cast.h>
30
31
#include <freerdp/api.h>
32
#include <freerdp/log.h>
33
#include <freerdp/freerdp.h>
34
#include <freerdp/codecs.h>
35
36
#include <freerdp/gdi/gdi.h>
37
#include <freerdp/gdi/dc.h>
38
#include <freerdp/gdi/pen.h>
39
#include <freerdp/gdi/shape.h>
40
#include <freerdp/gdi/region.h>
41
#include <freerdp/gdi/bitmap.h>
42
43
#include "drawing.h"
44
#include "clipping.h"
45
#include "brush.h"
46
#include "line.h"
47
#include "gdi.h"
48
#include "../core/graphics.h"
49
#include "../core/update.h"
50
#include "../cache/cache.h"
51
52
0
#define TAG FREERDP_TAG("gdi")
53
54
/* Ternary Raster Operation Table */
55
typedef struct
56
{
57
  DWORD code;
58
  const char* name;
59
} rop_table_entry;
60
61
static const rop_table_entry rop3_code_table[] = { { GDI_BLACKNESS, "0" },
62
                                                 { GDI_DPSoon, "DPSoon" },
63
                                                 { GDI_DPSona, "DPSona" },
64
                                                 { GDI_PSon, "PSon" },
65
                                                 { GDI_SDPona, "SDPona" },
66
                                                 { GDI_DPon, "DPon" },
67
                                                 { GDI_PDSxnon, "PDSxnon" },
68
                                                 { GDI_PDSaon, "PDSaon" },
69
                                                 { GDI_SDPnaa, "SDPnaa" },
70
                                                 { GDI_PDSxon, "PDSxon" },
71
                                                 { GDI_DPna, "DPna" },
72
                                                 { GDI_PSDnaon, "PSDnaon" },
73
                                                 { GDI_SPna, "SPna" },
74
                                                 { GDI_PDSnaon, "PDSnaon" },
75
                                                 { GDI_PDSonon, "PDSonon" },
76
                                                 { GDI_Pn, "Pn" },
77
                                                 { GDI_PDSona, "PDSona" },
78
                                                 { GDI_NOTSRCERASE, "DSon" },
79
                                                 { GDI_SDPxnon, "SDPxnon" },
80
                                                 { GDI_SDPaon, "SDPaon" },
81
                                                 { GDI_DPSxnon, "DPSxnon" },
82
                                                 { GDI_DPSaon, "DPSaon" },
83
                                                 { GDI_PSDPSanaxx, "PSDPSanaxx" },
84
                                                 { GDI_SSPxDSxaxn, "SSPxDSxaxn" },
85
                                                 { GDI_SPxPDxa, "SPxPDxa" },
86
                                                 { GDI_SDPSanaxn, "SDPSanaxn" },
87
                                                 { GDI_PDSPaox, "PDSPaox" },
88
                                                 { GDI_SDPSxaxn, "SDPSxaxn" },
89
                                                 { GDI_PSDPaox, "PSDPaox" },
90
                                                 { GDI_DSPDxaxn, "DSPDxaxn" },
91
                                                 { GDI_PDSox, "PDSox" },
92
                                                 { GDI_PDSoan, "PDSoan" },
93
                                                 { GDI_DPSnaa, "DPSnaa" },
94
                                                 { GDI_SDPxon, "SDPxon" },
95
                                                 { GDI_DSna, "DSna" },
96
                                                 { GDI_SPDnaon, "SPDnaon" },
97
                                                 { GDI_SPxDSxa, "SPxDSxa" },
98
                                                 { GDI_PDSPanaxn, "PDSPanaxn" },
99
                                                 { GDI_SDPSaox, "SDPSaox" },
100
                                                 { GDI_SDPSxnox, "SDPSxnox" },
101
                                                 { GDI_DPSxa, "DPSxa" },
102
                                                 { GDI_PSDPSaoxxn, "PSDPSaoxxn" },
103
                                                 { GDI_DPSana, "DPSana" },
104
                                                 { GDI_SSPxPDxaxn, "SSPxPDxaxn" },
105
                                                 { GDI_SPDSoax, "SPDSoax" },
106
                                                 { GDI_PSDnox, "PSDnox" },
107
                                                 { GDI_PSDPxox, "PSDPxox" },
108
                                                 { GDI_PSDnoan, "PSDnoan" },
109
                                                 { GDI_PSna, "PSna" },
110
                                                 { GDI_SDPnaon, "SDPnaon" },
111
                                                 { GDI_SDPSoox, "SDPSoox" },
112
                                                 { GDI_NOTSRCCOPY, "Sn" },
113
                                                 { GDI_SPDSaox, "SPDSaox" },
114
                                                 { GDI_SPDSxnox, "SPDSxnox" },
115
                                                 { GDI_SDPox, "SDPox" },
116
                                                 { GDI_SDPoan, "SDPoan" },
117
                                                 { GDI_PSDPoax, "PSDPoax" },
118
                                                 { GDI_SPDnox, "SPDnox" },
119
                                                 { GDI_SPDSxox, "SPDSxox" },
120
                                                 { GDI_SPDnoan, "SPDnoan" },
121
                                                 { GDI_PSx, "PSx" },
122
                                                 { GDI_SPDSonox, "SPDSonox" },
123
                                                 { GDI_SPDSnaox, "SPDSnaox" },
124
                                                 { GDI_PSan, "PSan" },
125
                                                 { GDI_PSDnaa, "PSDnaa" },
126
                                                 { GDI_DPSxon, "DPSxon" },
127
                                                 { GDI_SDxPDxa, "SDxPDxa" },
128
                                                 { GDI_SPDSanaxn, "SPDSanaxn" },
129
                                                 { GDI_SRCERASE, "SDna" },
130
                                                 { GDI_DPSnaon, "DPSnaon" },
131
                                                 { GDI_DSPDaox, "DSPDaox" },
132
                                                 { GDI_PSDPxaxn, "PSDPxaxn" },
133
                                                 { GDI_SDPxa, "SDPxa" },
134
                                                 { GDI_PDSPDaoxxn, "PDSPDaoxxn" },
135
                                                 { GDI_DPSDoax, "DPSDoax" },
136
                                                 { GDI_PDSnox, "PDSnox" },
137
                                                 { GDI_SDPana, "SDPana" },
138
                                                 { GDI_SSPxDSxoxn, "SSPxDSxoxn" },
139
                                                 { GDI_PDSPxox, "PDSPxox" },
140
                                                 { GDI_PDSnoan, "PDSnoan" },
141
                                                 { GDI_PDna, "PDna" },
142
                                                 { GDI_DSPnaon, "DSPnaon" },
143
                                                 { GDI_DPSDaox, "DPSDaox" },
144
                                                 { GDI_SPDSxaxn, "SPDSxaxn" },
145
                                                 { GDI_DPSonon, "DPSonon" },
146
                                                 { GDI_DSTINVERT, "Dn" },
147
                                                 { GDI_DPSox, "DPSox" },
148
                                                 { GDI_DPSoan, "DPSoan" },
149
                                                 { GDI_PDSPoax, "PDSPoax" },
150
                                                 { GDI_DPSnox, "DPSnox" },
151
                                                 { GDI_PATINVERT, "DPx" },
152
                                                 { GDI_DPSDonox, "DPSDonox" },
153
                                                 { GDI_DPSDxox, "DPSDxox" },
154
                                                 { GDI_DPSnoan, "DPSnoan" },
155
                                                 { GDI_DPSDnaox, "DPSDnaox" },
156
                                                 { GDI_DPan, "DPan" },
157
                                                 { GDI_PDSxa, "PDSxa" },
158
                                                 { GDI_DSPDSaoxxn, "DSPDSaoxxn" },
159
                                                 { GDI_DSPDoax, "DSPDoax" },
160
                                                 { GDI_SDPnox, "SDPnox" },
161
                                                 { GDI_SDPSoax, "SDPSoax" },
162
                                                 { GDI_DSPnox, "DSPnox" },
163
                                                 { GDI_SRCINVERT, "DSx" },
164
                                                 { GDI_SDPSonox, "SDPSonox" },
165
                                                 { GDI_DSPDSonoxxn, "DSPDSonoxxn" },
166
                                                 { GDI_PDSxxn, "PDSxxn" },
167
                                                 { GDI_DPSax, "DPSax" },
168
                                                 { GDI_PSDPSoaxxn, "PSDPSoaxxn" },
169
                                                 { GDI_SDPax, "SDPax" },
170
                                                 { GDI_PDSPDoaxxn, "PDSPDoaxxn" },
171
                                                 { GDI_SDPSnoax, "SDPSnoax" },
172
                                                 { GDI_PDSxnan, "PDSxnan" },
173
                                                 { GDI_PDSana, "PDSana" },
174
                                                 { GDI_SSDxPDxaxn, "SSDxPDxaxn" },
175
                                                 { GDI_SDPSxox, "SDPSxox" },
176
                                                 { GDI_SDPnoan, "SDPnoan" },
177
                                                 { GDI_DSPDxox, "DSPDxox" },
178
                                                 { GDI_DSPnoan, "DSPnoan" },
179
                                                 { GDI_SDPSnaox, "SDPSnaox" },
180
                                                 { GDI_DSan, "DSan" },
181
                                                 { GDI_PDSax, "PDSax" },
182
                                                 { GDI_DSPDSoaxxn, "DSPDSoaxxn" },
183
                                                 { GDI_DPSDnoax, "DPSDnoax" },
184
                                                 { GDI_SDPxnan, "SDPxnan" },
185
                                                 { GDI_SPDSnoax, "SPDSnoax" },
186
                                                 { GDI_DPSxnan, "DPSxnan" },
187
                                                 { GDI_SPxDSxo, "SPxDSxo" },
188
                                                 { GDI_DPSaan, "DPSaan" },
189
                                                 { GDI_DPSaa, "DPSaa" },
190
                                                 { GDI_SPxDSxon, "SPxDSxon" },
191
                                                 { GDI_DPSxna, "DPSxna" },
192
                                                 { GDI_SPDSnoaxn, "SPDSnoaxn" },
193
                                                 { GDI_SDPxna, "SDPxna" },
194
                                                 { GDI_PDSPnoaxn, "PDSPnoaxn" },
195
                                                 { GDI_DSPDSoaxx, "DSPDSoaxx" },
196
                                                 { GDI_PDSaxn, "PDSaxn" },
197
                                                 { GDI_SRCAND, "DSa" },
198
                                                 { GDI_SDPSnaoxn, "SDPSnaoxn" },
199
                                                 { GDI_DSPnoa, "DSPnoa" },
200
                                                 { GDI_DSPDxoxn, "DSPDxoxn" },
201
                                                 { GDI_SDPnoa, "SDPnoa" },
202
                                                 { GDI_SDPSxoxn, "SDPSxoxn" },
203
                                                 { GDI_SSDxPDxax, "SSDxPDxax" },
204
                                                 { GDI_PDSanan, "PDSanan" },
205
                                                 { GDI_PDSxna, "PDSxna" },
206
                                                 { GDI_SDPSnoaxn, "SDPSnoaxn" },
207
                                                 { GDI_DPSDPoaxx, "DPSDPoaxx" },
208
                                                 { GDI_SPDaxn, "SPDaxn" },
209
                                                 { GDI_PSDPSoaxx, "PSDPSoaxx" },
210
                                                 { GDI_DPSaxn, "DPSaxn" },
211
                                                 { GDI_DPSxx, "DPSxx" },
212
                                                 { GDI_PSDPSonoxx, "PSDPSonoxx" },
213
                                                 { GDI_SDPSonoxn, "SDPSonoxn" },
214
                                                 { GDI_DSxn, "DSxn" },
215
                                                 { GDI_DPSnax, "DPSnax" },
216
                                                 { GDI_SDPSoaxn, "SDPSoaxn" },
217
                                                 { GDI_SPDnax, "SPDnax" },
218
                                                 { GDI_DSPDoaxn, "DSPDoaxn" },
219
                                                 { GDI_DSPDSaoxx, "DSPDSaoxx" },
220
                                                 { GDI_PDSxan, "PDSxan" },
221
                                                 { GDI_DPa, "DPa" },
222
                                                 { GDI_PDSPnaoxn, "PDSPnaoxn" },
223
                                                 { GDI_DPSnoa, "DPSnoa" },
224
                                                 { GDI_DPSDxoxn, "DPSDxoxn" },
225
                                                 { GDI_PDSPonoxn, "PDSPonoxn" },
226
                                                 { GDI_PDxn, "PDxn" },
227
                                                 { GDI_DSPnax, "DSPnax" },
228
                                                 { GDI_PDSPoaxn, "PDSPoaxn" },
229
                                                 { GDI_DPSoa, "DPSoa" },
230
                                                 { GDI_DPSoxn, "DPSoxn" },
231
                                                 { GDI_DSTCOPY, "D" },
232
                                                 { GDI_DPSono, "DPSono" },
233
                                                 { GDI_SPDSxax, "SPDSxax" },
234
                                                 { GDI_DPSDaoxn, "DPSDaoxn" },
235
                                                 { GDI_DSPnao, "DSPnao" },
236
                                                 { GDI_DPno, "DPno" },
237
                                                 { GDI_PDSnoa, "PDSnoa" },
238
                                                 { GDI_PDSPxoxn, "PDSPxoxn" },
239
                                                 { GDI_SSPxDSxox, "SSPxDSxox" },
240
                                                 { GDI_SDPanan, "SDPanan" },
241
                                                 { GDI_PSDnax, "PSDnax" },
242
                                                 { GDI_DPSDoaxn, "DPSDoaxn" },
243
                                                 { GDI_DPSDPaoxx, "DPSDPaoxx" },
244
                                                 { GDI_SDPxan, "SDPxan" },
245
                                                 { GDI_PSDPxax, "PSDPxax" },
246
                                                 { GDI_DSPDaoxn, "DSPDaoxn" },
247
                                                 { GDI_DPSnao, "DPSnao" },
248
                                                 { GDI_MERGEPAINT, "DSno" },
249
                                                 { GDI_SPDSanax, "SPDSanax" },
250
                                                 { GDI_SDxPDxan, "SDxPDxan" },
251
                                                 { GDI_DPSxo, "DPSxo" },
252
                                                 { GDI_DPSano, "DPSano" },
253
                                                 { GDI_MERGECOPY, "PSa" },
254
                                                 { GDI_SPDSnaoxn, "SPDSnaoxn" },
255
                                                 { GDI_SPDSonoxn, "SPDSonoxn" },
256
                                                 { GDI_PSxn, "PSxn" },
257
                                                 { GDI_SPDnoa, "SPDnoa" },
258
                                                 { GDI_SPDSxoxn, "SPDSxoxn" },
259
                                                 { GDI_SDPnax, "SDPnax" },
260
                                                 { GDI_PSDPoaxn, "PSDPoaxn" },
261
                                                 { GDI_SDPoa, "SDPoa" },
262
                                                 { GDI_SPDoxn, "SPDoxn" },
263
                                                 { GDI_DPSDxax, "DPSDxax" },
264
                                                 { GDI_SPDSaoxn, "SPDSaoxn" },
265
                                                 { GDI_SRCCOPY, "S" },
266
                                                 { GDI_SDPono, "SDPono" },
267
                                                 { GDI_SDPnao, "SDPnao" },
268
                                                 { GDI_SPno, "SPno" },
269
                                                 { GDI_PSDnoa, "PSDnoa" },
270
                                                 { GDI_PSDPxoxn, "PSDPxoxn" },
271
                                                 { GDI_PDSnax, "PDSnax" },
272
                                                 { GDI_SPDSoaxn, "SPDSoaxn" },
273
                                                 { GDI_SSPxPDxax, "SSPxPDxax" },
274
                                                 { GDI_DPSanan, "DPSanan" },
275
                                                 { GDI_PSDPSaoxx, "PSDPSaoxx" },
276
                                                 { GDI_DPSxan, "DPSxan" },
277
                                                 { GDI_PDSPxax, "PDSPxax" },
278
                                                 { GDI_SDPSaoxn, "SDPSaoxn" },
279
                                                 { GDI_DPSDanax, "DPSDanax" },
280
                                                 { GDI_SPxDSxan, "SPxDSxan" },
281
                                                 { GDI_SPDnao, "SPDnao" },
282
                                                 { GDI_SDno, "SDno" },
283
                                                 { GDI_SDPxo, "SDPxo" },
284
                                                 { GDI_SDPano, "SDPano" },
285
                                                 { GDI_PDSoa, "PDSoa" },
286
                                                 { GDI_PDSoxn, "PDSoxn" },
287
                                                 { GDI_DSPDxax, "DSPDxax" },
288
                                                 { GDI_PSDPaoxn, "PSDPaoxn" },
289
                                                 { GDI_SDPSxax, "SDPSxax" },
290
                                                 { GDI_PDSPaoxn, "PDSPaoxn" },
291
                                                 { GDI_SDPSanax, "SDPSanax" },
292
                                                 { GDI_SPxPDxan, "SPxPDxan" },
293
                                                 { GDI_SSPxDSxax, "SSPxDSxax" },
294
                                                 { GDI_DSPDSanaxxn, "DSPDSanaxxn" },
295
                                                 { GDI_DPSao, "DPSao" },
296
                                                 { GDI_DPSxno, "DPSxno" },
297
                                                 { GDI_SDPao, "SDPao" },
298
                                                 { GDI_SDPxno, "SDPxno" },
299
                                                 { GDI_SRCPAINT, "DSo" },
300
                                                 { GDI_SDPnoo, "SDPnoo" },
301
                                                 { GDI_PATCOPY, "P" },
302
                                                 { GDI_PDSono, "PDSono" },
303
                                                 { GDI_PDSnao, "PDSnao" },
304
                                                 { GDI_PSno, "PSno" },
305
                                                 { GDI_PSDnao, "PSDnao" },
306
                                                 { GDI_PDno, "PDno" },
307
                                                 { GDI_PDSxo, "PDSxo" },
308
                                                 { GDI_PDSano, "PDSano" },
309
                                                 { GDI_PDSao, "PDSao" },
310
                                                 { GDI_PDSxno, "PDSxno" },
311
                                                 { GDI_DPo, "DPo" },
312
                                                 { GDI_PATPAINT, "DPSnoo" },
313
                                                 { GDI_PSo, "PSo" },
314
                                                 { GDI_PSDnoo, "PSDnoo" },
315
                                                 { GDI_DPSoo, "DPSoo" },
316
                                                 { GDI_WHITENESS, "1" } };
317
318
/* Hatch Patterns as monochrome data */
319
static const BYTE GDI_BS_HATCHED_PATTERNS[] = {
320
  0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, /* HS_HORIZONTAL */
321
  0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, /* HS_VERTICAL */
322
  0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F, /* HS_FDIAGONAL */
323
  0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE, /* HS_BDIAGONAL */
324
  0xF7, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0xF7, 0xF7, /* HS_CROSS */
325
  0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E  /* HS_DIACROSS */
326
};
327
328
0
#define gdi_rop3_code_checked(code) gdi_rop3_code_checked_int((code), __FILE__, __func__, __LINE__)
329
static inline DWORD gdi_rop3_code_checked_int(UINT32 code, WINPR_ATTR_UNUSED const char* file,
330
                                              WINPR_ATTR_UNUSED const char* fkt,
331
                                              WINPR_ATTR_UNUSED size_t line)
332
0
{
333
0
  WINPR_ASSERT_AT(code <= UINT8_MAX, file, fkt, line);
334
0
  return gdi_rop3_code((UINT8)code);
335
0
}
336
337
BOOL gdi_decode_color(rdpGdi* gdi, UINT32 srcColor, UINT32* color, UINT32* format)
338
0
{
339
0
  UINT32 SrcFormat = 0;
340
341
0
  if (!gdi || !color || !gdi->context || !gdi->context->settings)
342
0
    return FALSE;
343
344
0
  const UINT32 ColorDepth =
345
0
      freerdp_settings_get_uint32(gdi->context->settings, FreeRDP_ColorDepth);
346
347
0
  switch (ColorDepth)
348
0
  {
349
0
    case 32:
350
0
    case 24:
351
0
      SrcFormat = PIXEL_FORMAT_BGR24;
352
0
      break;
353
354
0
    case 16:
355
0
      SrcFormat = PIXEL_FORMAT_RGB16;
356
0
      break;
357
358
0
    case 15:
359
0
      SrcFormat = PIXEL_FORMAT_RGB15;
360
0
      break;
361
362
0
    case 8:
363
0
      SrcFormat = PIXEL_FORMAT_RGB8;
364
0
      break;
365
366
0
    default:
367
0
      return FALSE;
368
0
  }
369
370
0
  if (format)
371
0
    *format = gdi->dstFormat;
372
373
0
  *color = FreeRDPConvertColor(srcColor, SrcFormat, gdi->dstFormat, &gdi->palette);
374
0
  return TRUE;
375
0
}
376
377
/* GDI Helper Functions */
378
DWORD gdi_rop3_code(BYTE code)
379
0
{
380
0
  return rop3_code_table[code].code;
381
0
}
382
383
const char* gdi_rop3_code_string(BYTE code)
384
0
{
385
0
  return rop3_code_table[code].name;
386
0
}
387
388
const char* gdi_rop3_string(DWORD rop)
389
0
{
390
0
  const size_t count = sizeof(rop3_code_table) / sizeof(rop3_code_table[0]);
391
392
0
  for (size_t x = 0; x < count; x++)
393
0
  {
394
0
    if (rop3_code_table[x].code == rop)
395
0
      return rop3_code_table[x].name;
396
0
  }
397
398
0
  return "UNKNOWN";
399
0
}
400
401
UINT32 gdi_get_pixel_format(UINT32 bitsPerPixel)
402
0
{
403
0
  UINT32 format = 0;
404
405
0
  switch (bitsPerPixel)
406
0
  {
407
0
    case 32:
408
0
      format = PIXEL_FORMAT_BGRA32;
409
0
      break;
410
411
0
    case 24:
412
0
      format = PIXEL_FORMAT_BGR24;
413
0
      break;
414
415
0
    case 16:
416
0
      format = PIXEL_FORMAT_RGB16;
417
0
      break;
418
419
0
    case 15:
420
0
      format = PIXEL_FORMAT_RGB15;
421
0
      break;
422
423
0
    case 8:
424
0
      format = PIXEL_FORMAT_RGB8;
425
0
      break;
426
427
0
    default:
428
0
      WLog_ERR(TAG, "Unsupported color depth %" PRIu32, bitsPerPixel);
429
0
      format = 0;
430
0
      break;
431
0
  }
432
433
0
  return format;
434
0
}
435
436
gdiBitmap* gdi_bitmap_new_ex(rdpGdi* gdi, int width, int height, int bpp, BYTE* data)
437
0
{
438
0
  gdiBitmap* bitmap = (gdiBitmap*)calloc(1, sizeof(gdiBitmap));
439
440
0
  if (!bitmap)
441
0
    goto fail_bitmap;
442
443
0
  if (!(bitmap->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
444
0
    goto fail_hdc;
445
446
0
  WLog_Print(gdi->log, WLOG_DEBUG, "gdi_bitmap_new: width:%d height:%d bpp:%d", width, height,
447
0
             bpp);
448
449
0
  if (!data)
450
0
    bitmap->bitmap =
451
0
        gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, width),
452
0
                                   WINPR_ASSERTING_INT_CAST(uint32_t, height));
453
0
  else
454
0
    bitmap->bitmap = gdi_create_bitmap(gdi, WINPR_ASSERTING_INT_CAST(uint32_t, width),
455
0
                                       WINPR_ASSERTING_INT_CAST(uint32_t, height),
456
0
                                       WINPR_ASSERTING_INT_CAST(uint32_t, bpp), data);
457
458
0
  if (!bitmap->bitmap)
459
0
    goto fail_bitmap_bitmap;
460
461
0
  gdi_SelectObject(bitmap->hdc, (HGDIOBJECT)bitmap->bitmap);
462
0
  bitmap->org_bitmap = NULL;
463
0
  return bitmap;
464
0
fail_bitmap_bitmap:
465
0
  gdi_DeleteDC(bitmap->hdc);
466
0
fail_hdc:
467
0
  free(bitmap);
468
0
fail_bitmap:
469
0
  return NULL;
470
0
}
471
472
void gdi_bitmap_free_ex(gdiBitmap* bitmap)
473
0
{
474
0
  if (bitmap)
475
0
  {
476
0
    gdi_SelectObject(bitmap->hdc, (HGDIOBJECT)bitmap->org_bitmap);
477
0
    gdi_DeleteObject((HGDIOBJECT)bitmap->bitmap);
478
0
    gdi_DeleteDC(bitmap->hdc);
479
0
    free(bitmap);
480
0
  }
481
0
}
482
483
BOOL gdi_bitmap_update(rdpContext* context, const BITMAP_UPDATE* bitmapUpdate)
484
0
{
485
0
  if (!context || !bitmapUpdate || !context->gdi || !context->codecs)
486
0
  {
487
0
    WLog_ERR(TAG,
488
0
             "Invalid arguments: context=%p, bitmapUpdate=%p, context->gdi=%p, "
489
0
             "context->codecs=%p",
490
0
             WINPR_CXX_COMPAT_CAST(const void*, context),
491
0
             WINPR_CXX_COMPAT_CAST(const void*, bitmapUpdate),
492
0
             WINPR_CXX_COMPAT_CAST(const void*, context ? context->gdi : NULL),
493
0
             WINPR_CXX_COMPAT_CAST(const void*, context ? context->codecs : NULL));
494
0
    return FALSE;
495
0
  }
496
497
0
  for (UINT32 index = 0; index < bitmapUpdate->number; index++)
498
0
  {
499
0
    BOOL rc = FALSE;
500
0
    const BITMAP_DATA* bitmap = &(bitmapUpdate->rectangles[index]);
501
0
    rdpBitmap* bmp = Bitmap_Alloc(context);
502
503
0
    if (!bmp)
504
0
      goto fail;
505
506
0
    if (!Bitmap_SetDimensions(bmp, WINPR_ASSERTING_INT_CAST(UINT16, bitmap->width),
507
0
                              WINPR_ASSERTING_INT_CAST(UINT16, bitmap->height)))
508
0
      goto fail;
509
510
0
    if (!Bitmap_SetRectangle(bmp, WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destLeft),
511
0
                             WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destTop),
512
0
                             WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destRight),
513
0
                             WINPR_ASSERTING_INT_CAST(UINT16, bitmap->destBottom)))
514
0
      goto fail;
515
516
0
    if (!bmp->Decompress(context, bmp, bitmap->bitmapDataStream, bitmap->width, bitmap->height,
517
0
                         bitmap->bitsPerPixel, bitmap->bitmapLength, bitmap->compressed,
518
0
                         RDP_CODEC_ID_NONE))
519
0
      goto fail;
520
521
0
    if (!bmp->New(context, bmp))
522
0
      goto fail;
523
524
0
    if (!bmp->Paint(context, bmp))
525
0
      goto fail;
526
527
0
    rc = TRUE;
528
0
  fail:
529
0
    Bitmap_Free(context, bmp);
530
0
    if (!rc)
531
0
      return FALSE;
532
0
  }
533
534
0
  return TRUE;
535
0
}
536
537
static BOOL gdi_palette_update(rdpContext* context, const PALETTE_UPDATE* palette)
538
0
{
539
0
  if (!context || !palette)
540
0
    return FALSE;
541
542
0
  rdpGdi* gdi = context->gdi;
543
0
  if (!gdi)
544
0
    return FALSE;
545
546
0
  gdi->palette.format = gdi->dstFormat;
547
548
0
  for (UINT32 index = 0; index < palette->number; index++)
549
0
  {
550
0
    const PALETTE_ENTRY* pe = &(palette->entries[index]);
551
0
    gdi->palette.palette[index] =
552
0
        FreeRDPGetColor(gdi->dstFormat, pe->red, pe->green, pe->blue, 0xFF);
553
0
  }
554
555
0
  return TRUE;
556
0
}
557
558
static BOOL gdi_set_bounds(rdpContext* context, const rdpBounds* bounds)
559
0
{
560
0
  if (!context)
561
0
    return FALSE;
562
563
0
  rdpGdi* gdi = context->gdi;
564
0
  if (!gdi || !gdi->drawing)
565
0
    return FALSE;
566
567
0
  if (bounds)
568
0
    return gdi_SetClipRgn(gdi->drawing->hdc, bounds->left, bounds->top,
569
0
                          bounds->right - bounds->left + 1, bounds->bottom - bounds->top + 1);
570
571
0
  return gdi_SetNullClipRgn(gdi->drawing->hdc);
572
0
}
573
574
static BOOL gdi_dstblt(rdpContext* context, const DSTBLT_ORDER* dstblt)
575
0
{
576
0
  if (!context || !dstblt)
577
0
    return FALSE;
578
579
0
  rdpGdi* gdi = context->gdi;
580
0
  if (!gdi || !gdi->drawing)
581
0
    return FALSE;
582
0
  return gdi_BitBlt(gdi->drawing->hdc, dstblt->nLeftRect, dstblt->nTopRect, dstblt->nWidth,
583
0
                    dstblt->nHeight, NULL, 0, 0, gdi_rop3_code_checked(dstblt->bRop),
584
0
                    &gdi->palette);
585
0
}
586
587
static BOOL gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
588
0
{
589
0
  WINPR_ASSERT(context);
590
0
  WINPR_ASSERT(patblt);
591
592
0
  const rdpBrush* brush = &patblt->brush;
593
0
  UINT32 foreColor = 0;
594
0
  UINT32 backColor = 0;
595
0
  UINT32 originalColor = 0;
596
0
  HGDI_BRUSH originalBrush = NULL;
597
0
  HGDI_BRUSH hbrush = NULL;
598
0
  rdpGdi* gdi = context->gdi;
599
0
  BOOL ret = FALSE;
600
0
  const DWORD rop = gdi_rop3_code_checked(patblt->bRop);
601
0
  INT32 nXSrc = 0;
602
0
  INT32 nYSrc = 0;
603
0
  BYTE data[8 * 8 * 4];
604
0
  HGDI_BITMAP hBmp = NULL;
605
606
0
  if (!gdi || !gdi->drawing || !gdi->drawing->hdc)
607
0
    return FALSE;
608
609
0
  if (!gdi_decode_color(gdi, patblt->foreColor, &foreColor, NULL))
610
0
    return FALSE;
611
612
0
  if (!gdi_decode_color(gdi, patblt->backColor, &backColor, NULL))
613
0
    return FALSE;
614
615
0
  originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
616
0
  originalBrush = gdi->drawing->hdc->brush;
617
618
0
  switch (brush->style)
619
0
  {
620
0
    case GDI_BS_SOLID:
621
0
      hbrush = gdi_CreateSolidBrush(foreColor);
622
0
      break;
623
624
0
    case GDI_BS_HATCHED:
625
0
    {
626
0
      const BYTE* hatched = NULL;
627
0
      hatched = GDI_BS_HATCHED_PATTERNS + (8ULL * brush->hatch);
628
629
0
      if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
630
0
                                              hatched, backColor, foreColor, &gdi->palette))
631
0
        goto out_error;
632
633
0
      hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
634
635
0
      if (!hBmp)
636
0
        goto out_error;
637
638
0
      hbrush = gdi_CreateHatchBrush(hBmp);
639
0
    }
640
0
    break;
641
642
0
    case GDI_BS_PATTERN:
643
0
    {
644
0
      UINT32 brushFormat = 0;
645
646
0
      if (brush->bpp > 1)
647
0
      {
648
0
        UINT32 bpp = brush->bpp;
649
650
0
        if ((bpp == 16) &&
651
0
            (freerdp_settings_get_uint32(context->settings, FreeRDP_ColorDepth) == 15))
652
0
          bpp = 15;
653
654
0
        brushFormat = gdi_get_pixel_format(bpp);
655
656
0
        if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
657
0
                                           brush->data, brushFormat, 0, 0, 0, &gdi->palette,
658
0
                                           FREERDP_FLIP_NONE))
659
0
          goto out_error;
660
0
      }
661
0
      else
662
0
      {
663
0
        if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
664
0
                                                8, brush->data, backColor, foreColor,
665
0
                                                &gdi->palette))
666
0
          goto out_error;
667
0
      }
668
669
0
      hBmp = gdi_CreateBitmapEx(8, 8, gdi->drawing->hdc->format, 0, data, NULL);
670
671
0
      if (!hBmp)
672
0
        goto out_error;
673
674
0
      hbrush = gdi_CreatePatternBrush(hBmp);
675
0
    }
676
0
    break;
677
678
0
    default:
679
0
      WLog_ERR(TAG, "unimplemented brush style:%" PRIu32 "", brush->style);
680
0
      break;
681
0
  }
682
683
0
  if (hbrush)
684
0
  {
685
0
    hbrush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
686
0
    hbrush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
687
0
    gdi->drawing->hdc->brush = hbrush;
688
0
    ret = gdi_BitBlt(gdi->drawing->hdc, patblt->nLeftRect, patblt->nTopRect, patblt->nWidth,
689
0
                     patblt->nHeight, gdi->primary->hdc, nXSrc, nYSrc, rop, &gdi->palette);
690
0
  }
691
692
0
out_error:
693
0
  gdi_DeleteObject((HGDIOBJECT)hBmp);
694
0
  gdi_DeleteObject((HGDIOBJECT)hbrush);
695
0
  gdi->drawing->hdc->brush = originalBrush;
696
0
  gdi_SetTextColor(gdi->drawing->hdc, originalColor);
697
0
  return ret;
698
0
}
699
700
static BOOL gdi_scrblt(rdpContext* context, const SCRBLT_ORDER* scrblt)
701
0
{
702
0
  if (!context || !context->gdi)
703
0
    return FALSE;
704
705
0
  rdpGdi* gdi = context->gdi;
706
0
  if (!gdi->drawing || !gdi->primary)
707
0
    return FALSE;
708
709
0
  return gdi_BitBlt(gdi->drawing->hdc, scrblt->nLeftRect, scrblt->nTopRect, scrblt->nWidth,
710
0
                    scrblt->nHeight, gdi->primary->hdc, scrblt->nXSrc, scrblt->nYSrc,
711
0
                    gdi_rop3_code_checked(scrblt->bRop), &gdi->palette);
712
0
}
713
714
static BOOL gdi_opaque_rect(rdpContext* context, const OPAQUE_RECT_ORDER* opaque_rect)
715
0
{
716
0
  WINPR_ASSERT(context);
717
0
  WINPR_ASSERT(opaque_rect);
718
719
0
  GDI_RECT rect;
720
0
  HGDI_BRUSH hBrush = NULL;
721
0
  UINT32 brush_color = 0;
722
0
  rdpGdi* gdi = context->gdi;
723
0
  BOOL ret = 0;
724
0
  INT32 x = opaque_rect->nLeftRect;
725
0
  INT32 y = opaque_rect->nTopRect;
726
0
  INT32 w = opaque_rect->nWidth;
727
0
  INT32 h = opaque_rect->nHeight;
728
0
  if (!gdi || !gdi->drawing)
729
0
    return FALSE;
730
731
0
  if (!gdi_CRgnToRect(x, y, w, h, &rect))
732
0
    return TRUE;
733
734
0
  if (!gdi_decode_color(gdi, opaque_rect->color, &brush_color, NULL))
735
0
    return FALSE;
736
737
0
  if (!(hBrush = gdi_CreateSolidBrush(brush_color)))
738
0
    return FALSE;
739
740
0
  ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
741
0
  gdi_DeleteObject((HGDIOBJECT)hBrush);
742
0
  return ret;
743
0
}
744
745
static BOOL gdi_multi_opaque_rect(rdpContext* context,
746
                                  const MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect)
747
0
{
748
0
  WINPR_ASSERT(context);
749
0
  WINPR_ASSERT(multi_opaque_rect);
750
751
0
  GDI_RECT rect = WINPR_C_ARRAY_INIT;
752
0
  UINT32 brush_color = 0;
753
0
  rdpGdi* gdi = context->gdi;
754
0
  BOOL ret = TRUE;
755
756
0
  if (!gdi || !gdi->drawing)
757
0
    return FALSE;
758
759
0
  if (!gdi_decode_color(gdi, multi_opaque_rect->color, &brush_color, NULL))
760
0
    return FALSE;
761
762
0
  HGDI_BRUSH hBrush = gdi_CreateSolidBrush(brush_color);
763
764
0
  if (!hBrush)
765
0
    return FALSE;
766
767
0
  for (UINT32 i = 0; i < multi_opaque_rect->numRectangles; i++)
768
0
  {
769
0
    const DELTA_RECT* rectangle = &multi_opaque_rect->rectangles[i];
770
0
    const INT32 x = rectangle->left;
771
0
    const INT32 y = rectangle->top;
772
0
    const INT32 w = rectangle->width;
773
0
    const INT32 h = rectangle->height;
774
775
0
    ret = FALSE;
776
0
    if (!gdi_CRgnToRect(x, y, w, h, &rect))
777
0
      break;
778
0
    ret = gdi_FillRect(gdi->drawing->hdc, &rect, hBrush);
779
780
0
    if (!ret)
781
0
      break;
782
0
  }
783
784
0
  gdi_DeleteObject((HGDIOBJECT)hBrush);
785
0
  return ret;
786
0
}
787
788
static BOOL gdi_line_to(rdpContext* context, const LINE_TO_ORDER* lineTo)
789
0
{
790
0
  BOOL rc = FALSE;
791
0
  UINT32 color = 0;
792
0
  WINPR_ASSERT(context);
793
0
  WINPR_ASSERT(lineTo);
794
795
0
  rdpGdi* gdi = context->gdi;
796
0
  if (!gdi || !gdi->drawing || !gdi->drawing->hdc)
797
0
    return FALSE;
798
799
0
  if (!gdi_decode_color(gdi, lineTo->penColor, &color, NULL))
800
0
    return FALSE;
801
802
0
  HGDI_PEN hPen = gdi_CreatePen(lineTo->penStyle, lineTo->penWidth, color,
803
0
                                gdi->drawing->hdc->format, &gdi->palette);
804
0
  if (!hPen)
805
0
    return FALSE;
806
807
0
  WINPR_ASSERT(gdi->drawing);
808
809
0
  gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT)hPen);
810
0
  gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, lineTo->bRop2));
811
0
  if (!gdi_MoveToEx(gdi->drawing->hdc, lineTo->nXStart, lineTo->nYStart, NULL))
812
0
    goto fail;
813
0
  if (!gdi_LineTo(gdi->drawing->hdc, lineTo->nXEnd, lineTo->nYEnd))
814
0
    goto fail;
815
816
0
  rc = TRUE;
817
0
fail:
818
0
  gdi_DeleteObject((HGDIOBJECT)hPen);
819
0
  return rc;
820
0
}
821
822
static BOOL gdi_polyline(rdpContext* context, const POLYLINE_ORDER* polyline)
823
0
{
824
0
  BOOL rc = FALSE;
825
0
  WINPR_ASSERT(context);
826
0
  WINPR_ASSERT(polyline);
827
828
0
  rdpGdi* gdi = context->gdi;
829
0
  if (!gdi || !gdi->drawing || !gdi->drawing->hdc)
830
0
    return FALSE;
831
832
0
  UINT32 color = 0;
833
0
  if (!gdi_decode_color(gdi, polyline->penColor, &color, NULL))
834
0
    return FALSE;
835
836
0
  WINPR_ASSERT(gdi->drawing);
837
0
  WINPR_ASSERT(gdi->drawing->hdc);
838
839
0
  HGDI_PEN hPen = gdi_CreatePen(GDI_PS_SOLID, 1, color, gdi->drawing->hdc->format, &gdi->palette);
840
0
  if (!hPen)
841
0
    return FALSE;
842
843
0
  gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT)hPen);
844
0
  gdi_SetROP2(gdi->drawing->hdc, WINPR_ASSERTING_INT_CAST(int32_t, polyline->bRop2));
845
0
  INT32 x = polyline->xStart;
846
0
  INT32 y = polyline->yStart;
847
0
  if (!gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL))
848
0
    goto fail;
849
0
  DELTA_POINT* points = polyline->points;
850
851
0
  for (UINT32 i = 0; i < polyline->numDeltaEntries; i++)
852
0
  {
853
0
    x += points[i].x;
854
0
    y += points[i].y;
855
0
    if (!gdi_LineTo(gdi->drawing->hdc, x, y))
856
0
      goto fail;
857
0
    if (!gdi_MoveToEx(gdi->drawing->hdc, x, y, NULL))
858
0
      goto fail;
859
0
  }
860
861
0
  rc = TRUE;
862
0
fail:
863
0
  gdi_DeleteObject((HGDIOBJECT)hPen);
864
0
  return rc;
865
0
}
866
867
static BOOL gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
868
0
{
869
0
  if (!context || !memblt || !memblt->bitmap)
870
0
    return FALSE;
871
872
0
  gdiBitmap* bitmap = (gdiBitmap*)memblt->bitmap;
873
0
  rdpGdi* gdi = context->gdi;
874
0
  if (!gdi || !gdi->drawing)
875
0
    return FALSE;
876
0
  return gdi_BitBlt(gdi->drawing->hdc, memblt->nLeftRect, memblt->nTopRect, memblt->nWidth,
877
0
                    memblt->nHeight, bitmap->hdc, memblt->nXSrc, memblt->nYSrc,
878
0
                    gdi_rop3_code_checked(memblt->bRop), &gdi->palette);
879
0
}
880
881
static BOOL gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
882
0
{
883
0
  WINPR_ASSERT(context);
884
0
  WINPR_ASSERT(mem3blt);
885
886
0
  HGDI_BRUSH originalBrush = NULL;
887
0
  rdpGdi* gdi = context->gdi;
888
0
  if (!gdi || !gdi->drawing)
889
0
    return FALSE;
890
891
0
  BOOL ret = TRUE;
892
0
  const rdpBrush* brush = &mem3blt->brush;
893
0
  gdiBitmap* bitmap = (gdiBitmap*)mem3blt->bitmap;
894
0
  UINT32 foreColor = 0;
895
0
  UINT32 backColor = 0;
896
0
  UINT32 originalColor = 0;
897
898
0
  if (!gdi_decode_color(gdi, mem3blt->foreColor, &foreColor, NULL))
899
0
    return FALSE;
900
901
0
  if (!gdi_decode_color(gdi, mem3blt->backColor, &backColor, NULL))
902
0
    return FALSE;
903
904
0
  originalColor = gdi_SetTextColor(gdi->drawing->hdc, foreColor);
905
906
0
  switch (brush->style)
907
0
  {
908
0
    case GDI_BS_SOLID:
909
0
      originalBrush = gdi->drawing->hdc->brush;
910
0
      gdi->drawing->hdc->brush = gdi_CreateSolidBrush(foreColor);
911
912
0
      if (!gdi->drawing->hdc->brush)
913
0
      {
914
0
        ret = FALSE;
915
0
        goto out_fail;
916
0
      }
917
918
0
      ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
919
0
                       mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
920
0
                       mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
921
0
      gdi_DeleteObject((HGDIOBJECT)gdi->drawing->hdc->brush);
922
0
      gdi->drawing->hdc->brush = originalBrush;
923
0
      break;
924
925
0
    case GDI_BS_PATTERN:
926
0
    {
927
0
      HGDI_BITMAP hBmp = NULL;
928
0
      UINT32 brushFormat = 0;
929
0
      BYTE* data = (BYTE*)winpr_aligned_malloc(
930
0
          8ULL * 8ULL * FreeRDPGetBytesPerPixel(gdi->drawing->hdc->format), 16);
931
932
0
      if (!data)
933
0
      {
934
0
        ret = FALSE;
935
0
        goto out_fail;
936
0
      }
937
938
0
      if (brush->bpp > 1)
939
0
      {
940
0
        UINT32 bpp = brush->bpp;
941
942
0
        const UINT32 ColorDepth =
943
0
            freerdp_settings_get_uint32(gdi->context->settings, FreeRDP_ColorDepth);
944
0
        if ((bpp == 16) && (ColorDepth == 15))
945
0
          bpp = 15;
946
947
0
        brushFormat = gdi_get_pixel_format(bpp);
948
949
0
        if (!freerdp_image_copy_no_overlap(data, gdi->drawing->hdc->format, 0, 0, 0, 8, 8,
950
0
                                           brush->data, brushFormat, 0, 0, 0, &gdi->palette,
951
0
                                           FREERDP_FLIP_NONE))
952
0
        {
953
0
          ret = FALSE;
954
0
          winpr_aligned_free(data);
955
0
          goto out_fail;
956
0
        }
957
0
      }
958
0
      else
959
0
      {
960
0
        if (!freerdp_image_copy_from_monochrome(data, gdi->drawing->hdc->format, 0, 0, 0, 8,
961
0
                                                8, brush->data, backColor, foreColor,
962
0
                                                &gdi->palette))
963
0
        {
964
0
          ret = FALSE;
965
0
          winpr_aligned_free(data);
966
0
          goto out_fail;
967
0
        }
968
0
      }
969
970
0
      hBmp = gdi_CreateBitmap(8, 8, gdi->drawing->hdc->format, data);
971
972
0
      if (!hBmp)
973
0
      {
974
0
        ret = FALSE;
975
0
        winpr_aligned_free(data);
976
0
        goto out_fail;
977
0
      }
978
979
0
      originalBrush = gdi->drawing->hdc->brush;
980
0
      gdi->drawing->hdc->brush = gdi_CreatePatternBrush(hBmp);
981
982
0
      if (!gdi->drawing->hdc->brush)
983
0
      {
984
0
        gdi_DeleteObject((HGDIOBJECT)hBmp);
985
0
        goto out_fail;
986
0
      }
987
988
0
      gdi->drawing->hdc->brush->nXOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->x);
989
0
      gdi->drawing->hdc->brush->nYOrg = WINPR_ASSERTING_INT_CAST(int32_t, brush->y);
990
0
      ret = gdi_BitBlt(gdi->drawing->hdc, mem3blt->nLeftRect, mem3blt->nTopRect,
991
0
                       mem3blt->nWidth, mem3blt->nHeight, bitmap->hdc, mem3blt->nXSrc,
992
0
                       mem3blt->nYSrc, gdi_rop3_code_checked(mem3blt->bRop), &gdi->palette);
993
0
      gdi_DeleteObject((HGDIOBJECT)gdi->drawing->hdc->brush);
994
0
      gdi_DeleteObject((HGDIOBJECT)hBmp);
995
0
      gdi->drawing->hdc->brush = originalBrush;
996
0
    }
997
0
    break;
998
999
0
    default:
1000
0
      WLog_ERR(TAG, "Mem3Blt unimplemented brush style:%" PRIu32 "", brush->style);
1001
0
      break;
1002
0
  }
1003
1004
0
out_fail:
1005
0
  gdi_SetTextColor(gdi->drawing->hdc, originalColor);
1006
0
  return ret;
1007
0
}
1008
1009
static BOOL gdi_polygon_sc(WINPR_ATTR_UNUSED rdpContext* context,
1010
                           WINPR_ATTR_UNUSED const POLYGON_SC_ORDER* polygon_sc)
1011
0
{
1012
0
  WLog_WARN(TAG, "not implemented");
1013
0
  return FALSE;
1014
0
}
1015
1016
static BOOL gdi_polygon_cb(WINPR_ATTR_UNUSED rdpContext* context,
1017
                           WINPR_ATTR_UNUSED POLYGON_CB_ORDER* polygon_cb)
1018
0
{
1019
0
  WLog_WARN(TAG, "not implemented");
1020
0
  return FALSE;
1021
0
}
1022
1023
static BOOL gdi_ellipse_sc(WINPR_ATTR_UNUSED rdpContext* context,
1024
                           WINPR_ATTR_UNUSED const ELLIPSE_SC_ORDER* ellipse_sc)
1025
0
{
1026
0
  WLog_WARN(TAG, "not implemented");
1027
0
  return FALSE;
1028
0
}
1029
1030
static BOOL gdi_ellipse_cb(WINPR_ATTR_UNUSED rdpContext* context,
1031
                           WINPR_ATTR_UNUSED const ELLIPSE_CB_ORDER* ellipse_cb)
1032
0
{
1033
0
  WLog_WARN(TAG, "not implemented");
1034
0
  return FALSE;
1035
0
}
1036
1037
static BOOL gdi_frame_marker(WINPR_ATTR_UNUSED rdpContext* context,
1038
                             WINPR_ATTR_UNUSED const FRAME_MARKER_ORDER* frameMarker)
1039
0
{
1040
0
  return TRUE;
1041
0
}
1042
1043
static BOOL gdi_surface_frame_marker(rdpContext* context,
1044
                                     const SURFACE_FRAME_MARKER* surfaceFrameMarker)
1045
0
{
1046
0
  WINPR_ASSERT(context);
1047
0
  WINPR_ASSERT(context->gdi);
1048
0
  WINPR_ASSERT(context->update);
1049
0
  WINPR_ASSERT(surfaceFrameMarker);
1050
1051
0
  WLog_Print(context->gdi->log, WLOG_DEBUG, "frameId %" PRIu32 " frameAction %" PRIu32 "",
1052
0
             surfaceFrameMarker->frameId, surfaceFrameMarker->frameAction);
1053
1054
0
  switch (surfaceFrameMarker->frameAction)
1055
0
  {
1056
0
    case SURFACECMD_FRAMEACTION_BEGIN:
1057
0
      break;
1058
1059
0
    case SURFACECMD_FRAMEACTION_END:
1060
0
      if (freerdp_settings_get_uint32(context->settings, FreeRDP_FrameAcknowledge) > 0)
1061
0
      {
1062
0
        if (!IFCALLRESULT(TRUE, context->update->SurfaceFrameAcknowledge, context,
1063
0
                          surfaceFrameMarker->frameId))
1064
0
          return FALSE;
1065
0
      }
1066
1067
0
      break;
1068
0
    default:
1069
0
      break;
1070
0
  }
1071
1072
0
  return TRUE;
1073
0
}
1074
1075
static BOOL intersect_rect(const rdpGdi* gdi, const SURFACE_BITS_COMMAND* cmd, RECTANGLE_16* prect)
1076
0
{
1077
0
  WINPR_ASSERT(gdi);
1078
0
  WINPR_ASSERT(cmd);
1079
0
  WINPR_ASSERT(prect);
1080
1081
0
  const UINT32 w = (const UINT32)gdi->width;
1082
0
  const UINT32 h = (const UINT32)gdi->height;
1083
1084
0
  if (cmd->destLeft > w)
1085
0
    return FALSE;
1086
0
  if (cmd->destRight > w)
1087
0
    return FALSE;
1088
0
  if (cmd->destLeft > cmd->destRight)
1089
0
    return FALSE;
1090
0
  if (cmd->destRight > UINT16_MAX)
1091
0
    return FALSE;
1092
1093
0
  if (cmd->destTop > h)
1094
0
    return FALSE;
1095
0
  if (cmd->destBottom > h)
1096
0
    return FALSE;
1097
0
  if (cmd->destTop > cmd->destBottom)
1098
0
    return FALSE;
1099
0
  if (cmd->destBottom > UINT16_MAX)
1100
0
    return FALSE;
1101
1102
0
  prect->left = (const UINT16)cmd->destLeft;
1103
0
  prect->top = (const UINT16)cmd->destTop;
1104
0
  prect->right = MIN((UINT16)cmd->destRight, prect->left + cmd->bmp.width);
1105
0
  prect->bottom = MIN((UINT16)cmd->destBottom, prect->top + cmd->bmp.height);
1106
0
  return TRUE;
1107
0
}
1108
1109
static BOOL gdi_surface_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cmd)
1110
0
{
1111
0
  BOOL result = FALSE;
1112
0
  DWORD format = 0;
1113
0
  size_t size = 0;
1114
0
  REGION16 region;
1115
0
  RECTANGLE_16 cmdRect = WINPR_C_ARRAY_INIT;
1116
1117
0
  if (!context || !cmd)
1118
0
    return FALSE;
1119
1120
0
  rdpGdi* gdi = context->gdi;
1121
0
  if (!gdi)
1122
0
    return FALSE;
1123
1124
0
  WLog_Print(gdi->log, WLOG_DEBUG,
1125
0
             "destLeft %" PRIu32 " destTop %" PRIu32 " destRight %" PRIu32 " destBottom %" PRIu32
1126
0
             " "
1127
0
             "bpp %" PRIu8 " flags %" PRIx8 " codecID %s [0x%04" PRIu16 "] width %" PRIu16
1128
0
             " height %" PRIu16 " length %" PRIu32 "",
1129
0
             cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bmp.bpp,
1130
0
             cmd->bmp.flags, freerdp_codec_id_to_str(cmd->bmp.codecID), cmd->bmp.codecID,
1131
0
             cmd->bmp.width, cmd->bmp.height, cmd->bmp.bitmapDataLength);
1132
0
  region16_init(&region);
1133
1134
0
  if (!intersect_rect(gdi, cmd, &cmdRect))
1135
0
    goto out;
1136
1137
0
  switch (cmd->bmp.codecID)
1138
0
  {
1139
0
    case RDP_CODEC_ID_REMOTEFX:
1140
0
    case RDP_CODEC_ID_IMAGE_REMOTEFX:
1141
0
      if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData,
1142
0
                               cmd->bmp.bitmapDataLength, cmdRect.left, cmdRect.top,
1143
0
                               gdi->primary_buffer, gdi->dstFormat, gdi->stride,
1144
0
                               WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height), &region))
1145
0
      {
1146
0
        WLog_ERR(TAG, "Failed to process RemoteFX message");
1147
0
        goto out;
1148
0
      }
1149
1150
0
      break;
1151
1152
0
    case RDP_CODEC_ID_NSCODEC:
1153
0
      format = gdi->dstFormat;
1154
1155
0
      if (!nsc_process_message(
1156
0
              context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, cmd->bmp.height,
1157
0
              cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, format,
1158
0
              gdi->stride, cmdRect.left, cmdRect.top,
1159
0
              WINPR_ASSERTING_INT_CAST(UINT32, gdi->width),
1160
0
              WINPR_ASSERTING_INT_CAST(UINT32, gdi->height), FREERDP_FLIP_VERTICAL))
1161
0
      {
1162
0
        WLog_ERR(TAG, "Failed to process NSCodec message");
1163
0
        goto out;
1164
0
      }
1165
1166
0
      if (!region16_union_rect(&region, &region, &cmdRect))
1167
0
        goto out;
1168
0
      break;
1169
1170
0
    case RDP_CODEC_ID_NONE:
1171
0
      format = gdi_get_pixel_format(cmd->bmp.bpp);
1172
0
      size = 1ull * cmd->bmp.width * cmd->bmp.height * FreeRDPGetBytesPerPixel(format);
1173
0
      if (size > cmd->bmp.bitmapDataLength)
1174
0
      {
1175
0
        WLog_ERR(TAG, "Short nocodec message: got %" PRIu32 " bytes, require %" PRIuz,
1176
0
                 cmd->bmp.bitmapDataLength, size);
1177
0
        goto out;
1178
0
      }
1179
1180
0
      if (!freerdp_image_copy_no_overlap(
1181
0
              gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmdRect.left, cmdRect.top,
1182
0
              cmdRect.right - cmdRect.left, cmdRect.bottom - cmdRect.top, cmd->bmp.bitmapData,
1183
0
              format, 0, 0, 0, &gdi->palette, FREERDP_FLIP_VERTICAL))
1184
0
      {
1185
0
        WLog_ERR(TAG, "Failed to process nocodec message");
1186
0
        goto out;
1187
0
      }
1188
1189
0
      if (!region16_union_rect(&region, &region, &cmdRect))
1190
0
        goto out;
1191
0
      break;
1192
1193
0
    default:
1194
0
      WLog_ERR(TAG, "Unsupported codecID %" PRIu32 "", cmd->bmp.codecID);
1195
0
      break;
1196
0
  }
1197
1198
0
  {
1199
0
    UINT32 nbRects = 0;
1200
0
    const RECTANGLE_16* rects = region16_rects(&region, &nbRects);
1201
0
    if (!rects && (nbRects > 0))
1202
0
      goto out;
1203
1204
0
    if (nbRects == 0)
1205
0
    {
1206
0
      const int32_t w = cmdRect.right - cmdRect.left;
1207
0
      const int32_t h = cmdRect.bottom - cmdRect.top;
1208
0
      if (!gdi_InvalidateRegion(gdi->primary->hdc, cmdRect.left, cmdRect.top, w, h))
1209
0
        goto out;
1210
0
    }
1211
0
    for (UINT32 i = 0; i < nbRects; i++)
1212
0
    {
1213
0
      const RECTANGLE_16* rect = &rects[i];
1214
1215
0
      UINT32 left = rect->left;
1216
0
      UINT32 top = rect->top;
1217
0
      UINT32 width = rect->right - rect->left;
1218
0
      UINT32 height = rect->bottom - rect->top;
1219
1220
0
      if (!gdi_InvalidateRegion(gdi->primary->hdc, WINPR_ASSERTING_INT_CAST(int32_t, left),
1221
0
                                WINPR_ASSERTING_INT_CAST(int32_t, top),
1222
0
                                WINPR_ASSERTING_INT_CAST(int32_t, width),
1223
0
                                WINPR_ASSERTING_INT_CAST(int32_t, height)))
1224
0
      {
1225
0
        WLog_ERR(TAG, "Failed to update invalid region");
1226
0
        goto out;
1227
0
      }
1228
0
    }
1229
0
  }
1230
0
  result = TRUE;
1231
0
out:
1232
0
  region16_uninit(&region);
1233
0
  return result;
1234
0
}
1235
1236
/**
1237
 * Register GDI callbacks with libfreerdp-core.
1238
 * @param update current instance
1239
 */
1240
1241
static void gdi_register_update_callbacks(rdpUpdate* update)
1242
0
{
1243
0
  WINPR_ASSERT(update);
1244
0
  WINPR_ASSERT(update->context);
1245
1246
0
  const rdpSettings* settings = update->context->settings;
1247
0
  WINPR_ASSERT(settings);
1248
1249
0
  rdpPrimaryUpdate* primary = update->primary;
1250
0
  WINPR_ASSERT(primary);
1251
1252
0
  if (freerdp_settings_get_bool(settings, FreeRDP_DeactivateClientDecoding))
1253
0
    return;
1254
0
  update->Palette = gdi_palette_update;
1255
0
  update->SetBounds = gdi_set_bounds;
1256
0
  primary->DstBlt = gdi_dstblt;
1257
0
  primary->PatBlt = gdi_patblt;
1258
0
  primary->ScrBlt = gdi_scrblt;
1259
0
  primary->OpaqueRect = gdi_opaque_rect;
1260
0
  primary->DrawNineGrid = NULL;
1261
0
  primary->MultiDstBlt = NULL;
1262
0
  primary->MultiPatBlt = NULL;
1263
0
  primary->MultiScrBlt = NULL;
1264
0
  primary->MultiOpaqueRect = gdi_multi_opaque_rect;
1265
0
  primary->MultiDrawNineGrid = NULL;
1266
0
  primary->LineTo = gdi_line_to;
1267
0
  primary->Polyline = gdi_polyline;
1268
0
  primary->MemBlt = gdi_memblt;
1269
0
  primary->Mem3Blt = gdi_mem3blt;
1270
0
  primary->SaveBitmap = NULL;
1271
0
  primary->GlyphIndex = NULL;
1272
0
  primary->FastIndex = NULL;
1273
0
  primary->FastGlyph = NULL;
1274
0
  primary->PolygonSC = gdi_polygon_sc;
1275
0
  primary->PolygonCB = gdi_polygon_cb;
1276
0
  primary->EllipseSC = gdi_ellipse_sc;
1277
0
  primary->EllipseCB = gdi_ellipse_cb;
1278
0
  update->SurfaceBits = gdi_surface_bits;
1279
0
  update->SurfaceFrameMarker = gdi_surface_frame_marker;
1280
0
  update->altsec->FrameMarker = gdi_frame_marker;
1281
0
}
1282
1283
static BOOL gdi_init_primary(rdpGdi* gdi, UINT32 stride, UINT32 format, BYTE* buffer,
1284
                             void (*pfree)(void*), BOOL isLocked)
1285
0
{
1286
0
  WINPR_ASSERT(gdi);
1287
0
  WINPR_ASSERT(gdi->context);
1288
0
  WINPR_ASSERT(gdi->context->update);
1289
0
  if (!isLocked)
1290
0
    rdp_update_lock(gdi->context->update);
1291
1292
0
  gdi->primary = (gdiBitmap*)calloc(1, sizeof(gdiBitmap));
1293
1294
0
  if (format > 0)
1295
0
    gdi->dstFormat = format;
1296
1297
0
  if (stride > 0)
1298
0
    gdi->stride = stride;
1299
0
  else
1300
0
    gdi->stride = WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width) *
1301
0
                  FreeRDPGetBytesPerPixel(gdi->dstFormat);
1302
1303
0
  if (!gdi->primary)
1304
0
    goto fail_primary;
1305
1306
0
  if (!(gdi->primary->hdc = gdi_CreateCompatibleDC(gdi->hdc)))
1307
0
    goto fail_hdc;
1308
1309
0
  if (!buffer)
1310
0
  {
1311
0
    gdi->primary->bitmap =
1312
0
        gdi_CreateCompatibleBitmap(gdi->hdc, WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1313
0
                                   WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height));
1314
0
  }
1315
0
  else
1316
0
  {
1317
0
    gdi->primary->bitmap = gdi_CreateBitmapEx(WINPR_ASSERTING_INT_CAST(uint32_t, gdi->width),
1318
0
                                              WINPR_ASSERTING_INT_CAST(uint32_t, gdi->height),
1319
0
                                              gdi->dstFormat, gdi->stride, buffer, pfree);
1320
0
  }
1321
1322
0
  if (!gdi->primary->bitmap)
1323
0
    goto fail_bitmap;
1324
1325
0
  gdi->stride = gdi->primary->bitmap->scanline;
1326
0
  gdi_SelectObject(gdi->primary->hdc, (HGDIOBJECT)gdi->primary->bitmap);
1327
0
  gdi->primary->org_bitmap = NULL;
1328
0
  gdi->primary_buffer = gdi->primary->bitmap->data;
1329
1330
0
  if (!(gdi->primary->hdc->hwnd = (HGDI_WND)calloc(1, sizeof(GDI_WND))))
1331
0
    goto fail_hwnd;
1332
1333
0
  if (!(gdi->primary->hdc->hwnd->invalid = gdi_CreateRectRgn(0, 0, 0, 0)))
1334
0
    goto fail_hwnd;
1335
1336
0
  gdi->primary->hdc->hwnd->invalid->null = TRUE;
1337
0
  gdi->primary->hdc->hwnd->count = 32;
1338
1339
0
  if (!(gdi->primary->hdc->hwnd->cinvalid =
1340
0
            (GDI_RGN*)calloc(gdi->primary->hdc->hwnd->count, sizeof(GDI_RGN))))
1341
0
    goto fail_hwnd;
1342
1343
0
  gdi->primary->hdc->hwnd->ninvalid = 0;
1344
1345
0
  if (!gdi->drawing)
1346
0
    gdi->drawing = gdi->primary;
1347
1348
0
  rdp_update_unlock(gdi->context->update);
1349
0
  return TRUE;
1350
0
fail_hwnd:
1351
0
  gdi_DeleteObject((HGDIOBJECT)gdi->primary->bitmap);
1352
0
fail_bitmap:
1353
0
  gdi_DeleteDC(gdi->primary->hdc);
1354
0
fail_hdc:
1355
0
  free(gdi->primary);
1356
0
  gdi->primary = NULL;
1357
0
fail_primary:
1358
0
  rdp_update_unlock(gdi->context->update);
1359
0
  return FALSE;
1360
0
}
1361
1362
BOOL gdi_resize(rdpGdi* gdi, UINT32 width, UINT32 height)
1363
0
{
1364
0
  return gdi_resize_ex(gdi, width, height, 0, 0, NULL, NULL);
1365
0
}
1366
1367
BOOL gdi_resize_ex(rdpGdi* gdi, UINT32 width, UINT32 height, UINT32 stride, UINT32 format,
1368
                   BYTE* buffer, void (*pfree)(void*))
1369
0
{
1370
0
  if (!gdi || !gdi->primary)
1371
0
    return FALSE;
1372
1373
0
  if ((width > INT32_MAX) || (height > INT32_MAX))
1374
0
    return FALSE;
1375
1376
0
  if ((gdi->width == (INT32)width) && (gdi->height == (INT32)height) &&
1377
0
      (!buffer || (gdi->primary_buffer == buffer)))
1378
0
    return TRUE;
1379
1380
0
  WINPR_ASSERT(gdi->context);
1381
0
  WINPR_ASSERT(gdi->context->update);
1382
1383
  /* EndPaint might not have been called, ensure the update lock is released */
1384
0
  if (!update_end_paint(gdi->context->update))
1385
0
    return FALSE;
1386
0
  rdp_update_lock(gdi->context->update);
1387
1388
0
  if (gdi->drawing == gdi->primary)
1389
0
    gdi->drawing = NULL;
1390
1391
0
  gdi->width = (INT32)width;
1392
0
  gdi->height = (INT32)height;
1393
0
  gdi_bitmap_free_ex(gdi->primary);
1394
0
  gdi->primary = NULL;
1395
0
  gdi->primary_buffer = NULL;
1396
0
  return gdi_init_primary(gdi, stride, format, buffer, pfree, TRUE);
1397
0
}
1398
1399
/**
1400
 * Initialize GDI
1401
 *
1402
 * @param instance A pointer to the instance to use
1403
 * @param format The color format for the local framebuffer
1404
 * @return \b TRUE for success, \b FALSE for failure
1405
 */
1406
BOOL gdi_init(freerdp* instance, UINT32 format)
1407
0
{
1408
0
  return gdi_init_ex(instance, format, 0, NULL, winpr_aligned_free);
1409
0
}
1410
1411
/**
1412
 * Initialize GDI
1413
 *
1414
 * @param instance A pointer to the instance to use
1415
 * @param format The color format for the local framebuffer
1416
 * @param stride The size of a framebuffer line in bytes
1417
 * @param buffer A pointer to a buffer to be used as framebuffer
1418
 * @param pfree A custom function pointer to use to free the framebuffer
1419
 *
1420
 * @return \b TRUE for success, \b FALSE for failure
1421
 */
1422
BOOL gdi_init_ex(freerdp* instance, UINT32 format, UINT32 stride, BYTE* buffer,
1423
                 void (*pfree)(void*))
1424
0
{
1425
0
  rdpContext* context = NULL;
1426
0
  UINT32 SrcFormat = 0;
1427
0
  rdpGdi* gdi = NULL;
1428
1429
0
  WINPR_ASSERT(instance);
1430
1431
0
  context = instance->context;
1432
0
  WINPR_ASSERT(context);
1433
0
  WINPR_ASSERT(context->settings);
1434
1435
0
  const UINT32 ColorDepth = freerdp_settings_get_uint32(context->settings, FreeRDP_ColorDepth);
1436
0
  SrcFormat = gdi_get_pixel_format(ColorDepth);
1437
0
  gdi = (rdpGdi*)calloc(1, sizeof(rdpGdi));
1438
1439
0
  if (!gdi)
1440
0
    goto fail;
1441
1442
0
  context->gdi = gdi;
1443
0
  gdi->log = WLog_Get(TAG);
1444
1445
0
  if (!gdi->log)
1446
0
    goto fail;
1447
1448
0
  gdi->context = context;
1449
0
  gdi->width = WINPR_ASSERTING_INT_CAST(
1450
0
      int32_t, freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth));
1451
0
  gdi->height = WINPR_ASSERTING_INT_CAST(
1452
0
      int32_t, freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopHeight));
1453
0
  gdi->dstFormat = format;
1454
  /* default internal buffer format */
1455
0
  WLog_Print(gdi->log, WLOG_INFO, "Local framebuffer format  %s",
1456
0
             FreeRDPGetColorFormatName(gdi->dstFormat));
1457
0
  WLog_Print(gdi->log, WLOG_INFO, "Remote framebuffer format %s",
1458
0
             FreeRDPGetColorFormatName(SrcFormat));
1459
1460
0
  if (!(gdi->hdc = gdi_GetDC()))
1461
0
    goto fail;
1462
1463
0
  gdi->hdc->format = gdi->dstFormat;
1464
1465
0
  if (!gdi_init_primary(gdi, stride, gdi->dstFormat, buffer, pfree, FALSE))
1466
0
    goto fail;
1467
1468
0
  if (!(context->cache = cache_new(context)))
1469
0
    goto fail;
1470
1471
0
  gdi_register_update_callbacks(context->update);
1472
0
  brush_cache_register_callbacks(context->update);
1473
0
  glyph_cache_register_callbacks(context->update);
1474
0
  bitmap_cache_register_callbacks(context->update);
1475
0
  offscreen_cache_register_callbacks(context->update);
1476
0
  palette_cache_register_callbacks(context->update);
1477
1478
0
  if (!gdi_register_graphics(context->graphics))
1479
0
    goto fail;
1480
1481
0
  return TRUE;
1482
0
fail:
1483
0
  gdi_free(instance);
1484
0
  WLog_ERR(TAG, "failed to initialize gdi");
1485
0
  return FALSE;
1486
0
}
1487
1488
void gdi_free(freerdp* instance)
1489
0
{
1490
0
  rdpGdi* gdi = NULL;
1491
0
  rdpContext* context = NULL;
1492
1493
0
  if (!instance || !instance->context)
1494
0
    return;
1495
1496
0
  gdi = instance->context->gdi;
1497
1498
0
  if (gdi)
1499
0
  {
1500
0
    gdi_bitmap_free_ex(gdi->primary);
1501
0
    gdi_DeleteDC(gdi->hdc);
1502
0
    free(gdi);
1503
0
  }
1504
1505
0
  context = instance->context;
1506
0
  cache_free(context->cache);
1507
0
  context->cache = NULL;
1508
0
  instance->context->gdi = (rdpGdi*)NULL;
1509
0
}
1510
1511
BOOL gdi_send_suppress_output(rdpGdi* gdi, BOOL suppress)
1512
0
{
1513
0
  if (!gdi || !gdi->context)
1514
0
    return FALSE;
1515
1516
0
  if (gdi->suppressOutput == suppress)
1517
0
    return TRUE;
1518
1519
0
  gdi->suppressOutput = suppress;
1520
1521
0
  rdpContext* context = gdi->context;
1522
0
  rdpSettings* settings = context->settings;
1523
0
  WINPR_ASSERT(settings);
1524
1525
0
  rdpUpdate* update = context->update;
1526
0
  WINPR_ASSERT(update);
1527
1528
0
  const UINT32 w = freerdp_settings_get_uint32(settings, FreeRDP_DesktopWidth);
1529
0
  const UINT32 h = freerdp_settings_get_uint32(settings, FreeRDP_DesktopHeight);
1530
1531
0
  const RECTANGLE_16 rect = { .left = 0,
1532
0
                            .top = 0,
1533
0
                            .right = WINPR_ASSERTING_INT_CAST(UINT16, w),
1534
0
                            .bottom = WINPR_ASSERTING_INT_CAST(UINT16, h) };
1535
1536
0
  WINPR_ASSERT(update->SuppressOutput);
1537
0
  return update->SuppressOutput(context, !suppress, &rect);
1538
0
}