Coverage Report

Created: 2025-07-01 06:46

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