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