Coverage Report

Created: 2026-07-16 07:09

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
          if (size > length - index)
282
0
            goto fail;
283
0
          glyph_cache_fragment_put(glyph_cache, id, size, data);
284
0
          break;
285
286
0
        default:
287
0
          index = update_glyph_offset(data, length, index, &x, &y, ulCharInc, flAccel);
288
289
0
          if (!update_process_glyph(context, data, op, &x, &y, cacheId, flAccel,
290
0
                                    fOpRedundant, &bound))
291
0
            goto fail;
292
293
0
          break;
294
0
      }
295
0
    }
296
297
0
    if (!glyph->EndDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor))
298
0
      goto fail;
299
0
  }
300
301
0
  rc = TRUE;
302
303
0
fail:
304
0
  return rc;
305
0
}
306
307
static BOOL update_gdi_glyph_index(rdpContext* context, GLYPH_INDEX_ORDER* glyphIndex)
308
0
{
309
0
  INT32 bkWidth = 0;
310
0
  INT32 bkHeight = 0;
311
0
  INT32 opWidth = 0;
312
0
  INT32 opHeight = 0;
313
314
0
  if (!context || !glyphIndex || !context->cache)
315
0
    return FALSE;
316
317
0
  if (glyphIndex->bkRight > glyphIndex->bkLeft)
318
0
    bkWidth = glyphIndex->bkRight - glyphIndex->bkLeft + 1;
319
320
0
  if (glyphIndex->opRight > glyphIndex->opLeft)
321
0
    opWidth = glyphIndex->opRight - glyphIndex->opLeft + 1;
322
323
0
  if (glyphIndex->bkBottom > glyphIndex->bkTop)
324
0
    bkHeight = glyphIndex->bkBottom - glyphIndex->bkTop + 1;
325
326
0
  if (glyphIndex->opBottom > glyphIndex->opTop)
327
0
    opHeight = glyphIndex->opBottom - glyphIndex->opTop + 1;
328
329
0
  return update_process_glyph_fragments(
330
0
      context, glyphIndex->data, glyphIndex->cbData, glyphIndex->cacheId, glyphIndex->ulCharInc,
331
0
      glyphIndex->flAccel, glyphIndex->backColor, glyphIndex->foreColor, glyphIndex->x,
332
0
      glyphIndex->y, glyphIndex->bkLeft, glyphIndex->bkTop, bkWidth, bkHeight, glyphIndex->opLeft,
333
0
      glyphIndex->opTop, opWidth, opHeight,
334
0
      WINPR_ASSERTING_INT_CAST(int32_t, glyphIndex->fOpRedundant));
335
0
}
336
337
static BOOL update_gdi_fast_index(rdpContext* context, const FAST_INDEX_ORDER* fastIndex)
338
0
{
339
0
  INT32 opWidth = 0;
340
0
  INT32 opHeight = 0;
341
0
  INT32 bkWidth = 0;
342
0
  INT32 bkHeight = 0;
343
0
  BOOL rc = FALSE;
344
345
0
  if (!context || !fastIndex || !context->cache)
346
0
    return FALSE;
347
348
0
  INT32 opLeft = fastIndex->opLeft;
349
0
  INT32 opTop = fastIndex->opTop;
350
0
  INT32 opRight = fastIndex->opRight;
351
0
  INT32 opBottom = fastIndex->opBottom;
352
0
  INT32 x = fastIndex->x;
353
0
  INT32 y = fastIndex->y;
354
355
0
  if (opBottom == -32768)
356
0
  {
357
0
    BYTE flags = (BYTE)(opTop & 0x0F);
358
359
0
    if (flags & 0x01)
360
0
      opBottom = fastIndex->bkBottom;
361
362
0
    if (flags & 0x02)
363
0
      opRight = fastIndex->bkRight;
364
365
0
    if (flags & 0x04)
366
0
      opTop = fastIndex->bkTop;
367
368
0
    if (flags & 0x08)
369
0
      opLeft = fastIndex->bkLeft;
370
0
  }
371
372
0
  if (opLeft == 0)
373
0
    opLeft = fastIndex->bkLeft;
374
375
0
  if (opRight == 0)
376
0
    opRight = fastIndex->bkRight;
377
378
  /* Server can send a massive number (32766) which appears to be
379
   * undocumented special behavior for "Erase all the way right".
380
   * X11 has nondeterministic results asking for a draw that wide. */
381
0
  if (opRight > (INT64)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth))
382
0
    opRight = (int)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth);
383
384
0
  if (x == -32768)
385
0
    x = fastIndex->bkLeft;
386
387
0
  if (y == -32768)
388
0
    y = fastIndex->bkTop;
389
390
0
  if (fastIndex->bkRight > fastIndex->bkLeft)
391
0
    bkWidth = fastIndex->bkRight - fastIndex->bkLeft + 1;
392
393
0
  if (fastIndex->bkBottom > fastIndex->bkTop)
394
0
    bkHeight = fastIndex->bkBottom - fastIndex->bkTop + 1;
395
396
0
  if (opRight > opLeft)
397
0
    opWidth = opRight - opLeft + 1;
398
399
0
  if (opBottom > opTop)
400
0
    opHeight = opBottom - opTop + 1;
401
402
0
  if (!update_process_glyph_fragments(
403
0
          context, fastIndex->data, fastIndex->cbData, fastIndex->cacheId, fastIndex->ulCharInc,
404
0
          fastIndex->flAccel, fastIndex->backColor, fastIndex->foreColor, x, y, fastIndex->bkLeft,
405
0
          fastIndex->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE))
406
0
    goto fail;
407
408
0
  rc = TRUE;
409
0
fail:
410
0
  return rc;
411
0
}
412
413
static BOOL update_gdi_fast_glyph(rdpContext* context, const FAST_GLYPH_ORDER* fastGlyph)
414
0
{
415
0
  INT32 x = 0;
416
0
  INT32 y = 0;
417
0
  BYTE text_data[4] = WINPR_C_ARRAY_INIT;
418
0
  INT32 opLeft = 0;
419
0
  INT32 opTop = 0;
420
0
  INT32 opRight = 0;
421
0
  INT32 opBottom = 0;
422
0
  INT32 opWidth = 0;
423
0
  INT32 opHeight = 0;
424
0
  INT32 bkWidth = 0;
425
0
  INT32 bkHeight = 0;
426
0
  rdpCache* cache = nullptr;
427
428
0
  if (!context || !fastGlyph || !context->cache)
429
0
    return FALSE;
430
431
0
  cache = context->cache;
432
0
  opLeft = fastGlyph->opLeft;
433
0
  opTop = fastGlyph->opTop;
434
0
  opRight = fastGlyph->opRight;
435
0
  opBottom = fastGlyph->opBottom;
436
0
  x = fastGlyph->x;
437
0
  y = fastGlyph->y;
438
439
0
  if (opBottom == -32768)
440
0
  {
441
0
    BYTE flags = (BYTE)(opTop & 0x0F);
442
443
0
    if (flags & 0x01)
444
0
      opBottom = fastGlyph->bkBottom;
445
446
0
    if (flags & 0x02)
447
0
      opRight = fastGlyph->bkRight;
448
449
0
    if (flags & 0x04)
450
0
      opTop = fastGlyph->bkTop;
451
452
0
    if (flags & 0x08)
453
0
      opLeft = fastGlyph->bkLeft;
454
0
  }
455
456
0
  if (opLeft == 0)
457
0
    opLeft = fastGlyph->bkLeft;
458
459
0
  if (opRight == 0)
460
0
    opRight = fastGlyph->bkRight;
461
462
  /* See update_gdi_fast_index opRight comment. */
463
0
  if (opRight > (INT64)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth))
464
0
    opRight = (int)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth);
465
466
0
  if (x == -32768)
467
0
    x = fastGlyph->bkLeft;
468
469
0
  if (y == -32768)
470
0
    y = fastGlyph->bkTop;
471
472
0
  if ((fastGlyph->cbData > 1) && (fastGlyph->glyphData.aj))
473
0
  {
474
    /* got option font that needs to go into cache */
475
0
    rdpGlyph* glyph = nullptr;
476
0
    const GLYPH_DATA_V2* glyphData = &fastGlyph->glyphData;
477
478
0
    glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx, glyphData->cy,
479
0
                        glyphData->cb, glyphData->aj);
480
481
0
    if (!glyph)
482
0
      return FALSE;
483
484
0
    if (!glyph_cache_put(cache->glyph, fastGlyph->cacheId, fastGlyph->data[0], glyph))
485
0
    {
486
0
      glyph->Free(context, glyph);
487
0
      return FALSE;
488
0
    }
489
0
  }
490
491
0
  text_data[0] = fastGlyph->data[0];
492
0
  text_data[1] = 0;
493
494
0
  if (fastGlyph->bkRight > fastGlyph->bkLeft)
495
0
    bkWidth = fastGlyph->bkRight - fastGlyph->bkLeft + 1;
496
497
0
  if (fastGlyph->bkBottom > fastGlyph->bkTop)
498
0
    bkHeight = fastGlyph->bkBottom - fastGlyph->bkTop + 1;
499
500
0
  if (opRight > opLeft)
501
0
    opWidth = opRight - opLeft + 1;
502
503
0
  if (opBottom > opTop)
504
0
    opHeight = opBottom - opTop + 1;
505
506
0
  return update_process_glyph_fragments(
507
0
      context, text_data, sizeof(text_data), fastGlyph->cacheId, fastGlyph->ulCharInc,
508
0
      fastGlyph->flAccel, fastGlyph->backColor, fastGlyph->foreColor, x, y, fastGlyph->bkLeft,
509
0
      fastGlyph->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE);
510
0
}
511
512
static BOOL update_gdi_cache_glyph(rdpContext* context, const CACHE_GLYPH_ORDER* cacheGlyph)
513
0
{
514
0
  if (!context || !cacheGlyph || !context->cache)
515
0
    return FALSE;
516
517
0
  rdpCache* cache = context->cache;
518
519
0
  for (size_t i = 0; i < cacheGlyph->cGlyphs; i++)
520
0
  {
521
0
    const GLYPH_DATA* glyph_data = &cacheGlyph->glyphData[i];
522
0
    rdpGlyph* glyph = Glyph_Alloc(context, glyph_data->x, glyph_data->y, glyph_data->cx,
523
0
                                  glyph_data->cy, glyph_data->cb, glyph_data->aj);
524
0
    if (!glyph)
525
0
      return FALSE;
526
527
0
    if (!glyph_cache_put(cache->glyph, cacheGlyph->cacheId, glyph_data->cacheIndex, glyph))
528
0
    {
529
0
      glyph->Free(context, glyph);
530
0
      return FALSE;
531
0
    }
532
0
  }
533
534
0
  return TRUE;
535
0
}
536
537
static BOOL update_gdi_cache_glyph_v2(rdpContext* context, const CACHE_GLYPH_V2_ORDER* cacheGlyphV2)
538
0
{
539
0
  if (!context || !cacheGlyphV2 || !context->cache)
540
0
    return FALSE;
541
542
0
  rdpCache* cache = context->cache;
543
544
0
  for (size_t i = 0; i < cacheGlyphV2->cGlyphs; i++)
545
0
  {
546
0
    const GLYPH_DATA_V2* glyphData = &cacheGlyphV2->glyphData[i];
547
0
    rdpGlyph* glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx,
548
0
                                  glyphData->cy, glyphData->cb, glyphData->aj);
549
550
0
    if (!glyph)
551
0
      return FALSE;
552
553
0
    if (!glyph_cache_put(cache->glyph, cacheGlyphV2->cacheId, glyphData->cacheIndex, glyph))
554
0
    {
555
0
      glyph->Free(context, glyph);
556
0
      return FALSE;
557
0
    }
558
0
  }
559
560
0
  return TRUE;
561
0
}
562
563
rdpGlyph* glyph_cache_get(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index)
564
0
{
565
0
  WINPR_ASSERT(glyphCache);
566
567
0
  WLog_Print(glyphCache->log, WLOG_DEBUG, "GlyphCacheGet: id: %" PRIu32 " index: %" PRIu32 "", id,
568
0
             index);
569
570
0
  if (id >= ARRAYSIZE(glyphCache->glyphCache))
571
0
  {
572
0
    WLog_ERR(TAG, "invalid glyph cache id: %" PRIu32 "", id);
573
0
    return nullptr;
574
0
  }
575
576
0
  GLYPH_CACHE* cache = &glyphCache->glyphCache[id];
577
0
  if (index >= cache->number)
578
0
  {
579
0
    WLog_ERR(TAG, "index %" PRIu32 " out of range for cache id: %" PRIu32 "", index, id);
580
0
    return nullptr;
581
0
  }
582
583
0
  rdpGlyph* glyph = cache->entries[index];
584
0
  if (!glyph)
585
0
    WLog_ERR(TAG, "no glyph found at cache index: %" PRIu32 " in cache id: %" PRIu32 "", index,
586
0
             id);
587
588
0
  return glyph;
589
0
}
590
591
BOOL glyph_cache_put(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index, rdpGlyph* glyph)
592
0
{
593
0
  WINPR_ASSERT(glyphCache);
594
595
0
  if (id >= ARRAYSIZE(glyphCache->glyphCache))
596
0
  {
597
0
    WLog_ERR(TAG, "invalid glyph cache id: %" PRIu32 "", id);
598
0
    return FALSE;
599
0
  }
600
601
0
  GLYPH_CACHE* cache = &glyphCache->glyphCache[id];
602
0
  if (index >= cache->number)
603
0
  {
604
0
    WLog_ERR(TAG, "invalid glyph cache index: %" PRIu32 " in cache id: %" PRIu32 "", index, id);
605
0
    return FALSE;
606
0
  }
607
608
0
  WLog_Print(glyphCache->log, WLOG_DEBUG, "GlyphCachePut: id: %" PRIu32 " index: %" PRIu32 "", id,
609
0
             index);
610
0
  rdpGlyph* prevGlyph = cache->entries[index];
611
612
0
  if (prevGlyph)
613
0
  {
614
0
    WINPR_ASSERT(prevGlyph->Free);
615
0
    prevGlyph->Free(glyphCache->context, prevGlyph);
616
0
  }
617
618
0
  cache->entries[index] = glyph;
619
0
  return TRUE;
620
0
}
621
622
const void* glyph_cache_fragment_get(rdpGlyphCache* glyphCache, UINT32 index, UINT32* size)
623
0
{
624
0
  void* fragment = nullptr;
625
626
0
  WINPR_ASSERT(glyphCache);
627
0
  WINPR_ASSERT(glyphCache->fragCache.entries);
628
629
0
  if (index > 255)
630
0
  {
631
0
    WLog_ERR(TAG, "invalid glyph cache fragment index: %" PRIu32 "", index);
632
0
    return nullptr;
633
0
  }
634
635
0
  fragment = glyphCache->fragCache.entries[index].fragment;
636
0
  *size = (BYTE)glyphCache->fragCache.entries[index].size;
637
0
  WLog_Print(glyphCache->log, WLOG_DEBUG,
638
0
             "GlyphCacheFragmentGet: index: %" PRIu32 " size: %" PRIu32 "", index, *size);
639
640
0
  if (!fragment)
641
0
    WLog_ERR(TAG, "invalid glyph fragment at index:%" PRIu32 "", index);
642
643
0
  return fragment;
644
0
}
645
646
BOOL glyph_cache_fragment_put(rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
647
                              const void* fragment)
648
0
{
649
0
  WINPR_ASSERT(glyphCache);
650
0
  WINPR_ASSERT(glyphCache->fragCache.entries);
651
652
0
  if (index > 255)
653
0
  {
654
0
    WLog_ERR(TAG, "invalid glyph cache fragment index: %" PRIu32 "", index);
655
0
    return FALSE;
656
0
  }
657
658
0
  if (size == 0)
659
0
    return FALSE;
660
661
0
  void* copy = malloc(size);
662
663
0
  if (!copy)
664
0
    return FALSE;
665
666
0
  WLog_Print(glyphCache->log, WLOG_DEBUG,
667
0
             "GlyphCacheFragmentPut: index: %" PRIu32 " size: %" PRIu32 "", index, size);
668
0
  CopyMemory(copy, fragment, size);
669
670
0
  void* prevFragment = glyphCache->fragCache.entries[index].fragment;
671
0
  glyphCache->fragCache.entries[index].fragment = copy;
672
0
  glyphCache->fragCache.entries[index].size = size;
673
0
  free(prevFragment);
674
0
  return TRUE;
675
0
}
676
677
void glyph_cache_register_callbacks(rdpUpdate* update)
678
0
{
679
0
  WINPR_ASSERT(update);
680
0
  WINPR_ASSERT(update->context);
681
0
  WINPR_ASSERT(update->primary);
682
0
  WINPR_ASSERT(update->secondary);
683
684
0
  if (!freerdp_settings_get_bool(update->context->settings, FreeRDP_DeactivateClientDecoding))
685
0
  {
686
0
    update->primary->GlyphIndex = update_gdi_glyph_index;
687
0
    update->primary->FastIndex = update_gdi_fast_index;
688
0
    update->primary->FastGlyph = update_gdi_fast_glyph;
689
0
    update->secondary->CacheGlyph = update_gdi_cache_glyph;
690
0
    update->secondary->CacheGlyphV2 = update_gdi_cache_glyph_v2;
691
0
  }
692
0
}
693
694
rdpGlyphCache* glyph_cache_new(rdpContext* context)
695
0
{
696
0
  rdpGlyphCache* glyphCache = nullptr;
697
0
  rdpSettings* settings = nullptr;
698
699
0
  WINPR_ASSERT(context);
700
701
0
  settings = context->settings;
702
0
  WINPR_ASSERT(settings);
703
704
0
  glyphCache = (rdpGlyphCache*)calloc(1, sizeof(rdpGlyphCache));
705
706
0
  if (!glyphCache)
707
0
    return nullptr;
708
709
0
  glyphCache->log = WLog_Get("com.freerdp.cache.glyph");
710
0
  glyphCache->context = context;
711
712
0
  for (size_t i = 0; i < 10; i++)
713
0
  {
714
0
    const GLYPH_CACHE_DEFINITION* currentGlyph =
715
0
        freerdp_settings_get_pointer_array(settings, FreeRDP_GlyphCache, i);
716
0
    GLYPH_CACHE* currentCache = &glyphCache->glyphCache[i];
717
0
    currentCache->number = currentGlyph->cacheEntries;
718
0
    currentCache->maxCellSize = currentGlyph->cacheMaximumCellSize;
719
0
    currentCache->entries = (rdpGlyph**)calloc(currentCache->number, sizeof(rdpGlyph*));
720
721
0
    if (!currentCache->entries)
722
0
      goto fail;
723
0
  }
724
725
0
  return glyphCache;
726
0
fail:
727
0
  WINPR_PRAGMA_DIAG_PUSH
728
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
729
0
  glyph_cache_free(glyphCache);
730
0
  WINPR_PRAGMA_DIAG_POP
731
0
  return nullptr;
732
0
}
733
734
void glyph_cache_free(rdpGlyphCache* glyphCache)
735
0
{
736
0
  if (glyphCache)
737
0
  {
738
0
    GLYPH_CACHE* cache = glyphCache->glyphCache;
739
740
0
    for (size_t i = 0; i < 10; i++)
741
0
    {
742
0
      rdpGlyph** entries = cache[i].entries;
743
744
0
      if (!entries)
745
0
        continue;
746
747
0
      for (size_t j = 0; j < cache[i].number; j++)
748
0
      {
749
0
        rdpGlyph* glyph = entries[j];
750
751
0
        if (glyph)
752
0
        {
753
0
          glyph->Free(glyphCache->context, glyph);
754
0
          entries[j] = nullptr;
755
0
        }
756
0
      }
757
758
0
      free((void*)entries);
759
0
      cache[i].entries = nullptr;
760
0
    }
761
762
0
    for (size_t i = 0; i < ARRAYSIZE(glyphCache->fragCache.entries); i++)
763
0
    {
764
0
      free(glyphCache->fragCache.entries[i].fragment);
765
0
      glyphCache->fragCache.entries[i].fragment = nullptr;
766
0
    }
767
768
0
    free(glyphCache);
769
0
  }
770
0
}
771
772
CACHE_GLYPH_ORDER* copy_cache_glyph_order(rdpContext* context, const CACHE_GLYPH_ORDER* glyph)
773
0
{
774
0
  CACHE_GLYPH_ORDER* dst = nullptr;
775
776
0
  WINPR_ASSERT(context);
777
778
0
  dst = calloc(1, sizeof(CACHE_GLYPH_ORDER));
779
780
0
  if (!dst || !glyph)
781
0
    goto fail;
782
783
0
  *dst = *glyph;
784
785
0
  for (size_t x = 0; x < glyph->cGlyphs; x++)
786
0
  {
787
0
    const GLYPH_DATA* src = &glyph->glyphData[x];
788
0
    GLYPH_DATA* data = &dst->glyphData[x];
789
790
0
    if (src->aj)
791
0
    {
792
0
      const size_t size = src->cb;
793
0
      data->aj = malloc(size);
794
795
0
      if (!data->aj)
796
0
        goto fail;
797
798
0
      memcpy(data->aj, src->aj, size);
799
0
    }
800
0
  }
801
802
0
  if (glyph->unicodeCharacters)
803
0
  {
804
0
    if (glyph->cGlyphs == 0)
805
0
      goto fail;
806
807
0
    dst->unicodeCharacters = calloc(glyph->cGlyphs, sizeof(WCHAR));
808
809
0
    if (!dst->unicodeCharacters)
810
0
      goto fail;
811
812
0
    memcpy(dst->unicodeCharacters, glyph->unicodeCharacters, sizeof(WCHAR) * glyph->cGlyphs);
813
0
  }
814
815
0
  return dst;
816
0
fail:
817
0
  free_cache_glyph_order(context, dst);
818
0
  return nullptr;
819
0
}
820
821
void free_cache_glyph_order(WINPR_ATTR_UNUSED rdpContext* context, CACHE_GLYPH_ORDER* glyph)
822
0
{
823
0
  if (glyph)
824
0
  {
825
0
    for (size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
826
0
      free(glyph->glyphData[x].aj);
827
828
0
    free(glyph->unicodeCharacters);
829
0
  }
830
831
0
  free(glyph);
832
0
}
833
834
CACHE_GLYPH_V2_ORDER* copy_cache_glyph_v2_order(rdpContext* context,
835
                                                const CACHE_GLYPH_V2_ORDER* glyph)
836
0
{
837
0
  CACHE_GLYPH_V2_ORDER* dst = nullptr;
838
839
0
  WINPR_ASSERT(context);
840
841
0
  dst = calloc(1, sizeof(CACHE_GLYPH_V2_ORDER));
842
843
0
  if (!dst || !glyph)
844
0
    goto fail;
845
846
0
  *dst = *glyph;
847
848
0
  for (size_t x = 0; x < glyph->cGlyphs; x++)
849
0
  {
850
0
    const GLYPH_DATA_V2* src = &glyph->glyphData[x];
851
0
    GLYPH_DATA_V2* data = &dst->glyphData[x];
852
853
0
    if (src->aj)
854
0
    {
855
0
      const size_t size = src->cb;
856
0
      data->aj = malloc(size);
857
858
0
      if (!data->aj)
859
0
        goto fail;
860
861
0
      memcpy(data->aj, src->aj, size);
862
0
    }
863
0
  }
864
865
0
  if (glyph->unicodeCharacters)
866
0
  {
867
0
    if (glyph->cGlyphs == 0)
868
0
      goto fail;
869
870
0
    dst->unicodeCharacters = calloc(glyph->cGlyphs, sizeof(WCHAR));
871
872
0
    if (!dst->unicodeCharacters)
873
0
      goto fail;
874
875
0
    memcpy(dst->unicodeCharacters, glyph->unicodeCharacters, sizeof(WCHAR) * glyph->cGlyphs);
876
0
  }
877
878
0
  return dst;
879
0
fail:
880
0
  free_cache_glyph_v2_order(context, dst);
881
0
  return nullptr;
882
0
}
883
884
void free_cache_glyph_v2_order(WINPR_ATTR_UNUSED rdpContext* context, CACHE_GLYPH_V2_ORDER* glyph)
885
0
{
886
0
  if (glyph)
887
0
  {
888
0
    for (size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
889
0
      free(glyph->glyphData[x].aj);
890
891
0
    free(glyph->unicodeCharacters);
892
0
  }
893
894
0
  free(glyph);
895
0
}