Coverage Report

Created: 2024-05-20 06:11

/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
27
#include <freerdp/freerdp.h>
28
#include <winpr/stream.h>
29
30
#include <freerdp/log.h>
31
32
#include "glyph.h"
33
#include "cache.h"
34
35
#define TAG FREERDP_TAG("cache.glyph")
36
37
static rdpGlyph* glyph_cache_get(rdpGlyphCache* glyph_cache, UINT32 id, UINT32 index);
38
static BOOL glyph_cache_put(rdpGlyphCache* glyph_cache, UINT32 id, UINT32 index, rdpGlyph* entry);
39
40
static const void* glyph_cache_fragment_get(rdpGlyphCache* glyph, UINT32 index, UINT32* count);
41
static BOOL glyph_cache_fragment_put(rdpGlyphCache* glyph, UINT32 index, UINT32 count,
42
                                     const void* entry);
43
44
static UINT32 update_glyph_offset(const BYTE* data, size_t length, UINT32 index, INT32* x, INT32* y,
45
                                  UINT32 ulCharInc, UINT32 flAccel)
46
0
{
47
0
  if ((ulCharInc == 0) && (!(flAccel & SO_CHAR_INC_EQUAL_BM_BASE)))
48
0
  {
49
0
    UINT32 offset = data[index++];
50
51
0
    if (offset & 0x80)
52
0
    {
53
54
0
      if (index + 1 < length)
55
0
      {
56
0
        offset = data[index++];
57
0
        offset |= ((UINT32)data[index++]) << 8;
58
0
      }
59
0
      else
60
0
        WLog_WARN(TAG, "[%s] glyph index out of bound %" PRIu32 " [max %" PRIuz "]", index,
61
0
                  length);
62
0
    }
63
64
0
    if (flAccel & SO_VERTICAL)
65
0
      *y += offset;
66
67
0
    if (flAccel & SO_HORIZONTAL)
68
0
      *x += offset;
69
0
  }
70
71
0
  return index;
72
0
}
73
74
static BOOL update_process_glyph(rdpContext* context, const BYTE* data, UINT32 cacheIndex, INT32* x,
75
                                 INT32* y, UINT32 cacheId, UINT32 flAccel, BOOL fOpRedundant,
76
                                 const RDP_RECT* bound)
77
0
{
78
0
  INT32 sx = 0;
79
0
  INT32 sy = 0;
80
0
  INT32 dx = 0;
81
0
  INT32 dy = 0;
82
0
  rdpGlyph* glyph = NULL;
83
0
  rdpGlyphCache* glyph_cache = NULL;
84
85
0
  if (!context || !data || !x || !y || !context->graphics || !context->cache ||
86
0
      !context->cache->glyph)
87
0
    return FALSE;
88
89
0
  glyph_cache = context->cache->glyph;
90
0
  glyph = glyph_cache_get(glyph_cache, cacheId, cacheIndex);
91
92
0
  if (!glyph)
93
0
    return FALSE;
94
95
0
  dx = glyph->x + *x;
96
0
  dy = glyph->y + *y;
97
98
0
  if (dx < bound->x)
99
0
  {
100
0
    sx = bound->x - dx;
101
0
    dx = bound->x;
102
0
  }
103
104
0
  if (dy < bound->y)
105
0
  {
106
0
    sy = bound->y - dy;
107
0
    dy = bound->y;
108
0
  }
109
110
0
  if ((dx <= (bound->x + bound->width)) && (dy <= (bound->y + bound->height)))
111
0
  {
112
0
    INT32 dw = glyph->cx - sx;
113
0
    INT32 dh = glyph->cy - sy;
114
115
0
    if ((dw + dx) > (bound->x + bound->width))
116
0
      dw = (bound->x + bound->width) - (dw + dx);
117
118
0
    if ((dh + dy) > (bound->y + bound->height))
119
0
      dh = (bound->y + bound->height) - (dh + dy);
120
121
0
    if ((dh > 0) && (dw > 0))
122
0
    {
123
0
      if (!glyph->Draw(context, glyph, dx, dy, dw, dh, sx, sy, fOpRedundant))
124
0
        return FALSE;
125
0
    }
126
0
  }
127
128
0
  if (flAccel & SO_CHAR_INC_EQUAL_BM_BASE)
129
0
    *x += glyph->cx;
130
131
0
  return TRUE;
132
0
}
133
134
static BOOL update_process_glyph_fragments(rdpContext* context, const BYTE* data, UINT32 length,
135
                                           UINT32 cacheId, UINT32 ulCharInc, UINT32 flAccel,
136
                                           UINT32 bgcolor, UINT32 fgcolor, INT32 x, INT32 y,
137
                                           INT32 bkX, INT32 bkY, INT32 bkWidth, INT32 bkHeight,
138
                                           INT32 opX, INT32 opY, INT32 opWidth, INT32 opHeight,
139
                                           BOOL fOpRedundant)
140
0
{
141
0
  UINT32 id = 0;
142
0
  UINT32 size = 0;
143
0
  UINT32 index = 0;
144
0
  const BYTE* fragments = NULL;
145
0
  rdpGraphics* graphics = NULL;
146
0
  rdpGlyphCache* glyph_cache = NULL;
147
0
  rdpGlyph* glyph = NULL;
148
0
  RDP_RECT bound;
149
150
0
  if (!context || !data || !context->graphics || !context->cache || !context->cache->glyph)
151
0
    return FALSE;
152
153
0
  graphics = context->graphics;
154
0
  glyph_cache = context->cache->glyph;
155
0
  glyph = graphics->Glyph_Prototype;
156
157
0
  if (!glyph)
158
0
    return FALSE;
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
  if (opX + opWidth > (INT64)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth))
199
0
  {
200
    /**
201
     * Some Microsoft servers send erroneous high values close to the
202
     * sint16 maximum in the OpRight field of the GlyphIndex, FastIndex and
203
     * FastGlyph drawing orders, probably a result of applications trying to
204
     * clear the text line to the very right end.
205
     * One example where this can be seen is typing in notepad.exe within
206
     * a RDP session to Windows XP Professional SP3.
207
     * This workaround prevents resulting problems in the UI callbacks.
208
     */
209
0
    opWidth = freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth) - opX;
210
0
  }
211
212
0
  if (bkX + bkWidth > (INT64)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth))
213
0
  {
214
    /**
215
     * Some Microsoft servers send erroneous high values close to the
216
     * sint16 maximum in the OpRight field of the GlyphIndex, FastIndex and
217
     * FastGlyph drawing orders, probably a result of applications trying to
218
     * clear the text line to the very right end.
219
     * One example where this can be seen is typing in notepad.exe within
220
     * a RDP session to Windows XP Professional SP3.
221
     * This workaround prevents resulting problems in the UI callbacks.
222
     */
223
0
    bkWidth = freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth) - bkX;
224
0
  }
225
226
0
  bound.x = bkX;
227
0
  bound.y = bkY;
228
0
  bound.width = bkWidth;
229
0
  bound.height = bkHeight;
230
231
0
  if (!glyph->BeginDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor, fOpRedundant))
232
0
    return FALSE;
233
234
0
  if (!IFCALLRESULT(TRUE, glyph->SetBounds, context, bkX, bkY, bkWidth, bkHeight))
235
0
    return FALSE;
236
237
0
  while (index < length)
238
0
  {
239
0
    const UINT32 op = data[index++];
240
241
0
    switch (op)
242
0
    {
243
0
      case GLYPH_FRAGMENT_USE:
244
0
        if (index + 1 >= length)
245
0
          return FALSE;
246
247
0
        id = data[index++];
248
0
        fragments = (const BYTE*)glyph_cache_fragment_get(glyph_cache, id, &size);
249
250
0
        if (fragments == NULL)
251
0
          return FALSE;
252
253
0
        for (size_t n = 0; n < size;)
254
0
        {
255
0
          const UINT32 fop = fragments[n++];
256
0
          n = update_glyph_offset(fragments, size, n, &x, &y, ulCharInc, flAccel);
257
258
0
          if (!update_process_glyph(context, fragments, fop, &x, &y, cacheId, flAccel,
259
0
                                    fOpRedundant, &bound))
260
0
            return FALSE;
261
0
        }
262
263
0
        break;
264
265
0
      case GLYPH_FRAGMENT_ADD:
266
0
        if (index + 2 > length)
267
0
          return FALSE;
268
269
0
        id = data[index++];
270
0
        size = data[index++];
271
0
        glyph_cache_fragment_put(glyph_cache, id, size, data);
272
0
        break;
273
274
0
      default:
275
0
        index = update_glyph_offset(data, length, index, &x, &y, ulCharInc, flAccel);
276
277
0
        if (!update_process_glyph(context, data, op, &x, &y, cacheId, flAccel, fOpRedundant,
278
0
                                  &bound))
279
0
          return FALSE;
280
281
0
        break;
282
0
    }
283
0
  }
284
285
0
  return glyph->EndDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor);
286
0
}
287
288
static BOOL update_gdi_glyph_index(rdpContext* context, GLYPH_INDEX_ORDER* glyphIndex)
289
0
{
290
0
  INT32 bkWidth = 0;
291
0
  INT32 bkHeight = 0;
292
0
  INT32 opWidth = 0;
293
0
  INT32 opHeight = 0;
294
295
0
  if (!context || !glyphIndex || !context->cache)
296
0
    return FALSE;
297
298
0
  if (glyphIndex->bkRight > glyphIndex->bkLeft)
299
0
    bkWidth = glyphIndex->bkRight - glyphIndex->bkLeft + 1;
300
301
0
  if (glyphIndex->opRight > glyphIndex->opLeft)
302
0
    opWidth = glyphIndex->opRight - glyphIndex->opLeft + 1;
303
304
0
  if (glyphIndex->bkBottom > glyphIndex->bkTop)
305
0
    bkHeight = glyphIndex->bkBottom - glyphIndex->bkTop + 1;
306
307
0
  if (glyphIndex->opBottom > glyphIndex->opTop)
308
0
    opHeight = glyphIndex->opBottom - glyphIndex->opTop + 1;
309
310
0
  return update_process_glyph_fragments(
311
0
      context, glyphIndex->data, glyphIndex->cbData, glyphIndex->cacheId, glyphIndex->ulCharInc,
312
0
      glyphIndex->flAccel, glyphIndex->backColor, glyphIndex->foreColor, glyphIndex->x,
313
0
      glyphIndex->y, glyphIndex->bkLeft, glyphIndex->bkTop, bkWidth, bkHeight, glyphIndex->opLeft,
314
0
      glyphIndex->opTop, opWidth, opHeight, glyphIndex->fOpRedundant);
315
0
}
316
317
static BOOL update_gdi_fast_index(rdpContext* context, const FAST_INDEX_ORDER* fastIndex)
318
0
{
319
0
  INT32 x = 0;
320
0
  INT32 y = 0;
321
0
  INT32 opLeft = 0;
322
0
  INT32 opTop = 0;
323
0
  INT32 opRight = 0;
324
0
  INT32 opBottom = 0;
325
0
  INT32 opWidth = 0;
326
0
  INT32 opHeight = 0;
327
0
  INT32 bkWidth = 0;
328
0
  INT32 bkHeight = 0;
329
330
0
  if (!context || !fastIndex || !context->cache)
331
0
    return FALSE;
332
333
0
  opLeft = fastIndex->opLeft;
334
0
  opTop = fastIndex->opTop;
335
0
  opRight = fastIndex->opRight;
336
0
  opBottom = fastIndex->opBottom;
337
0
  x = fastIndex->x;
338
0
  y = fastIndex->y;
339
340
0
  if (opBottom == -32768)
341
0
  {
342
0
    BYTE flags = (BYTE)(opTop & 0x0F);
343
344
0
    if (flags & 0x01)
345
0
      opBottom = fastIndex->bkBottom;
346
347
0
    if (flags & 0x02)
348
0
      opRight = fastIndex->bkRight;
349
350
0
    if (flags & 0x04)
351
0
      opTop = fastIndex->bkTop;
352
353
0
    if (flags & 0x08)
354
0
      opLeft = fastIndex->bkLeft;
355
0
  }
356
357
0
  if (opLeft == 0)
358
0
    opLeft = fastIndex->bkLeft;
359
360
0
  if (opRight == 0)
361
0
    opRight = fastIndex->bkRight;
362
363
  /* Server can send a massive number (32766) which appears to be
364
   * undocumented special behavior for "Erase all the way right".
365
   * X11 has nondeterministic results asking for a draw that wide. */
366
0
  if (opRight > (INT64)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth))
367
0
    opRight = (int)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth);
368
369
0
  if (x == -32768)
370
0
    x = fastIndex->bkLeft;
371
372
0
  if (y == -32768)
373
0
    y = fastIndex->bkTop;
374
375
0
  if (fastIndex->bkRight > fastIndex->bkLeft)
376
0
    bkWidth = fastIndex->bkRight - fastIndex->bkLeft + 1;
377
378
0
  if (fastIndex->bkBottom > fastIndex->bkTop)
379
0
    bkHeight = fastIndex->bkBottom - fastIndex->bkTop + 1;
380
381
0
  if (opRight > opLeft)
382
0
    opWidth = opRight - opLeft + 1;
383
384
0
  if (opBottom > opTop)
385
0
    opHeight = opBottom - opTop + 1;
386
387
0
  return update_process_glyph_fragments(
388
0
      context, fastIndex->data, fastIndex->cbData, fastIndex->cacheId, fastIndex->ulCharInc,
389
0
      fastIndex->flAccel, fastIndex->backColor, fastIndex->foreColor, x, y, fastIndex->bkLeft,
390
0
      fastIndex->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE);
391
0
}
392
393
static BOOL update_gdi_fast_glyph(rdpContext* context, const FAST_GLYPH_ORDER* fastGlyph)
394
0
{
395
0
  INT32 x = 0;
396
0
  INT32 y = 0;
397
0
  BYTE text_data[4] = { 0 };
398
0
  INT32 opLeft = 0;
399
0
  INT32 opTop = 0;
400
0
  INT32 opRight = 0;
401
0
  INT32 opBottom = 0;
402
0
  INT32 opWidth = 0;
403
0
  INT32 opHeight = 0;
404
0
  INT32 bkWidth = 0;
405
0
  INT32 bkHeight = 0;
406
0
  rdpCache* cache = NULL;
407
408
0
  if (!context || !fastGlyph || !context->cache)
409
0
    return FALSE;
410
411
0
  cache = context->cache;
412
0
  opLeft = fastGlyph->opLeft;
413
0
  opTop = fastGlyph->opTop;
414
0
  opRight = fastGlyph->opRight;
415
0
  opBottom = fastGlyph->opBottom;
416
0
  x = fastGlyph->x;
417
0
  y = fastGlyph->y;
418
419
0
  if (opBottom == -32768)
420
0
  {
421
0
    BYTE flags = (BYTE)(opTop & 0x0F);
422
423
0
    if (flags & 0x01)
424
0
      opBottom = fastGlyph->bkBottom;
425
426
0
    if (flags & 0x02)
427
0
      opRight = fastGlyph->bkRight;
428
429
0
    if (flags & 0x04)
430
0
      opTop = fastGlyph->bkTop;
431
432
0
    if (flags & 0x08)
433
0
      opLeft = fastGlyph->bkLeft;
434
0
  }
435
436
0
  if (opLeft == 0)
437
0
    opLeft = fastGlyph->bkLeft;
438
439
0
  if (opRight == 0)
440
0
    opRight = fastGlyph->bkRight;
441
442
  /* See update_gdi_fast_index opRight comment. */
443
0
  if (opRight > (INT64)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth))
444
0
    opRight = (int)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth);
445
446
0
  if (x == -32768)
447
0
    x = fastGlyph->bkLeft;
448
449
0
  if (y == -32768)
450
0
    y = fastGlyph->bkTop;
451
452
0
  if ((fastGlyph->cbData > 1) && (fastGlyph->glyphData.aj))
453
0
  {
454
    /* got option font that needs to go into cache */
455
0
    rdpGlyph* glyph = NULL;
456
0
    const GLYPH_DATA_V2* glyphData = &fastGlyph->glyphData;
457
458
0
    glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx, glyphData->cy,
459
0
                        glyphData->cb, glyphData->aj);
460
461
0
    if (!glyph)
462
0
      return FALSE;
463
464
0
    if (!glyph_cache_put(cache->glyph, fastGlyph->cacheId, fastGlyph->data[0], glyph))
465
0
    {
466
0
      glyph->Free(context, glyph);
467
0
      return FALSE;
468
0
    }
469
0
  }
470
471
0
  text_data[0] = fastGlyph->data[0];
472
0
  text_data[1] = 0;
473
474
0
  if (fastGlyph->bkRight > fastGlyph->bkLeft)
475
0
    bkWidth = fastGlyph->bkRight - fastGlyph->bkLeft + 1;
476
477
0
  if (fastGlyph->bkBottom > fastGlyph->bkTop)
478
0
    bkHeight = fastGlyph->bkBottom - fastGlyph->bkTop + 1;
479
480
0
  if (opRight > opLeft)
481
0
    opWidth = opRight - opLeft + 1;
482
483
0
  if (opBottom > opTop)
484
0
    opHeight = opBottom - opTop + 1;
485
486
0
  return update_process_glyph_fragments(
487
0
      context, text_data, sizeof(text_data), fastGlyph->cacheId, fastGlyph->ulCharInc,
488
0
      fastGlyph->flAccel, fastGlyph->backColor, fastGlyph->foreColor, x, y, fastGlyph->bkLeft,
489
0
      fastGlyph->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE);
490
0
}
491
492
static BOOL update_gdi_cache_glyph(rdpContext* context, const CACHE_GLYPH_ORDER* cacheGlyph)
493
0
{
494
0
  rdpCache* cache = NULL;
495
496
0
  if (!context || !cacheGlyph || !context->cache)
497
0
    return FALSE;
498
499
0
  cache = context->cache;
500
501
0
  for (size_t i = 0; i < cacheGlyph->cGlyphs; i++)
502
0
  {
503
0
    const GLYPH_DATA* glyph_data = &cacheGlyph->glyphData[i];
504
0
    rdpGlyph* glyph = NULL;
505
506
0
    if (!glyph_data)
507
0
      return FALSE;
508
509
0
    if (!(glyph = Glyph_Alloc(context, glyph_data->x, glyph_data->y, glyph_data->cx,
510
0
                              glyph_data->cy, glyph_data->cb, glyph_data->aj)))
511
0
      return FALSE;
512
513
0
    if (!glyph_cache_put(cache->glyph, cacheGlyph->cacheId, glyph_data->cacheIndex, glyph))
514
0
    {
515
0
      glyph->Free(context, glyph);
516
0
      return FALSE;
517
0
    }
518
0
  }
519
520
0
  return TRUE;
521
0
}
522
523
static BOOL update_gdi_cache_glyph_v2(rdpContext* context, const CACHE_GLYPH_V2_ORDER* cacheGlyphV2)
524
0
{
525
0
  rdpCache* cache = NULL;
526
527
0
  if (!context || !cacheGlyphV2 || !context->cache)
528
0
    return FALSE;
529
530
0
  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 = NULL;
536
537
0
    if (!glyphData)
538
0
      return FALSE;
539
540
0
    glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx, glyphData->cy,
541
0
                        glyphData->cb, glyphData->aj);
542
543
0
    if (!glyph)
544
0
      return FALSE;
545
546
0
    if (!glyph_cache_put(cache->glyph, cacheGlyphV2->cacheId, glyphData->cacheIndex, glyph))
547
0
    {
548
0
      glyph->Free(context, glyph);
549
0
      return FALSE;
550
0
    }
551
0
  }
552
553
0
  return TRUE;
554
0
}
555
556
rdpGlyph* glyph_cache_get(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index)
557
0
{
558
0
  rdpGlyph* glyph = NULL;
559
560
0
  WINPR_ASSERT(glyphCache);
561
562
0
  WLog_Print(glyphCache->log, WLOG_DEBUG, "GlyphCacheGet: id: %" PRIu32 " index: %" PRIu32 "", id,
563
0
             index);
564
565
0
  if (id > 9)
566
0
  {
567
0
    WLog_ERR(TAG, "invalid glyph cache id: %" PRIu32 "", id);
568
0
    return NULL;
569
0
  }
570
571
0
  WINPR_ASSERT(glyphCache->glyphCache);
572
0
  if (index > glyphCache->glyphCache[id].number)
573
0
  {
574
0
    WLog_ERR(TAG, "index %" PRIu32 " out of range for cache id: %" PRIu32 "", index, id);
575
0
    return NULL;
576
0
  }
577
578
0
  glyph = glyphCache->glyphCache[id].entries[index];
579
580
0
  if (!glyph)
581
0
    WLog_ERR(TAG, "no glyph found at cache index: %" PRIu32 " in cache id: %" PRIu32 "", index,
582
0
             id);
583
584
0
  return glyph;
585
0
}
586
587
BOOL glyph_cache_put(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index, rdpGlyph* glyph)
588
0
{
589
0
  rdpGlyph* prevGlyph = NULL;
590
591
0
  WINPR_ASSERT(glyphCache);
592
593
0
  if (id > 9)
594
0
  {
595
0
    WLog_ERR(TAG, "invalid glyph cache id: %" PRIu32 "", id);
596
0
    return FALSE;
597
0
  }
598
599
0
  WINPR_ASSERT(glyphCache->glyphCache);
600
0
  if (index >= glyphCache->glyphCache[id].number)
601
0
  {
602
0
    WLog_ERR(TAG, "invalid glyph cache index: %" PRIu32 " in cache id: %" PRIu32 "", index, id);
603
0
    return FALSE;
604
0
  }
605
606
0
  WLog_Print(glyphCache->log, WLOG_DEBUG, "GlyphCachePut: id: %" PRIu32 " index: %" PRIu32 "", id,
607
0
             index);
608
0
  prevGlyph = glyphCache->glyphCache[id].entries[index];
609
610
0
  if (prevGlyph)
611
0
  {
612
0
    WINPR_ASSERT(prevGlyph->Free);
613
0
    prevGlyph->Free(glyphCache->context, prevGlyph);
614
0
  }
615
616
0
  glyphCache->glyphCache[id].entries[index] = glyph;
617
0
  return TRUE;
618
0
}
619
620
const void* glyph_cache_fragment_get(rdpGlyphCache* glyphCache, UINT32 index, UINT32* size)
621
0
{
622
0
  void* fragment = NULL;
623
624
0
  WINPR_ASSERT(glyphCache);
625
0
  WINPR_ASSERT(glyphCache->fragCache.entries);
626
627
0
  if (index > 255)
628
0
  {
629
0
    WLog_ERR(TAG, "invalid glyph cache fragment index: %" PRIu32 "", index);
630
0
    return NULL;
631
0
  }
632
633
0
  fragment = glyphCache->fragCache.entries[index].fragment;
634
0
  *size = (BYTE)glyphCache->fragCache.entries[index].size;
635
0
  WLog_Print(glyphCache->log, WLOG_DEBUG,
636
0
             "GlyphCacheFragmentGet: index: %" PRIu32 " size: %" PRIu32 "", index, *size);
637
638
0
  if (!fragment)
639
0
    WLog_ERR(TAG, "invalid glyph fragment at index:%" PRIu32 "", index);
640
641
0
  return fragment;
642
0
}
643
644
BOOL glyph_cache_fragment_put(rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
645
                              const void* fragment)
646
0
{
647
0
  void* prevFragment = NULL;
648
0
  void* copy = NULL;
649
650
0
  WINPR_ASSERT(glyphCache);
651
0
  WINPR_ASSERT(glyphCache->fragCache.entries);
652
653
0
  if (index > 255)
654
0
  {
655
0
    WLog_ERR(TAG, "invalid glyph cache fragment index: %" PRIu32 "", index);
656
0
    return FALSE;
657
0
  }
658
659
0
  copy = malloc(size);
660
661
0
  if (!copy)
662
0
    return FALSE;
663
664
0
  WLog_Print(glyphCache->log, WLOG_DEBUG,
665
0
             "GlyphCacheFragmentPut: index: %" PRIu32 " size: %" PRIu32 "", index, size);
666
0
  CopyMemory(copy, fragment, size);
667
0
  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(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(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(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
}