20#include <freerdp/config.h>
25#include <winpr/assert.h>
26#include <winpr/cast.h>
28#include <freerdp/freerdp.h>
29#include <winpr/stream.h>
31#include <freerdp/log.h>
36#define TAG FREERDP_TAG("cache.glyph")
49} FRAGMENT_CACHE_ENTRY;
53 FRAGMENT_CACHE_ENTRY entries[256];
58 FRAGMENT_CACHE fragCache;
59 GLYPH_CACHE glyphCache[10];
66static rdpGlyph* glyph_cache_get(rdpGlyphCache* glyphCache, UINT32
id, UINT32 index);
69static BOOL glyph_cache_put(rdpGlyphCache* glyphCache, UINT32
id, UINT32 index, rdpGlyph* glyph);
72static const void* glyph_cache_fragment_get(rdpGlyphCache* glyphCache, UINT32 index, UINT32* size);
75static BOOL glyph_cache_fragment_put(rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
76 const void* fragment);
79static UINT32 update_glyph_offset(
const BYTE* data,
size_t length, UINT32 index, INT32* x, INT32* y,
80 UINT32 ulCharInc, UINT32 flAccel)
82 if ((ulCharInc == 0) && (!(flAccel & SO_CHAR_INC_EQUAL_BM_BASE)))
86 WLog_WARN(TAG,
"glyph offset index out of bound %" PRIu32
" [max %" PRIuz
"]", index,
91 UINT32 offset = data[index++];
96 if (index + 1 < length)
98 offset = data[index++];
99 offset |= ((UINT32)data[index++]) << 8;
102 WLog_WARN(TAG,
"glyph index out of bound %" PRIu32
" [max %" PRIuz
"]", index,
106 if (flAccel & SO_VERTICAL)
107 *y += WINPR_ASSERTING_INT_CAST(int32_t, offset);
109 if (flAccel & SO_HORIZONTAL)
110 *x += WINPR_ASSERTING_INT_CAST(int32_t, offset);
117static BOOL update_process_glyph(rdpContext* context,
const BYTE* data, UINT32 cacheIndex, INT32* x,
118 const INT32* y, UINT32 cacheId, UINT32 flAccel, BOOL fOpRedundant,
124 if (!context || !data || !x || !y || !context->graphics || !context->cache ||
125 !context->cache->glyph)
128 rdpGlyphCache* glyph_cache = context->cache->glyph;
129 rdpGlyph* glyph = glyph_cache_get(glyph_cache, cacheId, cacheIndex);
133 FreeRDP_AllowUnanouncedOrdersFromServer);
135 INT32 dx = glyph->x + *x;
136 INT32 dy = glyph->y + *y;
150 if ((dx <= (bound->x + bound->width)) && (dy <= (bound->y + bound->height)))
152 INT32 dw = WINPR_ASSERTING_INT_CAST(int32_t, glyph->cx) - sx;
153 INT32 dh = WINPR_ASSERTING_INT_CAST(int32_t, glyph->cy) - sy;
155 if ((dw + dx) > (bound->x + bound->width))
156 dw = (bound->x + bound->width) - (dw + dx);
158 if ((dh + dy) > (bound->y + bound->height))
159 dh = (bound->y + bound->height) - (dh + dy);
161 if ((dh > 0) && (dw > 0))
163 if (!glyph->Draw(context, glyph, dx, dy, dw, dh, sx, sy, fOpRedundant))
168 if (flAccel & SO_CHAR_INC_EQUAL_BM_BASE)
169 *x += WINPR_ASSERTING_INT_CAST(int32_t, glyph->cx);
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,
185 const BYTE* fragments =
nullptr;
186 RDP_RECT bound = WINPR_C_ARRAY_INIT;
189 if (!context || !data || !context->graphics || !context->cache || !context->cache->glyph)
192 rdpGraphics* graphics = context->graphics;
193 WINPR_ASSERT(graphics);
195 WINPR_ASSERT(context->cache);
196 rdpGlyphCache* glyph_cache = context->cache->glyph;
197 WINPR_ASSERT(glyph_cache);
200 rdpGlyph* glyph = graphics->Glyph_Prototype;
244 if (opX + opWidth > (INT64)w)
255 opWidth = WINPR_ASSERTING_INT_CAST(
int, w) - opX;
258 if (bkX + bkWidth > (INT64)w)
269 bkWidth = WINPR_ASSERTING_INT_CAST(
int, w) - bkX;
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);
278 if (!glyph->BeginDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor, fOpRedundant))
281 if (!IFCALLRESULT(TRUE, glyph->SetBounds, context, bkX, bkY, bkWidth, bkHeight))
284 while (index < length)
286 const UINT32 op = data[index++];
290 case GLYPH_FRAGMENT_USE:
291 if (index + 1 > length)
295 fragments = (
const BYTE*)glyph_cache_fragment_get(glyph_cache,
id, &size);
297 if (fragments ==
nullptr)
300 for (UINT32 n = 0; n < size;)
302 const UINT32 fop = fragments[n++];
303 n = update_glyph_offset(fragments, size, n, &x, &y, ulCharInc, flAccel);
305 if (!update_process_glyph(context, fragments, fop, &x, &y, cacheId, flAccel,
306 fOpRedundant, &bound))
312 case GLYPH_FRAGMENT_ADD:
313 if (index + 2 > length)
317 size = data[index++];
318 if (size > length - index)
320 if (!glyph_cache_fragment_put(glyph_cache,
id, size, data))
325 index = update_glyph_offset(data, length, index, &x, &y, ulCharInc, flAccel);
327 if (!update_process_glyph(context, data, op, &x, &y, cacheId, flAccel,
328 fOpRedundant, &bound))
335 if (!glyph->EndDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor))
346static BOOL update_gdi_glyph_index(rdpContext* context,
GLYPH_INDEX_ORDER* glyphIndex)
353 if (!context || !glyphIndex || !context->cache)
356 if (glyphIndex->bkRight > glyphIndex->bkLeft)
357 bkWidth = glyphIndex->bkRight - glyphIndex->bkLeft + 1;
359 if (glyphIndex->opRight > glyphIndex->opLeft)
360 opWidth = glyphIndex->opRight - glyphIndex->opLeft + 1;
362 if (glyphIndex->bkBottom > glyphIndex->bkTop)
363 bkHeight = glyphIndex->bkBottom - glyphIndex->bkTop + 1;
365 if (glyphIndex->opBottom > glyphIndex->opTop)
366 opHeight = glyphIndex->opBottom - glyphIndex->opTop + 1;
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));
377static BOOL update_gdi_fast_index(rdpContext* context,
const FAST_INDEX_ORDER* fastIndex)
385 if (!context || !fastIndex || !context->cache)
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;
395 if (opBottom == -32768)
397 BYTE flags = (BYTE)(opTop & 0x0F);
400 opBottom = fastIndex->bkBottom;
403 opRight = fastIndex->bkRight;
406 opTop = fastIndex->bkTop;
409 opLeft = fastIndex->bkLeft;
413 opLeft = fastIndex->bkLeft;
416 opRight = fastIndex->bkRight;
425 x = fastIndex->bkLeft;
428 y = fastIndex->bkTop;
430 if (fastIndex->bkRight > fastIndex->bkLeft)
431 bkWidth = fastIndex->bkRight - fastIndex->bkLeft + 1;
433 if (fastIndex->bkBottom > fastIndex->bkTop)
434 bkHeight = fastIndex->bkBottom - fastIndex->bkTop + 1;
436 if (opRight > opLeft)
437 opWidth = opRight - opLeft + 1;
439 if (opBottom > opTop)
440 opHeight = opBottom - opTop + 1;
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))
454static BOOL update_gdi_fast_glyph(rdpContext* context,
const FAST_GLYPH_ORDER* fastGlyph)
458 BYTE text_data[4] = WINPR_C_ARRAY_INIT;
467 rdpCache* cache =
nullptr;
469 if (!context || !fastGlyph || !context->cache)
472 cache = context->cache;
473 opLeft = fastGlyph->opLeft;
474 opTop = fastGlyph->opTop;
475 opRight = fastGlyph->opRight;
476 opBottom = fastGlyph->opBottom;
480 if (opBottom == -32768)
482 BYTE flags = (BYTE)(opTop & 0x0F);
485 opBottom = fastGlyph->bkBottom;
488 opRight = fastGlyph->bkRight;
491 opTop = fastGlyph->bkTop;
494 opLeft = fastGlyph->bkLeft;
498 opLeft = fastGlyph->bkLeft;
501 opRight = fastGlyph->bkRight;
508 x = fastGlyph->bkLeft;
511 y = fastGlyph->bkTop;
513 if ((fastGlyph->cbData > 1) && (fastGlyph->glyphData.aj))
516 rdpGlyph* glyph =
nullptr;
519 glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx, glyphData->cy,
520 glyphData->cb, glyphData->aj);
525 if (!glyph_cache_put(cache->glyph, fastGlyph->cacheId, fastGlyph->data[0], glyph))
527 glyph->Free(context, glyph);
532 text_data[0] = fastGlyph->data[0];
535 if (fastGlyph->bkRight > fastGlyph->bkLeft)
536 bkWidth = fastGlyph->bkRight - fastGlyph->bkLeft + 1;
538 if (fastGlyph->bkBottom > fastGlyph->bkTop)
539 bkHeight = fastGlyph->bkBottom - fastGlyph->bkTop + 1;
541 if (opRight > opLeft)
542 opWidth = opRight - opLeft + 1;
544 if (opBottom > opTop)
545 opHeight = opBottom - opTop + 1;
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);
554static BOOL update_gdi_cache_glyph(rdpContext* context,
const CACHE_GLYPH_ORDER* cacheGlyph)
556 if (!context || !cacheGlyph || !context->cache)
559 rdpCache* cache = context->cache;
561 for (
size_t i = 0; i < cacheGlyph->cGlyphs; i++)
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);
569 if (!glyph_cache_put(cache->glyph, cacheGlyph->cacheId, glyph_data->cacheIndex, glyph))
571 glyph->Free(context, glyph);
580static BOOL update_gdi_cache_glyph_v2(rdpContext* context,
const CACHE_GLYPH_V2_ORDER* cacheGlyphV2)
582 if (!context || !cacheGlyphV2 || !context->cache)
585 rdpCache* cache = context->cache;
587 for (
size_t i = 0; i < cacheGlyphV2->cGlyphs; i++)
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);
596 if (!glyph_cache_put(cache->glyph, cacheGlyphV2->cacheId, glyphData->cacheIndex, glyph))
598 glyph->Free(context, glyph);
606rdpGlyph* glyph_cache_get(rdpGlyphCache* glyphCache, UINT32
id, UINT32 index)
608 WINPR_ASSERT(glyphCache);
610 WLog_Print(glyphCache->log, WLOG_DEBUG,
"GlyphCacheGet: id: %" PRIu32
" index: %" PRIu32
"",
id,
613 if (
id >= ARRAYSIZE(glyphCache->glyphCache))
615 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
619 GLYPH_CACHE* cache = &glyphCache->glyphCache[id];
620 if (index >= cache->number)
622 WLog_ERR(TAG,
"index %" PRIu32
" out of range for cache id: %" PRIu32
"", index,
id);
626 rdpGlyph* glyph = cache->entries[index];
628 WLog_ERR(TAG,
"no glyph found at cache index: %" PRIu32
" in cache id: %" PRIu32
"", index,
634BOOL glyph_cache_put(rdpGlyphCache* glyphCache, UINT32
id, UINT32 index, rdpGlyph* glyph)
636 WINPR_ASSERT(glyphCache);
638 if (
id >= ARRAYSIZE(glyphCache->glyphCache))
640 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
644 GLYPH_CACHE* cache = &glyphCache->glyphCache[id];
645 if (index >= cache->number)
647 WLog_ERR(TAG,
"invalid glyph cache index: %" PRIu32
" in cache id: %" PRIu32
"", index,
id);
651 WLog_Print(glyphCache->log, WLOG_DEBUG,
"GlyphCachePut: id: %" PRIu32
" index: %" PRIu32
"",
id,
653 rdpGlyph* prevGlyph = cache->entries[index];
657 WINPR_ASSERT(prevGlyph->Free);
658 prevGlyph->Free(glyphCache->context, prevGlyph);
661 cache->entries[index] = glyph;
665const void* glyph_cache_fragment_get(rdpGlyphCache* glyphCache, UINT32 index, UINT32* size)
667 void* fragment =
nullptr;
669 WINPR_ASSERT(glyphCache);
670 WINPR_ASSERT(glyphCache->fragCache.entries);
674 WLog_ERR(TAG,
"invalid glyph cache fragment index: %" PRIu32
"", index);
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);
684 WLog_ERR(TAG,
"invalid glyph fragment at index:%" PRIu32
"", index);
689BOOL glyph_cache_fragment_put(rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
690 const void* fragment)
692 WINPR_ASSERT(glyphCache);
693 WINPR_ASSERT(glyphCache->fragCache.entries);
697 WLog_ERR(TAG,
"invalid glyph cache fragment index: %" PRIu32
"", index);
704 void* copy = malloc(size);
709 WLog_Print(glyphCache->log, WLOG_DEBUG,
710 "GlyphCacheFragmentPut: index: %" PRIu32
" size: %" PRIu32
"", index, size);
711 CopyMemory(copy, fragment, size);
713 void* prevFragment = glyphCache->fragCache.entries[index].fragment;
714 glyphCache->fragCache.entries[index].fragment = copy;
715 glyphCache->fragCache.entries[index].size = size;
720void glyph_cache_register_callbacks(rdpUpdate* update)
722 WINPR_ASSERT(update);
723 WINPR_ASSERT(update->context);
724 WINPR_ASSERT(update->primary);
725 WINPR_ASSERT(update->secondary);
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;
737rdpGlyphCache* glyph_cache_new(rdpContext* context)
739 rdpGlyphCache* glyphCache =
nullptr;
740 rdpSettings* settings =
nullptr;
742 WINPR_ASSERT(context);
744 settings = context->settings;
745 WINPR_ASSERT(settings);
747 glyphCache = (rdpGlyphCache*)calloc(1,
sizeof(rdpGlyphCache));
752 glyphCache->log = WLog_Get(
"com.freerdp.cache.glyph");
753 glyphCache->context = context;
755 for (
size_t i = 0; i < 10; i++)
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*));
764 if (!currentCache->entries)
770 WINPR_PRAGMA_DIAG_PUSH
771 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
772 glyph_cache_free(glyphCache);
773 WINPR_PRAGMA_DIAG_POP
777void glyph_cache_free(rdpGlyphCache* glyphCache)
781 GLYPH_CACHE* cache = glyphCache->glyphCache;
783 for (
size_t i = 0; i < 10; i++)
785 rdpGlyph** entries = cache[i].entries;
790 for (
size_t j = 0; j < cache[i].number; j++)
792 rdpGlyph* glyph = entries[j];
796 glyph->Free(glyphCache->context, glyph);
797 entries[j] =
nullptr;
801 free((
void*)entries);
802 cache[i].entries =
nullptr;
805 for (
size_t i = 0; i < ARRAYSIZE(glyphCache->fragCache.entries); i++)
807 free(glyphCache->fragCache.entries[i].fragment);
808 glyphCache->fragCache.entries[i].fragment =
nullptr;
819 WINPR_ASSERT(context);
828 for (
size_t x = 0; x < glyph->cGlyphs; x++)
835 const size_t size = src->cb;
836 data->aj = malloc(size);
841 memcpy(data->aj, src->aj, size);
845 if (glyph->unicodeCharacters)
847 if (glyph->cGlyphs == 0)
850 dst->unicodeCharacters = calloc(glyph->cGlyphs,
sizeof(WCHAR));
852 if (!dst->unicodeCharacters)
855 memcpy(dst->unicodeCharacters, glyph->unicodeCharacters,
sizeof(WCHAR) * glyph->cGlyphs);
860 free_cache_glyph_order(context, dst);
864void free_cache_glyph_order(WINPR_ATTR_UNUSED rdpContext* context,
CACHE_GLYPH_ORDER* glyph)
868 for (
size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
869 free(glyph->glyphData[x].aj);
871 free(glyph->unicodeCharacters);
882 WINPR_ASSERT(context);
891 for (
size_t x = 0; x < glyph->cGlyphs; x++)
898 const size_t size = src->cb;
899 data->aj = malloc(size);
904 memcpy(data->aj, src->aj, size);
908 if (glyph->unicodeCharacters)
910 if (glyph->cGlyphs == 0)
913 dst->unicodeCharacters = calloc(glyph->cGlyphs,
sizeof(WCHAR));
915 if (!dst->unicodeCharacters)
918 memcpy(dst->unicodeCharacters, glyph->unicodeCharacters,
sizeof(WCHAR) * glyph->cGlyphs);
923 free_cache_glyph_v2_order(context, dst);
927void free_cache_glyph_v2_order(WINPR_ATTR_UNUSED rdpContext* context,
CACHE_GLYPH_V2_ORDER* glyph)
931 for (
size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
932 free(glyph->glyphData[x].aj);
934 free(glyph->unicodeCharacters);
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.