Coverage Report

Created: 2023-09-25 06:56

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