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)))
50 UINT32 offset = data[index++];
55 if (index + 1 < length)
57 offset = data[index++];
58 offset |= ((UINT32)data[index++]) << 8;
61 WLog_WARN(TAG,
"glyph index out of bound %" PRIu32
" [max %" PRIuz
"]", index,
65 if (flAccel & SO_VERTICAL)
66 *y += WINPR_ASSERTING_INT_CAST(int32_t, offset);
68 if (flAccel & SO_HORIZONTAL)
69 *x += WINPR_ASSERTING_INT_CAST(int32_t, offset);
75static BOOL update_process_glyph(rdpContext* context,
const BYTE* data, UINT32 cacheIndex, INT32* x,
76 const INT32* y, UINT32 cacheId, UINT32 flAccel, BOOL fOpRedundant,
82 if (!context || !data || !x || !y || !context->graphics || !context->cache ||
83 !context->cache->glyph)
87 rdpGlyph* glyph = glyph_cache_get(glyph_cache, cacheId, cacheIndex);
92 INT32 dx = glyph->x + *x;
93 INT32 dy = glyph->y + *y;
107 if ((dx <= (bound->x + bound->width)) && (dy <= (bound->y + bound->height)))
109 INT32 dw = WINPR_ASSERTING_INT_CAST(int32_t, glyph->cx) - sx;
110 INT32 dh = WINPR_ASSERTING_INT_CAST(int32_t, glyph->cy) - sy;
112 if ((dw + dx) > (bound->x + bound->width))
113 dw = (bound->x + bound->width) - (dw + dx);
115 if ((dh + dy) > (bound->y + bound->height))
116 dh = (bound->y + bound->height) - (dh + dy);
118 if ((dh > 0) && (dw > 0))
120 if (!glyph->Draw(context, glyph, dx, dy, dw, dh, sx, sy, fOpRedundant))
125 if (flAccel & SO_CHAR_INC_EQUAL_BM_BASE)
126 *x += WINPR_ASSERTING_INT_CAST(int32_t, glyph->cx);
131static BOOL update_process_glyph_fragments(rdpContext* context,
const BYTE* data, UINT32 length,
132 UINT32 cacheId, UINT32 ulCharInc, UINT32 flAccel,
133 UINT32 bgcolor, UINT32 fgcolor, INT32 x, INT32 y,
134 INT32 bkX, INT32 bkY, INT32 bkWidth, INT32 bkHeight,
135 INT32 opX, INT32 opY, INT32 opWidth, INT32 opHeight,
141 const BYTE* fragments = NULL;
145 if (!context || !data || !context->graphics || !context->cache || !context->cache->glyph)
148 rdpGraphics* graphics = context->graphics;
149 WINPR_ASSERT(graphics);
151 WINPR_ASSERT(context->cache);
153 WINPR_ASSERT(glyph_cache);
156 rdpGlyph* glyph = graphics->Glyph_Prototype;
200 if (opX + opWidth > (INT64)w)
211 opWidth = WINPR_ASSERTING_INT_CAST(
int, w) - opX;
214 if (bkX + bkWidth > (INT64)w)
225 bkWidth = WINPR_ASSERTING_INT_CAST(
int, w) - bkX;
229 bound.x = WINPR_ASSERTING_INT_CAST(INT16, bkX);
230 bound.y = WINPR_ASSERTING_INT_CAST(INT16, bkY);
231 bound.width = WINPR_ASSERTING_INT_CAST(INT16, bkWidth);
232 bound.height = WINPR_ASSERTING_INT_CAST(INT16, bkHeight);
234 if (!glyph->BeginDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor, fOpRedundant))
237 if (!IFCALLRESULT(TRUE, glyph->SetBounds, context, bkX, bkY, bkWidth, bkHeight))
240 while (index < length)
242 const UINT32 op = data[index++];
246 case GLYPH_FRAGMENT_USE:
247 if (index + 1 > length)
251 fragments = (
const BYTE*)glyph_cache_fragment_get(glyph_cache,
id, &size);
253 if (fragments == NULL)
256 for (UINT32 n = 0; n < size;)
258 const UINT32 fop = fragments[n++];
259 n = update_glyph_offset(fragments, size, n, &x, &y, ulCharInc, flAccel);
261 if (!update_process_glyph(context, fragments, fop, &x, &y, cacheId, flAccel,
262 fOpRedundant, &bound))
268 case GLYPH_FRAGMENT_ADD:
269 if (index + 2 > length)
273 size = data[index++];
274 glyph_cache_fragment_put(glyph_cache,
id, size, data);
278 index = update_glyph_offset(data, length, index, &x, &y, ulCharInc, flAccel);
280 if (!update_process_glyph(context, data, op, &x, &y, cacheId, flAccel,
281 fOpRedundant, &bound))
288 if (!glyph->EndDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor))
298static BOOL update_gdi_glyph_index(rdpContext* context,
GLYPH_INDEX_ORDER* glyphIndex)
305 if (!context || !glyphIndex || !context->cache)
308 if (glyphIndex->bkRight > glyphIndex->bkLeft)
309 bkWidth = glyphIndex->bkRight - glyphIndex->bkLeft + 1;
311 if (glyphIndex->opRight > glyphIndex->opLeft)
312 opWidth = glyphIndex->opRight - glyphIndex->opLeft + 1;
314 if (glyphIndex->bkBottom > glyphIndex->bkTop)
315 bkHeight = glyphIndex->bkBottom - glyphIndex->bkTop + 1;
317 if (glyphIndex->opBottom > glyphIndex->opTop)
318 opHeight = glyphIndex->opBottom - glyphIndex->opTop + 1;
320 return update_process_glyph_fragments(
321 context, glyphIndex->data, glyphIndex->cbData, glyphIndex->cacheId, glyphIndex->ulCharInc,
322 glyphIndex->flAccel, glyphIndex->backColor, glyphIndex->foreColor, glyphIndex->x,
323 glyphIndex->y, glyphIndex->bkLeft, glyphIndex->bkTop, bkWidth, bkHeight, glyphIndex->opLeft,
324 glyphIndex->opTop, opWidth, opHeight,
325 WINPR_ASSERTING_INT_CAST(int32_t, glyphIndex->fOpRedundant));
328static BOOL update_gdi_fast_index(rdpContext* context,
const FAST_INDEX_ORDER* fastIndex)
336 if (!context || !fastIndex || !context->cache)
339 INT32 opLeft = fastIndex->opLeft;
340 INT32 opTop = fastIndex->opTop;
341 INT32 opRight = fastIndex->opRight;
342 INT32 opBottom = fastIndex->opBottom;
343 INT32 x = fastIndex->x;
344 INT32 y = fastIndex->y;
346 if (opBottom == -32768)
348 BYTE flags = (BYTE)(opTop & 0x0F);
351 opBottom = fastIndex->bkBottom;
354 opRight = fastIndex->bkRight;
357 opTop = fastIndex->bkTop;
360 opLeft = fastIndex->bkLeft;
364 opLeft = fastIndex->bkLeft;
367 opRight = fastIndex->bkRight;
376 x = fastIndex->bkLeft;
379 y = fastIndex->bkTop;
381 if (fastIndex->bkRight > fastIndex->bkLeft)
382 bkWidth = fastIndex->bkRight - fastIndex->bkLeft + 1;
384 if (fastIndex->bkBottom > fastIndex->bkTop)
385 bkHeight = fastIndex->bkBottom - fastIndex->bkTop + 1;
387 if (opRight > opLeft)
388 opWidth = opRight - opLeft + 1;
390 if (opBottom > opTop)
391 opHeight = opBottom - opTop + 1;
393 if (!update_process_glyph_fragments(
394 context, fastIndex->data, fastIndex->cbData, fastIndex->cacheId, fastIndex->ulCharInc,
395 fastIndex->flAccel, fastIndex->backColor, fastIndex->foreColor, x, y, fastIndex->bkLeft,
396 fastIndex->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE))
404static BOOL update_gdi_fast_glyph(rdpContext* context,
const FAST_GLYPH_ORDER* fastGlyph)
408 BYTE text_data[4] = { 0 };
417 rdpCache* cache = NULL;
419 if (!context || !fastGlyph || !context->cache)
422 cache = context->cache;
423 opLeft = fastGlyph->opLeft;
424 opTop = fastGlyph->opTop;
425 opRight = fastGlyph->opRight;
426 opBottom = fastGlyph->opBottom;
430 if (opBottom == -32768)
432 BYTE flags = (BYTE)(opTop & 0x0F);
435 opBottom = fastGlyph->bkBottom;
438 opRight = fastGlyph->bkRight;
441 opTop = fastGlyph->bkTop;
444 opLeft = fastGlyph->bkLeft;
448 opLeft = fastGlyph->bkLeft;
451 opRight = fastGlyph->bkRight;
458 x = fastGlyph->bkLeft;
461 y = fastGlyph->bkTop;
463 if ((fastGlyph->cbData > 1) && (fastGlyph->glyphData.aj))
466 rdpGlyph* glyph = NULL;
469 glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx, glyphData->cy,
470 glyphData->cb, glyphData->aj);
475 if (!glyph_cache_put(cache->glyph, fastGlyph->cacheId, fastGlyph->data[0], glyph))
477 glyph->Free(context, glyph);
482 text_data[0] = fastGlyph->data[0];
485 if (fastGlyph->bkRight > fastGlyph->bkLeft)
486 bkWidth = fastGlyph->bkRight - fastGlyph->bkLeft + 1;
488 if (fastGlyph->bkBottom > fastGlyph->bkTop)
489 bkHeight = fastGlyph->bkBottom - fastGlyph->bkTop + 1;
491 if (opRight > opLeft)
492 opWidth = opRight - opLeft + 1;
494 if (opBottom > opTop)
495 opHeight = opBottom - opTop + 1;
497 return update_process_glyph_fragments(
498 context, text_data,
sizeof(text_data), fastGlyph->cacheId, fastGlyph->ulCharInc,
499 fastGlyph->flAccel, fastGlyph->backColor, fastGlyph->foreColor, x, y, fastGlyph->bkLeft,
500 fastGlyph->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE);
503static BOOL update_gdi_cache_glyph(rdpContext* context,
const CACHE_GLYPH_ORDER* cacheGlyph)
505 if (!context || !cacheGlyph || !context->cache)
508 rdpCache* cache = context->cache;
510 for (
size_t i = 0; i < cacheGlyph->cGlyphs; i++)
512 const GLYPH_DATA* glyph_data = &cacheGlyph->glyphData[i];
513 rdpGlyph* glyph = Glyph_Alloc(context, glyph_data->x, glyph_data->y, glyph_data->cx,
514 glyph_data->cy, glyph_data->cb, glyph_data->aj);
518 if (!glyph_cache_put(cache->glyph, cacheGlyph->cacheId, glyph_data->cacheIndex, glyph))
520 glyph->Free(context, glyph);
528static BOOL update_gdi_cache_glyph_v2(rdpContext* context,
const CACHE_GLYPH_V2_ORDER* cacheGlyphV2)
530 if (!context || !cacheGlyphV2 || !context->cache)
533 rdpCache* cache = context->cache;
535 for (
size_t i = 0; i < cacheGlyphV2->cGlyphs; i++)
537 const GLYPH_DATA_V2* glyphData = &cacheGlyphV2->glyphData[i];
538 rdpGlyph* glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx,
539 glyphData->cy, glyphData->cb, glyphData->aj);
544 if (!glyph_cache_put(cache->glyph, cacheGlyphV2->cacheId, glyphData->cacheIndex, glyph))
546 glyph->Free(context, glyph);
554rdpGlyph* glyph_cache_get(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index)
556 WINPR_ASSERT(glyphCache);
558 WLog_Print(glyphCache->log, WLOG_DEBUG,
"GlyphCacheGet: id: %" PRIu32
" index: %" PRIu32
"",
id,
561 if (
id >= ARRAYSIZE(glyphCache->glyphCache))
563 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
568 if (index > cache->number)
570 WLog_ERR(TAG,
"index %" PRIu32
" out of range for cache id: %" PRIu32
"", index,
id);
574 rdpGlyph* glyph = cache->entries[index];
576 WLog_ERR(TAG,
"no glyph found at cache index: %" PRIu32
" in cache id: %" PRIu32
"", index,
582BOOL glyph_cache_put(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index, rdpGlyph* glyph)
584 WINPR_ASSERT(glyphCache);
586 if (
id >= ARRAYSIZE(glyphCache->glyphCache))
588 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
593 if (index >= cache->number)
595 WLog_ERR(TAG,
"invalid glyph cache index: %" PRIu32
" in cache id: %" PRIu32
"", index,
id);
599 WLog_Print(glyphCache->log, WLOG_DEBUG,
"GlyphCachePut: id: %" PRIu32
" index: %" PRIu32
"",
id,
601 rdpGlyph* prevGlyph = cache->entries[index];
605 WINPR_ASSERT(prevGlyph->Free);
606 prevGlyph->Free(glyphCache->context, prevGlyph);
609 cache->entries[index] = glyph;
613const void* glyph_cache_fragment_get(
rdpGlyphCache* glyphCache, UINT32 index, UINT32* size)
615 void* fragment = NULL;
617 WINPR_ASSERT(glyphCache);
618 WINPR_ASSERT(glyphCache->fragCache.entries);
622 WLog_ERR(TAG,
"invalid glyph cache fragment index: %" PRIu32
"", index);
626 fragment = glyphCache->fragCache.entries[index].fragment;
627 *size = (BYTE)glyphCache->fragCache.entries[index].size;
628 WLog_Print(glyphCache->log, WLOG_DEBUG,
629 "GlyphCacheFragmentGet: index: %" PRIu32
" size: %" PRIu32
"", index, *size);
632 WLog_ERR(TAG,
"invalid glyph fragment at index:%" PRIu32
"", index);
637BOOL glyph_cache_fragment_put(
rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
638 const void* fragment)
640 WINPR_ASSERT(glyphCache);
641 WINPR_ASSERT(glyphCache->fragCache.entries);
645 WLog_ERR(TAG,
"invalid glyph cache fragment index: %" PRIu32
"", index);
652 void* copy = malloc(size);
657 WLog_Print(glyphCache->log, WLOG_DEBUG,
658 "GlyphCacheFragmentPut: index: %" PRIu32
" size: %" PRIu32
"", index, size);
659 CopyMemory(copy, fragment, size);
661 void* prevFragment = glyphCache->fragCache.entries[index].fragment;
662 glyphCache->fragCache.entries[index].fragment = copy;
663 glyphCache->fragCache.entries[index].size = size;
668void glyph_cache_register_callbacks(rdpUpdate* update)
670 WINPR_ASSERT(update);
671 WINPR_ASSERT(update->context);
672 WINPR_ASSERT(update->primary);
673 WINPR_ASSERT(update->secondary);
677 update->primary->GlyphIndex = update_gdi_glyph_index;
678 update->primary->FastIndex = update_gdi_fast_index;
679 update->primary->FastGlyph = update_gdi_fast_glyph;
680 update->secondary->CacheGlyph = update_gdi_cache_glyph;
681 update->secondary->CacheGlyphV2 = update_gdi_cache_glyph_v2;
688 rdpSettings* settings = NULL;
690 WINPR_ASSERT(context);
692 settings = context->settings;
693 WINPR_ASSERT(settings);
700 glyphCache->log = WLog_Get(
"com.freerdp.cache.glyph");
701 glyphCache->context = context;
703 for (
size_t i = 0; i < 10; i++)
706 freerdp_settings_get_pointer_array(settings, FreeRDP_GlyphCache, i);
707 GLYPH_CACHE* currentCache = &glyphCache->glyphCache[i];
708 currentCache->number = currentGlyph->cacheEntries;
709 currentCache->maxCellSize = currentGlyph->cacheMaximumCellSize;
710 currentCache->entries = (rdpGlyph**)calloc(currentCache->number,
sizeof(rdpGlyph*));
712 if (!currentCache->entries)
718 WINPR_PRAGMA_DIAG_PUSH
719 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
720 glyph_cache_free(glyphCache);
721 WINPR_PRAGMA_DIAG_POP
731 for (
size_t i = 0; i < 10; i++)
733 rdpGlyph** entries = cache[i].entries;
738 for (
size_t j = 0; j < cache[i].number; j++)
740 rdpGlyph* glyph = entries[j];
744 glyph->Free(glyphCache->context, glyph);
749 free((
void*)entries);
750 cache[i].entries = NULL;
753 for (
size_t i = 0; i < ARRAYSIZE(glyphCache->fragCache.entries); i++)
755 free(glyphCache->fragCache.entries[i].fragment);
756 glyphCache->fragCache.entries[i].fragment = NULL;
767 WINPR_ASSERT(context);
776 for (
size_t x = 0; x < glyph->cGlyphs; x++)
783 const size_t size = src->cb;
784 data->aj = malloc(size);
789 memcpy(data->aj, src->aj, size);
793 if (glyph->unicodeCharacters)
795 if (glyph->cGlyphs == 0)
798 dst->unicodeCharacters = calloc(glyph->cGlyphs,
sizeof(WCHAR));
800 if (!dst->unicodeCharacters)
803 memcpy(dst->unicodeCharacters, glyph->unicodeCharacters,
sizeof(WCHAR) * glyph->cGlyphs);
808 free_cache_glyph_order(context, dst);
812void free_cache_glyph_order(WINPR_ATTR_UNUSED rdpContext* context,
CACHE_GLYPH_ORDER* glyph)
816 for (
size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
817 free(glyph->glyphData[x].aj);
819 free(glyph->unicodeCharacters);
830 WINPR_ASSERT(context);
839 for (
size_t x = 0; x < glyph->cGlyphs; x++)
846 const size_t size = src->cb;
847 data->aj = malloc(size);
852 memcpy(data->aj, src->aj, size);
856 if (glyph->unicodeCharacters)
858 if (glyph->cGlyphs == 0)
861 dst->unicodeCharacters = calloc(glyph->cGlyphs,
sizeof(WCHAR));
863 if (!dst->unicodeCharacters)
866 memcpy(dst->unicodeCharacters, glyph->unicodeCharacters,
sizeof(WCHAR) * glyph->cGlyphs);
871 free_cache_glyph_v2_order(context, dst);
875void free_cache_glyph_v2_order(WINPR_ATTR_UNUSED rdpContext* context,
CACHE_GLYPH_V2_ORDER* glyph)
879 for (
size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
880 free(glyph->glyphData[x].aj);
882 free(glyph->unicodeCharacters);
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.