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,
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);
155 rdpGlyph* glyph = graphics->Glyph_Prototype;
199 if (opX + opWidth > (INT64)w)
210 opWidth = WINPR_ASSERTING_INT_CAST(
int, w) - opX;
213 if (bkX + bkWidth > (INT64)w)
224 bkWidth = WINPR_ASSERTING_INT_CAST(
int, w) - bkX;
227 bound.x = WINPR_ASSERTING_INT_CAST(INT16, bkX);
228 bound.y = WINPR_ASSERTING_INT_CAST(INT16, bkY);
229 bound.width = WINPR_ASSERTING_INT_CAST(INT16, bkWidth);
230 bound.height = WINPR_ASSERTING_INT_CAST(INT16, bkHeight);
232 if (!glyph->BeginDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor, fOpRedundant))
235 if (!IFCALLRESULT(TRUE, glyph->SetBounds, context, bkX, bkY, bkWidth, bkHeight))
238 while (index < length)
240 const UINT32 op = data[index++];
244 case GLYPH_FRAGMENT_USE:
245 if (index + 1 > length)
249 fragments = (
const BYTE*)glyph_cache_fragment_get(glyph_cache,
id, &size);
251 if (fragments == NULL)
254 for (UINT32 n = 0; n < size;)
256 const UINT32 fop = fragments[n++];
257 n = update_glyph_offset(fragments, size, n, &x, &y, ulCharInc, flAccel);
259 if (!update_process_glyph(context, fragments, fop, &x, &y, cacheId, flAccel,
260 fOpRedundant, &bound))
266 case GLYPH_FRAGMENT_ADD:
267 if (index + 2 > length)
271 size = data[index++];
272 glyph_cache_fragment_put(glyph_cache,
id, size, data);
276 index = update_glyph_offset(data, length, index, &x, &y, ulCharInc, flAccel);
278 if (!update_process_glyph(context, data, op, &x, &y, cacheId, flAccel, fOpRedundant,
286 if (!glyph->EndDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor))
295static BOOL update_gdi_glyph_index(rdpContext* context,
GLYPH_INDEX_ORDER* glyphIndex)
302 if (!context || !glyphIndex || !context->cache)
305 if (glyphIndex->bkRight > glyphIndex->bkLeft)
306 bkWidth = glyphIndex->bkRight - glyphIndex->bkLeft + 1;
308 if (glyphIndex->opRight > glyphIndex->opLeft)
309 opWidth = glyphIndex->opRight - glyphIndex->opLeft + 1;
311 if (glyphIndex->bkBottom > glyphIndex->bkTop)
312 bkHeight = glyphIndex->bkBottom - glyphIndex->bkTop + 1;
314 if (glyphIndex->opBottom > glyphIndex->opTop)
315 opHeight = glyphIndex->opBottom - glyphIndex->opTop + 1;
317 return update_process_glyph_fragments(
318 context, glyphIndex->data, glyphIndex->cbData, glyphIndex->cacheId, glyphIndex->ulCharInc,
319 glyphIndex->flAccel, glyphIndex->backColor, glyphIndex->foreColor, glyphIndex->x,
320 glyphIndex->y, glyphIndex->bkLeft, glyphIndex->bkTop, bkWidth, bkHeight, glyphIndex->opLeft,
321 glyphIndex->opTop, opWidth, opHeight,
322 WINPR_ASSERTING_INT_CAST(int32_t, glyphIndex->fOpRedundant));
325static BOOL update_gdi_fast_index(rdpContext* context,
const FAST_INDEX_ORDER* fastIndex)
333 if (!context || !fastIndex || !context->cache)
336 INT32 opLeft = fastIndex->opLeft;
337 INT32 opTop = fastIndex->opTop;
338 INT32 opRight = fastIndex->opRight;
339 INT32 opBottom = fastIndex->opBottom;
340 INT32 x = fastIndex->x;
341 INT32 y = fastIndex->y;
343 if (opBottom == -32768)
345 BYTE flags = (BYTE)(opTop & 0x0F);
348 opBottom = fastIndex->bkBottom;
351 opRight = fastIndex->bkRight;
354 opTop = fastIndex->bkTop;
357 opLeft = fastIndex->bkLeft;
361 opLeft = fastIndex->bkLeft;
364 opRight = fastIndex->bkRight;
373 x = fastIndex->bkLeft;
376 y = fastIndex->bkTop;
378 if (fastIndex->bkRight > fastIndex->bkLeft)
379 bkWidth = fastIndex->bkRight - fastIndex->bkLeft + 1;
381 if (fastIndex->bkBottom > fastIndex->bkTop)
382 bkHeight = fastIndex->bkBottom - fastIndex->bkTop + 1;
384 if (opRight > opLeft)
385 opWidth = opRight - opLeft + 1;
387 if (opBottom > opTop)
388 opHeight = opBottom - opTop + 1;
390 if (!update_process_glyph_fragments(
391 context, fastIndex->data, fastIndex->cbData, fastIndex->cacheId, fastIndex->ulCharInc,
392 fastIndex->flAccel, fastIndex->backColor, fastIndex->foreColor, x, y, fastIndex->bkLeft,
393 fastIndex->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE))
401static BOOL update_gdi_fast_glyph(rdpContext* context,
const FAST_GLYPH_ORDER* fastGlyph)
405 BYTE text_data[4] = { 0 };
414 rdpCache* cache = NULL;
416 if (!context || !fastGlyph || !context->cache)
419 cache = context->cache;
420 opLeft = fastGlyph->opLeft;
421 opTop = fastGlyph->opTop;
422 opRight = fastGlyph->opRight;
423 opBottom = fastGlyph->opBottom;
427 if (opBottom == -32768)
429 BYTE flags = (BYTE)(opTop & 0x0F);
432 opBottom = fastGlyph->bkBottom;
435 opRight = fastGlyph->bkRight;
438 opTop = fastGlyph->bkTop;
441 opLeft = fastGlyph->bkLeft;
445 opLeft = fastGlyph->bkLeft;
448 opRight = fastGlyph->bkRight;
455 x = fastGlyph->bkLeft;
458 y = fastGlyph->bkTop;
460 if ((fastGlyph->cbData > 1) && (fastGlyph->glyphData.aj))
463 rdpGlyph* glyph = NULL;
466 glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx, glyphData->cy,
467 glyphData->cb, glyphData->aj);
472 if (!glyph_cache_put(cache->glyph, fastGlyph->cacheId, fastGlyph->data[0], glyph))
474 glyph->Free(context, glyph);
479 text_data[0] = fastGlyph->data[0];
482 if (fastGlyph->bkRight > fastGlyph->bkLeft)
483 bkWidth = fastGlyph->bkRight - fastGlyph->bkLeft + 1;
485 if (fastGlyph->bkBottom > fastGlyph->bkTop)
486 bkHeight = fastGlyph->bkBottom - fastGlyph->bkTop + 1;
488 if (opRight > opLeft)
489 opWidth = opRight - opLeft + 1;
491 if (opBottom > opTop)
492 opHeight = opBottom - opTop + 1;
494 return update_process_glyph_fragments(
495 context, text_data,
sizeof(text_data), fastGlyph->cacheId, fastGlyph->ulCharInc,
496 fastGlyph->flAccel, fastGlyph->backColor, fastGlyph->foreColor, x, y, fastGlyph->bkLeft,
497 fastGlyph->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE);
500static BOOL update_gdi_cache_glyph(rdpContext* context,
const CACHE_GLYPH_ORDER* cacheGlyph)
502 if (!context || !cacheGlyph || !context->cache)
505 rdpCache* cache = context->cache;
507 for (
size_t i = 0; i < cacheGlyph->cGlyphs; i++)
509 const GLYPH_DATA* glyph_data = &cacheGlyph->glyphData[i];
510 rdpGlyph* glyph = Glyph_Alloc(context, glyph_data->x, glyph_data->y, glyph_data->cx,
511 glyph_data->cy, glyph_data->cb, glyph_data->aj);
515 if (!glyph_cache_put(cache->glyph, cacheGlyph->cacheId, glyph_data->cacheIndex, glyph))
517 glyph->Free(context, glyph);
525static BOOL update_gdi_cache_glyph_v2(rdpContext* context,
const CACHE_GLYPH_V2_ORDER* cacheGlyphV2)
527 if (!context || !cacheGlyphV2 || !context->cache)
530 rdpCache* cache = context->cache;
532 for (
size_t i = 0; i < cacheGlyphV2->cGlyphs; i++)
534 const GLYPH_DATA_V2* glyphData = &cacheGlyphV2->glyphData[i];
535 rdpGlyph* glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx,
536 glyphData->cy, glyphData->cb, glyphData->aj);
541 if (!glyph_cache_put(cache->glyph, cacheGlyphV2->cacheId, glyphData->cacheIndex, glyph))
543 glyph->Free(context, glyph);
551rdpGlyph* glyph_cache_get(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index)
553 WINPR_ASSERT(glyphCache);
555 WLog_Print(glyphCache->log, WLOG_DEBUG,
"GlyphCacheGet: id: %" PRIu32
" index: %" PRIu32
"",
id,
558 if (
id >= ARRAYSIZE(glyphCache->glyphCache))
560 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
565 if (index > cache->number)
567 WLog_ERR(TAG,
"index %" PRIu32
" out of range for cache id: %" PRIu32
"", index,
id);
571 rdpGlyph* glyph = cache->entries[index];
573 WLog_ERR(TAG,
"no glyph found at cache index: %" PRIu32
" in cache id: %" PRIu32
"", index,
579BOOL glyph_cache_put(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index, rdpGlyph* glyph)
581 WINPR_ASSERT(glyphCache);
583 if (
id >= ARRAYSIZE(glyphCache->glyphCache))
585 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
590 if (index >= cache->number)
592 WLog_ERR(TAG,
"invalid glyph cache index: %" PRIu32
" in cache id: %" PRIu32
"", index,
id);
596 WLog_Print(glyphCache->log, WLOG_DEBUG,
"GlyphCachePut: id: %" PRIu32
" index: %" PRIu32
"",
id,
598 rdpGlyph* prevGlyph = cache->entries[index];
602 WINPR_ASSERT(prevGlyph->Free);
603 prevGlyph->Free(glyphCache->context, prevGlyph);
606 cache->entries[index] = glyph;
610const void* glyph_cache_fragment_get(
rdpGlyphCache* glyphCache, UINT32 index, UINT32* size)
612 void* fragment = NULL;
614 WINPR_ASSERT(glyphCache);
615 WINPR_ASSERT(glyphCache->fragCache.entries);
619 WLog_ERR(TAG,
"invalid glyph cache fragment index: %" PRIu32
"", index);
623 fragment = glyphCache->fragCache.entries[index].fragment;
624 *size = (BYTE)glyphCache->fragCache.entries[index].size;
625 WLog_Print(glyphCache->log, WLOG_DEBUG,
626 "GlyphCacheFragmentGet: index: %" PRIu32
" size: %" PRIu32
"", index, *size);
629 WLog_ERR(TAG,
"invalid glyph fragment at index:%" PRIu32
"", index);
634BOOL glyph_cache_fragment_put(
rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
635 const void* fragment)
637 WINPR_ASSERT(glyphCache);
638 WINPR_ASSERT(glyphCache->fragCache.entries);
642 WLog_ERR(TAG,
"invalid glyph cache fragment index: %" PRIu32
"", index);
649 void* copy = malloc(size);
654 WLog_Print(glyphCache->log, WLOG_DEBUG,
655 "GlyphCacheFragmentPut: index: %" PRIu32
" size: %" PRIu32
"", index, size);
656 CopyMemory(copy, fragment, size);
658 void* prevFragment = glyphCache->fragCache.entries[index].fragment;
659 glyphCache->fragCache.entries[index].fragment = copy;
660 glyphCache->fragCache.entries[index].size = size;
665void glyph_cache_register_callbacks(rdpUpdate* update)
667 WINPR_ASSERT(update);
668 WINPR_ASSERT(update->context);
669 WINPR_ASSERT(update->primary);
670 WINPR_ASSERT(update->secondary);
674 update->primary->GlyphIndex = update_gdi_glyph_index;
675 update->primary->FastIndex = update_gdi_fast_index;
676 update->primary->FastGlyph = update_gdi_fast_glyph;
677 update->secondary->CacheGlyph = update_gdi_cache_glyph;
678 update->secondary->CacheGlyphV2 = update_gdi_cache_glyph_v2;
685 rdpSettings* settings = NULL;
687 WINPR_ASSERT(context);
689 settings = context->settings;
690 WINPR_ASSERT(settings);
697 glyphCache->log = WLog_Get(
"com.freerdp.cache.glyph");
698 glyphCache->context = context;
700 for (
size_t i = 0; i < 10; i++)
703 freerdp_settings_get_pointer_array(settings, FreeRDP_GlyphCache, i);
704 GLYPH_CACHE* currentCache = &glyphCache->glyphCache[i];
705 currentCache->number = currentGlyph->cacheEntries;
706 currentCache->maxCellSize = currentGlyph->cacheMaximumCellSize;
707 currentCache->entries = (rdpGlyph**)calloc(currentCache->number,
sizeof(rdpGlyph*));
709 if (!currentCache->entries)
715 WINPR_PRAGMA_DIAG_PUSH
716 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
717 glyph_cache_free(glyphCache);
718 WINPR_PRAGMA_DIAG_POP
728 for (
size_t i = 0; i < 10; i++)
730 rdpGlyph** entries = cache[i].entries;
735 for (
size_t j = 0; j < cache[i].number; j++)
737 rdpGlyph* glyph = entries[j];
741 glyph->Free(glyphCache->context, glyph);
746 free((
void*)entries);
747 cache[i].entries = NULL;
750 for (
size_t i = 0; i < ARRAYSIZE(glyphCache->fragCache.entries); i++)
752 free(glyphCache->fragCache.entries[i].fragment);
753 glyphCache->fragCache.entries[i].fragment = NULL;
764 WINPR_ASSERT(context);
773 for (
size_t x = 0; x < glyph->cGlyphs; x++)
780 const size_t size = src->cb;
781 data->aj = malloc(size);
786 memcpy(data->aj, src->aj, size);
790 if (glyph->unicodeCharacters)
792 if (glyph->cGlyphs == 0)
795 dst->unicodeCharacters = calloc(glyph->cGlyphs,
sizeof(WCHAR));
797 if (!dst->unicodeCharacters)
800 memcpy(dst->unicodeCharacters, glyph->unicodeCharacters,
sizeof(WCHAR) * glyph->cGlyphs);
805 free_cache_glyph_order(context, dst);
809void free_cache_glyph_order(WINPR_ATTR_UNUSED rdpContext* context,
CACHE_GLYPH_ORDER* glyph)
813 for (
size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
814 free(glyph->glyphData[x].aj);
816 free(glyph->unicodeCharacters);
827 WINPR_ASSERT(context);
836 for (
size_t x = 0; x < glyph->cGlyphs; x++)
843 const size_t size = src->cb;
844 data->aj = malloc(size);
849 memcpy(data->aj, src->aj, size);
853 if (glyph->unicodeCharacters)
855 if (glyph->cGlyphs == 0)
858 dst->unicodeCharacters = calloc(glyph->cGlyphs,
sizeof(WCHAR));
860 if (!dst->unicodeCharacters)
863 memcpy(dst->unicodeCharacters, glyph->unicodeCharacters,
sizeof(WCHAR) * glyph->cGlyphs);
868 free_cache_glyph_v2_order(context, dst);
872void free_cache_glyph_v2_order(WINPR_ATTR_UNUSED rdpContext* context,
CACHE_GLYPH_V2_ORDER* glyph)
876 for (
size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
877 free(glyph->glyphData[x].aj);
879 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.