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,
"[%s] 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,
83 rdpGlyph* glyph = NULL;
86 if (!context || !data || !x || !y || !context->graphics || !context->cache ||
87 !context->cache->glyph)
90 glyph_cache = context->cache->glyph;
91 glyph = glyph_cache_get(glyph_cache, cacheId, cacheIndex);
111 if ((dx <= (bound->x + bound->width)) && (dy <= (bound->y + bound->height)))
113 INT32 dw = WINPR_ASSERTING_INT_CAST(int32_t, glyph->cx) - sx;
114 INT32 dh = WINPR_ASSERTING_INT_CAST(int32_t, glyph->cy) - sy;
116 if ((dw + dx) > (bound->x + bound->width))
117 dw = (bound->x + bound->width) - (dw + dx);
119 if ((dh + dy) > (bound->y + bound->height))
120 dh = (bound->y + bound->height) - (dh + dy);
122 if ((dh > 0) && (dw > 0))
124 if (!glyph->Draw(context, glyph, dx, dy, dw, dh, sx, sy, fOpRedundant))
129 if (flAccel & SO_CHAR_INC_EQUAL_BM_BASE)
130 *x += WINPR_ASSERTING_INT_CAST(int32_t, glyph->cx);
135static BOOL update_process_glyph_fragments(rdpContext* context,
const BYTE* data, UINT32 length,
136 UINT32 cacheId, UINT32 ulCharInc, UINT32 flAccel,
137 UINT32 bgcolor, UINT32 fgcolor, INT32 x, INT32 y,
138 INT32 bkX, INT32 bkY, INT32 bkWidth, INT32 bkHeight,
139 INT32 opX, INT32 opY, INT32 opWidth, INT32 opHeight,
145 const BYTE* fragments = NULL;
149 if (!context || !data || !context->graphics || !context->cache || !context->cache->glyph)
152 rdpGraphics* graphics = context->graphics;
153 WINPR_ASSERT(graphics);
155 WINPR_ASSERT(context->cache);
157 WINPR_ASSERT(glyph_cache);
159 rdpGlyph* glyph = graphics->Glyph_Prototype;
203 if (opX + opWidth > (INT64)w)
214 opWidth = WINPR_ASSERTING_INT_CAST(
int, w) - opX;
217 if (bkX + bkWidth > (INT64)w)
228 bkWidth = WINPR_ASSERTING_INT_CAST(
int, w) - bkX;
231 bound.x = WINPR_ASSERTING_INT_CAST(INT16, bkX);
232 bound.y = WINPR_ASSERTING_INT_CAST(INT16, bkY);
233 bound.width = WINPR_ASSERTING_INT_CAST(INT16, bkWidth);
234 bound.height = WINPR_ASSERTING_INT_CAST(INT16, bkHeight);
236 if (!glyph->BeginDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor, fOpRedundant))
239 if (!IFCALLRESULT(TRUE, glyph->SetBounds, context, bkX, bkY, bkWidth, bkHeight))
242 while (index < length)
244 const UINT32 op = data[index++];
248 case GLYPH_FRAGMENT_USE:
249 if (index + 1 > length)
253 fragments = (
const BYTE*)glyph_cache_fragment_get(glyph_cache,
id, &size);
255 if (fragments == NULL)
258 for (UINT32 n = 0; n < size;)
260 const UINT32 fop = fragments[n++];
261 n = update_glyph_offset(fragments, size, n, &x, &y, ulCharInc, flAccel);
263 if (!update_process_glyph(context, fragments, fop, &x, &y, cacheId, flAccel,
264 fOpRedundant, &bound))
270 case GLYPH_FRAGMENT_ADD:
271 if (index + 2 > length)
275 size = data[index++];
276 glyph_cache_fragment_put(glyph_cache,
id, size, data);
280 index = update_glyph_offset(data, length, index, &x, &y, ulCharInc, flAccel);
282 if (!update_process_glyph(context, data, op, &x, &y, cacheId, flAccel, fOpRedundant,
290 if (!glyph->EndDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor))
299static BOOL update_gdi_glyph_index(rdpContext* context,
GLYPH_INDEX_ORDER* glyphIndex)
306 if (!context || !glyphIndex || !context->cache)
309 if (glyphIndex->bkRight > glyphIndex->bkLeft)
310 bkWidth = glyphIndex->bkRight - glyphIndex->bkLeft + 1;
312 if (glyphIndex->opRight > glyphIndex->opLeft)
313 opWidth = glyphIndex->opRight - glyphIndex->opLeft + 1;
315 if (glyphIndex->bkBottom > glyphIndex->bkTop)
316 bkHeight = glyphIndex->bkBottom - glyphIndex->bkTop + 1;
318 if (glyphIndex->opBottom > glyphIndex->opTop)
319 opHeight = glyphIndex->opBottom - glyphIndex->opTop + 1;
321 return update_process_glyph_fragments(
322 context, glyphIndex->data, glyphIndex->cbData, glyphIndex->cacheId, glyphIndex->ulCharInc,
323 glyphIndex->flAccel, glyphIndex->backColor, glyphIndex->foreColor, glyphIndex->x,
324 glyphIndex->y, glyphIndex->bkLeft, glyphIndex->bkTop, bkWidth, bkHeight, glyphIndex->opLeft,
325 glyphIndex->opTop, opWidth, opHeight,
326 WINPR_ASSERTING_INT_CAST(int32_t, glyphIndex->fOpRedundant));
329static BOOL update_gdi_fast_index(rdpContext* context,
const FAST_INDEX_ORDER* fastIndex)
337 if (!context || !fastIndex || !context->cache)
340 INT32 opLeft = fastIndex->opLeft;
341 INT32 opTop = fastIndex->opTop;
342 INT32 opRight = fastIndex->opRight;
343 INT32 opBottom = fastIndex->opBottom;
344 INT32 x = fastIndex->x;
345 INT32 y = fastIndex->y;
347 if (opBottom == -32768)
349 BYTE flags = (BYTE)(opTop & 0x0F);
352 opBottom = fastIndex->bkBottom;
355 opRight = fastIndex->bkRight;
358 opTop = fastIndex->bkTop;
361 opLeft = fastIndex->bkLeft;
365 opLeft = fastIndex->bkLeft;
368 opRight = fastIndex->bkRight;
377 x = fastIndex->bkLeft;
380 y = fastIndex->bkTop;
382 if (fastIndex->bkRight > fastIndex->bkLeft)
383 bkWidth = fastIndex->bkRight - fastIndex->bkLeft + 1;
385 if (fastIndex->bkBottom > fastIndex->bkTop)
386 bkHeight = fastIndex->bkBottom - fastIndex->bkTop + 1;
388 if (opRight > opLeft)
389 opWidth = opRight - opLeft + 1;
391 if (opBottom > opTop)
392 opHeight = opBottom - opTop + 1;
394 if (!update_process_glyph_fragments(
395 context, fastIndex->data, fastIndex->cbData, fastIndex->cacheId, fastIndex->ulCharInc,
396 fastIndex->flAccel, fastIndex->backColor, fastIndex->foreColor, x, y, fastIndex->bkLeft,
397 fastIndex->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE))
405static BOOL update_gdi_fast_glyph(rdpContext* context,
const FAST_GLYPH_ORDER* fastGlyph)
409 BYTE text_data[4] = { 0 };
418 rdpCache* cache = NULL;
420 if (!context || !fastGlyph || !context->cache)
423 cache = context->cache;
424 opLeft = fastGlyph->opLeft;
425 opTop = fastGlyph->opTop;
426 opRight = fastGlyph->opRight;
427 opBottom = fastGlyph->opBottom;
431 if (opBottom == -32768)
433 BYTE flags = (BYTE)(opTop & 0x0F);
436 opBottom = fastGlyph->bkBottom;
439 opRight = fastGlyph->bkRight;
442 opTop = fastGlyph->bkTop;
445 opLeft = fastGlyph->bkLeft;
449 opLeft = fastGlyph->bkLeft;
452 opRight = fastGlyph->bkRight;
459 x = fastGlyph->bkLeft;
462 y = fastGlyph->bkTop;
464 if ((fastGlyph->cbData > 1) && (fastGlyph->glyphData.aj))
467 rdpGlyph* glyph = NULL;
470 glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx, glyphData->cy,
471 glyphData->cb, glyphData->aj);
476 if (!glyph_cache_put(cache->glyph, fastGlyph->cacheId, fastGlyph->data[0], glyph))
478 glyph->Free(context, glyph);
483 text_data[0] = fastGlyph->data[0];
486 if (fastGlyph->bkRight > fastGlyph->bkLeft)
487 bkWidth = fastGlyph->bkRight - fastGlyph->bkLeft + 1;
489 if (fastGlyph->bkBottom > fastGlyph->bkTop)
490 bkHeight = fastGlyph->bkBottom - fastGlyph->bkTop + 1;
492 if (opRight > opLeft)
493 opWidth = opRight - opLeft + 1;
495 if (opBottom > opTop)
496 opHeight = opBottom - opTop + 1;
498 return update_process_glyph_fragments(
499 context, text_data,
sizeof(text_data), fastGlyph->cacheId, fastGlyph->ulCharInc,
500 fastGlyph->flAccel, fastGlyph->backColor, fastGlyph->foreColor, x, y, fastGlyph->bkLeft,
501 fastGlyph->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE);
504static BOOL update_gdi_cache_glyph(rdpContext* context,
const CACHE_GLYPH_ORDER* cacheGlyph)
506 if (!context || !cacheGlyph || !context->cache)
509 rdpCache* cache = context->cache;
511 for (
size_t i = 0; i < cacheGlyph->cGlyphs; i++)
513 const GLYPH_DATA* glyph_data = &cacheGlyph->glyphData[i];
514 rdpGlyph* glyph = Glyph_Alloc(context, glyph_data->x, glyph_data->y, glyph_data->cx,
515 glyph_data->cy, glyph_data->cb, glyph_data->aj);
519 if (!glyph_cache_put(cache->glyph, cacheGlyph->cacheId, glyph_data->cacheIndex, glyph))
521 glyph->Free(context, glyph);
529static BOOL update_gdi_cache_glyph_v2(rdpContext* context,
const CACHE_GLYPH_V2_ORDER* cacheGlyphV2)
531 if (!context || !cacheGlyphV2 || !context->cache)
534 rdpCache* cache = context->cache;
536 for (
size_t i = 0; i < cacheGlyphV2->cGlyphs; i++)
538 const GLYPH_DATA_V2* glyphData = &cacheGlyphV2->glyphData[i];
539 rdpGlyph* glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx,
540 glyphData->cy, glyphData->cb, glyphData->aj);
545 if (!glyph_cache_put(cache->glyph, cacheGlyphV2->cacheId, glyphData->cacheIndex, glyph))
547 glyph->Free(context, glyph);
555rdpGlyph* glyph_cache_get(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index)
557 rdpGlyph* glyph = NULL;
559 WINPR_ASSERT(glyphCache);
561 WLog_Print(glyphCache->log, WLOG_DEBUG,
"GlyphCacheGet: id: %" PRIu32
" index: %" PRIu32
"",
id,
566 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
570 WINPR_ASSERT(glyphCache->glyphCache);
571 if (index > glyphCache->glyphCache[
id].number)
573 WLog_ERR(TAG,
"index %" PRIu32
" out of range for cache id: %" PRIu32
"", index,
id);
577 glyph = glyphCache->glyphCache[id].entries[index];
580 WLog_ERR(TAG,
"no glyph found at cache index: %" PRIu32
" in cache id: %" PRIu32
"", index,
586BOOL glyph_cache_put(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index, rdpGlyph* glyph)
588 rdpGlyph* prevGlyph = NULL;
590 WINPR_ASSERT(glyphCache);
594 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
598 WINPR_ASSERT(glyphCache->glyphCache);
599 if (index >= glyphCache->glyphCache[
id].number)
601 WLog_ERR(TAG,
"invalid glyph cache index: %" PRIu32
" in cache id: %" PRIu32
"", index,
id);
605 WLog_Print(glyphCache->log, WLOG_DEBUG,
"GlyphCachePut: id: %" PRIu32
" index: %" PRIu32
"",
id,
607 prevGlyph = glyphCache->glyphCache[id].entries[index];
611 WINPR_ASSERT(prevGlyph->Free);
612 prevGlyph->Free(glyphCache->context, prevGlyph);
615 glyphCache->glyphCache[id].entries[index] = glyph;
619const void* glyph_cache_fragment_get(
rdpGlyphCache* glyphCache, UINT32 index, UINT32* size)
621 void* fragment = NULL;
623 WINPR_ASSERT(glyphCache);
624 WINPR_ASSERT(glyphCache->fragCache.entries);
628 WLog_ERR(TAG,
"invalid glyph cache fragment index: %" PRIu32
"", index);
632 fragment = glyphCache->fragCache.entries[index].fragment;
633 *size = (BYTE)glyphCache->fragCache.entries[index].size;
634 WLog_Print(glyphCache->log, WLOG_DEBUG,
635 "GlyphCacheFragmentGet: index: %" PRIu32
" size: %" PRIu32
"", index, *size);
638 WLog_ERR(TAG,
"invalid glyph fragment at index:%" PRIu32
"", index);
643BOOL glyph_cache_fragment_put(
rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
644 const void* fragment)
646 WINPR_ASSERT(glyphCache);
647 WINPR_ASSERT(glyphCache->fragCache.entries);
651 WLog_ERR(TAG,
"invalid glyph cache fragment index: %" PRIu32
"", index);
658 void* copy = malloc(size);
663 WLog_Print(glyphCache->log, WLOG_DEBUG,
664 "GlyphCacheFragmentPut: index: %" PRIu32
" size: %" PRIu32
"", index, size);
665 CopyMemory(copy, fragment, size);
667 void* prevFragment = glyphCache->fragCache.entries[index].fragment;
668 glyphCache->fragCache.entries[index].fragment = copy;
669 glyphCache->fragCache.entries[index].size = size;
674void glyph_cache_register_callbacks(rdpUpdate* update)
676 WINPR_ASSERT(update);
677 WINPR_ASSERT(update->context);
678 WINPR_ASSERT(update->primary);
679 WINPR_ASSERT(update->secondary);
683 update->primary->GlyphIndex = update_gdi_glyph_index;
684 update->primary->FastIndex = update_gdi_fast_index;
685 update->primary->FastGlyph = update_gdi_fast_glyph;
686 update->secondary->CacheGlyph = update_gdi_cache_glyph;
687 update->secondary->CacheGlyphV2 = update_gdi_cache_glyph_v2;
694 rdpSettings* settings = NULL;
696 WINPR_ASSERT(context);
698 settings = context->settings;
699 WINPR_ASSERT(settings);
706 glyphCache->log = WLog_Get(
"com.freerdp.cache.glyph");
707 glyphCache->context = context;
709 for (
size_t i = 0; i < 10; i++)
712 freerdp_settings_get_pointer_array(settings, FreeRDP_GlyphCache, i);
713 GLYPH_CACHE* currentCache = &glyphCache->glyphCache[i];
714 currentCache->number = currentGlyph->cacheEntries;
715 currentCache->maxCellSize = currentGlyph->cacheMaximumCellSize;
716 currentCache->entries = (rdpGlyph**)calloc(currentCache->number,
sizeof(rdpGlyph*));
718 if (!currentCache->entries)
724 WINPR_PRAGMA_DIAG_PUSH
725 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
726 glyph_cache_free(glyphCache);
727 WINPR_PRAGMA_DIAG_POP
737 for (
size_t i = 0; i < 10; i++)
739 rdpGlyph** entries = cache[i].entries;
744 for (
size_t j = 0; j < cache[i].number; j++)
746 rdpGlyph* glyph = entries[j];
750 glyph->Free(glyphCache->context, glyph);
755 free((
void*)entries);
756 cache[i].entries = NULL;
759 for (
size_t i = 0; i < ARRAYSIZE(glyphCache->fragCache.entries); i++)
761 free(glyphCache->fragCache.entries[i].fragment);
762 glyphCache->fragCache.entries[i].fragment = NULL;
773 WINPR_ASSERT(context);
782 for (
size_t x = 0; x < glyph->cGlyphs; x++)
789 const size_t size = src->cb;
790 data->aj = malloc(size);
795 memcpy(data->aj, src->aj, size);
799 if (glyph->unicodeCharacters)
801 if (glyph->cGlyphs == 0)
804 dst->unicodeCharacters = calloc(glyph->cGlyphs,
sizeof(WCHAR));
806 if (!dst->unicodeCharacters)
809 memcpy(dst->unicodeCharacters, glyph->unicodeCharacters,
sizeof(WCHAR) * glyph->cGlyphs);
814 free_cache_glyph_order(context, dst);
818void free_cache_glyph_order(WINPR_ATTR_UNUSED rdpContext* context,
CACHE_GLYPH_ORDER* glyph)
822 for (
size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
823 free(glyph->glyphData[x].aj);
825 free(glyph->unicodeCharacters);
836 WINPR_ASSERT(context);
845 for (
size_t x = 0; x < glyph->cGlyphs; x++)
852 const size_t size = src->cb;
853 data->aj = malloc(size);
858 memcpy(data->aj, src->aj, size);
862 if (glyph->unicodeCharacters)
864 if (glyph->cGlyphs == 0)
867 dst->unicodeCharacters = calloc(glyph->cGlyphs,
sizeof(WCHAR));
869 if (!dst->unicodeCharacters)
872 memcpy(dst->unicodeCharacters, glyph->unicodeCharacters,
sizeof(WCHAR) * glyph->cGlyphs);
877 free_cache_glyph_v2_order(context, dst);
881void free_cache_glyph_v2_order(WINPR_ATTR_UNUSED rdpContext* context,
CACHE_GLYPH_V2_ORDER* glyph)
885 for (
size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
886 free(glyph->glyphData[x].aj);
888 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.