Coverage Report

Created: 2025-11-24 06:38

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