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 if (size > length - index)
283 glyph_cache_fragment_put(glyph_cache,
id, size, data);
287 index = update_glyph_offset(data, length, index, &x, &y, ulCharInc, flAccel);
289 if (!update_process_glyph(context, data, op, &x, &y, cacheId, flAccel,
290 fOpRedundant, &bound))
297 if (!glyph->EndDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor))
307static BOOL update_gdi_glyph_index(rdpContext* context,
GLYPH_INDEX_ORDER* glyphIndex)
314 if (!context || !glyphIndex || !context->cache)
317 if (glyphIndex->bkRight > glyphIndex->bkLeft)
318 bkWidth = glyphIndex->bkRight - glyphIndex->bkLeft + 1;
320 if (glyphIndex->opRight > glyphIndex->opLeft)
321 opWidth = glyphIndex->opRight - glyphIndex->opLeft + 1;
323 if (glyphIndex->bkBottom > glyphIndex->bkTop)
324 bkHeight = glyphIndex->bkBottom - glyphIndex->bkTop + 1;
326 if (glyphIndex->opBottom > glyphIndex->opTop)
327 opHeight = glyphIndex->opBottom - glyphIndex->opTop + 1;
329 return update_process_glyph_fragments(
330 context, glyphIndex->data, glyphIndex->cbData, glyphIndex->cacheId, glyphIndex->ulCharInc,
331 glyphIndex->flAccel, glyphIndex->backColor, glyphIndex->foreColor, glyphIndex->x,
332 glyphIndex->y, glyphIndex->bkLeft, glyphIndex->bkTop, bkWidth, bkHeight, glyphIndex->opLeft,
333 glyphIndex->opTop, opWidth, opHeight,
334 WINPR_ASSERTING_INT_CAST(int32_t, glyphIndex->fOpRedundant));
337static BOOL update_gdi_fast_index(rdpContext* context,
const FAST_INDEX_ORDER* fastIndex)
345 if (!context || !fastIndex || !context->cache)
348 INT32 opLeft = fastIndex->opLeft;
349 INT32 opTop = fastIndex->opTop;
350 INT32 opRight = fastIndex->opRight;
351 INT32 opBottom = fastIndex->opBottom;
352 INT32 x = fastIndex->x;
353 INT32 y = fastIndex->y;
355 if (opBottom == -32768)
357 BYTE flags = (BYTE)(opTop & 0x0F);
360 opBottom = fastIndex->bkBottom;
363 opRight = fastIndex->bkRight;
366 opTop = fastIndex->bkTop;
369 opLeft = fastIndex->bkLeft;
373 opLeft = fastIndex->bkLeft;
376 opRight = fastIndex->bkRight;
385 x = fastIndex->bkLeft;
388 y = fastIndex->bkTop;
390 if (fastIndex->bkRight > fastIndex->bkLeft)
391 bkWidth = fastIndex->bkRight - fastIndex->bkLeft + 1;
393 if (fastIndex->bkBottom > fastIndex->bkTop)
394 bkHeight = fastIndex->bkBottom - fastIndex->bkTop + 1;
396 if (opRight > opLeft)
397 opWidth = opRight - opLeft + 1;
399 if (opBottom > opTop)
400 opHeight = opBottom - opTop + 1;
402 if (!update_process_glyph_fragments(
403 context, fastIndex->data, fastIndex->cbData, fastIndex->cacheId, fastIndex->ulCharInc,
404 fastIndex->flAccel, fastIndex->backColor, fastIndex->foreColor, x, y, fastIndex->bkLeft,
405 fastIndex->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE))
413static BOOL update_gdi_fast_glyph(rdpContext* context,
const FAST_GLYPH_ORDER* fastGlyph)
417 BYTE text_data[4] = WINPR_C_ARRAY_INIT;
426 rdpCache* cache =
nullptr;
428 if (!context || !fastGlyph || !context->cache)
431 cache = context->cache;
432 opLeft = fastGlyph->opLeft;
433 opTop = fastGlyph->opTop;
434 opRight = fastGlyph->opRight;
435 opBottom = fastGlyph->opBottom;
439 if (opBottom == -32768)
441 BYTE flags = (BYTE)(opTop & 0x0F);
444 opBottom = fastGlyph->bkBottom;
447 opRight = fastGlyph->bkRight;
450 opTop = fastGlyph->bkTop;
453 opLeft = fastGlyph->bkLeft;
457 opLeft = fastGlyph->bkLeft;
460 opRight = fastGlyph->bkRight;
467 x = fastGlyph->bkLeft;
470 y = fastGlyph->bkTop;
472 if ((fastGlyph->cbData > 1) && (fastGlyph->glyphData.aj))
475 rdpGlyph* glyph =
nullptr;
478 glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx, glyphData->cy,
479 glyphData->cb, glyphData->aj);
484 if (!glyph_cache_put(cache->glyph, fastGlyph->cacheId, fastGlyph->data[0], glyph))
486 glyph->Free(context, glyph);
491 text_data[0] = fastGlyph->data[0];
494 if (fastGlyph->bkRight > fastGlyph->bkLeft)
495 bkWidth = fastGlyph->bkRight - fastGlyph->bkLeft + 1;
497 if (fastGlyph->bkBottom > fastGlyph->bkTop)
498 bkHeight = fastGlyph->bkBottom - fastGlyph->bkTop + 1;
500 if (opRight > opLeft)
501 opWidth = opRight - opLeft + 1;
503 if (opBottom > opTop)
504 opHeight = opBottom - opTop + 1;
506 return update_process_glyph_fragments(
507 context, text_data,
sizeof(text_data), fastGlyph->cacheId, fastGlyph->ulCharInc,
508 fastGlyph->flAccel, fastGlyph->backColor, fastGlyph->foreColor, x, y, fastGlyph->bkLeft,
509 fastGlyph->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE);
512static BOOL update_gdi_cache_glyph(rdpContext* context,
const CACHE_GLYPH_ORDER* cacheGlyph)
514 if (!context || !cacheGlyph || !context->cache)
517 rdpCache* cache = context->cache;
519 for (
size_t i = 0; i < cacheGlyph->cGlyphs; i++)
521 const GLYPH_DATA* glyph_data = &cacheGlyph->glyphData[i];
522 rdpGlyph* glyph = Glyph_Alloc(context, glyph_data->x, glyph_data->y, glyph_data->cx,
523 glyph_data->cy, glyph_data->cb, glyph_data->aj);
527 if (!glyph_cache_put(cache->glyph, cacheGlyph->cacheId, glyph_data->cacheIndex, glyph))
529 glyph->Free(context, glyph);
537static BOOL update_gdi_cache_glyph_v2(rdpContext* context,
const CACHE_GLYPH_V2_ORDER* cacheGlyphV2)
539 if (!context || !cacheGlyphV2 || !context->cache)
542 rdpCache* cache = context->cache;
544 for (
size_t i = 0; i < cacheGlyphV2->cGlyphs; i++)
546 const GLYPH_DATA_V2* glyphData = &cacheGlyphV2->glyphData[i];
547 rdpGlyph* glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx,
548 glyphData->cy, glyphData->cb, glyphData->aj);
553 if (!glyph_cache_put(cache->glyph, cacheGlyphV2->cacheId, glyphData->cacheIndex, glyph))
555 glyph->Free(context, glyph);
563rdpGlyph* glyph_cache_get(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index)
565 WINPR_ASSERT(glyphCache);
567 WLog_Print(glyphCache->log, WLOG_DEBUG,
"GlyphCacheGet: id: %" PRIu32
" index: %" PRIu32
"",
id,
570 if (
id >= ARRAYSIZE(glyphCache->glyphCache))
572 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
577 if (index >= cache->number)
579 WLog_ERR(TAG,
"index %" PRIu32
" out of range for cache id: %" PRIu32
"", index,
id);
583 rdpGlyph* glyph = cache->entries[index];
585 WLog_ERR(TAG,
"no glyph found at cache index: %" PRIu32
" in cache id: %" PRIu32
"", index,
591BOOL glyph_cache_put(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index, rdpGlyph* glyph)
593 WINPR_ASSERT(glyphCache);
595 if (
id >= ARRAYSIZE(glyphCache->glyphCache))
597 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
602 if (index >= cache->number)
604 WLog_ERR(TAG,
"invalid glyph cache index: %" PRIu32
" in cache id: %" PRIu32
"", index,
id);
608 WLog_Print(glyphCache->log, WLOG_DEBUG,
"GlyphCachePut: id: %" PRIu32
" index: %" PRIu32
"",
id,
610 rdpGlyph* prevGlyph = cache->entries[index];
614 WINPR_ASSERT(prevGlyph->Free);
615 prevGlyph->Free(glyphCache->context, prevGlyph);
618 cache->entries[index] = glyph;
622const void* glyph_cache_fragment_get(
rdpGlyphCache* glyphCache, UINT32 index, UINT32* size)
624 void* fragment =
nullptr;
626 WINPR_ASSERT(glyphCache);
627 WINPR_ASSERT(glyphCache->fragCache.entries);
631 WLog_ERR(TAG,
"invalid glyph cache fragment index: %" PRIu32
"", index);
635 fragment = glyphCache->fragCache.entries[index].fragment;
636 *size = (BYTE)glyphCache->fragCache.entries[index].size;
637 WLog_Print(glyphCache->log, WLOG_DEBUG,
638 "GlyphCacheFragmentGet: index: %" PRIu32
" size: %" PRIu32
"", index, *size);
641 WLog_ERR(TAG,
"invalid glyph fragment at index:%" PRIu32
"", index);
646BOOL glyph_cache_fragment_put(
rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
647 const void* fragment)
649 WINPR_ASSERT(glyphCache);
650 WINPR_ASSERT(glyphCache->fragCache.entries);
654 WLog_ERR(TAG,
"invalid glyph cache fragment index: %" PRIu32
"", index);
661 void* copy = malloc(size);
666 WLog_Print(glyphCache->log, WLOG_DEBUG,
667 "GlyphCacheFragmentPut: index: %" PRIu32
" size: %" PRIu32
"", index, size);
668 CopyMemory(copy, fragment, size);
670 void* prevFragment = glyphCache->fragCache.entries[index].fragment;
671 glyphCache->fragCache.entries[index].fragment = copy;
672 glyphCache->fragCache.entries[index].size = size;
677void glyph_cache_register_callbacks(rdpUpdate* update)
679 WINPR_ASSERT(update);
680 WINPR_ASSERT(update->context);
681 WINPR_ASSERT(update->primary);
682 WINPR_ASSERT(update->secondary);
686 update->primary->GlyphIndex = update_gdi_glyph_index;
687 update->primary->FastIndex = update_gdi_fast_index;
688 update->primary->FastGlyph = update_gdi_fast_glyph;
689 update->secondary->CacheGlyph = update_gdi_cache_glyph;
690 update->secondary->CacheGlyphV2 = update_gdi_cache_glyph_v2;
697 rdpSettings* settings =
nullptr;
699 WINPR_ASSERT(context);
701 settings = context->settings;
702 WINPR_ASSERT(settings);
709 glyphCache->log = WLog_Get(
"com.freerdp.cache.glyph");
710 glyphCache->context = context;
712 for (
size_t i = 0; i < 10; i++)
715 freerdp_settings_get_pointer_array(settings, FreeRDP_GlyphCache, i);
716 GLYPH_CACHE* currentCache = &glyphCache->glyphCache[i];
717 currentCache->number = currentGlyph->cacheEntries;
718 currentCache->maxCellSize = currentGlyph->cacheMaximumCellSize;
719 currentCache->entries = (rdpGlyph**)calloc(currentCache->number,
sizeof(rdpGlyph*));
721 if (!currentCache->entries)
727 WINPR_PRAGMA_DIAG_PUSH
728 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
729 glyph_cache_free(glyphCache);
730 WINPR_PRAGMA_DIAG_POP
740 for (
size_t i = 0; i < 10; i++)
742 rdpGlyph** entries = cache[i].entries;
747 for (
size_t j = 0; j < cache[i].number; j++)
749 rdpGlyph* glyph = entries[j];
753 glyph->Free(glyphCache->context, glyph);
754 entries[j] =
nullptr;
758 free((
void*)entries);
759 cache[i].entries =
nullptr;
762 for (
size_t i = 0; i < ARRAYSIZE(glyphCache->fragCache.entries); i++)
764 free(glyphCache->fragCache.entries[i].fragment);
765 glyphCache->fragCache.entries[i].fragment =
nullptr;
776 WINPR_ASSERT(context);
785 for (
size_t x = 0; x < glyph->cGlyphs; x++)
792 const size_t size = src->cb;
793 data->aj = malloc(size);
798 memcpy(data->aj, src->aj, size);
802 if (glyph->unicodeCharacters)
804 if (glyph->cGlyphs == 0)
807 dst->unicodeCharacters = calloc(glyph->cGlyphs,
sizeof(WCHAR));
809 if (!dst->unicodeCharacters)
812 memcpy(dst->unicodeCharacters, glyph->unicodeCharacters,
sizeof(WCHAR) * glyph->cGlyphs);
817 free_cache_glyph_order(context, dst);
821void free_cache_glyph_order(WINPR_ATTR_UNUSED rdpContext* context,
CACHE_GLYPH_ORDER* glyph)
825 for (
size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
826 free(glyph->glyphData[x].aj);
828 free(glyph->unicodeCharacters);
839 WINPR_ASSERT(context);
848 for (
size_t x = 0; x < glyph->cGlyphs; x++)
855 const size_t size = src->cb;
856 data->aj = malloc(size);
861 memcpy(data->aj, src->aj, size);
865 if (glyph->unicodeCharacters)
867 if (glyph->cGlyphs == 0)
870 dst->unicodeCharacters = calloc(glyph->cGlyphs,
sizeof(WCHAR));
872 if (!dst->unicodeCharacters)
875 memcpy(dst->unicodeCharacters, glyph->unicodeCharacters,
sizeof(WCHAR) * glyph->cGlyphs);
880 free_cache_glyph_v2_order(context, dst);
884void free_cache_glyph_v2_order(WINPR_ATTR_UNUSED rdpContext* context,
CACHE_GLYPH_V2_ORDER* glyph)
888 for (
size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
889 free(glyph->glyphData[x].aj);
891 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.