Coverage Report

Created: 2026-06-15 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/cache/glyph.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Glyph Cache
4
 *
5
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <freerdp/config.h>
21
22
#include <stdio.h>
23
24
#include <winpr/crt.h>
25
#include <winpr/assert.h>
26
#include <winpr/cast.h>
27
28
#include <freerdp/freerdp.h>
29
#include <winpr/stream.h>
30
31
#include <freerdp/log.h>
32
33
#include "glyph.h"
34
#include "cache.h"
35
36
#define TAG FREERDP_TAG("cache.glyph")
37
38
static rdpGlyph* glyph_cache_get(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index);
39
static BOOL glyph_cache_put(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index, rdpGlyph* glyph);
40
41
static const void* glyph_cache_fragment_get(rdpGlyphCache* glyphCache, UINT32 index, UINT32* size);
42
static BOOL glyph_cache_fragment_put(rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
43
                                     const void* fragment);
44
45
static UINT32 update_glyph_offset(const BYTE* data, size_t length, UINT32 index, INT32* x, INT32* y,
46
                                  UINT32 ulCharInc, UINT32 flAccel)
47
0
{
48
0
  if ((ulCharInc == 0) && (!(flAccel & SO_CHAR_INC_EQUAL_BM_BASE)))
49
0
  {
50
0
    if (index >= length)
51
0
    {
52
0
      WLog_WARN(TAG, "glyph offset index out of bound %" PRIu32 " [max %" PRIuz "]", index,
53
0
                length);
54
0
      return index;
55
0
    }
56
57
0
    UINT32 offset = data[index++];
58
59
0
    if (offset & 0x80)
60
0
    {
61
62
0
      if (index + 1 < length)
63
0
      {
64
0
        offset = data[index++];
65
0
        offset |= ((UINT32)data[index++]) << 8;
66
0
      }
67
0
      else
68
0
        WLog_WARN(TAG, "glyph index out of bound %" PRIu32 " [max %" PRIuz "]", index,
69
0
                  length);
70
0
    }
71
72
0
    if (flAccel & SO_VERTICAL)
73
0
      *y += WINPR_ASSERTING_INT_CAST(int32_t, offset);
74
75
0
    if (flAccel & SO_HORIZONTAL)
76
0
      *x += WINPR_ASSERTING_INT_CAST(int32_t, offset);
77
0
  }
78
79
0
  return index;
80
0
}
81
82
static BOOL update_process_glyph(rdpContext* context, const BYTE* data, UINT32 cacheIndex, INT32* x,
83
                                 const INT32* y, UINT32 cacheId, UINT32 flAccel, BOOL fOpRedundant,
84
                                 const RDP_RECT* bound)
85
0
{
86
0
  INT32 sx = 0;
87
0
  INT32 sy = 0;
88
89
0
  if (!context || !data || !x || !y || !context->graphics || !context->cache ||
90
0
      !context->cache->glyph)
91
0
    return FALSE;
92
93
0
  rdpGlyphCache* glyph_cache = context->cache->glyph;
94
0
  rdpGlyph* glyph = glyph_cache_get(glyph_cache, cacheId, cacheIndex);
95
96
0
  if (!glyph)
97
0
    return FALSE;
98
99
0
  INT32 dx = glyph->x + *x;
100
0
  INT32 dy = glyph->y + *y;
101
102
0
  if (dx < bound->x)
103
0
  {
104
0
    sx = bound->x - dx;
105
0
    dx = bound->x;
106
0
  }
107
108
0
  if (dy < bound->y)
109
0
  {
110
0
    sy = bound->y - dy;
111
0
    dy = bound->y;
112
0
  }
113
114
0
  if ((dx <= (bound->x + bound->width)) && (dy <= (bound->y + bound->height)))
115
0
  {
116
0
    INT32 dw = WINPR_ASSERTING_INT_CAST(int32_t, glyph->cx) - sx;
117
0
    INT32 dh = WINPR_ASSERTING_INT_CAST(int32_t, glyph->cy) - sy;
118
119
0
    if ((dw + dx) > (bound->x + bound->width))
120
0
      dw = (bound->x + bound->width) - (dw + dx);
121
122
0
    if ((dh + dy) > (bound->y + bound->height))
123
0
      dh = (bound->y + bound->height) - (dh + dy);
124
125
0
    if ((dh > 0) && (dw > 0))
126
0
    {
127
0
      if (!glyph->Draw(context, glyph, dx, dy, dw, dh, sx, sy, fOpRedundant))
128
0
        return FALSE;
129
0
    }
130
0
  }
131
132
0
  if (flAccel & SO_CHAR_INC_EQUAL_BM_BASE)
133
0
    *x += WINPR_ASSERTING_INT_CAST(int32_t, glyph->cx);
134
135
0
  return TRUE;
136
0
}
137
138
static BOOL update_process_glyph_fragments(rdpContext* context, const BYTE* data, UINT32 length,
139
                                           UINT32 cacheId, UINT32 ulCharInc, UINT32 flAccel,
140
                                           UINT32 bgcolor, UINT32 fgcolor, INT32 x, INT32 y,
141
                                           INT32 bkX, INT32 bkY, INT32 bkWidth, INT32 bkHeight,
142
                                           INT32 opX, INT32 opY, INT32 opWidth, INT32 opHeight,
143
                                           BOOL fOpRedundant)
144
0
{
145
0
  UINT32 id = 0;
146
0
  UINT32 size = 0;
147
0
  UINT32 index = 0;
148
0
  const BYTE* fragments = nullptr;
149
0
  RDP_RECT bound = WINPR_C_ARRAY_INIT;
150
0
  BOOL rc = FALSE;
151
152
0
  if (!context || !data || !context->graphics || !context->cache || !context->cache->glyph)
153
0
    return FALSE;
154
155
0
  rdpGraphics* graphics = context->graphics;
156
0
  WINPR_ASSERT(graphics);
157
158
0
  WINPR_ASSERT(context->cache);
159
0
  rdpGlyphCache* glyph_cache = context->cache->glyph;
160
0
  WINPR_ASSERT(glyph_cache);
161
162
0
  {
163
0
    rdpGlyph* glyph = graphics->Glyph_Prototype;
164
0
    if (!glyph)
165
0
      goto fail;
166
167
    /* Limit op rectangle to visible screen. */
168
0
    if (opX < 0)
169
0
    {
170
0
      opWidth += opX;
171
0
      opX = 0;
172
0
    }
173
174
0
    if (opY < 0)
175
0
    {
176
0
      opHeight += opY;
177
0
      opY = 0;
178
0
    }
179
180
0
    if (opWidth < 0)
181
0
      opWidth = 0;
182
183
0
    if (opHeight < 0)
184
0
      opHeight = 0;
185
186
    /* Limit bk rectangle to visible screen. */
187
0
    if (bkX < 0)
188
0
    {
189
0
      bkWidth += bkX;
190
0
      bkX = 0;
191
0
    }
192
193
0
    if (bkY < 0)
194
0
    {
195
0
      bkHeight += bkY;
196
0
      bkY = 0;
197
0
    }
198
199
0
    if (bkWidth < 0)
200
0
      bkWidth = 0;
201
202
0
    if (bkHeight < 0)
203
0
      bkHeight = 0;
204
205
0
    {
206
0
      const UINT32 w = freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth);
207
0
      if (opX + opWidth > (INT64)w)
208
0
      {
209
        /**
210
         * Some Microsoft servers send erroneous high values close to the
211
         * sint16 maximum in the OpRight field of the GlyphIndex, FastIndex and
212
         * FastGlyph drawing orders, probably a result of applications trying to
213
         * clear the text line to the very right end.
214
         * One example where this can be seen is typing in notepad.exe within
215
         * a RDP session to Windows XP Professional SP3.
216
         * This workaround prevents resulting problems in the UI callbacks.
217
         */
218
0
        opWidth = WINPR_ASSERTING_INT_CAST(int, w) - opX;
219
0
      }
220
221
0
      if (bkX + bkWidth > (INT64)w)
222
0
      {
223
        /**
224
         * Some Microsoft servers send erroneous high values close to the
225
         * sint16 maximum in the OpRight field of the GlyphIndex, FastIndex and
226
         * FastGlyph drawing orders, probably a result of applications trying to
227
         * clear the text line to the very right end.
228
         * One example where this can be seen is typing in notepad.exe within
229
         * a RDP session to Windows XP Professional SP3.
230
         * This workaround prevents resulting problems in the UI callbacks.
231
         */
232
0
        bkWidth = WINPR_ASSERTING_INT_CAST(int, w) - bkX;
233
0
      }
234
0
    }
235
236
0
    bound.x = WINPR_ASSERTING_INT_CAST(INT16, bkX);
237
0
    bound.y = WINPR_ASSERTING_INT_CAST(INT16, bkY);
238
0
    bound.width = WINPR_ASSERTING_INT_CAST(INT16, bkWidth);
239
0
    bound.height = WINPR_ASSERTING_INT_CAST(INT16, bkHeight);
240
241
0
    if (!glyph->BeginDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor, fOpRedundant))
242
0
      goto fail;
243
244
0
    if (!IFCALLRESULT(TRUE, glyph->SetBounds, context, bkX, bkY, bkWidth, bkHeight))
245
0
      goto fail;
246
247
0
    while (index < length)
248
0
    {
249
0
      const UINT32 op = data[index++];
250
251
0
      switch (op)
252
0
      {
253
0
        case GLYPH_FRAGMENT_USE:
254
0
          if (index + 1 > length)
255
0
            goto fail;
256
257
0
          id = data[index++];
258
0
          fragments = (const BYTE*)glyph_cache_fragment_get(glyph_cache, id, &size);
259
260
0
          if (fragments == nullptr)
261
0
            goto fail;
262
263
0
          for (UINT32 n = 0; n < size;)
264
0
          {
265
0
            const UINT32 fop = fragments[n++];
266
0
            n = update_glyph_offset(fragments, size, n, &x, &y, ulCharInc, flAccel);
267
268
0
            if (!update_process_glyph(context, fragments, fop, &x, &y, cacheId, flAccel,
269
0
                                      fOpRedundant, &bound))
270
0
              goto fail;
271
0
          }
272
273
0
          break;
274
275
0
        case GLYPH_FRAGMENT_ADD:
276
0
          if (index + 2 > length)
277
0
            goto fail;
278
279
0
          id = data[index++];
280
0
          size = data[index++];
281
0
          glyph_cache_fragment_put(glyph_cache, id, size, data);
282
0
          break;
283
284
0
        default:
285
0
          index = update_glyph_offset(data, length, index, &x, &y, ulCharInc, flAccel);
286
287
0
          if (!update_process_glyph(context, data, op, &x, &y, cacheId, flAccel,
288
0
                                    fOpRedundant, &bound))
289
0
            goto fail;
290
291
0
          break;
292
0
      }
293
0
    }
294
295
0
    if (!glyph->EndDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor))
296
0
      goto fail;
297
0
  }
298
299
0
  rc = TRUE;
300
301
0
fail:
302
0
  return rc;
303
0
}
304
305
static BOOL update_gdi_glyph_index(rdpContext* context, GLYPH_INDEX_ORDER* glyphIndex)
306
0
{
307
0
  INT32 bkWidth = 0;
308
0
  INT32 bkHeight = 0;
309
0
  INT32 opWidth = 0;
310
0
  INT32 opHeight = 0;
311
312
0
  if (!context || !glyphIndex || !context->cache)
313
0
    return FALSE;
314
315
0
  if (glyphIndex->bkRight > glyphIndex->bkLeft)
316
0
    bkWidth = glyphIndex->bkRight - glyphIndex->bkLeft + 1;
317
318
0
  if (glyphIndex->opRight > glyphIndex->opLeft)
319
0
    opWidth = glyphIndex->opRight - glyphIndex->opLeft + 1;
320
321
0
  if (glyphIndex->bkBottom > glyphIndex->bkTop)
322
0
    bkHeight = glyphIndex->bkBottom - glyphIndex->bkTop + 1;
323
324
0
  if (glyphIndex->opBottom > glyphIndex->opTop)
325
0
    opHeight = glyphIndex->opBottom - glyphIndex->opTop + 1;
326
327
0
  return update_process_glyph_fragments(
328
0
      context, glyphIndex->data, glyphIndex->cbData, glyphIndex->cacheId, glyphIndex->ulCharInc,
329
0
      glyphIndex->flAccel, glyphIndex->backColor, glyphIndex->foreColor, glyphIndex->x,
330
0
      glyphIndex->y, glyphIndex->bkLeft, glyphIndex->bkTop, bkWidth, bkHeight, glyphIndex->opLeft,
331
0
      glyphIndex->opTop, opWidth, opHeight,
332
0
      WINPR_ASSERTING_INT_CAST(int32_t, glyphIndex->fOpRedundant));
333
0
}
334
335
static BOOL update_gdi_fast_index(rdpContext* context, const FAST_INDEX_ORDER* fastIndex)
336
0
{
337
0
  INT32 opWidth = 0;
338
0
  INT32 opHeight = 0;
339
0
  INT32 bkWidth = 0;
340
0
  INT32 bkHeight = 0;
341
0
  BOOL rc = FALSE;
342
343
0
  if (!context || !fastIndex || !context->cache)
344
0
    return FALSE;
345
346
0
  INT32 opLeft = fastIndex->opLeft;
347
0
  INT32 opTop = fastIndex->opTop;
348
0
  INT32 opRight = fastIndex->opRight;
349
0
  INT32 opBottom = fastIndex->opBottom;
350
0
  INT32 x = fastIndex->x;
351
0
  INT32 y = fastIndex->y;
352
353
0
  if (opBottom == -32768)
354
0
  {
355
0
    BYTE flags = (BYTE)(opTop & 0x0F);
356
357
0
    if (flags & 0x01)
358
0
      opBottom = fastIndex->bkBottom;
359
360
0
    if (flags & 0x02)
361
0
      opRight = fastIndex->bkRight;
362
363
0
    if (flags & 0x04)
364
0
      opTop = fastIndex->bkTop;
365
366
0
    if (flags & 0x08)
367
0
      opLeft = fastIndex->bkLeft;
368
0
  }
369
370
0
  if (opLeft == 0)
371
0
    opLeft = fastIndex->bkLeft;
372
373
0
  if (opRight == 0)
374
0
    opRight = fastIndex->bkRight;
375
376
  /* Server can send a massive number (32766) which appears to be
377
   * undocumented special behavior for "Erase all the way right".
378
   * X11 has nondeterministic results asking for a draw that wide. */
379
0
  if (opRight > (INT64)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth))
380
0
    opRight = (int)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth);
381
382
0
  if (x == -32768)
383
0
    x = fastIndex->bkLeft;
384
385
0
  if (y == -32768)
386
0
    y = fastIndex->bkTop;
387
388
0
  if (fastIndex->bkRight > fastIndex->bkLeft)
389
0
    bkWidth = fastIndex->bkRight - fastIndex->bkLeft + 1;
390
391
0
  if (fastIndex->bkBottom > fastIndex->bkTop)
392
0
    bkHeight = fastIndex->bkBottom - fastIndex->bkTop + 1;
393
394
0
  if (opRight > opLeft)
395
0
    opWidth = opRight - opLeft + 1;
396
397
0
  if (opBottom > opTop)
398
0
    opHeight = opBottom - opTop + 1;
399
400
0
  if (!update_process_glyph_fragments(
401
0
          context, fastIndex->data, fastIndex->cbData, fastIndex->cacheId, fastIndex->ulCharInc,
402
0
          fastIndex->flAccel, fastIndex->backColor, fastIndex->foreColor, x, y, fastIndex->bkLeft,
403
0
          fastIndex->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE))
404
0
    goto fail;
405
406
0
  rc = TRUE;
407
0
fail:
408
0
  return rc;
409
0
}
410
411
static BOOL update_gdi_fast_glyph(rdpContext* context, const FAST_GLYPH_ORDER* fastGlyph)
412
0
{
413
0
  INT32 x = 0;
414
0
  INT32 y = 0;
415
0
  BYTE text_data[4] = WINPR_C_ARRAY_INIT;
416
0
  INT32 opLeft = 0;
417
0
  INT32 opTop = 0;
418
0
  INT32 opRight = 0;
419
0
  INT32 opBottom = 0;
420
0
  INT32 opWidth = 0;
421
0
  INT32 opHeight = 0;
422
0
  INT32 bkWidth = 0;
423
0
  INT32 bkHeight = 0;
424
0
  rdpCache* cache = nullptr;
425
426
0
  if (!context || !fastGlyph || !context->cache)
427
0
    return FALSE;
428
429
0
  cache = context->cache;
430
0
  opLeft = fastGlyph->opLeft;
431
0
  opTop = fastGlyph->opTop;
432
0
  opRight = fastGlyph->opRight;
433
0
  opBottom = fastGlyph->opBottom;
434
0
  x = fastGlyph->x;
435
0
  y = fastGlyph->y;
436
437
0
  if (opBottom == -32768)
438
0
  {
439
0
    BYTE flags = (BYTE)(opTop & 0x0F);
440
441
0
    if (flags & 0x01)
442
0
      opBottom = fastGlyph->bkBottom;
443
444
0
    if (flags & 0x02)
445
0
      opRight = fastGlyph->bkRight;
446
447
0
    if (flags & 0x04)
448
0
      opTop = fastGlyph->bkTop;
449
450
0
    if (flags & 0x08)
451
0
      opLeft = fastGlyph->bkLeft;
452
0
  }
453
454
0
  if (opLeft == 0)
455
0
    opLeft = fastGlyph->bkLeft;
456
457
0
  if (opRight == 0)
458
0
    opRight = fastGlyph->bkRight;
459
460
  /* See update_gdi_fast_index opRight comment. */
461
0
  if (opRight > (INT64)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth))
462
0
    opRight = (int)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth);
463
464
0
  if (x == -32768)
465
0
    x = fastGlyph->bkLeft;
466
467
0
  if (y == -32768)
468
0
    y = fastGlyph->bkTop;
469
470
0
  if ((fastGlyph->cbData > 1) && (fastGlyph->glyphData.aj))
471
0
  {
472
    /* got option font that needs to go into cache */
473
0
    rdpGlyph* glyph = nullptr;
474
0
    const GLYPH_DATA_V2* glyphData = &fastGlyph->glyphData;
475
476
0
    glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx, glyphData->cy,
477
0
                        glyphData->cb, glyphData->aj);
478
479
0
    if (!glyph)
480
0
      return FALSE;
481
482
0
    if (!glyph_cache_put(cache->glyph, fastGlyph->cacheId, fastGlyph->data[0], glyph))
483
0
    {
484
0
      glyph->Free(context, glyph);
485
0
      return FALSE;
486
0
    }
487
0
  }
488
489
0
  text_data[0] = fastGlyph->data[0];
490
0
  text_data[1] = 0;
491
492
0
  if (fastGlyph->bkRight > fastGlyph->bkLeft)
493
0
    bkWidth = fastGlyph->bkRight - fastGlyph->bkLeft + 1;
494
495
0
  if (fastGlyph->bkBottom > fastGlyph->bkTop)
496
0
    bkHeight = fastGlyph->bkBottom - fastGlyph->bkTop + 1;
497
498
0
  if (opRight > opLeft)
499
0
    opWidth = opRight - opLeft + 1;
500
501
0
  if (opBottom > opTop)
502
0
    opHeight = opBottom - opTop + 1;
503
504
0
  return update_process_glyph_fragments(
505
0
      context, text_data, sizeof(text_data), fastGlyph->cacheId, fastGlyph->ulCharInc,
506
0
      fastGlyph->flAccel, fastGlyph->backColor, fastGlyph->foreColor, x, y, fastGlyph->bkLeft,
507
0
      fastGlyph->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE);
508
0
}
509
510
static BOOL update_gdi_cache_glyph(rdpContext* context, const CACHE_GLYPH_ORDER* cacheGlyph)
511
0
{
512
0
  if (!context || !cacheGlyph || !context->cache)
513
0
    return FALSE;
514
515
0
  rdpCache* cache = context->cache;
516
517
0
  for (size_t i = 0; i < cacheGlyph->cGlyphs; i++)
518
0
  {
519
0
    const GLYPH_DATA* glyph_data = &cacheGlyph->glyphData[i];
520
0
    rdpGlyph* glyph = Glyph_Alloc(context, glyph_data->x, glyph_data->y, glyph_data->cx,
521
0
                                  glyph_data->cy, glyph_data->cb, glyph_data->aj);
522
0
    if (!glyph)
523
0
      return FALSE;
524
525
0
    if (!glyph_cache_put(cache->glyph, cacheGlyph->cacheId, glyph_data->cacheIndex, glyph))
526
0
    {
527
0
      glyph->Free(context, glyph);
528
0
      return FALSE;
529
0
    }
530
0
  }
531
532
0
  return TRUE;
533
0
}
534
535
static BOOL update_gdi_cache_glyph_v2(rdpContext* context, const CACHE_GLYPH_V2_ORDER* cacheGlyphV2)
536
0
{
537
0
  if (!context || !cacheGlyphV2 || !context->cache)
538
0
    return FALSE;
539
540
0
  rdpCache* cache = context->cache;
541
542
0
  for (size_t i = 0; i < cacheGlyphV2->cGlyphs; i++)
543
0
  {
544
0
    const GLYPH_DATA_V2* glyphData = &cacheGlyphV2->glyphData[i];
545
0
    rdpGlyph* glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx,
546
0
                                  glyphData->cy, glyphData->cb, glyphData->aj);
547
548
0
    if (!glyph)
549
0
      return FALSE;
550
551
0
    if (!glyph_cache_put(cache->glyph, cacheGlyphV2->cacheId, glyphData->cacheIndex, glyph))
552
0
    {
553
0
      glyph->Free(context, glyph);
554
0
      return FALSE;
555
0
    }
556
0
  }
557
558
0
  return TRUE;
559
0
}
560
561
rdpGlyph* glyph_cache_get(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index)
562
0
{
563
0
  WINPR_ASSERT(glyphCache);
564
565
0
  WLog_Print(glyphCache->log, WLOG_DEBUG, "GlyphCacheGet: id: %" PRIu32 " index: %" PRIu32 "", id,
566
0
             index);
567
568
0
  if (id >= ARRAYSIZE(glyphCache->glyphCache))
569
0
  {
570
0
    WLog_ERR(TAG, "invalid glyph cache id: %" PRIu32 "", id);
571
0
    return nullptr;
572
0
  }
573
574
0
  GLYPH_CACHE* cache = &glyphCache->glyphCache[id];
575
0
  if (index >= cache->number)
576
0
  {
577
0
    WLog_ERR(TAG, "index %" PRIu32 " out of range for cache id: %" PRIu32 "", index, id);
578
0
    return nullptr;
579
0
  }
580
581
0
  rdpGlyph* glyph = cache->entries[index];
582
0
  if (!glyph)
583
0
    WLog_ERR(TAG, "no glyph found at cache index: %" PRIu32 " in cache id: %" PRIu32 "", index,
584
0
             id);
585
586
0
  return glyph;
587
0
}
588
589
BOOL glyph_cache_put(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index, rdpGlyph* glyph)
590
0
{
591
0
  WINPR_ASSERT(glyphCache);
592
593
0
  if (id >= ARRAYSIZE(glyphCache->glyphCache))
594
0
  {
595
0
    WLog_ERR(TAG, "invalid glyph cache id: %" PRIu32 "", id);
596
0
    return FALSE;
597
0
  }
598
599
0
  GLYPH_CACHE* cache = &glyphCache->glyphCache[id];
600
0
  if (index >= cache->number)
601
0
  {
602
0
    WLog_ERR(TAG, "invalid glyph cache index: %" PRIu32 " in cache id: %" PRIu32 "", index, id);
603
0
    return FALSE;
604
0
  }
605
606
0
  WLog_Print(glyphCache->log, WLOG_DEBUG, "GlyphCachePut: id: %" PRIu32 " index: %" PRIu32 "", id,
607
0
             index);
608
0
  rdpGlyph* prevGlyph = cache->entries[index];
609
610
0
  if (prevGlyph)
611
0
  {
612
0
    WINPR_ASSERT(prevGlyph->Free);
613
0
    prevGlyph->Free(glyphCache->context, prevGlyph);
614
0
  }
615
616
0
  cache->entries[index] = glyph;
617
0
  return TRUE;
618
0
}
619
620
const void* glyph_cache_fragment_get(rdpGlyphCache* glyphCache, UINT32 index, UINT32* size)
621
0
{
622
0
  void* fragment = nullptr;
623
624
0
  WINPR_ASSERT(glyphCache);
625
0
  WINPR_ASSERT(glyphCache->fragCache.entries);
626
627
0
  if (index > 255)
628
0
  {
629
0
    WLog_ERR(TAG, "invalid glyph cache fragment index: %" PRIu32 "", index);
630
0
    return nullptr;
631
0
  }
632
633
0
  fragment = glyphCache->fragCache.entries[index].fragment;
634
0
  *size = (BYTE)glyphCache->fragCache.entries[index].size;
635
0
  WLog_Print(glyphCache->log, WLOG_DEBUG,
636
0
             "GlyphCacheFragmentGet: index: %" PRIu32 " size: %" PRIu32 "", index, *size);
637
638
0
  if (!fragment)
639
0
    WLog_ERR(TAG, "invalid glyph fragment at index:%" PRIu32 "", index);
640
641
0
  return fragment;
642
0
}
643
644
BOOL glyph_cache_fragment_put(rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
645
                              const void* fragment)
646
0
{
647
0
  WINPR_ASSERT(glyphCache);
648
0
  WINPR_ASSERT(glyphCache->fragCache.entries);
649
650
0
  if (index > 255)
651
0
  {
652
0
    WLog_ERR(TAG, "invalid glyph cache fragment index: %" PRIu32 "", index);
653
0
    return FALSE;
654
0
  }
655
656
0
  if (size == 0)
657
0
    return FALSE;
658
659
0
  void* copy = malloc(size);
660
661
0
  if (!copy)
662
0
    return FALSE;
663
664
0
  WLog_Print(glyphCache->log, WLOG_DEBUG,
665
0
             "GlyphCacheFragmentPut: index: %" PRIu32 " size: %" PRIu32 "", index, size);
666
0
  CopyMemory(copy, fragment, size);
667
668
0
  void* prevFragment = glyphCache->fragCache.entries[index].fragment;
669
0
  glyphCache->fragCache.entries[index].fragment = copy;
670
0
  glyphCache->fragCache.entries[index].size = size;
671
0
  free(prevFragment);
672
0
  return TRUE;
673
0
}
674
675
void glyph_cache_register_callbacks(rdpUpdate* update)
676
0
{
677
0
  WINPR_ASSERT(update);
678
0
  WINPR_ASSERT(update->context);
679
0
  WINPR_ASSERT(update->primary);
680
0
  WINPR_ASSERT(update->secondary);
681
682
0
  if (!freerdp_settings_get_bool(update->context->settings, FreeRDP_DeactivateClientDecoding))
683
0
  {
684
0
    update->primary->GlyphIndex = update_gdi_glyph_index;
685
0
    update->primary->FastIndex = update_gdi_fast_index;
686
0
    update->primary->FastGlyph = update_gdi_fast_glyph;
687
0
    update->secondary->CacheGlyph = update_gdi_cache_glyph;
688
0
    update->secondary->CacheGlyphV2 = update_gdi_cache_glyph_v2;
689
0
  }
690
0
}
691
692
rdpGlyphCache* glyph_cache_new(rdpContext* context)
693
0
{
694
0
  rdpGlyphCache* glyphCache = nullptr;
695
0
  rdpSettings* settings = nullptr;
696
697
0
  WINPR_ASSERT(context);
698
699
0
  settings = context->settings;
700
0
  WINPR_ASSERT(settings);
701
702
0
  glyphCache = (rdpGlyphCache*)calloc(1, sizeof(rdpGlyphCache));
703
704
0
  if (!glyphCache)
705
0
    return nullptr;
706
707
0
  glyphCache->log = WLog_Get("com.freerdp.cache.glyph");
708
0
  glyphCache->context = context;
709
710
0
  for (size_t i = 0; i < 10; i++)
711
0
  {
712
0
    const GLYPH_CACHE_DEFINITION* currentGlyph =
713
0
        freerdp_settings_get_pointer_array(settings, FreeRDP_GlyphCache, i);
714
0
    GLYPH_CACHE* currentCache = &glyphCache->glyphCache[i];
715
0
    currentCache->number = currentGlyph->cacheEntries;
716
0
    currentCache->maxCellSize = currentGlyph->cacheMaximumCellSize;
717
0
    currentCache->entries = (rdpGlyph**)calloc(currentCache->number, sizeof(rdpGlyph*));
718
719
0
    if (!currentCache->entries)
720
0
      goto fail;
721
0
  }
722
723
0
  return glyphCache;
724
0
fail:
725
0
  WINPR_PRAGMA_DIAG_PUSH
726
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
727
0
  glyph_cache_free(glyphCache);
728
0
  WINPR_PRAGMA_DIAG_POP
729
0
  return nullptr;
730
0
}
731
732
void glyph_cache_free(rdpGlyphCache* glyphCache)
733
0
{
734
0
  if (glyphCache)
735
0
  {
736
0
    GLYPH_CACHE* cache = glyphCache->glyphCache;
737
738
0
    for (size_t i = 0; i < 10; i++)
739
0
    {
740
0
      rdpGlyph** entries = cache[i].entries;
741
742
0
      if (!entries)
743
0
        continue;
744
745
0
      for (size_t j = 0; j < cache[i].number; j++)
746
0
      {
747
0
        rdpGlyph* glyph = entries[j];
748
749
0
        if (glyph)
750
0
        {
751
0
          glyph->Free(glyphCache->context, glyph);
752
0
          entries[j] = nullptr;
753
0
        }
754
0
      }
755
756
0
      free((void*)entries);
757
0
      cache[i].entries = nullptr;
758
0
    }
759
760
0
    for (size_t i = 0; i < ARRAYSIZE(glyphCache->fragCache.entries); i++)
761
0
    {
762
0
      free(glyphCache->fragCache.entries[i].fragment);
763
0
      glyphCache->fragCache.entries[i].fragment = nullptr;
764
0
    }
765
766
0
    free(glyphCache);
767
0
  }
768
0
}
769
770
CACHE_GLYPH_ORDER* copy_cache_glyph_order(rdpContext* context, const CACHE_GLYPH_ORDER* glyph)
771
0
{
772
0
  CACHE_GLYPH_ORDER* dst = nullptr;
773
774
0
  WINPR_ASSERT(context);
775
776
0
  dst = calloc(1, sizeof(CACHE_GLYPH_ORDER));
777
778
0
  if (!dst || !glyph)
779
0
    goto fail;
780
781
0
  *dst = *glyph;
782
783
0
  for (size_t x = 0; x < glyph->cGlyphs; x++)
784
0
  {
785
0
    const GLYPH_DATA* src = &glyph->glyphData[x];
786
0
    GLYPH_DATA* data = &dst->glyphData[x];
787
788
0
    if (src->aj)
789
0
    {
790
0
      const size_t size = src->cb;
791
0
      data->aj = malloc(size);
792
793
0
      if (!data->aj)
794
0
        goto fail;
795
796
0
      memcpy(data->aj, src->aj, size);
797
0
    }
798
0
  }
799
800
0
  if (glyph->unicodeCharacters)
801
0
  {
802
0
    if (glyph->cGlyphs == 0)
803
0
      goto fail;
804
805
0
    dst->unicodeCharacters = calloc(glyph->cGlyphs, sizeof(WCHAR));
806
807
0
    if (!dst->unicodeCharacters)
808
0
      goto fail;
809
810
0
    memcpy(dst->unicodeCharacters, glyph->unicodeCharacters, sizeof(WCHAR) * glyph->cGlyphs);
811
0
  }
812
813
0
  return dst;
814
0
fail:
815
0
  free_cache_glyph_order(context, dst);
816
0
  return nullptr;
817
0
}
818
819
void free_cache_glyph_order(WINPR_ATTR_UNUSED rdpContext* context, CACHE_GLYPH_ORDER* glyph)
820
0
{
821
0
  if (glyph)
822
0
  {
823
0
    for (size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
824
0
      free(glyph->glyphData[x].aj);
825
826
0
    free(glyph->unicodeCharacters);
827
0
  }
828
829
0
  free(glyph);
830
0
}
831
832
CACHE_GLYPH_V2_ORDER* copy_cache_glyph_v2_order(rdpContext* context,
833
                                                const CACHE_GLYPH_V2_ORDER* glyph)
834
0
{
835
0
  CACHE_GLYPH_V2_ORDER* dst = nullptr;
836
837
0
  WINPR_ASSERT(context);
838
839
0
  dst = calloc(1, sizeof(CACHE_GLYPH_V2_ORDER));
840
841
0
  if (!dst || !glyph)
842
0
    goto fail;
843
844
0
  *dst = *glyph;
845
846
0
  for (size_t x = 0; x < glyph->cGlyphs; x++)
847
0
  {
848
0
    const GLYPH_DATA_V2* src = &glyph->glyphData[x];
849
0
    GLYPH_DATA_V2* data = &dst->glyphData[x];
850
851
0
    if (src->aj)
852
0
    {
853
0
      const size_t size = src->cb;
854
0
      data->aj = malloc(size);
855
856
0
      if (!data->aj)
857
0
        goto fail;
858
859
0
      memcpy(data->aj, src->aj, size);
860
0
    }
861
0
  }
862
863
0
  if (glyph->unicodeCharacters)
864
0
  {
865
0
    if (glyph->cGlyphs == 0)
866
0
      goto fail;
867
868
0
    dst->unicodeCharacters = calloc(glyph->cGlyphs, sizeof(WCHAR));
869
870
0
    if (!dst->unicodeCharacters)
871
0
      goto fail;
872
873
0
    memcpy(dst->unicodeCharacters, glyph->unicodeCharacters, sizeof(WCHAR) * glyph->cGlyphs);
874
0
  }
875
876
0
  return dst;
877
0
fail:
878
0
  free_cache_glyph_v2_order(context, dst);
879
0
  return nullptr;
880
0
}
881
882
void free_cache_glyph_v2_order(WINPR_ATTR_UNUSED rdpContext* context, CACHE_GLYPH_V2_ORDER* glyph)
883
0
{
884
0
  if (glyph)
885
0
  {
886
0
    for (size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
887
0
      free(glyph->glyphData[x].aj);
888
889
0
    free(glyph->unicodeCharacters);
890
0
  }
891
892
0
  free(glyph);
893
0
}