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.