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")
38static rdpGlyph* glyph_cache_get(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index);
39static BOOL glyph_cache_put(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index, rdpGlyph* glyph);
41static const void* glyph_cache_fragment_get(
rdpGlyphCache* glyphCache, UINT32 index, UINT32* size);
42static BOOL glyph_cache_fragment_put(
rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
43 const void* fragment);
45static UINT32 update_glyph_offset(
const BYTE* data,
size_t length, UINT32 index, INT32* x, INT32* y,
46 UINT32 ulCharInc, UINT32 flAccel)
48 if ((ulCharInc == 0) && (!(flAccel & SO_CHAR_INC_EQUAL_BM_BASE)))
52 WLog_WARN(TAG,
"glyph offset index out of bound %" PRIu32
" [max %" PRIuz
"]", index,
57 UINT32 offset = data[index++];
62 if (index + 1 < length)
64 offset = data[index++];
65 offset |= ((UINT32)data[index++]) << 8;
68 WLog_WARN(TAG,
"glyph index out of bound %" PRIu32
" [max %" PRIuz
"]", index,
72 if (flAccel & SO_VERTICAL)
73 *y += WINPR_ASSERTING_INT_CAST(int32_t, offset);
75 if (flAccel & SO_HORIZONTAL)
76 *x += WINPR_ASSERTING_INT_CAST(int32_t, offset);
82static BOOL update_process_glyph(rdpContext* context,
const BYTE* data, UINT32 cacheIndex, INT32* x,
83 const INT32* y, UINT32 cacheId, UINT32 flAccel, BOOL fOpRedundant,
89 if (!context || !data || !x || !y || !context->graphics || !context->cache ||
90 !context->cache->glyph)
94 rdpGlyph* glyph = glyph_cache_get(glyph_cache, cacheId, cacheIndex);
99 INT32 dx = glyph->x + *x;
100 INT32 dy = glyph->y + *y;
114 if ((dx <= (bound->x + bound->width)) && (dy <= (bound->y + bound->height)))
116 INT32 dw = WINPR_ASSERTING_INT_CAST(int32_t, glyph->cx) - sx;
117 INT32 dh = WINPR_ASSERTING_INT_CAST(int32_t, glyph->cy) - sy;
119 if ((dw + dx) > (bound->x + bound->width))
120 dw = (bound->x + bound->width) - (dw + dx);
122 if ((dh + dy) > (bound->y + bound->height))
123 dh = (bound->y + bound->height) - (dh + dy);
125 if ((dh > 0) && (dw > 0))
127 if (!glyph->Draw(context, glyph, dx, dy, dw, dh, sx, sy, fOpRedundant))
132 if (flAccel & SO_CHAR_INC_EQUAL_BM_BASE)
133 *x += WINPR_ASSERTING_INT_CAST(int32_t, glyph->cx);
138static BOOL update_process_glyph_fragments(rdpContext* context,
const BYTE* data, UINT32 length,
139 UINT32 cacheId, UINT32 ulCharInc, UINT32 flAccel,
140 UINT32 bgcolor, UINT32 fgcolor, INT32 x, INT32 y,
141 INT32 bkX, INT32 bkY, INT32 bkWidth, INT32 bkHeight,
142 INT32 opX, INT32 opY, INT32 opWidth, INT32 opHeight,
148 const BYTE* fragments =
nullptr;
149 RDP_RECT bound = WINPR_C_ARRAY_INIT;
152 if (!context || !data || !context->graphics || !context->cache || !context->cache->glyph)
155 rdpGraphics* graphics = context->graphics;
156 WINPR_ASSERT(graphics);
158 WINPR_ASSERT(context->cache);
160 WINPR_ASSERT(glyph_cache);
163 rdpGlyph* glyph = graphics->Glyph_Prototype;
207 if (opX + opWidth > (INT64)w)
218 opWidth = WINPR_ASSERTING_INT_CAST(
int, w) - opX;
221 if (bkX + bkWidth > (INT64)w)
232 bkWidth = WINPR_ASSERTING_INT_CAST(
int, w) - bkX;
236 bound.x = WINPR_ASSERTING_INT_CAST(INT16, bkX);
237 bound.y = WINPR_ASSERTING_INT_CAST(INT16, bkY);
238 bound.width = WINPR_ASSERTING_INT_CAST(INT16, bkWidth);
239 bound.height = WINPR_ASSERTING_INT_CAST(INT16, bkHeight);
241 if (!glyph->BeginDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor, fOpRedundant))
244 if (!IFCALLRESULT(TRUE, glyph->SetBounds, context, bkX, bkY, bkWidth, bkHeight))
247 while (index < length)
249 const UINT32 op = data[index++];
253 case GLYPH_FRAGMENT_USE:
254 if (index + 1 > length)
258 fragments = (
const BYTE*)glyph_cache_fragment_get(glyph_cache,
id, &size);
260 if (fragments ==
nullptr)
263 for (UINT32 n = 0; n < size;)
265 const UINT32 fop = fragments[n++];
266 n = update_glyph_offset(fragments, size, n, &x, &y, ulCharInc, flAccel);
268 if (!update_process_glyph(context, fragments, fop, &x, &y, cacheId, flAccel,
269 fOpRedundant, &bound))
275 case GLYPH_FRAGMENT_ADD:
276 if (index + 2 > length)
280 size = data[index++];
281 glyph_cache_fragment_put(glyph_cache,
id, size, data);
285 index = update_glyph_offset(data, length, index, &x, &y, ulCharInc, flAccel);
287 if (!update_process_glyph(context, data, op, &x, &y, cacheId, flAccel,
288 fOpRedundant, &bound))
295 if (!glyph->EndDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor))
305static BOOL update_gdi_glyph_index(rdpContext* context,
GLYPH_INDEX_ORDER* glyphIndex)
312 if (!context || !glyphIndex || !context->cache)
315 if (glyphIndex->bkRight > glyphIndex->bkLeft)
316 bkWidth = glyphIndex->bkRight - glyphIndex->bkLeft + 1;
318 if (glyphIndex->opRight > glyphIndex->opLeft)
319 opWidth = glyphIndex->opRight - glyphIndex->opLeft + 1;
321 if (glyphIndex->bkBottom > glyphIndex->bkTop)
322 bkHeight = glyphIndex->bkBottom - glyphIndex->bkTop + 1;
324 if (glyphIndex->opBottom > glyphIndex->opTop)
325 opHeight = glyphIndex->opBottom - glyphIndex->opTop + 1;
327 return update_process_glyph_fragments(
328 context, glyphIndex->data, glyphIndex->cbData, glyphIndex->cacheId, glyphIndex->ulCharInc,
329 glyphIndex->flAccel, glyphIndex->backColor, glyphIndex->foreColor, glyphIndex->x,
330 glyphIndex->y, glyphIndex->bkLeft, glyphIndex->bkTop, bkWidth, bkHeight, glyphIndex->opLeft,
331 glyphIndex->opTop, opWidth, opHeight,
332 WINPR_ASSERTING_INT_CAST(int32_t, glyphIndex->fOpRedundant));
335static BOOL update_gdi_fast_index(rdpContext* context,
const FAST_INDEX_ORDER* fastIndex)
343 if (!context || !fastIndex || !context->cache)
346 INT32 opLeft = fastIndex->opLeft;
347 INT32 opTop = fastIndex->opTop;
348 INT32 opRight = fastIndex->opRight;
349 INT32 opBottom = fastIndex->opBottom;
350 INT32 x = fastIndex->x;
351 INT32 y = fastIndex->y;
353 if (opBottom == -32768)
355 BYTE flags = (BYTE)(opTop & 0x0F);
358 opBottom = fastIndex->bkBottom;
361 opRight = fastIndex->bkRight;
364 opTop = fastIndex->bkTop;
367 opLeft = fastIndex->bkLeft;
371 opLeft = fastIndex->bkLeft;
374 opRight = fastIndex->bkRight;
383 x = fastIndex->bkLeft;
386 y = fastIndex->bkTop;
388 if (fastIndex->bkRight > fastIndex->bkLeft)
389 bkWidth = fastIndex->bkRight - fastIndex->bkLeft + 1;
391 if (fastIndex->bkBottom > fastIndex->bkTop)
392 bkHeight = fastIndex->bkBottom - fastIndex->bkTop + 1;
394 if (opRight > opLeft)
395 opWidth = opRight - opLeft + 1;
397 if (opBottom > opTop)
398 opHeight = opBottom - opTop + 1;
400 if (!update_process_glyph_fragments(
401 context, fastIndex->data, fastIndex->cbData, fastIndex->cacheId, fastIndex->ulCharInc,
402 fastIndex->flAccel, fastIndex->backColor, fastIndex->foreColor, x, y, fastIndex->bkLeft,
403 fastIndex->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE))
411static BOOL update_gdi_fast_glyph(rdpContext* context,
const FAST_GLYPH_ORDER* fastGlyph)
415 BYTE text_data[4] = WINPR_C_ARRAY_INIT;
424 rdpCache* cache =
nullptr;
426 if (!context || !fastGlyph || !context->cache)
429 cache = context->cache;
430 opLeft = fastGlyph->opLeft;
431 opTop = fastGlyph->opTop;
432 opRight = fastGlyph->opRight;
433 opBottom = fastGlyph->opBottom;
437 if (opBottom == -32768)
439 BYTE flags = (BYTE)(opTop & 0x0F);
442 opBottom = fastGlyph->bkBottom;
445 opRight = fastGlyph->bkRight;
448 opTop = fastGlyph->bkTop;
451 opLeft = fastGlyph->bkLeft;
455 opLeft = fastGlyph->bkLeft;
458 opRight = fastGlyph->bkRight;
465 x = fastGlyph->bkLeft;
468 y = fastGlyph->bkTop;
470 if ((fastGlyph->cbData > 1) && (fastGlyph->glyphData.aj))
473 rdpGlyph* glyph =
nullptr;
476 glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx, glyphData->cy,
477 glyphData->cb, glyphData->aj);
482 if (!glyph_cache_put(cache->glyph, fastGlyph->cacheId, fastGlyph->data[0], glyph))
484 glyph->Free(context, glyph);
489 text_data[0] = fastGlyph->data[0];
492 if (fastGlyph->bkRight > fastGlyph->bkLeft)
493 bkWidth = fastGlyph->bkRight - fastGlyph->bkLeft + 1;
495 if (fastGlyph->bkBottom > fastGlyph->bkTop)
496 bkHeight = fastGlyph->bkBottom - fastGlyph->bkTop + 1;
498 if (opRight > opLeft)
499 opWidth = opRight - opLeft + 1;
501 if (opBottom > opTop)
502 opHeight = opBottom - opTop + 1;
504 return update_process_glyph_fragments(
505 context, text_data,
sizeof(text_data), fastGlyph->cacheId, fastGlyph->ulCharInc,
506 fastGlyph->flAccel, fastGlyph->backColor, fastGlyph->foreColor, x, y, fastGlyph->bkLeft,
507 fastGlyph->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE);
510static BOOL update_gdi_cache_glyph(rdpContext* context,
const CACHE_GLYPH_ORDER* cacheGlyph)
512 if (!context || !cacheGlyph || !context->cache)
515 rdpCache* cache = context->cache;
517 for (
size_t i = 0; i < cacheGlyph->cGlyphs; i++)
519 const GLYPH_DATA* glyph_data = &cacheGlyph->glyphData[i];
520 rdpGlyph* glyph = Glyph_Alloc(context, glyph_data->x, glyph_data->y, glyph_data->cx,
521 glyph_data->cy, glyph_data->cb, glyph_data->aj);
525 if (!glyph_cache_put(cache->glyph, cacheGlyph->cacheId, glyph_data->cacheIndex, glyph))
527 glyph->Free(context, glyph);
535static BOOL update_gdi_cache_glyph_v2(rdpContext* context,
const CACHE_GLYPH_V2_ORDER* cacheGlyphV2)
537 if (!context || !cacheGlyphV2 || !context->cache)
540 rdpCache* cache = context->cache;
542 for (
size_t i = 0; i < cacheGlyphV2->cGlyphs; i++)
544 const GLYPH_DATA_V2* glyphData = &cacheGlyphV2->glyphData[i];
545 rdpGlyph* glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx,
546 glyphData->cy, glyphData->cb, glyphData->aj);
551 if (!glyph_cache_put(cache->glyph, cacheGlyphV2->cacheId, glyphData->cacheIndex, glyph))
553 glyph->Free(context, glyph);
561rdpGlyph* glyph_cache_get(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index)
563 WINPR_ASSERT(glyphCache);
565 WLog_Print(glyphCache->log, WLOG_DEBUG,
"GlyphCacheGet: id: %" PRIu32
" index: %" PRIu32
"",
id,
568 if (
id >= ARRAYSIZE(glyphCache->glyphCache))
570 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
575 if (index >= cache->number)
577 WLog_ERR(TAG,
"index %" PRIu32
" out of range for cache id: %" PRIu32
"", index,
id);
581 rdpGlyph* glyph = cache->entries[index];
583 WLog_ERR(TAG,
"no glyph found at cache index: %" PRIu32
" in cache id: %" PRIu32
"", index,
589BOOL glyph_cache_put(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index, rdpGlyph* glyph)
591 WINPR_ASSERT(glyphCache);
593 if (
id >= ARRAYSIZE(glyphCache->glyphCache))
595 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
600 if (index >= cache->number)
602 WLog_ERR(TAG,
"invalid glyph cache index: %" PRIu32
" in cache id: %" PRIu32
"", index,
id);
606 WLog_Print(glyphCache->log, WLOG_DEBUG,
"GlyphCachePut: id: %" PRIu32
" index: %" PRIu32
"",
id,
608 rdpGlyph* prevGlyph = cache->entries[index];
612 WINPR_ASSERT(prevGlyph->Free);
613 prevGlyph->Free(glyphCache->context, prevGlyph);
616 cache->entries[index] = glyph;
620const void* glyph_cache_fragment_get(
rdpGlyphCache* glyphCache, UINT32 index, UINT32* size)
622 void* fragment =
nullptr;
624 WINPR_ASSERT(glyphCache);
625 WINPR_ASSERT(glyphCache->fragCache.entries);
629 WLog_ERR(TAG,
"invalid glyph cache fragment index: %" PRIu32
"", index);
633 fragment = glyphCache->fragCache.entries[index].fragment;
634 *size = (BYTE)glyphCache->fragCache.entries[index].size;
635 WLog_Print(glyphCache->log, WLOG_DEBUG,
636 "GlyphCacheFragmentGet: index: %" PRIu32
" size: %" PRIu32
"", index, *size);
639 WLog_ERR(TAG,
"invalid glyph fragment at index:%" PRIu32
"", index);
644BOOL glyph_cache_fragment_put(
rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
645 const void* fragment)
647 WINPR_ASSERT(glyphCache);
648 WINPR_ASSERT(glyphCache->fragCache.entries);
652 WLog_ERR(TAG,
"invalid glyph cache fragment index: %" PRIu32
"", index);
659 void* copy = malloc(size);
664 WLog_Print(glyphCache->log, WLOG_DEBUG,
665 "GlyphCacheFragmentPut: index: %" PRIu32
" size: %" PRIu32
"", index, size);
666 CopyMemory(copy, fragment, size);
668 void* prevFragment = glyphCache->fragCache.entries[index].fragment;
669 glyphCache->fragCache.entries[index].fragment = copy;
670 glyphCache->fragCache.entries[index].size = size;
675void glyph_cache_register_callbacks(rdpUpdate* update)
677 WINPR_ASSERT(update);
678 WINPR_ASSERT(update->context);
679 WINPR_ASSERT(update->primary);
680 WINPR_ASSERT(update->secondary);
684 update->primary->GlyphIndex = update_gdi_glyph_index;
685 update->primary->FastIndex = update_gdi_fast_index;
686 update->primary->FastGlyph = update_gdi_fast_glyph;
687 update->secondary->CacheGlyph = update_gdi_cache_glyph;
688 update->secondary->CacheGlyphV2 = update_gdi_cache_glyph_v2;
695 rdpSettings* settings =
nullptr;
697 WINPR_ASSERT(context);
699 settings = context->settings;
700 WINPR_ASSERT(settings);
707 glyphCache->log = WLog_Get(
"com.freerdp.cache.glyph");
708 glyphCache->context = context;
710 for (
size_t i = 0; i < 10; i++)
713 freerdp_settings_get_pointer_array(settings, FreeRDP_GlyphCache, i);
714 GLYPH_CACHE* currentCache = &glyphCache->glyphCache[i];
715 currentCache->number = currentGlyph->cacheEntries;
716 currentCache->maxCellSize = currentGlyph->cacheMaximumCellSize;
717 currentCache->entries = (rdpGlyph**)calloc(currentCache->number,
sizeof(rdpGlyph*));
719 if (!currentCache->entries)
725 WINPR_PRAGMA_DIAG_PUSH
726 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
727 glyph_cache_free(glyphCache);
728 WINPR_PRAGMA_DIAG_POP
738 for (
size_t i = 0; i < 10; i++)
740 rdpGlyph** entries = cache[i].entries;
745 for (
size_t j = 0; j < cache[i].number; j++)
747 rdpGlyph* glyph = entries[j];
751 glyph->Free(glyphCache->context, glyph);
752 entries[j] =
nullptr;
756 free((
void*)entries);
757 cache[i].entries =
nullptr;
760 for (
size_t i = 0; i < ARRAYSIZE(glyphCache->fragCache.entries); i++)
762 free(glyphCache->fragCache.entries[i].fragment);
763 glyphCache->fragCache.entries[i].fragment =
nullptr;
774 WINPR_ASSERT(context);
783 for (
size_t x = 0; x < glyph->cGlyphs; x++)
790 const size_t size = src->cb;
791 data->aj = malloc(size);
796 memcpy(data->aj, src->aj, size);
800 if (glyph->unicodeCharacters)
802 if (glyph->cGlyphs == 0)
805 dst->unicodeCharacters = calloc(glyph->cGlyphs,
sizeof(WCHAR));
807 if (!dst->unicodeCharacters)
810 memcpy(dst->unicodeCharacters, glyph->unicodeCharacters,
sizeof(WCHAR) * glyph->cGlyphs);
815 free_cache_glyph_order(context, dst);
819void free_cache_glyph_order(WINPR_ATTR_UNUSED rdpContext* context,
CACHE_GLYPH_ORDER* glyph)
823 for (
size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
824 free(glyph->glyphData[x].aj);
826 free(glyph->unicodeCharacters);
837 WINPR_ASSERT(context);
846 for (
size_t x = 0; x < glyph->cGlyphs; x++)
853 const size_t size = src->cb;
854 data->aj = malloc(size);
859 memcpy(data->aj, src->aj, size);
863 if (glyph->unicodeCharacters)
865 if (glyph->cGlyphs == 0)
868 dst->unicodeCharacters = calloc(glyph->cGlyphs,
sizeof(WCHAR));
870 if (!dst->unicodeCharacters)
873 memcpy(dst->unicodeCharacters, glyph->unicodeCharacters,
sizeof(WCHAR) * glyph->cGlyphs);
878 free_cache_glyph_v2_order(context, dst);
882void free_cache_glyph_v2_order(WINPR_ATTR_UNUSED rdpContext* context,
CACHE_GLYPH_V2_ORDER* glyph)
886 for (
size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
887 free(glyph->glyphData[x].aj);
889 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.