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