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