20 #include <freerdp/config.h>
24 #include <winpr/crt.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")
38 static rdpGlyph* glyph_cache_get(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index);
39 static BOOL glyph_cache_put(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index, rdpGlyph* glyph);
41 static const void* glyph_cache_fragment_get(
rdpGlyphCache* glyphCache, UINT32 index, UINT32* size);
42 static BOOL glyph_cache_fragment_put(
rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
43 const void* fragment);
45 static 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);
75 static 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);
135 static 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;
146 rdpGraphics* graphics = NULL;
148 rdpGlyph* glyph = NULL;
151 if (!context || !data || !context->graphics || !context->cache || !context->cache->glyph)
154 graphics = context->graphics;
155 glyph_cache = context->cache->glyph;
156 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;
228 bound.x = WINPR_ASSERTING_INT_CAST(INT16, bkX);
229 bound.y = WINPR_ASSERTING_INT_CAST(INT16, bkY);
230 bound.width = WINPR_ASSERTING_INT_CAST(INT16, bkWidth);
231 bound.height = WINPR_ASSERTING_INT_CAST(INT16, bkHeight);
233 if (!glyph->BeginDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor, fOpRedundant))
236 if (!IFCALLRESULT(TRUE, glyph->SetBounds, context, bkX, bkY, bkWidth, bkHeight))
239 while (index < length)
241 const UINT32 op = data[index++];
245 case GLYPH_FRAGMENT_USE:
246 if (index + 1 >= length)
250 fragments = (
const BYTE*)glyph_cache_fragment_get(glyph_cache,
id, &size);
252 if (fragments == NULL)
255 for (UINT32 n = 0; n < size;)
257 const UINT32 fop = fragments[n++];
258 n = update_glyph_offset(fragments, size, n, &x, &y, ulCharInc, flAccel);
260 if (!update_process_glyph(context, fragments, fop, &x, &y, cacheId, flAccel,
261 fOpRedundant, &bound))
267 case GLYPH_FRAGMENT_ADD:
268 if (index + 2 > length)
272 size = data[index++];
273 glyph_cache_fragment_put(glyph_cache,
id, size, data);
277 index = update_glyph_offset(data, length, index, &x, &y, ulCharInc, flAccel);
279 if (!update_process_glyph(context, data, op, &x, &y, cacheId, flAccel, fOpRedundant,
287 return glyph->EndDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor);
290 static BOOL update_gdi_glyph_index(rdpContext* context,
GLYPH_INDEX_ORDER* glyphIndex)
297 if (!context || !glyphIndex || !context->cache)
300 if (glyphIndex->bkRight > glyphIndex->bkLeft)
301 bkWidth = glyphIndex->bkRight - glyphIndex->bkLeft + 1;
303 if (glyphIndex->opRight > glyphIndex->opLeft)
304 opWidth = glyphIndex->opRight - glyphIndex->opLeft + 1;
306 if (glyphIndex->bkBottom > glyphIndex->bkTop)
307 bkHeight = glyphIndex->bkBottom - glyphIndex->bkTop + 1;
309 if (glyphIndex->opBottom > glyphIndex->opTop)
310 opHeight = glyphIndex->opBottom - glyphIndex->opTop + 1;
312 return update_process_glyph_fragments(
313 context, glyphIndex->data, glyphIndex->cbData, glyphIndex->cacheId, glyphIndex->ulCharInc,
314 glyphIndex->flAccel, glyphIndex->backColor, glyphIndex->foreColor, glyphIndex->x,
315 glyphIndex->y, glyphIndex->bkLeft, glyphIndex->bkTop, bkWidth, bkHeight, glyphIndex->opLeft,
316 glyphIndex->opTop, opWidth, opHeight,
317 WINPR_ASSERTING_INT_CAST(int32_t, glyphIndex->fOpRedundant));
320 static BOOL update_gdi_fast_index(rdpContext* context,
const FAST_INDEX_ORDER* fastIndex)
333 if (!context || !fastIndex || !context->cache)
336 opLeft = fastIndex->opLeft;
337 opTop = fastIndex->opTop;
338 opRight = fastIndex->opRight;
339 opBottom = fastIndex->opBottom;
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 return 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);
396 static BOOL update_gdi_fast_glyph(rdpContext* context,
const FAST_GLYPH_ORDER* fastGlyph)
400 BYTE text_data[4] = { 0 };
409 rdpCache* cache = NULL;
411 if (!context || !fastGlyph || !context->cache)
414 cache = context->cache;
415 opLeft = fastGlyph->opLeft;
416 opTop = fastGlyph->opTop;
417 opRight = fastGlyph->opRight;
418 opBottom = fastGlyph->opBottom;
422 if (opBottom == -32768)
424 BYTE flags = (BYTE)(opTop & 0x0F);
427 opBottom = fastGlyph->bkBottom;
430 opRight = fastGlyph->bkRight;
433 opTop = fastGlyph->bkTop;
436 opLeft = fastGlyph->bkLeft;
440 opLeft = fastGlyph->bkLeft;
443 opRight = fastGlyph->bkRight;
450 x = fastGlyph->bkLeft;
453 y = fastGlyph->bkTop;
455 if ((fastGlyph->cbData > 1) && (fastGlyph->glyphData.aj))
458 rdpGlyph* glyph = NULL;
461 glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx, glyphData->cy,
462 glyphData->cb, glyphData->aj);
467 if (!glyph_cache_put(cache->glyph, fastGlyph->cacheId, fastGlyph->data[0], glyph))
469 glyph->Free(context, glyph);
474 text_data[0] = fastGlyph->data[0];
477 if (fastGlyph->bkRight > fastGlyph->bkLeft)
478 bkWidth = fastGlyph->bkRight - fastGlyph->bkLeft + 1;
480 if (fastGlyph->bkBottom > fastGlyph->bkTop)
481 bkHeight = fastGlyph->bkBottom - fastGlyph->bkTop + 1;
483 if (opRight > opLeft)
484 opWidth = opRight - opLeft + 1;
486 if (opBottom > opTop)
487 opHeight = opBottom - opTop + 1;
489 return update_process_glyph_fragments(
490 context, text_data,
sizeof(text_data), fastGlyph->cacheId, fastGlyph->ulCharInc,
491 fastGlyph->flAccel, fastGlyph->backColor, fastGlyph->foreColor, x, y, fastGlyph->bkLeft,
492 fastGlyph->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE);
495 static BOOL update_gdi_cache_glyph(rdpContext* context,
const CACHE_GLYPH_ORDER* cacheGlyph)
497 if (!context || !cacheGlyph || !context->cache)
500 rdpCache* cache = context->cache;
502 for (
size_t i = 0; i < cacheGlyph->cGlyphs; i++)
504 const GLYPH_DATA* glyph_data = &cacheGlyph->glyphData[i];
505 rdpGlyph* glyph = Glyph_Alloc(context, glyph_data->x, glyph_data->y, glyph_data->cx,
506 glyph_data->cy, glyph_data->cb, glyph_data->aj);
510 if (!glyph_cache_put(cache->glyph, cacheGlyph->cacheId, glyph_data->cacheIndex, glyph))
512 glyph->Free(context, glyph);
520 static BOOL update_gdi_cache_glyph_v2(rdpContext* context,
const CACHE_GLYPH_V2_ORDER* cacheGlyphV2)
522 if (!context || !cacheGlyphV2 || !context->cache)
525 rdpCache* cache = context->cache;
527 for (
size_t i = 0; i < cacheGlyphV2->cGlyphs; i++)
529 const GLYPH_DATA_V2* glyphData = &cacheGlyphV2->glyphData[i];
530 rdpGlyph* glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx,
531 glyphData->cy, glyphData->cb, glyphData->aj);
536 if (!glyph_cache_put(cache->glyph, cacheGlyphV2->cacheId, glyphData->cacheIndex, glyph))
538 glyph->Free(context, glyph);
546 rdpGlyph* glyph_cache_get(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index)
548 rdpGlyph* glyph = NULL;
550 WINPR_ASSERT(glyphCache);
552 WLog_Print(glyphCache->log, WLOG_DEBUG,
"GlyphCacheGet: id: %" PRIu32
" index: %" PRIu32
"",
id,
557 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
561 WINPR_ASSERT(glyphCache->glyphCache);
562 if (index > glyphCache->glyphCache[
id].number)
564 WLog_ERR(TAG,
"index %" PRIu32
" out of range for cache id: %" PRIu32
"", index,
id);
568 glyph = glyphCache->glyphCache[id].entries[index];
571 WLog_ERR(TAG,
"no glyph found at cache index: %" PRIu32
" in cache id: %" PRIu32
"", index,
577 BOOL glyph_cache_put(
rdpGlyphCache* glyphCache, UINT32
id, UINT32 index, rdpGlyph* glyph)
579 rdpGlyph* prevGlyph = NULL;
581 WINPR_ASSERT(glyphCache);
585 WLog_ERR(TAG,
"invalid glyph cache id: %" PRIu32
"",
id);
589 WINPR_ASSERT(glyphCache->glyphCache);
590 if (index >= glyphCache->glyphCache[
id].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 prevGlyph = glyphCache->glyphCache[id].entries[index];
602 WINPR_ASSERT(prevGlyph->Free);
603 prevGlyph->Free(glyphCache->context, prevGlyph);
606 glyphCache->glyphCache[id].entries[index] = glyph;
610 const 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);
634 BOOL 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;
665 void 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);
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);
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.