Coverage Report

Created: 2026-01-09 06:43

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