20 #include <freerdp/config.h>
24 #include <winpr/crt.h>
25 #include <winpr/assert.h>
27 #include <freerdp/freerdp.h>
28 #include <winpr/stream.h>
30 #include <freerdp/log.h>
35 #define TAG FREERDP_TAG("cache.glyph")
37 static rdpGlyph* glyph_cache_get(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index);
38 static BOOL glyph_cache_put(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index, rdpGlyph* glyph);
40 static const void* glyph_cache_fragment_get(
rdpGlyphCache* glyphCache, UINT32 index, UINT32* size);
41 static BOOL glyph_cache_fragment_put(
rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
42 const void* fragment);
44 static UINT32 update_glyph_offset(
const BYTE* data,
size_t length, UINT32 index, INT32* x, INT32* y,
45 UINT32 ulCharInc, UINT32 flAccel)
47 if ((ulCharInc == 0) && (!(flAccel & SO_CHAR_INC_EQUAL_BM_BASE)))
49 UINT32 offset = data[index++];
54 if (index + 1 < length)
56 offset = data[index++];
57 offset |= ((UINT32)data[index++]) << 8;
60 WLog_WARN(TAG,
"[%s] glyph index out of bound %" PRIu32
" [max %" PRIuz
"]", index,
64 if (flAccel & SO_VERTICAL)
67 if (flAccel & SO_HORIZONTAL)
74 static BOOL update_process_glyph(rdpContext* context,
const BYTE* data, UINT32 cacheIndex, INT32* x,
75 const INT32* y, UINT32 cacheId, UINT32 flAccel, BOOL fOpRedundant,
82 rdpGlyph* glyph = NULL;
85 if (!context || !data || !x || !y || !context->graphics || !context->cache ||
86 !context->cache->glyph)
89 glyph_cache = context->cache->glyph;
90 glyph = glyph_cache_get(glyph_cache, cacheId, cacheIndex);
110 if ((dx <= (bound->x + bound->width)) && (dy <= (bound->y + bound->height)))
112 INT32 dw = glyph->cx - sx;
113 INT32 dh = glyph->cy - sy;
115 if ((dw + dx) > (bound->x + bound->width))
116 dw = (bound->x + bound->width) - (dw + dx);
118 if ((dh + dy) > (bound->y + bound->height))
119 dh = (bound->y + bound->height) - (dh + dy);
121 if ((dh > 0) && (dw > 0))
123 if (!glyph->Draw(context, glyph, dx, dy, dw, dh, sx, sy, fOpRedundant))
128 if (flAccel & SO_CHAR_INC_EQUAL_BM_BASE)
134 static BOOL update_process_glyph_fragments(rdpContext* context,
const BYTE* data, UINT32 length,
135 UINT32 cacheId, UINT32 ulCharInc, UINT32 flAccel,
136 UINT32 bgcolor, UINT32 fgcolor, INT32 x, INT32 y,
137 INT32 bkX, INT32 bkY, INT32 bkWidth, INT32 bkHeight,
138 INT32 opX, INT32 opY, INT32 opWidth, INT32 opHeight,
144 const BYTE* fragments = NULL;
145 rdpGraphics* graphics = NULL;
147 rdpGlyph* glyph = NULL;
150 if (!context || !data || !context->graphics || !context->cache || !context->cache->glyph)
153 graphics = context->graphics;
154 glyph_cache = context->cache->glyph;
155 glyph = graphics->Glyph_Prototype;
228 bound.width = bkWidth;
229 bound.height = bkHeight;
231 if (!glyph->BeginDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor, fOpRedundant))
234 if (!IFCALLRESULT(TRUE, glyph->SetBounds, context, bkX, bkY, bkWidth, bkHeight))
237 while (index < length)
239 const UINT32 op = data[index++];
243 case GLYPH_FRAGMENT_USE:
244 if (index + 1 >= length)
248 fragments = (
const BYTE*)glyph_cache_fragment_get(glyph_cache,
id, &size);
250 if (fragments == NULL)
253 for (UINT32 n = 0; n < size;)
255 const UINT32 fop = fragments[n++];
256 n = update_glyph_offset(fragments, size, n, &x, &y, ulCharInc, flAccel);
258 if (!update_process_glyph(context, fragments, fop, &x, &y, cacheId, flAccel,
259 fOpRedundant, &bound))
265 case GLYPH_FRAGMENT_ADD:
266 if (index + 2 > length)
270 size = data[index++];
271 glyph_cache_fragment_put(glyph_cache,
id, size, data);
275 index = update_glyph_offset(data, length, index, &x, &y, ulCharInc, flAccel);
277 if (!update_process_glyph(context, data, op, &x, &y, cacheId, flAccel, fOpRedundant,
285 return glyph->EndDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor);
288 static BOOL update_gdi_glyph_index(rdpContext* context,
GLYPH_INDEX_ORDER* glyphIndex)
295 if (!context || !glyphIndex || !context->cache)
298 if (glyphIndex->bkRight > glyphIndex->bkLeft)
299 bkWidth = glyphIndex->bkRight - glyphIndex->bkLeft + 1;
301 if (glyphIndex->opRight > glyphIndex->opLeft)
302 opWidth = glyphIndex->opRight - glyphIndex->opLeft + 1;
304 if (glyphIndex->bkBottom > glyphIndex->bkTop)
305 bkHeight = glyphIndex->bkBottom - glyphIndex->bkTop + 1;
307 if (glyphIndex->opBottom > glyphIndex->opTop)
308 opHeight = glyphIndex->opBottom - glyphIndex->opTop + 1;
310 return update_process_glyph_fragments(
311 context, glyphIndex->data, glyphIndex->cbData, glyphIndex->cacheId, glyphIndex->ulCharInc,
312 glyphIndex->flAccel, glyphIndex->backColor, glyphIndex->foreColor, glyphIndex->x,
313 glyphIndex->y, glyphIndex->bkLeft, glyphIndex->bkTop, bkWidth, bkHeight, glyphIndex->opLeft,
314 glyphIndex->opTop, opWidth, opHeight, glyphIndex->fOpRedundant);
317 static BOOL update_gdi_fast_index(rdpContext* context,
const FAST_INDEX_ORDER* fastIndex)
330 if (!context || !fastIndex || !context->cache)
333 opLeft = fastIndex->opLeft;
334 opTop = fastIndex->opTop;
335 opRight = fastIndex->opRight;
336 opBottom = fastIndex->opBottom;
340 if (opBottom == -32768)
342 BYTE flags = (BYTE)(opTop & 0x0F);
345 opBottom = fastIndex->bkBottom;
348 opRight = fastIndex->bkRight;
351 opTop = fastIndex->bkTop;
354 opLeft = fastIndex->bkLeft;
358 opLeft = fastIndex->bkLeft;
361 opRight = fastIndex->bkRight;
370 x = fastIndex->bkLeft;
373 y = fastIndex->bkTop;
375 if (fastIndex->bkRight > fastIndex->bkLeft)
376 bkWidth = fastIndex->bkRight - fastIndex->bkLeft + 1;
378 if (fastIndex->bkBottom > fastIndex->bkTop)
379 bkHeight = fastIndex->bkBottom - fastIndex->bkTop + 1;
381 if (opRight > opLeft)
382 opWidth = opRight - opLeft + 1;
384 if (opBottom > opTop)
385 opHeight = opBottom - opTop + 1;
387 return update_process_glyph_fragments(
388 context, fastIndex->data, fastIndex->cbData, fastIndex->cacheId, fastIndex->ulCharInc,
389 fastIndex->flAccel, fastIndex->backColor, fastIndex->foreColor, x, y, fastIndex->bkLeft,
390 fastIndex->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE);
393 static BOOL update_gdi_fast_glyph(rdpContext* context,
const FAST_GLYPH_ORDER* fastGlyph)
397 BYTE text_data[4] = { 0 };
406 rdpCache* cache = NULL;
408 if (!context || !fastGlyph || !context->cache)
411 cache = context->cache;
412 opLeft = fastGlyph->opLeft;
413 opTop = fastGlyph->opTop;
414 opRight = fastGlyph->opRight;
415 opBottom = fastGlyph->opBottom;
419 if (opBottom == -32768)
421 BYTE flags = (BYTE)(opTop & 0x0F);
424 opBottom = fastGlyph->bkBottom;
427 opRight = fastGlyph->bkRight;
430 opTop = fastGlyph->bkTop;
433 opLeft = fastGlyph->bkLeft;
437 opLeft = fastGlyph->bkLeft;
440 opRight = fastGlyph->bkRight;
447 x = fastGlyph->bkLeft;
450 y = fastGlyph->bkTop;
452 if ((fastGlyph->cbData > 1) && (fastGlyph->glyphData.aj))
455 rdpGlyph* glyph = NULL;
458 glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx, glyphData->cy,
459 glyphData->cb, glyphData->aj);
464 if (!glyph_cache_put(cache->glyph, fastGlyph->cacheId, fastGlyph->data[0], glyph))
466 glyph->Free(context, glyph);
471 text_data[0] = fastGlyph->data[0];
474 if (fastGlyph->bkRight > fastGlyph->bkLeft)
475 bkWidth = fastGlyph->bkRight - fastGlyph->bkLeft + 1;
477 if (fastGlyph->bkBottom > fastGlyph->bkTop)
478 bkHeight = fastGlyph->bkBottom - fastGlyph->bkTop + 1;
480 if (opRight > opLeft)
481 opWidth = opRight - opLeft + 1;
483 if (opBottom > opTop)
484 opHeight = opBottom - opTop + 1;
486 return update_process_glyph_fragments(
487 context, text_data,
sizeof(text_data), fastGlyph->cacheId, fastGlyph->ulCharInc,
488 fastGlyph->flAccel, fastGlyph->backColor, fastGlyph->foreColor, x, y, fastGlyph->bkLeft,
489 fastGlyph->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE);
492 static BOOL update_gdi_cache_glyph(rdpContext* context,
const CACHE_GLYPH_ORDER* cacheGlyph)
494 if (!context || !cacheGlyph || !context->cache)
497 rdpCache* cache = context->cache;
499 for (
size_t i = 0; i < cacheGlyph->cGlyphs; i++)
501 const GLYPH_DATA* glyph_data = &cacheGlyph->glyphData[i];
502 rdpGlyph* glyph = Glyph_Alloc(context, glyph_data->x, glyph_data->y, glyph_data->cx,
503 glyph_data->cy, glyph_data->cb, glyph_data->aj);
507 if (!glyph_cache_put(cache->glyph, cacheGlyph->cacheId, glyph_data->cacheIndex, glyph))
509 glyph->Free(context, glyph);
517 static BOOL update_gdi_cache_glyph_v2(rdpContext* context,
const CACHE_GLYPH_V2_ORDER* cacheGlyphV2)
519 if (!context || !cacheGlyphV2 || !context->cache)
522 rdpCache* cache = context->cache;
524 for (
size_t i = 0; i < cacheGlyphV2->cGlyphs; i++)
526 const GLYPH_DATA_V2* glyphData = &cacheGlyphV2->glyphData[i];
527 rdpGlyph* glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx,
528 glyphData->cy, glyphData->cb, glyphData->aj);
533 if (!glyph_cache_put(cache->glyph, cacheGlyphV2->cacheId, glyphData->cacheIndex, glyph))
535 glyph->Free(context, glyph);
543 rdpGlyph* glyph_cache_get(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index)
545 rdpGlyph* glyph = NULL;
547 WINPR_ASSERT(glyphCache);
549 WLog_Print(glyphCache->log, WLOG_DEBUG,
"GlyphCacheGet: id: %" PRIu32
" index: %" PRIu32
"",
id,
554 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
558 WINPR_ASSERT(glyphCache->glyphCache);
559 if (index > glyphCache->glyphCache[
id].number)
561 WLog_ERR(TAG,
"index %" PRIu32
" out of range for cache id: %" PRIu32
"", index,
id);
565 glyph = glyphCache->glyphCache[id].entries[index];
568 WLog_ERR(TAG,
"no glyph found at cache index: %" PRIu32
" in cache id: %" PRIu32
"", index,
574 BOOL glyph_cache_put(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index, rdpGlyph* glyph)
576 rdpGlyph* prevGlyph = NULL;
578 WINPR_ASSERT(glyphCache);
582 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
586 WINPR_ASSERT(glyphCache->glyphCache);
587 if (index >= glyphCache->glyphCache[
id].number)
589 WLog_ERR(TAG,
"invalid glyph cache index: %" PRIu32
" in cache id: %" PRIu32
"", index,
id);
593 WLog_Print(glyphCache->log, WLOG_DEBUG,
"GlyphCachePut: id: %" PRIu32
" index: %" PRIu32
"",
id,
595 prevGlyph = glyphCache->glyphCache[id].entries[index];
599 WINPR_ASSERT(prevGlyph->Free);
600 prevGlyph->Free(glyphCache->context, prevGlyph);
603 glyphCache->glyphCache[id].entries[index] = glyph;
607 const void* glyph_cache_fragment_get(
rdpGlyphCache* glyphCache, UINT32 index, UINT32* size)
609 void* fragment = NULL;
611 WINPR_ASSERT(glyphCache);
612 WINPR_ASSERT(glyphCache->fragCache.entries);
616 WLog_ERR(TAG,
"invalid glyph cache fragment index: %" PRIu32
"", index);
620 fragment = glyphCache->fragCache.entries[index].fragment;
621 *size = (BYTE)glyphCache->fragCache.entries[index].size;
622 WLog_Print(glyphCache->log, WLOG_DEBUG,
623 "GlyphCacheFragmentGet: index: %" PRIu32
" size: %" PRIu32
"", index, *size);
626 WLog_ERR(TAG,
"invalid glyph fragment at index:%" PRIu32
"", index);
631 BOOL glyph_cache_fragment_put(
rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
632 const void* fragment)
634 WINPR_ASSERT(glyphCache);
635 WINPR_ASSERT(glyphCache->fragCache.entries);
639 WLog_ERR(TAG,
"invalid glyph cache fragment index: %" PRIu32
"", index);
646 void* copy = malloc(size);
651 WLog_Print(glyphCache->log, WLOG_DEBUG,
652 "GlyphCacheFragmentPut: index: %" PRIu32
" size: %" PRIu32
"", index, size);
653 CopyMemory(copy, fragment, size);
655 void* prevFragment = glyphCache->fragCache.entries[index].fragment;
656 glyphCache->fragCache.entries[index].fragment = copy;
657 glyphCache->fragCache.entries[index].size = size;
662 void glyph_cache_register_callbacks(rdpUpdate* update)
664 WINPR_ASSERT(update);
665 WINPR_ASSERT(update->context);
666 WINPR_ASSERT(update->primary);
667 WINPR_ASSERT(update->secondary);
671 update->primary->GlyphIndex = update_gdi_glyph_index;
672 update->primary->FastIndex = update_gdi_fast_index;
673 update->primary->FastGlyph = update_gdi_fast_glyph;
674 update->secondary->CacheGlyph = update_gdi_cache_glyph;
675 update->secondary->CacheGlyphV2 = update_gdi_cache_glyph_v2;
682 rdpSettings* settings = NULL;
684 WINPR_ASSERT(context);
686 settings = context->settings;
687 WINPR_ASSERT(settings);
694 glyphCache->log = WLog_Get(
"com.freerdp.cache.glyph");
695 glyphCache->context = context;
697 for (
size_t i = 0; i < 10; i++)
700 freerdp_settings_get_pointer_array(settings, FreeRDP_GlyphCache, i);
701 GLYPH_CACHE* currentCache = &glyphCache->glyphCache[i];
702 currentCache->number = currentGlyph->cacheEntries;
703 currentCache->maxCellSize = currentGlyph->cacheMaximumCellSize;
704 currentCache->entries = (rdpGlyph**)calloc(currentCache->number,
sizeof(rdpGlyph*));
706 if (!currentCache->entries)
712 WINPR_PRAGMA_DIAG_PUSH
713 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
714 glyph_cache_free(glyphCache);
715 WINPR_PRAGMA_DIAG_POP
725 for (
size_t i = 0; i < 10; i++)
727 rdpGlyph** entries = cache[i].entries;
732 for (
size_t j = 0; j < cache[i].number; j++)
734 rdpGlyph* glyph = entries[j];
738 glyph->Free(glyphCache->context, glyph);
744 cache[i].entries = NULL;
747 for (
size_t i = 0; i < ARRAYSIZE(glyphCache->fragCache.entries); i++)
749 free(glyphCache->fragCache.entries[i].fragment);
750 glyphCache->fragCache.entries[i].fragment = NULL;
761 WINPR_ASSERT(context);
770 for (
size_t x = 0; x < glyph->cGlyphs; x++)
777 const size_t size = src->cb;
778 data->aj = malloc(size);
783 memcpy(data->aj, src->aj, size);
787 if (glyph->unicodeCharacters)
789 if (glyph->cGlyphs == 0)
792 dst->unicodeCharacters = calloc(glyph->cGlyphs,
sizeof(WCHAR));
794 if (!dst->unicodeCharacters)
797 memcpy(dst->unicodeCharacters, glyph->unicodeCharacters,
sizeof(WCHAR) * glyph->cGlyphs);
802 free_cache_glyph_order(context, dst);
810 for (
size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
811 free(glyph->glyphData[x].aj);
813 free(glyph->unicodeCharacters);
824 WINPR_ASSERT(context);
833 for (
size_t x = 0; x < glyph->cGlyphs; x++)
840 const size_t size = src->cb;
841 data->aj = malloc(size);
846 memcpy(data->aj, src->aj, size);
850 if (glyph->unicodeCharacters)
852 if (glyph->cGlyphs == 0)
855 dst->unicodeCharacters = calloc(glyph->cGlyphs,
sizeof(WCHAR));
857 if (!dst->unicodeCharacters)
860 memcpy(dst->unicodeCharacters, glyph->unicodeCharacters,
sizeof(WCHAR) * glyph->cGlyphs);
865 free_cache_glyph_v2_order(context, dst);
873 for (
size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
874 free(glyph->glyphData[x].aj);
876 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.