Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
39
third_party/FreeRDP/libfreerdp/cache/CMakeLists.txt
vendored
Normal file
39
third_party/FreeRDP/libfreerdp/cache/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# libfreerdp-cache cmake build script
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
set(MODULE_NAME "freerdp-cache")
|
||||
set(MODULE_PREFIX "FREERDP_CACHE")
|
||||
|
||||
freerdp_module_add(
|
||||
brush.c
|
||||
brush.h
|
||||
pointer.c
|
||||
pointer.h
|
||||
bitmap.c
|
||||
bitmap.h
|
||||
persistent.c
|
||||
nine_grid.c
|
||||
nine_grid.h
|
||||
offscreen.c
|
||||
offscreen.h
|
||||
palette.c
|
||||
palette.h
|
||||
glyph.c
|
||||
glyph.h
|
||||
cache.c
|
||||
cache.h
|
||||
)
|
||||
622
third_party/FreeRDP/libfreerdp/cache/bitmap.c
vendored
Normal file
622
third_party/FreeRDP/libfreerdp/cache/bitmap.c
vendored
Normal file
@@ -0,0 +1,622 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Bitmap Cache V2
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/cast.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/gdi/bitmap.h>
|
||||
|
||||
#include "../gdi/gdi.h"
|
||||
#include "../core/graphics.h"
|
||||
|
||||
#include "bitmap.h"
|
||||
#include "cache.h"
|
||||
|
||||
#define TAG FREERDP_TAG("cache.bitmap")
|
||||
|
||||
static rdpBitmap* bitmap_cache_get(rdpBitmapCache* bitmapCache, UINT32 id, UINT32 index);
|
||||
static BOOL bitmap_cache_put(rdpBitmapCache* bitmapCache, UINT32 id, UINT32 index,
|
||||
rdpBitmap* bitmap);
|
||||
|
||||
static BOOL update_gdi_memblt(rdpContext* context, MEMBLT_ORDER* memblt)
|
||||
{
|
||||
rdpBitmap* bitmap = nullptr;
|
||||
rdpCache* cache = nullptr;
|
||||
|
||||
cache = context->cache;
|
||||
|
||||
if (memblt->cacheId == 0xFF)
|
||||
bitmap = offscreen_cache_get(cache->offscreen, memblt->cacheIndex);
|
||||
else
|
||||
bitmap = bitmap_cache_get(cache->bitmap, (BYTE)memblt->cacheId, memblt->cacheIndex);
|
||||
|
||||
/* XP-SP2 servers sometimes ask for cached bitmaps they've never defined. */
|
||||
if (bitmap == nullptr)
|
||||
return TRUE;
|
||||
|
||||
memblt->bitmap = bitmap;
|
||||
return IFCALLRESULT(TRUE, cache->bitmap->MemBlt, context, memblt);
|
||||
}
|
||||
|
||||
static BOOL update_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt)
|
||||
{
|
||||
rdpBitmap* bitmap = nullptr;
|
||||
rdpCache* cache = context->cache;
|
||||
rdpBrush* brush = &mem3blt->brush;
|
||||
BOOL ret = TRUE;
|
||||
|
||||
if (mem3blt->cacheId == 0xFF)
|
||||
bitmap = offscreen_cache_get(cache->offscreen, mem3blt->cacheIndex);
|
||||
else
|
||||
bitmap = bitmap_cache_get(cache->bitmap, (BYTE)mem3blt->cacheId, mem3blt->cacheIndex);
|
||||
|
||||
/* XP-SP2 servers sometimes ask for cached bitmaps they've never defined. */
|
||||
if (!bitmap)
|
||||
return TRUE;
|
||||
|
||||
const BYTE style = WINPR_ASSERTING_INT_CAST(UINT8, brush->style);
|
||||
|
||||
if (brush->style & CACHED_BRUSH)
|
||||
{
|
||||
brush->data = brush_cache_get(cache->brush, brush->index, &brush->bpp);
|
||||
|
||||
if (!brush->data)
|
||||
return FALSE;
|
||||
|
||||
brush->style = 0x03;
|
||||
}
|
||||
|
||||
mem3blt->bitmap = bitmap;
|
||||
IFCALLRET(cache->bitmap->Mem3Blt, ret, context, mem3blt);
|
||||
brush->style = style;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL update_gdi_cache_bitmap(rdpContext* context, const CACHE_BITMAP_ORDER* cacheBitmap)
|
||||
{
|
||||
rdpBitmap* bitmap = nullptr;
|
||||
rdpBitmap* prevBitmap = nullptr;
|
||||
rdpCache* cache = context->cache;
|
||||
bitmap = Bitmap_Alloc(context);
|
||||
|
||||
if (!bitmap)
|
||||
return FALSE;
|
||||
|
||||
if (!Bitmap_SetDimensions(bitmap, WINPR_ASSERTING_INT_CAST(UINT16, cacheBitmap->bitmapWidth),
|
||||
WINPR_ASSERTING_INT_CAST(UINT16, cacheBitmap->bitmapHeight)))
|
||||
goto fail;
|
||||
|
||||
if (!bitmap->Decompress(context, bitmap, cacheBitmap->bitmapDataStream,
|
||||
cacheBitmap->bitmapWidth, cacheBitmap->bitmapHeight,
|
||||
cacheBitmap->bitmapBpp, cacheBitmap->bitmapLength,
|
||||
cacheBitmap->compressed, RDP_CODEC_ID_NONE))
|
||||
goto fail;
|
||||
|
||||
if (!bitmap->New(context, bitmap))
|
||||
goto fail;
|
||||
|
||||
prevBitmap = bitmap_cache_get(cache->bitmap, cacheBitmap->cacheId, cacheBitmap->cacheIndex);
|
||||
Bitmap_Free(context, prevBitmap);
|
||||
return bitmap_cache_put(cache->bitmap, cacheBitmap->cacheId, cacheBitmap->cacheIndex, bitmap);
|
||||
|
||||
fail:
|
||||
Bitmap_Free(context, bitmap);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL update_gdi_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORDER* cacheBitmapV2)
|
||||
|
||||
{
|
||||
rdpBitmap* prevBitmap = nullptr;
|
||||
rdpCache* cache = context->cache;
|
||||
rdpSettings* settings = context->settings;
|
||||
rdpBitmap* bitmap = Bitmap_Alloc(context);
|
||||
|
||||
if (!bitmap)
|
||||
return FALSE;
|
||||
|
||||
const UINT32 ColorDepth = freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
|
||||
bitmap->key64 = ((UINT64)cacheBitmapV2->key1 | (((UINT64)cacheBitmapV2->key2) << 32));
|
||||
|
||||
if (!cacheBitmapV2->bitmapBpp)
|
||||
cacheBitmapV2->bitmapBpp = ColorDepth;
|
||||
|
||||
if ((ColorDepth == 15) && (cacheBitmapV2->bitmapBpp == 16))
|
||||
cacheBitmapV2->bitmapBpp = ColorDepth;
|
||||
|
||||
if (!Bitmap_SetDimensions(bitmap, WINPR_ASSERTING_INT_CAST(UINT16, cacheBitmapV2->bitmapWidth),
|
||||
WINPR_ASSERTING_INT_CAST(UINT16, cacheBitmapV2->bitmapHeight)))
|
||||
goto fail;
|
||||
|
||||
if (!bitmap->Decompress(context, bitmap, cacheBitmapV2->bitmapDataStream,
|
||||
cacheBitmapV2->bitmapWidth, cacheBitmapV2->bitmapHeight,
|
||||
cacheBitmapV2->bitmapBpp, cacheBitmapV2->bitmapLength,
|
||||
cacheBitmapV2->compressed, RDP_CODEC_ID_NONE))
|
||||
goto fail;
|
||||
|
||||
prevBitmap = bitmap_cache_get(cache->bitmap, cacheBitmapV2->cacheId, cacheBitmapV2->cacheIndex);
|
||||
|
||||
if (!bitmap->New(context, bitmap))
|
||||
goto fail;
|
||||
|
||||
Bitmap_Free(context, prevBitmap);
|
||||
return bitmap_cache_put(cache->bitmap, cacheBitmapV2->cacheId, cacheBitmapV2->cacheIndex,
|
||||
bitmap);
|
||||
|
||||
fail:
|
||||
Bitmap_Free(context, bitmap);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL update_gdi_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORDER* cacheBitmapV3)
|
||||
{
|
||||
rdpBitmap* bitmap = nullptr;
|
||||
rdpBitmap* prevBitmap = nullptr;
|
||||
BOOL compressed = TRUE;
|
||||
rdpCache* cache = context->cache;
|
||||
rdpSettings* settings = context->settings;
|
||||
BITMAP_DATA_EX* bitmapData = &cacheBitmapV3->bitmapData;
|
||||
bitmap = Bitmap_Alloc(context);
|
||||
|
||||
if (!bitmap)
|
||||
return FALSE;
|
||||
|
||||
const UINT32 ColorDepth = freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth);
|
||||
bitmap->key64 = ((UINT64)cacheBitmapV3->key1 | (((UINT64)cacheBitmapV3->key2) << 32));
|
||||
|
||||
if (!cacheBitmapV3->bpp)
|
||||
cacheBitmapV3->bpp = ColorDepth;
|
||||
|
||||
compressed = (bitmapData->codecID != RDP_CODEC_ID_NONE);
|
||||
|
||||
if (!Bitmap_SetDimensions(bitmap, WINPR_ASSERTING_INT_CAST(UINT16, bitmapData->width),
|
||||
WINPR_ASSERTING_INT_CAST(UINT16, bitmapData->height)))
|
||||
goto fail;
|
||||
|
||||
if (!bitmap->Decompress(context, bitmap, bitmapData->data, bitmapData->width,
|
||||
bitmapData->height, bitmapData->bpp, bitmapData->length, compressed,
|
||||
bitmapData->codecID))
|
||||
goto fail;
|
||||
|
||||
if (!bitmap->New(context, bitmap))
|
||||
goto fail;
|
||||
|
||||
prevBitmap = bitmap_cache_get(cache->bitmap, cacheBitmapV3->cacheId, cacheBitmapV3->cacheIndex);
|
||||
Bitmap_Free(context, prevBitmap);
|
||||
return bitmap_cache_put(cache->bitmap, cacheBitmapV3->cacheId, cacheBitmapV3->cacheIndex,
|
||||
bitmap);
|
||||
|
||||
fail:
|
||||
Bitmap_Free(context, bitmap);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rdpBitmap* bitmap_cache_get(rdpBitmapCache* bitmapCache, UINT32 id, UINT32 index)
|
||||
{
|
||||
rdpBitmap* bitmap = nullptr;
|
||||
|
||||
if (id >= bitmapCache->maxCells)
|
||||
{
|
||||
WLog_ERR(TAG, "get invalid bitmap cell id: %" PRIu32 "", id);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (index == BITMAP_CACHE_WAITING_LIST_INDEX)
|
||||
{
|
||||
index = bitmapCache->cells[id].number;
|
||||
}
|
||||
else if (index > bitmapCache->cells[id].number)
|
||||
{
|
||||
WLog_ERR(TAG, "get invalid bitmap index %" PRIu32 " in cell id: %" PRIu32 "", index, id);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bitmap = bitmapCache->cells[id].entries[index];
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
BOOL bitmap_cache_put(rdpBitmapCache* bitmapCache, UINT32 id, UINT32 index, rdpBitmap* bitmap)
|
||||
{
|
||||
if (id > bitmapCache->maxCells)
|
||||
{
|
||||
WLog_ERR(TAG, "put invalid bitmap cell id: %" PRIu32 "", id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (index == BITMAP_CACHE_WAITING_LIST_INDEX)
|
||||
{
|
||||
index = bitmapCache->cells[id].number;
|
||||
}
|
||||
else if (index > bitmapCache->cells[id].number)
|
||||
{
|
||||
WLog_ERR(TAG, "put invalid bitmap index %" PRIu32 " in cell id: %" PRIu32 "", index, id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bitmapCache->cells[id].entries[index] = bitmap;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void bitmap_cache_register_callbacks(rdpUpdate* update)
|
||||
{
|
||||
rdpCache* cache = nullptr;
|
||||
|
||||
WINPR_ASSERT(update);
|
||||
WINPR_ASSERT(update->context);
|
||||
WINPR_ASSERT(update->context->cache);
|
||||
|
||||
cache = update->context->cache;
|
||||
WINPR_ASSERT(cache);
|
||||
|
||||
if (!freerdp_settings_get_bool(update->context->settings, FreeRDP_DeactivateClientDecoding))
|
||||
{
|
||||
cache->bitmap->MemBlt = update->primary->MemBlt;
|
||||
cache->bitmap->Mem3Blt = update->primary->Mem3Blt;
|
||||
update->primary->MemBlt = update_gdi_memblt;
|
||||
update->primary->Mem3Blt = update_gdi_mem3blt;
|
||||
update->secondary->CacheBitmap = update_gdi_cache_bitmap;
|
||||
update->secondary->CacheBitmapV2 = update_gdi_cache_bitmap_v2;
|
||||
update->secondary->CacheBitmapV3 = update_gdi_cache_bitmap_v3;
|
||||
update->BitmapUpdate = gdi_bitmap_update;
|
||||
}
|
||||
}
|
||||
|
||||
static int bitmap_cache_save_persistent(rdpBitmapCache* bitmapCache)
|
||||
{
|
||||
rdpContext* context = bitmapCache->context;
|
||||
rdpSettings* settings = context->settings;
|
||||
|
||||
const UINT32 version = freerdp_settings_get_uint32(settings, FreeRDP_BitmapCacheVersion);
|
||||
|
||||
if (version != 2)
|
||||
return 0; /* persistent bitmap cache already saved in egfx channel */
|
||||
|
||||
if (!freerdp_settings_get_bool(settings, FreeRDP_BitmapCachePersistEnabled))
|
||||
return 0;
|
||||
|
||||
const char* BitmapCachePersistFile =
|
||||
freerdp_settings_get_string(settings, FreeRDP_BitmapCachePersistFile);
|
||||
if (!BitmapCachePersistFile)
|
||||
return 0;
|
||||
|
||||
rdpPersistentCache* persistent = persistent_cache_new();
|
||||
|
||||
if (!persistent)
|
||||
return -1;
|
||||
|
||||
int status = persistent_cache_open(persistent, BitmapCachePersistFile, TRUE, version);
|
||||
|
||||
if (status < 1)
|
||||
goto end;
|
||||
|
||||
if (bitmapCache->cells)
|
||||
{
|
||||
for (UINT32 i = 0; i < bitmapCache->maxCells; i++)
|
||||
{
|
||||
BITMAP_V2_CELL* cell = &bitmapCache->cells[i];
|
||||
for (UINT32 j = 0; j < cell->number + 1 && cell->entries; j++)
|
||||
{
|
||||
PERSISTENT_CACHE_ENTRY cacheEntry = WINPR_C_ARRAY_INIT;
|
||||
rdpBitmap* bitmap = cell->entries[j];
|
||||
|
||||
if (!bitmap || !bitmap->key64)
|
||||
continue;
|
||||
|
||||
cacheEntry.key64 = bitmap->key64;
|
||||
|
||||
cacheEntry.width = WINPR_ASSERTING_INT_CAST(UINT16, bitmap->width);
|
||||
cacheEntry.height = WINPR_ASSERTING_INT_CAST(UINT16, bitmap->height);
|
||||
const UINT64 size = 4ULL * bitmap->width * bitmap->height;
|
||||
if (size > UINT32_MAX)
|
||||
continue;
|
||||
cacheEntry.size = (UINT32)size;
|
||||
cacheEntry.flags = 0;
|
||||
cacheEntry.data = bitmap->data;
|
||||
|
||||
if (persistent_cache_write_entry(persistent, &cacheEntry) < 1)
|
||||
{
|
||||
status = -1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status = 1;
|
||||
|
||||
end:
|
||||
persistent_cache_free(persistent);
|
||||
return status;
|
||||
}
|
||||
|
||||
rdpBitmapCache* bitmap_cache_new(rdpContext* context)
|
||||
{
|
||||
rdpSettings* settings = nullptr;
|
||||
rdpBitmapCache* bitmapCache = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
settings = context->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
bitmapCache = (rdpBitmapCache*)calloc(1, sizeof(rdpBitmapCache));
|
||||
|
||||
if (!bitmapCache)
|
||||
return nullptr;
|
||||
|
||||
const UINT32 BitmapCacheV2NumCells =
|
||||
freerdp_settings_get_uint32(settings, FreeRDP_BitmapCacheV2NumCells);
|
||||
bitmapCache->context = context;
|
||||
|
||||
/* overallocate by 1. older RDP servers do send a off by 1 cache index. */
|
||||
bitmapCache->cells =
|
||||
(BITMAP_V2_CELL*)calloc(BitmapCacheV2NumCells + 1ull, sizeof(BITMAP_V2_CELL));
|
||||
|
||||
if (!bitmapCache->cells)
|
||||
goto fail;
|
||||
bitmapCache->maxCells = BitmapCacheV2NumCells;
|
||||
|
||||
for (UINT32 i = 0; i < bitmapCache->maxCells; i++)
|
||||
{
|
||||
const BITMAP_CACHE_V2_CELL_INFO* info =
|
||||
freerdp_settings_get_pointer_array(settings, FreeRDP_BitmapCacheV2CellInfo, i);
|
||||
BITMAP_V2_CELL* cell = &bitmapCache->cells[i];
|
||||
UINT32 nr = info->numEntries;
|
||||
/* allocate an extra entry for BITMAP_CACHE_WAITING_LIST_INDEX */
|
||||
cell->entries = (rdpBitmap**)calloc((nr + 1), sizeof(rdpBitmap*));
|
||||
|
||||
if (!cell->entries)
|
||||
goto fail;
|
||||
cell->number = nr;
|
||||
}
|
||||
|
||||
return bitmapCache;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
bitmap_cache_free(bitmapCache);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void bitmap_cache_free(rdpBitmapCache* bitmapCache)
|
||||
{
|
||||
if (!bitmapCache)
|
||||
return;
|
||||
|
||||
bitmap_cache_save_persistent(bitmapCache);
|
||||
|
||||
if (bitmapCache->cells)
|
||||
{
|
||||
for (UINT32 i = 0; i < bitmapCache->maxCells; i++)
|
||||
{
|
||||
UINT32 j = 0;
|
||||
BITMAP_V2_CELL* cell = &bitmapCache->cells[i];
|
||||
|
||||
if (!cell->entries)
|
||||
continue;
|
||||
|
||||
for (j = 0; j < cell->number + 1; j++)
|
||||
{
|
||||
rdpBitmap* bitmap = cell->entries[j];
|
||||
Bitmap_Free(bitmapCache->context, bitmap);
|
||||
}
|
||||
|
||||
free((void*)cell->entries);
|
||||
}
|
||||
|
||||
free(bitmapCache->cells);
|
||||
}
|
||||
|
||||
persistent_cache_free(bitmapCache->persistent);
|
||||
|
||||
free(bitmapCache);
|
||||
}
|
||||
|
||||
static void free_bitmap_data(BITMAP_DATA* data, size_t count)
|
||||
{
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
for (size_t x = 0; x < count; x++)
|
||||
free(data[x].bitmapDataStream);
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
static BITMAP_DATA* copy_bitmap_data(const BITMAP_DATA* data, size_t count)
|
||||
{
|
||||
BITMAP_DATA* dst = (BITMAP_DATA*)calloc(count, sizeof(BITMAP_DATA));
|
||||
|
||||
if (!dst)
|
||||
goto fail;
|
||||
|
||||
for (size_t x = 0; x < count; x++)
|
||||
{
|
||||
dst[x] = data[x];
|
||||
|
||||
if (data[x].bitmapLength > 0)
|
||||
{
|
||||
dst[x].bitmapDataStream = malloc(data[x].bitmapLength);
|
||||
|
||||
if (!dst[x].bitmapDataStream)
|
||||
goto fail;
|
||||
|
||||
memcpy(dst[x].bitmapDataStream, data[x].bitmapDataStream, data[x].bitmapLength);
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
fail:
|
||||
free_bitmap_data(dst, count);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void free_bitmap_update(WINPR_ATTR_UNUSED rdpContext* context,
|
||||
WINPR_ATTR_UNUSED BITMAP_UPDATE* pointer)
|
||||
{
|
||||
if (!pointer)
|
||||
return;
|
||||
|
||||
free_bitmap_data(pointer->rectangles, pointer->number);
|
||||
free(pointer);
|
||||
}
|
||||
|
||||
BITMAP_UPDATE* copy_bitmap_update(rdpContext* context, const BITMAP_UPDATE* pointer)
|
||||
{
|
||||
BITMAP_UPDATE* dst = calloc(1, sizeof(BITMAP_UPDATE));
|
||||
|
||||
if (!dst || !pointer)
|
||||
goto fail;
|
||||
|
||||
*dst = *pointer;
|
||||
dst->rectangles = copy_bitmap_data(pointer->rectangles, pointer->number);
|
||||
|
||||
if (!dst->rectangles)
|
||||
goto fail;
|
||||
|
||||
return dst;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
free_bitmap_update(context, dst);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CACHE_BITMAP_ORDER* copy_cache_bitmap_order(rdpContext* context, const CACHE_BITMAP_ORDER* order)
|
||||
{
|
||||
CACHE_BITMAP_ORDER* dst = calloc(1, sizeof(CACHE_BITMAP_ORDER));
|
||||
|
||||
if (!dst || !order)
|
||||
goto fail;
|
||||
|
||||
*dst = *order;
|
||||
|
||||
if (order->bitmapLength > 0)
|
||||
{
|
||||
dst->bitmapDataStream = malloc(order->bitmapLength);
|
||||
|
||||
if (!dst->bitmapDataStream)
|
||||
goto fail;
|
||||
|
||||
memcpy(dst->bitmapDataStream, order->bitmapDataStream, order->bitmapLength);
|
||||
}
|
||||
|
||||
return dst;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
free_cache_bitmap_order(context, dst);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void free_cache_bitmap_order(WINPR_ATTR_UNUSED rdpContext* context, CACHE_BITMAP_ORDER* order)
|
||||
{
|
||||
if (order)
|
||||
free(order->bitmapDataStream);
|
||||
|
||||
free(order);
|
||||
}
|
||||
|
||||
CACHE_BITMAP_V2_ORDER* copy_cache_bitmap_v2_order(rdpContext* context,
|
||||
const CACHE_BITMAP_V2_ORDER* order)
|
||||
{
|
||||
CACHE_BITMAP_V2_ORDER* dst = calloc(1, sizeof(CACHE_BITMAP_V2_ORDER));
|
||||
|
||||
if (!dst || !order)
|
||||
goto fail;
|
||||
|
||||
*dst = *order;
|
||||
|
||||
if (order->bitmapLength > 0)
|
||||
{
|
||||
dst->bitmapDataStream = malloc(order->bitmapLength);
|
||||
|
||||
if (!dst->bitmapDataStream)
|
||||
goto fail;
|
||||
|
||||
memcpy(dst->bitmapDataStream, order->bitmapDataStream, order->bitmapLength);
|
||||
}
|
||||
|
||||
return dst;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
free_cache_bitmap_v2_order(context, dst);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void free_cache_bitmap_v2_order(WINPR_ATTR_UNUSED rdpContext* context,
|
||||
WINPR_ATTR_UNUSED CACHE_BITMAP_V2_ORDER* order)
|
||||
{
|
||||
if (order)
|
||||
free(order->bitmapDataStream);
|
||||
|
||||
free(order);
|
||||
}
|
||||
|
||||
CACHE_BITMAP_V3_ORDER* copy_cache_bitmap_v3_order(rdpContext* context,
|
||||
const CACHE_BITMAP_V3_ORDER* order)
|
||||
{
|
||||
CACHE_BITMAP_V3_ORDER* dst = calloc(1, sizeof(CACHE_BITMAP_V3_ORDER));
|
||||
|
||||
if (!dst || !order)
|
||||
goto fail;
|
||||
|
||||
*dst = *order;
|
||||
|
||||
if (order->bitmapData.length > 0)
|
||||
{
|
||||
dst->bitmapData.data = malloc(order->bitmapData.length);
|
||||
|
||||
if (!dst->bitmapData.data)
|
||||
goto fail;
|
||||
|
||||
memcpy(dst->bitmapData.data, order->bitmapData.data, order->bitmapData.length);
|
||||
}
|
||||
|
||||
return dst;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
free_cache_bitmap_v3_order(context, dst);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void free_cache_bitmap_v3_order(WINPR_ATTR_UNUSED rdpContext* context, CACHE_BITMAP_V3_ORDER* order)
|
||||
{
|
||||
if (order)
|
||||
free(order->bitmapData.data);
|
||||
|
||||
free(order);
|
||||
}
|
||||
100
third_party/FreeRDP/libfreerdp/cache/bitmap.h
vendored
Normal file
100
third_party/FreeRDP/libfreerdp/cache/bitmap.h
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2018 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_LIB_CACHE_BITMAP_H
|
||||
#define FREERDP_LIB_CACHE_BITMAP_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/update.h>
|
||||
|
||||
#include <freerdp/cache/persistent.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT32 number;
|
||||
rdpBitmap** entries;
|
||||
} BITMAP_V2_CELL;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WINPR_ATTR_NODISCARD pMemBlt MemBlt; /* 0 */
|
||||
WINPR_ATTR_NODISCARD pMem3Blt Mem3Blt; /* 1 */
|
||||
WINPR_ATTR_NODISCARD pCacheBitmap CacheBitmap; /* 2 */
|
||||
WINPR_ATTR_NODISCARD pCacheBitmapV2 CacheBitmapV2; /* 3 */
|
||||
WINPR_ATTR_NODISCARD pCacheBitmapV3 CacheBitmapV3; /* 4 */
|
||||
WINPR_ATTR_NODISCARD pBitmapUpdate BitmapUpdate; /* 5 */
|
||||
UINT32 paddingA[16 - 6]; /* 6 */
|
||||
|
||||
UINT32 maxCells; /* 16 */
|
||||
BITMAP_V2_CELL* cells; /* 17 */
|
||||
UINT32 paddingB[32 - 18]; /* 18 */
|
||||
|
||||
/* internal */
|
||||
rdpContext* context;
|
||||
rdpPersistentCache* persistent;
|
||||
} rdpBitmapCache;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
FREERDP_LOCAL void bitmap_cache_register_callbacks(rdpUpdate* update);
|
||||
|
||||
FREERDP_LOCAL void bitmap_cache_free(rdpBitmapCache* bitmapCache);
|
||||
|
||||
WINPR_ATTR_MALLOC(bitmap_cache_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL rdpBitmapCache* bitmap_cache_new(rdpContext* context);
|
||||
|
||||
FREERDP_LOCAL void free_bitmap_update(rdpContext* context, BITMAP_UPDATE* pointer);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_bitmap_update, 2)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL BITMAP_UPDATE* copy_bitmap_update(rdpContext* context,
|
||||
const BITMAP_UPDATE* pointer);
|
||||
|
||||
FREERDP_LOCAL void free_cache_bitmap_order(rdpContext* context, CACHE_BITMAP_ORDER* order);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_cache_bitmap_order, 2)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL CACHE_BITMAP_ORDER* copy_cache_bitmap_order(rdpContext* context,
|
||||
const CACHE_BITMAP_ORDER* order);
|
||||
|
||||
FREERDP_LOCAL void free_cache_bitmap_v2_order(rdpContext* context,
|
||||
CACHE_BITMAP_V2_ORDER* order);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_cache_bitmap_v2_order, 2)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL CACHE_BITMAP_V2_ORDER*
|
||||
copy_cache_bitmap_v2_order(rdpContext* context, const CACHE_BITMAP_V2_ORDER* order);
|
||||
|
||||
FREERDP_LOCAL void free_cache_bitmap_v3_order(rdpContext* context,
|
||||
CACHE_BITMAP_V3_ORDER* order);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_cache_bitmap_v3_order, 2)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL CACHE_BITMAP_V3_ORDER*
|
||||
copy_cache_bitmap_v3_order(rdpContext* context, const CACHE_BITMAP_V3_ORDER* order);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_LIB_CACHE_BITMAP_H */
|
||||
322
third_party/FreeRDP/libfreerdp/cache/brush.c
vendored
Normal file
322
third_party/FreeRDP/libfreerdp/cache/brush.c
vendored
Normal file
@@ -0,0 +1,322 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Brush Cache
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/update.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include "brush.h"
|
||||
#include "cache.h"
|
||||
|
||||
#define TAG FREERDP_TAG("cache.brush")
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT32 bpp;
|
||||
void* entry;
|
||||
} BRUSH_ENTRY;
|
||||
|
||||
struct rdp_brush_cache
|
||||
{
|
||||
pPatBlt PatBlt; /* 0 */
|
||||
pCacheBrush CacheBrush; /* 1 */
|
||||
pPolygonSC PolygonSC; /* 2 */
|
||||
pPolygonCB PolygonCB; /* 3 */
|
||||
UINT32 paddingA[16 - 4]; /* 4 */
|
||||
|
||||
UINT32 maxEntries; /* 16 */
|
||||
UINT32 maxMonoEntries; /* 17 */
|
||||
BRUSH_ENTRY* entries; /* 18 */
|
||||
BRUSH_ENTRY* monoEntries; /* 19 */
|
||||
UINT32 paddingB[32 - 20]; /* 20 */
|
||||
|
||||
rdpContext* context;
|
||||
};
|
||||
|
||||
static BOOL update_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt)
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(patblt);
|
||||
|
||||
const rdpCache* cache = context->cache;
|
||||
WINPR_ASSERT(cache);
|
||||
|
||||
rdpBrush* brush = &patblt->brush;
|
||||
WINPR_ASSERT(brush->style <= UINT8_MAX);
|
||||
const BYTE style = (BYTE)brush->style;
|
||||
|
||||
if (brush->style & CACHED_BRUSH)
|
||||
{
|
||||
brush->data = brush_cache_get(cache->brush, brush->index, &brush->bpp);
|
||||
brush->style = 0x03;
|
||||
}
|
||||
|
||||
WINPR_ASSERT(cache->brush);
|
||||
IFCALLRET(cache->brush->PatBlt, ret, context, patblt);
|
||||
brush->style = style;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL update_gdi_polygon_sc(rdpContext* context, const POLYGON_SC_ORDER* polygon_sc)
|
||||
{
|
||||
rdpCache* cache = nullptr;
|
||||
WINPR_ASSERT(context);
|
||||
cache = context->cache;
|
||||
WINPR_ASSERT(cache);
|
||||
WINPR_ASSERT(cache->brush);
|
||||
return IFCALLRESULT(TRUE, cache->brush->PolygonSC, context, polygon_sc);
|
||||
}
|
||||
|
||||
static BOOL update_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb)
|
||||
{
|
||||
BOOL ret = TRUE;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(polygon_cb);
|
||||
|
||||
rdpCache* cache = context->cache;
|
||||
WINPR_ASSERT(cache);
|
||||
|
||||
rdpBrush* brush = &polygon_cb->brush;
|
||||
WINPR_ASSERT(brush->style <= UINT8_MAX);
|
||||
const BYTE style = (UINT8)brush->style;
|
||||
|
||||
if (brush->style & CACHED_BRUSH)
|
||||
{
|
||||
brush->data = brush_cache_get(cache->brush, brush->index, &brush->bpp);
|
||||
brush->style = 0x03;
|
||||
}
|
||||
|
||||
WINPR_ASSERT(cache->brush);
|
||||
IFCALLRET(cache->brush->PolygonCB, ret, context, polygon_cb);
|
||||
brush->style = style;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL update_gdi_cache_brush(rdpContext* context, const CACHE_BRUSH_ORDER* cacheBrush)
|
||||
{
|
||||
UINT32 length = 0;
|
||||
void* data = nullptr;
|
||||
rdpCache* cache = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(cacheBrush);
|
||||
|
||||
cache = context->cache;
|
||||
WINPR_ASSERT(cache);
|
||||
|
||||
length = cacheBrush->bpp * 64 / 8;
|
||||
data = malloc(length);
|
||||
|
||||
if (!data)
|
||||
return FALSE;
|
||||
|
||||
CopyMemory(data, cacheBrush->data, length);
|
||||
brush_cache_put(cache->brush, cacheBrush->index, data, cacheBrush->bpp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void* brush_cache_get(rdpBrushCache* brushCache, UINT32 index, UINT32* bpp)
|
||||
{
|
||||
void* entry = nullptr;
|
||||
|
||||
if (!brushCache)
|
||||
return nullptr;
|
||||
|
||||
if (!bpp)
|
||||
return nullptr;
|
||||
|
||||
if (*bpp == 1)
|
||||
{
|
||||
if (index >= brushCache->maxMonoEntries)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid brush (%" PRIu32 " bpp) index: 0x%08" PRIX32 "", *bpp, index);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*bpp = brushCache->monoEntries[index].bpp;
|
||||
entry = brushCache->monoEntries[index].entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index >= brushCache->maxEntries)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid brush (%" PRIu32 " bpp) index: 0x%08" PRIX32 "", *bpp, index);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*bpp = brushCache->entries[index].bpp;
|
||||
entry = brushCache->entries[index].entry;
|
||||
}
|
||||
|
||||
if (entry == nullptr)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid brush (%" PRIu32 " bpp) at index: 0x%08" PRIX32 "", *bpp, index);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void brush_cache_put(rdpBrushCache* brushCache, UINT32 index, void* entry, UINT32 bpp)
|
||||
{
|
||||
WINPR_ASSERT(brushCache);
|
||||
|
||||
if (bpp == 1)
|
||||
{
|
||||
if (index >= brushCache->maxMonoEntries)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid brush (%" PRIu32 " bpp) index: 0x%08" PRIX32 "", bpp, index);
|
||||
free(entry);
|
||||
return;
|
||||
}
|
||||
|
||||
WINPR_ASSERT(brushCache->monoEntries);
|
||||
free(brushCache->monoEntries[index].entry);
|
||||
brushCache->monoEntries[index].bpp = bpp;
|
||||
brushCache->monoEntries[index].entry = entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index >= brushCache->maxEntries)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid brush (%" PRIu32 " bpp) index: 0x%08" PRIX32 "", bpp, index);
|
||||
free(entry);
|
||||
return;
|
||||
}
|
||||
|
||||
WINPR_ASSERT(brushCache->entries);
|
||||
free(brushCache->entries[index].entry);
|
||||
brushCache->entries[index].bpp = bpp;
|
||||
brushCache->entries[index].entry = entry;
|
||||
}
|
||||
}
|
||||
|
||||
void brush_cache_register_callbacks(rdpUpdate* update)
|
||||
{
|
||||
WINPR_ASSERT(update);
|
||||
WINPR_ASSERT(update->context);
|
||||
WINPR_ASSERT(update->primary);
|
||||
WINPR_ASSERT(update->secondary);
|
||||
|
||||
if (!freerdp_settings_get_bool(update->context->settings, FreeRDP_DeactivateClientDecoding))
|
||||
{
|
||||
rdpCache* cache = update->context->cache;
|
||||
WINPR_ASSERT(cache);
|
||||
WINPR_ASSERT(cache->brush);
|
||||
|
||||
cache->brush->PatBlt = update->primary->PatBlt;
|
||||
cache->brush->PolygonSC = update->primary->PolygonSC;
|
||||
cache->brush->PolygonCB = update->primary->PolygonCB;
|
||||
update->primary->PatBlt = update_gdi_patblt;
|
||||
update->primary->PolygonSC = update_gdi_polygon_sc;
|
||||
update->primary->PolygonCB = update_gdi_polygon_cb;
|
||||
update->secondary->CacheBrush = update_gdi_cache_brush;
|
||||
}
|
||||
}
|
||||
|
||||
rdpBrushCache* brush_cache_new(rdpContext* context)
|
||||
{
|
||||
rdpBrushCache* brushCache = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
brushCache = (rdpBrushCache*)calloc(1, sizeof(rdpBrushCache));
|
||||
|
||||
if (!brushCache)
|
||||
return nullptr;
|
||||
|
||||
brushCache->context = context;
|
||||
brushCache->maxEntries = 64;
|
||||
brushCache->maxMonoEntries = 64;
|
||||
brushCache->entries = (BRUSH_ENTRY*)calloc(brushCache->maxEntries, sizeof(BRUSH_ENTRY));
|
||||
|
||||
if (!brushCache->entries)
|
||||
goto fail;
|
||||
|
||||
brushCache->monoEntries = (BRUSH_ENTRY*)calloc(brushCache->maxMonoEntries, sizeof(BRUSH_ENTRY));
|
||||
|
||||
if (!brushCache->monoEntries)
|
||||
goto fail;
|
||||
|
||||
return brushCache;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
brush_cache_free(brushCache);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void brush_cache_free(rdpBrushCache* brushCache)
|
||||
{
|
||||
if (brushCache)
|
||||
{
|
||||
if (brushCache->entries)
|
||||
{
|
||||
for (size_t i = 0; i < brushCache->maxEntries; i++)
|
||||
free(brushCache->entries[i].entry);
|
||||
|
||||
free(brushCache->entries);
|
||||
}
|
||||
|
||||
if (brushCache->monoEntries)
|
||||
{
|
||||
for (size_t i = 0; i < brushCache->maxMonoEntries; i++)
|
||||
free(brushCache->monoEntries[i].entry);
|
||||
|
||||
free(brushCache->monoEntries);
|
||||
}
|
||||
|
||||
free(brushCache);
|
||||
}
|
||||
}
|
||||
|
||||
void free_cache_brush_order(rdpContext* context, CACHE_BRUSH_ORDER* order)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
free(order);
|
||||
}
|
||||
|
||||
CACHE_BRUSH_ORDER* copy_cache_brush_order(rdpContext* context, const CACHE_BRUSH_ORDER* order)
|
||||
{
|
||||
CACHE_BRUSH_ORDER* dst = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
dst = calloc(1, sizeof(CACHE_BRUSH_ORDER));
|
||||
|
||||
if (!dst || !order)
|
||||
goto fail;
|
||||
|
||||
*dst = *order;
|
||||
return dst;
|
||||
fail:
|
||||
free_cache_brush_order(context, dst);
|
||||
return nullptr;
|
||||
}
|
||||
60
third_party/FreeRDP/libfreerdp/cache/brush.h
vendored
Normal file
60
third_party/FreeRDP/libfreerdp/cache/brush.h
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Brush Cache
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_LIB_BRUSH_CACHE_H
|
||||
#define FREERDP_LIB_BRUSH_CACHE_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/update.h>
|
||||
|
||||
#include <winpr/stream.h>
|
||||
|
||||
typedef struct rdp_brush_cache rdpBrushCache;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL void* brush_cache_get(rdpBrushCache* brush, UINT32 index, UINT32* bpp);
|
||||
FREERDP_LOCAL void brush_cache_put(rdpBrushCache* brush, UINT32 index, void* entry, UINT32 bpp);
|
||||
|
||||
FREERDP_LOCAL void brush_cache_register_callbacks(rdpUpdate* update);
|
||||
|
||||
FREERDP_LOCAL void brush_cache_free(rdpBrushCache* brush);
|
||||
|
||||
WINPR_ATTR_MALLOC(brush_cache_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL rdpBrushCache* brush_cache_new(rdpContext* context);
|
||||
|
||||
FREERDP_LOCAL void free_cache_brush_order(rdpContext* context, CACHE_BRUSH_ORDER* order);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_cache_brush_order, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL CACHE_BRUSH_ORDER* copy_cache_brush_order(rdpContext* context,
|
||||
const CACHE_BRUSH_ORDER* order);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_LIB_BRUSH_CACHE_H */
|
||||
153
third_party/FreeRDP/libfreerdp/cache/cache.c
vendored
Normal file
153
third_party/FreeRDP/libfreerdp/cache/cache.c
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* RDP Caches
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include "cache.h"
|
||||
|
||||
rdpCache* cache_new(rdpContext* context)
|
||||
{
|
||||
rdpCache* cache = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
cache = (rdpCache*)calloc(1, sizeof(rdpCache));
|
||||
|
||||
if (!cache)
|
||||
return nullptr;
|
||||
|
||||
cache->glyph = glyph_cache_new(context);
|
||||
|
||||
if (!cache->glyph)
|
||||
goto error;
|
||||
|
||||
cache->brush = brush_cache_new(context);
|
||||
|
||||
if (!cache->brush)
|
||||
goto error;
|
||||
|
||||
cache->pointer = pointer_cache_new(context);
|
||||
|
||||
if (!cache->pointer)
|
||||
goto error;
|
||||
|
||||
cache->bitmap = bitmap_cache_new(context);
|
||||
|
||||
if (!cache->bitmap)
|
||||
goto error;
|
||||
|
||||
cache->offscreen = offscreen_cache_new(context);
|
||||
|
||||
if (!cache->offscreen)
|
||||
goto error;
|
||||
|
||||
cache->palette = palette_cache_new(context);
|
||||
|
||||
if (!cache->palette)
|
||||
goto error;
|
||||
|
||||
cache->nine_grid = nine_grid_cache_new(context);
|
||||
|
||||
if (!cache->nine_grid)
|
||||
goto error;
|
||||
|
||||
return cache;
|
||||
error:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
cache_free(cache);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void cache_free(rdpCache* cache)
|
||||
{
|
||||
if (cache != nullptr)
|
||||
{
|
||||
glyph_cache_free(cache->glyph);
|
||||
brush_cache_free(cache->brush);
|
||||
pointer_cache_free(cache->pointer);
|
||||
bitmap_cache_free(cache->bitmap);
|
||||
offscreen_cache_free(cache->offscreen);
|
||||
palette_cache_free(cache->palette);
|
||||
nine_grid_cache_free(cache->nine_grid);
|
||||
free(cache);
|
||||
}
|
||||
}
|
||||
|
||||
CACHE_COLOR_TABLE_ORDER* copy_cache_color_table_order(rdpContext* context,
|
||||
const CACHE_COLOR_TABLE_ORDER* order)
|
||||
{
|
||||
CACHE_COLOR_TABLE_ORDER* dst = calloc(1, sizeof(CACHE_COLOR_TABLE_ORDER));
|
||||
|
||||
if (!dst || !order)
|
||||
goto fail;
|
||||
|
||||
*dst = *order;
|
||||
return dst;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
free_cache_color_table_order(context, dst);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void free_cache_color_table_order(WINPR_ATTR_UNUSED rdpContext* context,
|
||||
CACHE_COLOR_TABLE_ORDER* order)
|
||||
{
|
||||
free(order);
|
||||
}
|
||||
|
||||
SURFACE_BITS_COMMAND* copy_surface_bits_command(rdpContext* context,
|
||||
const SURFACE_BITS_COMMAND* order)
|
||||
{
|
||||
SURFACE_BITS_COMMAND* dst = calloc(1, sizeof(SURFACE_BITS_COMMAND));
|
||||
if (!dst || !order)
|
||||
goto fail;
|
||||
|
||||
*dst = *order;
|
||||
|
||||
dst->bmp.bitmapData = (BYTE*)malloc(order->bmp.bitmapDataLength);
|
||||
|
||||
if (!dst->bmp.bitmapData)
|
||||
goto fail;
|
||||
|
||||
CopyMemory(dst->bmp.bitmapData, order->bmp.bitmapData, order->bmp.bitmapDataLength);
|
||||
|
||||
return dst;
|
||||
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
free_surface_bits_command(context, dst);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void free_surface_bits_command(WINPR_ATTR_UNUSED rdpContext* context, SURFACE_BITS_COMMAND* order)
|
||||
{
|
||||
if (order)
|
||||
free(order->bmp.bitmapData);
|
||||
free(order);
|
||||
}
|
||||
76
third_party/FreeRDP/libfreerdp/cache/cache.h
vendored
Normal file
76
third_party/FreeRDP/libfreerdp/cache/cache.h
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2018 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_LIB_CACHE_CACHE_H
|
||||
#define FREERDP_LIB_CACHE_CACHE_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/pointer.h>
|
||||
|
||||
#include "glyph.h"
|
||||
#include "brush.h"
|
||||
#include "pointer.h"
|
||||
#include "bitmap.h"
|
||||
#include "nine_grid.h"
|
||||
#include "offscreen.h"
|
||||
#include "palette.h"
|
||||
|
||||
struct rdp_cache
|
||||
{
|
||||
rdpGlyphCache* glyph; /* 0 */
|
||||
rdpBrushCache* brush; /* 1 */
|
||||
rdpPointerCache* pointer; /* 2 */
|
||||
rdpBitmapCache* bitmap; /* 3 */
|
||||
rdpOffscreenCache* offscreen; /* 4 */
|
||||
rdpPaletteCache* palette; /* 5 */
|
||||
rdpNineGridCache* nine_grid; /* 6 */
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
FREERDP_LOCAL void cache_free(rdpCache* cache);
|
||||
|
||||
WINPR_ATTR_MALLOC(cache_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL rdpCache* cache_new(rdpContext* context);
|
||||
|
||||
FREERDP_LOCAL void free_cache_color_table_order(rdpContext* context,
|
||||
CACHE_COLOR_TABLE_ORDER* order);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_cache_color_table_order, 2)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL CACHE_COLOR_TABLE_ORDER*
|
||||
copy_cache_color_table_order(rdpContext* context, const CACHE_COLOR_TABLE_ORDER* order);
|
||||
|
||||
FREERDP_LOCAL void free_surface_bits_command(rdpContext* context, SURFACE_BITS_COMMAND* order);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_surface_bits_command, 2)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL SURFACE_BITS_COMMAND*
|
||||
copy_surface_bits_command(rdpContext* context, const SURFACE_BITS_COMMAND* order);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_LIB_CACHE_CACHE_H */
|
||||
886
third_party/FreeRDP/libfreerdp/cache/glyph.c
vendored
Normal file
886
third_party/FreeRDP/libfreerdp/cache/glyph.c
vendored
Normal file
@@ -0,0 +1,886 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Glyph Cache
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/cast.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#include "glyph.h"
|
||||
#include "cache.h"
|
||||
|
||||
#define TAG FREERDP_TAG("cache.glyph")
|
||||
|
||||
static rdpGlyph* glyph_cache_get(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index);
|
||||
static BOOL glyph_cache_put(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index, rdpGlyph* glyph);
|
||||
|
||||
static const void* glyph_cache_fragment_get(rdpGlyphCache* glyphCache, UINT32 index, UINT32* size);
|
||||
static BOOL glyph_cache_fragment_put(rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
|
||||
const void* fragment);
|
||||
|
||||
static UINT32 update_glyph_offset(const BYTE* data, size_t length, UINT32 index, INT32* x, INT32* y,
|
||||
UINT32 ulCharInc, UINT32 flAccel)
|
||||
{
|
||||
if ((ulCharInc == 0) && (!(flAccel & SO_CHAR_INC_EQUAL_BM_BASE)))
|
||||
{
|
||||
UINT32 offset = data[index++];
|
||||
|
||||
if (offset & 0x80)
|
||||
{
|
||||
|
||||
if (index + 1 < length)
|
||||
{
|
||||
offset = data[index++];
|
||||
offset |= ((UINT32)data[index++]) << 8;
|
||||
}
|
||||
else
|
||||
WLog_WARN(TAG, "glyph index out of bound %" PRIu32 " [max %" PRIuz "]", index,
|
||||
length);
|
||||
}
|
||||
|
||||
if (flAccel & SO_VERTICAL)
|
||||
*y += WINPR_ASSERTING_INT_CAST(int32_t, offset);
|
||||
|
||||
if (flAccel & SO_HORIZONTAL)
|
||||
*x += WINPR_ASSERTING_INT_CAST(int32_t, offset);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static BOOL update_process_glyph(rdpContext* context, const BYTE* data, UINT32 cacheIndex, INT32* x,
|
||||
const INT32* y, UINT32 cacheId, UINT32 flAccel, BOOL fOpRedundant,
|
||||
const RDP_RECT* bound)
|
||||
{
|
||||
INT32 sx = 0;
|
||||
INT32 sy = 0;
|
||||
|
||||
if (!context || !data || !x || !y || !context->graphics || !context->cache ||
|
||||
!context->cache->glyph)
|
||||
return FALSE;
|
||||
|
||||
rdpGlyphCache* glyph_cache = context->cache->glyph;
|
||||
rdpGlyph* glyph = glyph_cache_get(glyph_cache, cacheId, cacheIndex);
|
||||
|
||||
if (!glyph)
|
||||
return FALSE;
|
||||
|
||||
INT32 dx = glyph->x + *x;
|
||||
INT32 dy = glyph->y + *y;
|
||||
|
||||
if (dx < bound->x)
|
||||
{
|
||||
sx = bound->x - dx;
|
||||
dx = bound->x;
|
||||
}
|
||||
|
||||
if (dy < bound->y)
|
||||
{
|
||||
sy = bound->y - dy;
|
||||
dy = bound->y;
|
||||
}
|
||||
|
||||
if ((dx <= (bound->x + bound->width)) && (dy <= (bound->y + bound->height)))
|
||||
{
|
||||
INT32 dw = WINPR_ASSERTING_INT_CAST(int32_t, glyph->cx) - sx;
|
||||
INT32 dh = WINPR_ASSERTING_INT_CAST(int32_t, glyph->cy) - sy;
|
||||
|
||||
if ((dw + dx) > (bound->x + bound->width))
|
||||
dw = (bound->x + bound->width) - (dw + dx);
|
||||
|
||||
if ((dh + dy) > (bound->y + bound->height))
|
||||
dh = (bound->y + bound->height) - (dh + dy);
|
||||
|
||||
if ((dh > 0) && (dw > 0))
|
||||
{
|
||||
if (!glyph->Draw(context, glyph, dx, dy, dw, dh, sx, sy, fOpRedundant))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (flAccel & SO_CHAR_INC_EQUAL_BM_BASE)
|
||||
*x += WINPR_ASSERTING_INT_CAST(int32_t, glyph->cx);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL update_process_glyph_fragments(rdpContext* context, const BYTE* data, UINT32 length,
|
||||
UINT32 cacheId, UINT32 ulCharInc, UINT32 flAccel,
|
||||
UINT32 bgcolor, UINT32 fgcolor, INT32 x, INT32 y,
|
||||
INT32 bkX, INT32 bkY, INT32 bkWidth, INT32 bkHeight,
|
||||
INT32 opX, INT32 opY, INT32 opWidth, INT32 opHeight,
|
||||
BOOL fOpRedundant)
|
||||
{
|
||||
UINT32 id = 0;
|
||||
UINT32 size = 0;
|
||||
UINT32 index = 0;
|
||||
const BYTE* fragments = nullptr;
|
||||
RDP_RECT bound = WINPR_C_ARRAY_INIT;
|
||||
BOOL rc = FALSE;
|
||||
|
||||
if (!context || !data || !context->graphics || !context->cache || !context->cache->glyph)
|
||||
return FALSE;
|
||||
|
||||
rdpGraphics* graphics = context->graphics;
|
||||
WINPR_ASSERT(graphics);
|
||||
|
||||
WINPR_ASSERT(context->cache);
|
||||
rdpGlyphCache* glyph_cache = context->cache->glyph;
|
||||
WINPR_ASSERT(glyph_cache);
|
||||
|
||||
{
|
||||
rdpGlyph* glyph = graphics->Glyph_Prototype;
|
||||
if (!glyph)
|
||||
goto fail;
|
||||
|
||||
/* Limit op rectangle to visible screen. */
|
||||
if (opX < 0)
|
||||
{
|
||||
opWidth += opX;
|
||||
opX = 0;
|
||||
}
|
||||
|
||||
if (opY < 0)
|
||||
{
|
||||
opHeight += opY;
|
||||
opY = 0;
|
||||
}
|
||||
|
||||
if (opWidth < 0)
|
||||
opWidth = 0;
|
||||
|
||||
if (opHeight < 0)
|
||||
opHeight = 0;
|
||||
|
||||
/* Limit bk rectangle to visible screen. */
|
||||
if (bkX < 0)
|
||||
{
|
||||
bkWidth += bkX;
|
||||
bkX = 0;
|
||||
}
|
||||
|
||||
if (bkY < 0)
|
||||
{
|
||||
bkHeight += bkY;
|
||||
bkY = 0;
|
||||
}
|
||||
|
||||
if (bkWidth < 0)
|
||||
bkWidth = 0;
|
||||
|
||||
if (bkHeight < 0)
|
||||
bkHeight = 0;
|
||||
|
||||
{
|
||||
const UINT32 w = freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth);
|
||||
if (opX + opWidth > (INT64)w)
|
||||
{
|
||||
/**
|
||||
* Some Microsoft servers send erroneous high values close to the
|
||||
* sint16 maximum in the OpRight field of the GlyphIndex, FastIndex and
|
||||
* FastGlyph drawing orders, probably a result of applications trying to
|
||||
* clear the text line to the very right end.
|
||||
* One example where this can be seen is typing in notepad.exe within
|
||||
* a RDP session to Windows XP Professional SP3.
|
||||
* This workaround prevents resulting problems in the UI callbacks.
|
||||
*/
|
||||
opWidth = WINPR_ASSERTING_INT_CAST(int, w) - opX;
|
||||
}
|
||||
|
||||
if (bkX + bkWidth > (INT64)w)
|
||||
{
|
||||
/**
|
||||
* Some Microsoft servers send erroneous high values close to the
|
||||
* sint16 maximum in the OpRight field of the GlyphIndex, FastIndex and
|
||||
* FastGlyph drawing orders, probably a result of applications trying to
|
||||
* clear the text line to the very right end.
|
||||
* One example where this can be seen is typing in notepad.exe within
|
||||
* a RDP session to Windows XP Professional SP3.
|
||||
* This workaround prevents resulting problems in the UI callbacks.
|
||||
*/
|
||||
bkWidth = WINPR_ASSERTING_INT_CAST(int, w) - bkX;
|
||||
}
|
||||
}
|
||||
|
||||
bound.x = WINPR_ASSERTING_INT_CAST(INT16, bkX);
|
||||
bound.y = WINPR_ASSERTING_INT_CAST(INT16, bkY);
|
||||
bound.width = WINPR_ASSERTING_INT_CAST(INT16, bkWidth);
|
||||
bound.height = WINPR_ASSERTING_INT_CAST(INT16, bkHeight);
|
||||
|
||||
if (!glyph->BeginDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor, fOpRedundant))
|
||||
goto fail;
|
||||
|
||||
if (!IFCALLRESULT(TRUE, glyph->SetBounds, context, bkX, bkY, bkWidth, bkHeight))
|
||||
goto fail;
|
||||
|
||||
while (index < length)
|
||||
{
|
||||
const UINT32 op = data[index++];
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case GLYPH_FRAGMENT_USE:
|
||||
if (index + 1 > length)
|
||||
goto fail;
|
||||
|
||||
id = data[index++];
|
||||
fragments = (const BYTE*)glyph_cache_fragment_get(glyph_cache, id, &size);
|
||||
|
||||
if (fragments == nullptr)
|
||||
goto fail;
|
||||
|
||||
for (UINT32 n = 0; n < size;)
|
||||
{
|
||||
const UINT32 fop = fragments[n++];
|
||||
n = update_glyph_offset(fragments, size, n, &x, &y, ulCharInc, flAccel);
|
||||
|
||||
if (!update_process_glyph(context, fragments, fop, &x, &y, cacheId, flAccel,
|
||||
fOpRedundant, &bound))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case GLYPH_FRAGMENT_ADD:
|
||||
if (index + 2 > length)
|
||||
goto fail;
|
||||
|
||||
id = data[index++];
|
||||
size = data[index++];
|
||||
glyph_cache_fragment_put(glyph_cache, id, size, data);
|
||||
break;
|
||||
|
||||
default:
|
||||
index = update_glyph_offset(data, length, index, &x, &y, ulCharInc, flAccel);
|
||||
|
||||
if (!update_process_glyph(context, data, op, &x, &y, cacheId, flAccel,
|
||||
fOpRedundant, &bound))
|
||||
goto fail;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!glyph->EndDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
|
||||
fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL update_gdi_glyph_index(rdpContext* context, GLYPH_INDEX_ORDER* glyphIndex)
|
||||
{
|
||||
INT32 bkWidth = 0;
|
||||
INT32 bkHeight = 0;
|
||||
INT32 opWidth = 0;
|
||||
INT32 opHeight = 0;
|
||||
|
||||
if (!context || !glyphIndex || !context->cache)
|
||||
return FALSE;
|
||||
|
||||
if (glyphIndex->bkRight > glyphIndex->bkLeft)
|
||||
bkWidth = glyphIndex->bkRight - glyphIndex->bkLeft + 1;
|
||||
|
||||
if (glyphIndex->opRight > glyphIndex->opLeft)
|
||||
opWidth = glyphIndex->opRight - glyphIndex->opLeft + 1;
|
||||
|
||||
if (glyphIndex->bkBottom > glyphIndex->bkTop)
|
||||
bkHeight = glyphIndex->bkBottom - glyphIndex->bkTop + 1;
|
||||
|
||||
if (glyphIndex->opBottom > glyphIndex->opTop)
|
||||
opHeight = glyphIndex->opBottom - glyphIndex->opTop + 1;
|
||||
|
||||
return update_process_glyph_fragments(
|
||||
context, glyphIndex->data, glyphIndex->cbData, glyphIndex->cacheId, glyphIndex->ulCharInc,
|
||||
glyphIndex->flAccel, glyphIndex->backColor, glyphIndex->foreColor, glyphIndex->x,
|
||||
glyphIndex->y, glyphIndex->bkLeft, glyphIndex->bkTop, bkWidth, bkHeight, glyphIndex->opLeft,
|
||||
glyphIndex->opTop, opWidth, opHeight,
|
||||
WINPR_ASSERTING_INT_CAST(int32_t, glyphIndex->fOpRedundant));
|
||||
}
|
||||
|
||||
static BOOL update_gdi_fast_index(rdpContext* context, const FAST_INDEX_ORDER* fastIndex)
|
||||
{
|
||||
INT32 opWidth = 0;
|
||||
INT32 opHeight = 0;
|
||||
INT32 bkWidth = 0;
|
||||
INT32 bkHeight = 0;
|
||||
BOOL rc = FALSE;
|
||||
|
||||
if (!context || !fastIndex || !context->cache)
|
||||
return FALSE;
|
||||
|
||||
INT32 opLeft = fastIndex->opLeft;
|
||||
INT32 opTop = fastIndex->opTop;
|
||||
INT32 opRight = fastIndex->opRight;
|
||||
INT32 opBottom = fastIndex->opBottom;
|
||||
INT32 x = fastIndex->x;
|
||||
INT32 y = fastIndex->y;
|
||||
|
||||
if (opBottom == -32768)
|
||||
{
|
||||
BYTE flags = (BYTE)(opTop & 0x0F);
|
||||
|
||||
if (flags & 0x01)
|
||||
opBottom = fastIndex->bkBottom;
|
||||
|
||||
if (flags & 0x02)
|
||||
opRight = fastIndex->bkRight;
|
||||
|
||||
if (flags & 0x04)
|
||||
opTop = fastIndex->bkTop;
|
||||
|
||||
if (flags & 0x08)
|
||||
opLeft = fastIndex->bkLeft;
|
||||
}
|
||||
|
||||
if (opLeft == 0)
|
||||
opLeft = fastIndex->bkLeft;
|
||||
|
||||
if (opRight == 0)
|
||||
opRight = fastIndex->bkRight;
|
||||
|
||||
/* Server can send a massive number (32766) which appears to be
|
||||
* undocumented special behavior for "Erase all the way right".
|
||||
* X11 has nondeterministic results asking for a draw that wide. */
|
||||
if (opRight > (INT64)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth))
|
||||
opRight = (int)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth);
|
||||
|
||||
if (x == -32768)
|
||||
x = fastIndex->bkLeft;
|
||||
|
||||
if (y == -32768)
|
||||
y = fastIndex->bkTop;
|
||||
|
||||
if (fastIndex->bkRight > fastIndex->bkLeft)
|
||||
bkWidth = fastIndex->bkRight - fastIndex->bkLeft + 1;
|
||||
|
||||
if (fastIndex->bkBottom > fastIndex->bkTop)
|
||||
bkHeight = fastIndex->bkBottom - fastIndex->bkTop + 1;
|
||||
|
||||
if (opRight > opLeft)
|
||||
opWidth = opRight - opLeft + 1;
|
||||
|
||||
if (opBottom > opTop)
|
||||
opHeight = opBottom - opTop + 1;
|
||||
|
||||
if (!update_process_glyph_fragments(
|
||||
context, fastIndex->data, fastIndex->cbData, fastIndex->cacheId, fastIndex->ulCharInc,
|
||||
fastIndex->flAccel, fastIndex->backColor, fastIndex->foreColor, x, y, fastIndex->bkLeft,
|
||||
fastIndex->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE))
|
||||
goto fail;
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL update_gdi_fast_glyph(rdpContext* context, const FAST_GLYPH_ORDER* fastGlyph)
|
||||
{
|
||||
INT32 x = 0;
|
||||
INT32 y = 0;
|
||||
BYTE text_data[4] = WINPR_C_ARRAY_INIT;
|
||||
INT32 opLeft = 0;
|
||||
INT32 opTop = 0;
|
||||
INT32 opRight = 0;
|
||||
INT32 opBottom = 0;
|
||||
INT32 opWidth = 0;
|
||||
INT32 opHeight = 0;
|
||||
INT32 bkWidth = 0;
|
||||
INT32 bkHeight = 0;
|
||||
rdpCache* cache = nullptr;
|
||||
|
||||
if (!context || !fastGlyph || !context->cache)
|
||||
return FALSE;
|
||||
|
||||
cache = context->cache;
|
||||
opLeft = fastGlyph->opLeft;
|
||||
opTop = fastGlyph->opTop;
|
||||
opRight = fastGlyph->opRight;
|
||||
opBottom = fastGlyph->opBottom;
|
||||
x = fastGlyph->x;
|
||||
y = fastGlyph->y;
|
||||
|
||||
if (opBottom == -32768)
|
||||
{
|
||||
BYTE flags = (BYTE)(opTop & 0x0F);
|
||||
|
||||
if (flags & 0x01)
|
||||
opBottom = fastGlyph->bkBottom;
|
||||
|
||||
if (flags & 0x02)
|
||||
opRight = fastGlyph->bkRight;
|
||||
|
||||
if (flags & 0x04)
|
||||
opTop = fastGlyph->bkTop;
|
||||
|
||||
if (flags & 0x08)
|
||||
opLeft = fastGlyph->bkLeft;
|
||||
}
|
||||
|
||||
if (opLeft == 0)
|
||||
opLeft = fastGlyph->bkLeft;
|
||||
|
||||
if (opRight == 0)
|
||||
opRight = fastGlyph->bkRight;
|
||||
|
||||
/* See update_gdi_fast_index opRight comment. */
|
||||
if (opRight > (INT64)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth))
|
||||
opRight = (int)freerdp_settings_get_uint32(context->settings, FreeRDP_DesktopWidth);
|
||||
|
||||
if (x == -32768)
|
||||
x = fastGlyph->bkLeft;
|
||||
|
||||
if (y == -32768)
|
||||
y = fastGlyph->bkTop;
|
||||
|
||||
if ((fastGlyph->cbData > 1) && (fastGlyph->glyphData.aj))
|
||||
{
|
||||
/* got option font that needs to go into cache */
|
||||
rdpGlyph* glyph = nullptr;
|
||||
const GLYPH_DATA_V2* glyphData = &fastGlyph->glyphData;
|
||||
|
||||
glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx, glyphData->cy,
|
||||
glyphData->cb, glyphData->aj);
|
||||
|
||||
if (!glyph)
|
||||
return FALSE;
|
||||
|
||||
if (!glyph_cache_put(cache->glyph, fastGlyph->cacheId, fastGlyph->data[0], glyph))
|
||||
{
|
||||
glyph->Free(context, glyph);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
text_data[0] = fastGlyph->data[0];
|
||||
text_data[1] = 0;
|
||||
|
||||
if (fastGlyph->bkRight > fastGlyph->bkLeft)
|
||||
bkWidth = fastGlyph->bkRight - fastGlyph->bkLeft + 1;
|
||||
|
||||
if (fastGlyph->bkBottom > fastGlyph->bkTop)
|
||||
bkHeight = fastGlyph->bkBottom - fastGlyph->bkTop + 1;
|
||||
|
||||
if (opRight > opLeft)
|
||||
opWidth = opRight - opLeft + 1;
|
||||
|
||||
if (opBottom > opTop)
|
||||
opHeight = opBottom - opTop + 1;
|
||||
|
||||
return update_process_glyph_fragments(
|
||||
context, text_data, sizeof(text_data), fastGlyph->cacheId, fastGlyph->ulCharInc,
|
||||
fastGlyph->flAccel, fastGlyph->backColor, fastGlyph->foreColor, x, y, fastGlyph->bkLeft,
|
||||
fastGlyph->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE);
|
||||
}
|
||||
|
||||
static BOOL update_gdi_cache_glyph(rdpContext* context, const CACHE_GLYPH_ORDER* cacheGlyph)
|
||||
{
|
||||
if (!context || !cacheGlyph || !context->cache)
|
||||
return FALSE;
|
||||
|
||||
rdpCache* cache = context->cache;
|
||||
|
||||
for (size_t i = 0; i < cacheGlyph->cGlyphs; i++)
|
||||
{
|
||||
const GLYPH_DATA* glyph_data = &cacheGlyph->glyphData[i];
|
||||
rdpGlyph* glyph = Glyph_Alloc(context, glyph_data->x, glyph_data->y, glyph_data->cx,
|
||||
glyph_data->cy, glyph_data->cb, glyph_data->aj);
|
||||
if (!glyph)
|
||||
return FALSE;
|
||||
|
||||
if (!glyph_cache_put(cache->glyph, cacheGlyph->cacheId, glyph_data->cacheIndex, glyph))
|
||||
{
|
||||
glyph->Free(context, glyph);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL update_gdi_cache_glyph_v2(rdpContext* context, const CACHE_GLYPH_V2_ORDER* cacheGlyphV2)
|
||||
{
|
||||
if (!context || !cacheGlyphV2 || !context->cache)
|
||||
return FALSE;
|
||||
|
||||
rdpCache* cache = context->cache;
|
||||
|
||||
for (size_t i = 0; i < cacheGlyphV2->cGlyphs; i++)
|
||||
{
|
||||
const GLYPH_DATA_V2* glyphData = &cacheGlyphV2->glyphData[i];
|
||||
rdpGlyph* glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx,
|
||||
glyphData->cy, glyphData->cb, glyphData->aj);
|
||||
|
||||
if (!glyph)
|
||||
return FALSE;
|
||||
|
||||
if (!glyph_cache_put(cache->glyph, cacheGlyphV2->cacheId, glyphData->cacheIndex, glyph))
|
||||
{
|
||||
glyph->Free(context, glyph);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
rdpGlyph* glyph_cache_get(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index)
|
||||
{
|
||||
WINPR_ASSERT(glyphCache);
|
||||
|
||||
WLog_Print(glyphCache->log, WLOG_DEBUG, "GlyphCacheGet: id: %" PRIu32 " index: %" PRIu32 "", id,
|
||||
index);
|
||||
|
||||
if (id >= ARRAYSIZE(glyphCache->glyphCache))
|
||||
{
|
||||
WLog_ERR(TAG, "invalid glyph cache id: %" PRIu32 "", id);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GLYPH_CACHE* cache = &glyphCache->glyphCache[id];
|
||||
if (index > cache->number)
|
||||
{
|
||||
WLog_ERR(TAG, "index %" PRIu32 " out of range for cache id: %" PRIu32 "", index, id);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rdpGlyph* glyph = cache->entries[index];
|
||||
if (!glyph)
|
||||
WLog_ERR(TAG, "no glyph found at cache index: %" PRIu32 " in cache id: %" PRIu32 "", index,
|
||||
id);
|
||||
|
||||
return glyph;
|
||||
}
|
||||
|
||||
BOOL glyph_cache_put(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index, rdpGlyph* glyph)
|
||||
{
|
||||
WINPR_ASSERT(glyphCache);
|
||||
|
||||
if (id >= ARRAYSIZE(glyphCache->glyphCache))
|
||||
{
|
||||
WLog_ERR(TAG, "invalid glyph cache id: %" PRIu32 "", id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GLYPH_CACHE* cache = &glyphCache->glyphCache[id];
|
||||
if (index >= cache->number)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid glyph cache index: %" PRIu32 " in cache id: %" PRIu32 "", index, id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
WLog_Print(glyphCache->log, WLOG_DEBUG, "GlyphCachePut: id: %" PRIu32 " index: %" PRIu32 "", id,
|
||||
index);
|
||||
rdpGlyph* prevGlyph = cache->entries[index];
|
||||
|
||||
if (prevGlyph)
|
||||
{
|
||||
WINPR_ASSERT(prevGlyph->Free);
|
||||
prevGlyph->Free(glyphCache->context, prevGlyph);
|
||||
}
|
||||
|
||||
cache->entries[index] = glyph;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
const void* glyph_cache_fragment_get(rdpGlyphCache* glyphCache, UINT32 index, UINT32* size)
|
||||
{
|
||||
void* fragment = nullptr;
|
||||
|
||||
WINPR_ASSERT(glyphCache);
|
||||
WINPR_ASSERT(glyphCache->fragCache.entries);
|
||||
|
||||
if (index > 255)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid glyph cache fragment index: %" PRIu32 "", index);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fragment = glyphCache->fragCache.entries[index].fragment;
|
||||
*size = (BYTE)glyphCache->fragCache.entries[index].size;
|
||||
WLog_Print(glyphCache->log, WLOG_DEBUG,
|
||||
"GlyphCacheFragmentGet: index: %" PRIu32 " size: %" PRIu32 "", index, *size);
|
||||
|
||||
if (!fragment)
|
||||
WLog_ERR(TAG, "invalid glyph fragment at index:%" PRIu32 "", index);
|
||||
|
||||
return fragment;
|
||||
}
|
||||
|
||||
BOOL glyph_cache_fragment_put(rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
|
||||
const void* fragment)
|
||||
{
|
||||
WINPR_ASSERT(glyphCache);
|
||||
WINPR_ASSERT(glyphCache->fragCache.entries);
|
||||
|
||||
if (index > 255)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid glyph cache fragment index: %" PRIu32 "", index);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (size == 0)
|
||||
return FALSE;
|
||||
|
||||
void* copy = malloc(size);
|
||||
|
||||
if (!copy)
|
||||
return FALSE;
|
||||
|
||||
WLog_Print(glyphCache->log, WLOG_DEBUG,
|
||||
"GlyphCacheFragmentPut: index: %" PRIu32 " size: %" PRIu32 "", index, size);
|
||||
CopyMemory(copy, fragment, size);
|
||||
|
||||
void* prevFragment = glyphCache->fragCache.entries[index].fragment;
|
||||
glyphCache->fragCache.entries[index].fragment = copy;
|
||||
glyphCache->fragCache.entries[index].size = size;
|
||||
free(prevFragment);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void glyph_cache_register_callbacks(rdpUpdate* update)
|
||||
{
|
||||
WINPR_ASSERT(update);
|
||||
WINPR_ASSERT(update->context);
|
||||
WINPR_ASSERT(update->primary);
|
||||
WINPR_ASSERT(update->secondary);
|
||||
|
||||
if (!freerdp_settings_get_bool(update->context->settings, FreeRDP_DeactivateClientDecoding))
|
||||
{
|
||||
update->primary->GlyphIndex = update_gdi_glyph_index;
|
||||
update->primary->FastIndex = update_gdi_fast_index;
|
||||
update->primary->FastGlyph = update_gdi_fast_glyph;
|
||||
update->secondary->CacheGlyph = update_gdi_cache_glyph;
|
||||
update->secondary->CacheGlyphV2 = update_gdi_cache_glyph_v2;
|
||||
}
|
||||
}
|
||||
|
||||
rdpGlyphCache* glyph_cache_new(rdpContext* context)
|
||||
{
|
||||
rdpGlyphCache* glyphCache = nullptr;
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
settings = context->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
glyphCache = (rdpGlyphCache*)calloc(1, sizeof(rdpGlyphCache));
|
||||
|
||||
if (!glyphCache)
|
||||
return nullptr;
|
||||
|
||||
glyphCache->log = WLog_Get("com.freerdp.cache.glyph");
|
||||
glyphCache->context = context;
|
||||
|
||||
for (size_t i = 0; i < 10; i++)
|
||||
{
|
||||
const GLYPH_CACHE_DEFINITION* currentGlyph =
|
||||
freerdp_settings_get_pointer_array(settings, FreeRDP_GlyphCache, i);
|
||||
GLYPH_CACHE* currentCache = &glyphCache->glyphCache[i];
|
||||
currentCache->number = currentGlyph->cacheEntries;
|
||||
currentCache->maxCellSize = currentGlyph->cacheMaximumCellSize;
|
||||
currentCache->entries = (rdpGlyph**)calloc(currentCache->number, sizeof(rdpGlyph*));
|
||||
|
||||
if (!currentCache->entries)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return glyphCache;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
glyph_cache_free(glyphCache);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void glyph_cache_free(rdpGlyphCache* glyphCache)
|
||||
{
|
||||
if (glyphCache)
|
||||
{
|
||||
GLYPH_CACHE* cache = glyphCache->glyphCache;
|
||||
|
||||
for (size_t i = 0; i < 10; i++)
|
||||
{
|
||||
rdpGlyph** entries = cache[i].entries;
|
||||
|
||||
if (!entries)
|
||||
continue;
|
||||
|
||||
for (size_t j = 0; j < cache[i].number; j++)
|
||||
{
|
||||
rdpGlyph* glyph = entries[j];
|
||||
|
||||
if (glyph)
|
||||
{
|
||||
glyph->Free(glyphCache->context, glyph);
|
||||
entries[j] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
free((void*)entries);
|
||||
cache[i].entries = nullptr;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ARRAYSIZE(glyphCache->fragCache.entries); i++)
|
||||
{
|
||||
free(glyphCache->fragCache.entries[i].fragment);
|
||||
glyphCache->fragCache.entries[i].fragment = nullptr;
|
||||
}
|
||||
|
||||
free(glyphCache);
|
||||
}
|
||||
}
|
||||
|
||||
CACHE_GLYPH_ORDER* copy_cache_glyph_order(rdpContext* context, const CACHE_GLYPH_ORDER* glyph)
|
||||
{
|
||||
CACHE_GLYPH_ORDER* dst = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
dst = calloc(1, sizeof(CACHE_GLYPH_ORDER));
|
||||
|
||||
if (!dst || !glyph)
|
||||
goto fail;
|
||||
|
||||
*dst = *glyph;
|
||||
|
||||
for (size_t x = 0; x < glyph->cGlyphs; x++)
|
||||
{
|
||||
const GLYPH_DATA* src = &glyph->glyphData[x];
|
||||
GLYPH_DATA* data = &dst->glyphData[x];
|
||||
|
||||
if (src->aj)
|
||||
{
|
||||
const size_t size = src->cb;
|
||||
data->aj = malloc(size);
|
||||
|
||||
if (!data->aj)
|
||||
goto fail;
|
||||
|
||||
memcpy(data->aj, src->aj, size);
|
||||
}
|
||||
}
|
||||
|
||||
if (glyph->unicodeCharacters)
|
||||
{
|
||||
if (glyph->cGlyphs == 0)
|
||||
goto fail;
|
||||
|
||||
dst->unicodeCharacters = calloc(glyph->cGlyphs, sizeof(WCHAR));
|
||||
|
||||
if (!dst->unicodeCharacters)
|
||||
goto fail;
|
||||
|
||||
memcpy(dst->unicodeCharacters, glyph->unicodeCharacters, sizeof(WCHAR) * glyph->cGlyphs);
|
||||
}
|
||||
|
||||
return dst;
|
||||
fail:
|
||||
free_cache_glyph_order(context, dst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void free_cache_glyph_order(WINPR_ATTR_UNUSED rdpContext* context, CACHE_GLYPH_ORDER* glyph)
|
||||
{
|
||||
if (glyph)
|
||||
{
|
||||
for (size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
|
||||
free(glyph->glyphData[x].aj);
|
||||
|
||||
free(glyph->unicodeCharacters);
|
||||
}
|
||||
|
||||
free(glyph);
|
||||
}
|
||||
|
||||
CACHE_GLYPH_V2_ORDER* copy_cache_glyph_v2_order(rdpContext* context,
|
||||
const CACHE_GLYPH_V2_ORDER* glyph)
|
||||
{
|
||||
CACHE_GLYPH_V2_ORDER* dst = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
dst = calloc(1, sizeof(CACHE_GLYPH_V2_ORDER));
|
||||
|
||||
if (!dst || !glyph)
|
||||
goto fail;
|
||||
|
||||
*dst = *glyph;
|
||||
|
||||
for (size_t x = 0; x < glyph->cGlyphs; x++)
|
||||
{
|
||||
const GLYPH_DATA_V2* src = &glyph->glyphData[x];
|
||||
GLYPH_DATA_V2* data = &dst->glyphData[x];
|
||||
|
||||
if (src->aj)
|
||||
{
|
||||
const size_t size = src->cb;
|
||||
data->aj = malloc(size);
|
||||
|
||||
if (!data->aj)
|
||||
goto fail;
|
||||
|
||||
memcpy(data->aj, src->aj, size);
|
||||
}
|
||||
}
|
||||
|
||||
if (glyph->unicodeCharacters)
|
||||
{
|
||||
if (glyph->cGlyphs == 0)
|
||||
goto fail;
|
||||
|
||||
dst->unicodeCharacters = calloc(glyph->cGlyphs, sizeof(WCHAR));
|
||||
|
||||
if (!dst->unicodeCharacters)
|
||||
goto fail;
|
||||
|
||||
memcpy(dst->unicodeCharacters, glyph->unicodeCharacters, sizeof(WCHAR) * glyph->cGlyphs);
|
||||
}
|
||||
|
||||
return dst;
|
||||
fail:
|
||||
free_cache_glyph_v2_order(context, dst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void free_cache_glyph_v2_order(WINPR_ATTR_UNUSED rdpContext* context, CACHE_GLYPH_V2_ORDER* glyph)
|
||||
{
|
||||
if (glyph)
|
||||
{
|
||||
for (size_t x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
|
||||
free(glyph->glyphData[x].aj);
|
||||
|
||||
free(glyph->unicodeCharacters);
|
||||
}
|
||||
|
||||
free(glyph);
|
||||
}
|
||||
85
third_party/FreeRDP/libfreerdp/cache/glyph.h
vendored
Normal file
85
third_party/FreeRDP/libfreerdp/cache/glyph.h
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2018 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_LIB_CACHE_GLYPH_H
|
||||
#define FREERDP_LIB_CACHE_GLYPH_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/pointer.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT32 number;
|
||||
UINT32 maxCellSize;
|
||||
rdpGlyph** entries;
|
||||
} GLYPH_CACHE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* fragment;
|
||||
UINT32 size;
|
||||
} FRAGMENT_CACHE_ENTRY;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FRAGMENT_CACHE_ENTRY entries[256];
|
||||
} FRAGMENT_CACHE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FRAGMENT_CACHE fragCache;
|
||||
GLYPH_CACHE glyphCache[10];
|
||||
|
||||
wLog* log;
|
||||
rdpContext* context;
|
||||
} rdpGlyphCache;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
FREERDP_LOCAL void glyph_cache_register_callbacks(rdpUpdate* update);
|
||||
|
||||
FREERDP_LOCAL void glyph_cache_free(rdpGlyphCache* glyph);
|
||||
|
||||
WINPR_ATTR_MALLOC(glyph_cache_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL rdpGlyphCache* glyph_cache_new(rdpContext* context);
|
||||
|
||||
FREERDP_LOCAL void free_cache_glyph_order(rdpContext* context, CACHE_GLYPH_ORDER* glyph);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_cache_glyph_order, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL CACHE_GLYPH_ORDER* copy_cache_glyph_order(rdpContext* context,
|
||||
const CACHE_GLYPH_ORDER* glyph);
|
||||
|
||||
FREERDP_LOCAL void free_cache_glyph_v2_order(rdpContext* context, CACHE_GLYPH_V2_ORDER* glyph);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_cache_glyph_v2_order, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL CACHE_GLYPH_V2_ORDER*
|
||||
copy_cache_glyph_v2_order(rdpContext* context, const CACHE_GLYPH_V2_ORDER* glyph);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_LIB_CACHE_GLYPH_H */
|
||||
130
third_party/FreeRDP/libfreerdp/cache/nine_grid.c
vendored
Normal file
130
third_party/FreeRDP/libfreerdp/cache/nine_grid.c
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* NineGrid Cache
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <freerdp/update.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include "nine_grid.h"
|
||||
#include "cache.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* entry;
|
||||
} NINE_GRID_ENTRY;
|
||||
|
||||
struct rdp_nine_grid_cache
|
||||
{
|
||||
pDrawNineGrid DrawNineGrid; /* 0 */
|
||||
pMultiDrawNineGrid MultiDrawNineGrid; /* 1 */
|
||||
UINT32 paddingA[16 - 2]; /* 2 */
|
||||
|
||||
UINT32 maxEntries; /* 16 */
|
||||
UINT32 maxSize; /* 17 */
|
||||
NINE_GRID_ENTRY* entries; /* 18 */
|
||||
UINT32 paddingB[32 - 19]; /* 19 */
|
||||
|
||||
rdpContext* context;
|
||||
};
|
||||
|
||||
static BOOL update_gdi_draw_nine_grid(rdpContext* context,
|
||||
const DRAW_NINE_GRID_ORDER* draw_nine_grid)
|
||||
{
|
||||
rdpCache* cache = context->cache;
|
||||
return IFCALLRESULT(TRUE, cache->nine_grid->DrawNineGrid, context, draw_nine_grid);
|
||||
}
|
||||
|
||||
static BOOL update_gdi_multi_draw_nine_grid(rdpContext* context,
|
||||
const MULTI_DRAW_NINE_GRID_ORDER* multi_draw_nine_grid)
|
||||
{
|
||||
rdpCache* cache = context->cache;
|
||||
return IFCALLRESULT(TRUE, cache->nine_grid->MultiDrawNineGrid, context, multi_draw_nine_grid);
|
||||
}
|
||||
|
||||
void nine_grid_cache_register_callbacks(rdpUpdate* update)
|
||||
{
|
||||
rdpCache* cache = update->context->cache;
|
||||
|
||||
cache->nine_grid->DrawNineGrid = update->primary->DrawNineGrid;
|
||||
cache->nine_grid->MultiDrawNineGrid = update->primary->MultiDrawNineGrid;
|
||||
|
||||
update->primary->DrawNineGrid = update_gdi_draw_nine_grid;
|
||||
update->primary->MultiDrawNineGrid = update_gdi_multi_draw_nine_grid;
|
||||
}
|
||||
|
||||
rdpNineGridCache* nine_grid_cache_new(rdpContext* context)
|
||||
{
|
||||
rdpNineGridCache* nine_grid = nullptr;
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
settings = context->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
nine_grid = (rdpNineGridCache*)calloc(1, sizeof(rdpNineGridCache));
|
||||
if (!nine_grid)
|
||||
return nullptr;
|
||||
|
||||
nine_grid->context = context;
|
||||
|
||||
nine_grid->maxSize = 2560;
|
||||
nine_grid->maxEntries = 256;
|
||||
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_DrawNineGridCacheSize, nine_grid->maxSize))
|
||||
goto fail;
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_DrawNineGridCacheEntries,
|
||||
nine_grid->maxEntries))
|
||||
goto fail;
|
||||
|
||||
nine_grid->entries = (NINE_GRID_ENTRY*)calloc(nine_grid->maxEntries, sizeof(NINE_GRID_ENTRY));
|
||||
if (!nine_grid->entries)
|
||||
goto fail;
|
||||
|
||||
return nine_grid;
|
||||
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
nine_grid_cache_free(nine_grid);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void nine_grid_cache_free(rdpNineGridCache* nine_grid)
|
||||
{
|
||||
if (nine_grid != nullptr)
|
||||
{
|
||||
if (nine_grid->entries != nullptr)
|
||||
{
|
||||
for (size_t i = 0; i < nine_grid->maxEntries; i++)
|
||||
free(nine_grid->entries[i].entry);
|
||||
|
||||
free(nine_grid->entries);
|
||||
}
|
||||
|
||||
free(nine_grid);
|
||||
}
|
||||
}
|
||||
51
third_party/FreeRDP/libfreerdp/cache/nine_grid.h
vendored
Normal file
51
third_party/FreeRDP/libfreerdp/cache/nine_grid.h
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* NineGrid Cache
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_LIB_NINE_GRID_CACHE_H
|
||||
#define FREERDP_LIB_NINE_GRID_CACHE_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/update.h>
|
||||
|
||||
#include <winpr/stream.h>
|
||||
|
||||
typedef struct rdp_nine_grid_cache rdpNineGridCache;
|
||||
|
||||
#include "nine_grid.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
FREERDP_LOCAL void nine_grid_cache_register_callbacks(rdpUpdate* update);
|
||||
|
||||
FREERDP_LOCAL void nine_grid_cache_free(rdpNineGridCache* nine_grid);
|
||||
|
||||
WINPR_ATTR_MALLOC(nine_grid_cache_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL rdpNineGridCache* nine_grid_cache_new(rdpContext* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_LIB_NINE_GRID_CACHE_H */
|
||||
255
third_party/FreeRDP/libfreerdp/cache/offscreen.c
vendored
Normal file
255
third_party/FreeRDP/libfreerdp/cache/offscreen.c
vendored
Normal file
@@ -0,0 +1,255 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Offscreen Bitmap Cache
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/cast.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#include "../core/graphics.h"
|
||||
|
||||
#include "offscreen.h"
|
||||
#include "cache.h"
|
||||
|
||||
#define TAG FREERDP_TAG("cache.offscreen")
|
||||
|
||||
struct rdp_offscreen_cache
|
||||
{
|
||||
UINT32 maxSize; /* 0 */
|
||||
UINT32 maxEntries; /* 1 */
|
||||
rdpBitmap** entries; /* 2 */
|
||||
UINT32 currentSurface; /* 3 */
|
||||
|
||||
rdpContext* context;
|
||||
};
|
||||
|
||||
static void offscreen_cache_put(rdpOffscreenCache* offscreenCache, UINT32 index, rdpBitmap* bitmap);
|
||||
static void offscreen_cache_delete(rdpOffscreenCache* offscreen, UINT32 index);
|
||||
|
||||
static BOOL
|
||||
update_gdi_create_offscreen_bitmap(rdpContext* context,
|
||||
const CREATE_OFFSCREEN_BITMAP_ORDER* createOffscreenBitmap)
|
||||
{
|
||||
if (!context || !createOffscreenBitmap || !context->cache)
|
||||
return FALSE;
|
||||
|
||||
rdpCache* cache = context->cache;
|
||||
rdpBitmap* bitmap = Bitmap_Alloc(context);
|
||||
|
||||
if (!bitmap)
|
||||
return FALSE;
|
||||
|
||||
if (!Bitmap_SetDimensions(bitmap, WINPR_ASSERTING_INT_CAST(UINT16, createOffscreenBitmap->cx),
|
||||
WINPR_ASSERTING_INT_CAST(UINT16, createOffscreenBitmap->cy)))
|
||||
{
|
||||
Bitmap_Free(context, bitmap);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!bitmap->New(context, bitmap))
|
||||
{
|
||||
Bitmap_Free(context, bitmap);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
offscreen_cache_delete(cache->offscreen, createOffscreenBitmap->id);
|
||||
offscreen_cache_put(cache->offscreen, createOffscreenBitmap->id, bitmap);
|
||||
|
||||
if (cache->offscreen->currentSurface == createOffscreenBitmap->id)
|
||||
{
|
||||
if (!bitmap->SetSurface(context, bitmap, FALSE))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (UINT32 i = 0; i < createOffscreenBitmap->deleteList.cIndices; i++)
|
||||
{
|
||||
const UINT16 index = createOffscreenBitmap->deleteList.indices[i];
|
||||
offscreen_cache_delete(cache->offscreen, index);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL update_gdi_switch_surface(rdpContext* context,
|
||||
const SWITCH_SURFACE_ORDER* switchSurface)
|
||||
{
|
||||
if (!context || !context->cache || !switchSurface || !context->graphics)
|
||||
return FALSE;
|
||||
|
||||
rdpCache* cache = context->cache;
|
||||
rdpBitmap* bitmap = context->graphics->Bitmap_Prototype;
|
||||
if (!bitmap)
|
||||
return FALSE;
|
||||
|
||||
if (switchSurface->bitmapId == SCREEN_BITMAP_SURFACE)
|
||||
{
|
||||
if (!bitmap->SetSurface(context, nullptr, TRUE))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
rdpBitmap* bmp = nullptr;
|
||||
bmp = offscreen_cache_get(cache->offscreen, switchSurface->bitmapId);
|
||||
if (bmp == nullptr)
|
||||
return FALSE;
|
||||
|
||||
if (!bitmap->SetSurface(context, bmp, FALSE))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
cache->offscreen->currentSurface = switchSurface->bitmapId;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
rdpBitmap* offscreen_cache_get(rdpOffscreenCache* offscreenCache, UINT32 index)
|
||||
{
|
||||
rdpBitmap* bitmap = nullptr;
|
||||
|
||||
WINPR_ASSERT(offscreenCache);
|
||||
|
||||
if (index >= offscreenCache->maxEntries)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid offscreen bitmap index: 0x%08" PRIX32 "", index);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bitmap = offscreenCache->entries[index];
|
||||
|
||||
if (!bitmap)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid offscreen bitmap at index: 0x%08" PRIX32 "", index);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
void offscreen_cache_put(rdpOffscreenCache* offscreenCache, UINT32 index, rdpBitmap* bitmap)
|
||||
{
|
||||
WINPR_ASSERT(offscreenCache);
|
||||
|
||||
if (index >= offscreenCache->maxEntries)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid offscreen bitmap index: 0x%08" PRIX32 "", index);
|
||||
return;
|
||||
}
|
||||
|
||||
offscreen_cache_delete(offscreenCache, index);
|
||||
offscreenCache->entries[index] = bitmap;
|
||||
}
|
||||
|
||||
void offscreen_cache_delete(rdpOffscreenCache* offscreenCache, UINT32 index)
|
||||
{
|
||||
WINPR_ASSERT(offscreenCache);
|
||||
|
||||
if (index >= offscreenCache->maxEntries)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid offscreen bitmap index (delete): 0x%08" PRIX32 "", index);
|
||||
return;
|
||||
}
|
||||
|
||||
rdpBitmap* prevBitmap = offscreenCache->entries[index];
|
||||
|
||||
if (prevBitmap != nullptr)
|
||||
{
|
||||
WINPR_ASSERT(offscreenCache->context);
|
||||
|
||||
/* Ensure that the bitmap is no longer used in GDI */
|
||||
if (prevBitmap->SetSurface)
|
||||
{
|
||||
if (!prevBitmap->SetSurface(offscreenCache->context, nullptr, FALSE))
|
||||
WLog_WARN(TAG, "prevBitmap->SetSurface failed");
|
||||
}
|
||||
|
||||
Bitmap_Free(offscreenCache->context, prevBitmap);
|
||||
}
|
||||
|
||||
offscreenCache->entries[index] = nullptr;
|
||||
}
|
||||
|
||||
void offscreen_cache_register_callbacks(rdpUpdate* update)
|
||||
{
|
||||
WINPR_ASSERT(update);
|
||||
WINPR_ASSERT(update->altsec);
|
||||
|
||||
update->altsec->CreateOffscreenBitmap = update_gdi_create_offscreen_bitmap;
|
||||
update->altsec->SwitchSurface = update_gdi_switch_surface;
|
||||
}
|
||||
|
||||
rdpOffscreenCache* offscreen_cache_new(rdpContext* context)
|
||||
{
|
||||
rdpOffscreenCache* offscreenCache = nullptr;
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
settings = context->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
offscreenCache = (rdpOffscreenCache*)calloc(1, sizeof(rdpOffscreenCache));
|
||||
|
||||
if (!offscreenCache)
|
||||
return nullptr;
|
||||
|
||||
offscreenCache->context = context;
|
||||
offscreenCache->currentSurface = SCREEN_BITMAP_SURFACE;
|
||||
offscreenCache->maxSize = 7680;
|
||||
offscreenCache->maxEntries = 2000;
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_OffscreenCacheSize, offscreenCache->maxSize))
|
||||
goto fail;
|
||||
if (!freerdp_settings_set_uint32(settings, FreeRDP_OffscreenCacheEntries,
|
||||
offscreenCache->maxEntries))
|
||||
goto fail;
|
||||
offscreenCache->entries = (rdpBitmap**)calloc(offscreenCache->maxEntries, sizeof(rdpBitmap*));
|
||||
|
||||
if (!offscreenCache->entries)
|
||||
goto fail;
|
||||
|
||||
return offscreenCache;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
offscreen_cache_free(offscreenCache);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void offscreen_cache_free(rdpOffscreenCache* offscreenCache)
|
||||
{
|
||||
if (offscreenCache)
|
||||
{
|
||||
if (offscreenCache->entries)
|
||||
{
|
||||
for (size_t i = 0; i < offscreenCache->maxEntries; i++)
|
||||
{
|
||||
rdpBitmap* bitmap = offscreenCache->entries[i];
|
||||
Bitmap_Free(offscreenCache->context, bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
free((void*)offscreenCache->entries);
|
||||
free(offscreenCache);
|
||||
}
|
||||
}
|
||||
52
third_party/FreeRDP/libfreerdp/cache/offscreen.h
vendored
Normal file
52
third_party/FreeRDP/libfreerdp/cache/offscreen.h
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Offscreen Bitmap Cache
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_LIB_OFFSCREEN_CACHE_H
|
||||
#define FREERDP_LIB_OFFSCREEN_CACHE_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/update.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
|
||||
#include <winpr/stream.h>
|
||||
|
||||
typedef struct rdp_offscreen_cache rdpOffscreenCache;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL rdpBitmap* offscreen_cache_get(rdpOffscreenCache* offscreenCache, UINT32 index);
|
||||
|
||||
FREERDP_LOCAL void offscreen_cache_register_callbacks(rdpUpdate* update);
|
||||
|
||||
FREERDP_LOCAL void offscreen_cache_free(rdpOffscreenCache* offscreen);
|
||||
|
||||
WINPR_ATTR_MALLOC(offscreen_cache_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL rdpOffscreenCache* offscreen_cache_new(rdpContext* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_LIB_OFFSCREEN_CACHE_H */
|
||||
121
third_party/FreeRDP/libfreerdp/cache/palette.c
vendored
Normal file
121
third_party/FreeRDP/libfreerdp/cache/palette.c
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Palette (Color Table) Cache
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#include "palette.h"
|
||||
#include "cache.h"
|
||||
|
||||
#define TAG FREERDP_TAG("cache.palette")
|
||||
|
||||
static void palette_cache_put(rdpPaletteCache* palette, UINT32 index, void* entry);
|
||||
|
||||
static BOOL update_gdi_cache_color_table(rdpContext* context,
|
||||
const CACHE_COLOR_TABLE_ORDER* cacheColorTable)
|
||||
{
|
||||
UINT32* colorTable = nullptr;
|
||||
rdpCache* cache = context->cache;
|
||||
colorTable = (UINT32*)malloc(sizeof(UINT32) * 256);
|
||||
|
||||
if (!colorTable)
|
||||
return FALSE;
|
||||
|
||||
CopyMemory(colorTable, cacheColorTable->colorTable, sizeof(UINT32) * 256);
|
||||
palette_cache_put(cache->palette, cacheColorTable->cacheIndex, (void*)colorTable);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void palette_cache_put(rdpPaletteCache* paletteCache, UINT32 index, void* entry)
|
||||
{
|
||||
if (index >= paletteCache->maxEntries)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid color table index: 0x%08" PRIX32 "", index);
|
||||
free(entry);
|
||||
return;
|
||||
}
|
||||
|
||||
free(paletteCache->entries[index].entry);
|
||||
paletteCache->entries[index].entry = entry;
|
||||
}
|
||||
|
||||
void palette_cache_register_callbacks(rdpUpdate* update)
|
||||
{
|
||||
WINPR_ASSERT(update);
|
||||
WINPR_ASSERT(update->secondary);
|
||||
update->secondary->CacheColorTable = update_gdi_cache_color_table;
|
||||
}
|
||||
|
||||
rdpPaletteCache* palette_cache_new(rdpContext* context)
|
||||
{
|
||||
rdpPaletteCache* paletteCache = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
paletteCache = (rdpPaletteCache*)calloc(1, sizeof(rdpPaletteCache));
|
||||
|
||||
if (paletteCache)
|
||||
{
|
||||
paletteCache->context = context;
|
||||
paletteCache->maxEntries = 6;
|
||||
paletteCache->entries =
|
||||
(PALETTE_TABLE_ENTRY*)calloc(paletteCache->maxEntries, sizeof(PALETTE_TABLE_ENTRY));
|
||||
}
|
||||
|
||||
return paletteCache;
|
||||
}
|
||||
|
||||
void palette_cache_free(rdpPaletteCache* paletteCache)
|
||||
{
|
||||
if (paletteCache)
|
||||
{
|
||||
for (UINT32 i = 0; i < paletteCache->maxEntries; i++)
|
||||
free(paletteCache->entries[i].entry);
|
||||
|
||||
free(paletteCache->entries);
|
||||
free(paletteCache);
|
||||
}
|
||||
}
|
||||
|
||||
void free_palette_update(WINPR_ATTR_UNUSED rdpContext* context, PALETTE_UPDATE* pointer)
|
||||
{
|
||||
free(pointer);
|
||||
}
|
||||
|
||||
PALETTE_UPDATE* copy_palette_update(rdpContext* context, const PALETTE_UPDATE* pointer)
|
||||
{
|
||||
PALETTE_UPDATE* dst = calloc(1, sizeof(PALETTE_UPDATE));
|
||||
|
||||
if (!dst || !pointer)
|
||||
goto fail;
|
||||
|
||||
*dst = *pointer;
|
||||
return dst;
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
free_palette_update(context, dst);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
67
third_party/FreeRDP/libfreerdp/cache/palette.h
vendored
Normal file
67
third_party/FreeRDP/libfreerdp/cache/palette.h
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2018 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_LIB_CACHE_PALETTE_H
|
||||
#define FREERDP_LIB_CACHE_PALETTE_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/update.h>
|
||||
|
||||
typedef struct rdp_palette_cache rdpPaletteCache;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* entry;
|
||||
} PALETTE_TABLE_ENTRY;
|
||||
|
||||
struct rdp_palette_cache
|
||||
{
|
||||
UINT32 maxEntries; /* 0 */
|
||||
PALETTE_TABLE_ENTRY* entries; /* 1 */
|
||||
|
||||
/* internal */
|
||||
|
||||
rdpContext* context;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
FREERDP_LOCAL void palette_cache_register_callbacks(rdpUpdate* update);
|
||||
|
||||
FREERDP_LOCAL void palette_cache_free(rdpPaletteCache* paletteCache);
|
||||
|
||||
WINPR_ATTR_MALLOC(palette_cache_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL rdpPaletteCache* palette_cache_new(rdpContext* context);
|
||||
|
||||
FREERDP_LOCAL void free_palette_update(rdpContext* context, PALETTE_UPDATE* pointer);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_palette_update, 2)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL PALETTE_UPDATE* copy_palette_update(rdpContext* context,
|
||||
const PALETTE_UPDATE* pointer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_LIB_CACHE_PALETTE_H */
|
||||
376
third_party/FreeRDP/libfreerdp/cache/persistent.c
vendored
Normal file
376
third_party/FreeRDP/libfreerdp/cache/persistent.c
vendored
Normal file
@@ -0,0 +1,376 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Persistent Bitmap Cache
|
||||
*
|
||||
* Copyright 2016 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/constants.h>
|
||||
|
||||
#include <freerdp/cache/persistent.h>
|
||||
|
||||
struct rdp_persistent_cache
|
||||
{
|
||||
FILE* fp;
|
||||
BOOL write;
|
||||
int version;
|
||||
int count;
|
||||
char* filename;
|
||||
BYTE* bmpData;
|
||||
UINT32 bmpSize;
|
||||
};
|
||||
|
||||
static const char sig_str[] = "RDP8bmp";
|
||||
|
||||
int persistent_cache_get_version(rdpPersistentCache* persistent)
|
||||
{
|
||||
WINPR_ASSERT(persistent);
|
||||
return persistent->version;
|
||||
}
|
||||
|
||||
int persistent_cache_get_count(rdpPersistentCache* persistent)
|
||||
{
|
||||
WINPR_ASSERT(persistent);
|
||||
return persistent->count;
|
||||
}
|
||||
|
||||
static int persistent_cache_read_entry_v2(rdpPersistentCache* persistent,
|
||||
PERSISTENT_CACHE_ENTRY* entry)
|
||||
{
|
||||
PERSISTENT_CACHE_ENTRY_V2 entry2 = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(persistent);
|
||||
WINPR_ASSERT(entry);
|
||||
|
||||
if (fread((void*)&entry2, sizeof(entry2), 1, persistent->fp) != 1)
|
||||
return -1;
|
||||
|
||||
entry->key64 = entry2.key64;
|
||||
entry->width = entry2.width;
|
||||
entry->height = entry2.height;
|
||||
entry->size = entry2.width * entry2.height * 4;
|
||||
entry->flags = entry2.flags;
|
||||
|
||||
entry->data = persistent->bmpData;
|
||||
|
||||
if (fread((void*)entry->data, 0x4000, 1, persistent->fp) != 1)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int persistent_cache_write_entry_v2(rdpPersistentCache* persistent,
|
||||
const PERSISTENT_CACHE_ENTRY* entry)
|
||||
{
|
||||
PERSISTENT_CACHE_ENTRY_V2 entry2 = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(persistent);
|
||||
WINPR_ASSERT(entry);
|
||||
entry2.key64 = entry->key64;
|
||||
entry2.width = entry->width;
|
||||
entry2.height = entry->height;
|
||||
entry2.size = entry->size;
|
||||
entry2.flags = entry->flags;
|
||||
|
||||
if (!entry2.flags)
|
||||
entry2.flags = 0x00000011;
|
||||
|
||||
if (fwrite(&entry2, sizeof(entry2), 1, persistent->fp) != 1)
|
||||
return -1;
|
||||
|
||||
if (fwrite(entry->data, entry->size, 1, persistent->fp) != 1)
|
||||
return -1;
|
||||
|
||||
if (0x4000 > entry->size)
|
||||
{
|
||||
const size_t padding = 0x4000 - entry->size;
|
||||
|
||||
if (fwrite(persistent->bmpData, padding, 1, persistent->fp) != 1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
persistent->count++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int persistent_cache_read_v2(rdpPersistentCache* persistent)
|
||||
{
|
||||
WINPR_ASSERT(persistent);
|
||||
while (1)
|
||||
{
|
||||
PERSISTENT_CACHE_ENTRY_V2 entry = WINPR_C_ARRAY_INIT;
|
||||
|
||||
if (fread((void*)&entry, sizeof(entry), 1, persistent->fp) != 1)
|
||||
break;
|
||||
|
||||
if (fseek(persistent->fp, 0x4000, SEEK_CUR) != 0)
|
||||
break;
|
||||
|
||||
persistent->count++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int persistent_cache_read_entry_v3(rdpPersistentCache* persistent,
|
||||
PERSISTENT_CACHE_ENTRY* entry)
|
||||
{
|
||||
PERSISTENT_CACHE_ENTRY_V3 entry3 = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(persistent);
|
||||
WINPR_ASSERT(entry);
|
||||
|
||||
if (fread(&entry3, sizeof(entry3), 1, persistent->fp) != 1)
|
||||
return -1;
|
||||
|
||||
entry->key64 = entry3.key64;
|
||||
entry->width = entry3.width;
|
||||
entry->height = entry3.height;
|
||||
const UINT64 size = 4ull * entry3.width * entry3.height;
|
||||
if (size > UINT32_MAX)
|
||||
return -1;
|
||||
entry->size = (UINT32)size;
|
||||
entry->flags = 0;
|
||||
|
||||
if (entry->size > persistent->bmpSize)
|
||||
{
|
||||
persistent->bmpSize = entry->size;
|
||||
BYTE* bmpData = (BYTE*)winpr_aligned_recalloc(persistent->bmpData, persistent->bmpSize,
|
||||
sizeof(BYTE), 32);
|
||||
|
||||
if (!bmpData)
|
||||
return -1;
|
||||
|
||||
persistent->bmpData = bmpData;
|
||||
}
|
||||
|
||||
entry->data = persistent->bmpData;
|
||||
|
||||
if (fread((void*)entry->data, entry->size, 1, persistent->fp) != 1)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int persistent_cache_write_entry_v3(rdpPersistentCache* persistent,
|
||||
const PERSISTENT_CACHE_ENTRY* entry)
|
||||
{
|
||||
PERSISTENT_CACHE_ENTRY_V3 entry3 = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(persistent);
|
||||
WINPR_ASSERT(entry);
|
||||
|
||||
entry3.key64 = entry->key64;
|
||||
entry3.width = entry->width;
|
||||
entry3.height = entry->height;
|
||||
|
||||
if (fwrite((void*)&entry3, sizeof(entry3), 1, persistent->fp) != 1)
|
||||
return -1;
|
||||
|
||||
if (fwrite((void*)entry->data, entry->size, 1, persistent->fp) != 1)
|
||||
return -1;
|
||||
|
||||
persistent->count++;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int persistent_cache_read_v3(rdpPersistentCache* persistent)
|
||||
{
|
||||
WINPR_ASSERT(persistent);
|
||||
while (1)
|
||||
{
|
||||
PERSISTENT_CACHE_ENTRY_V3 entry = WINPR_C_ARRAY_INIT;
|
||||
|
||||
if (fread((void*)&entry, sizeof(entry), 1, persistent->fp) != 1)
|
||||
break;
|
||||
|
||||
if (_fseeki64(persistent->fp, (4LL * entry.width * entry.height), SEEK_CUR) != 0)
|
||||
break;
|
||||
|
||||
persistent->count++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int persistent_cache_read_entry(rdpPersistentCache* persistent, PERSISTENT_CACHE_ENTRY* entry)
|
||||
{
|
||||
WINPR_ASSERT(persistent);
|
||||
WINPR_ASSERT(entry);
|
||||
|
||||
if (persistent->version == 3)
|
||||
return persistent_cache_read_entry_v3(persistent, entry);
|
||||
else if (persistent->version == 2)
|
||||
return persistent_cache_read_entry_v2(persistent, entry);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int persistent_cache_write_entry(rdpPersistentCache* persistent,
|
||||
const PERSISTENT_CACHE_ENTRY* entry)
|
||||
{
|
||||
WINPR_ASSERT(persistent);
|
||||
WINPR_ASSERT(entry);
|
||||
|
||||
if (persistent->version == 3)
|
||||
return persistent_cache_write_entry_v3(persistent, entry);
|
||||
else if (persistent->version == 2)
|
||||
return persistent_cache_write_entry_v2(persistent, entry);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int persistent_cache_open_read(rdpPersistentCache* persistent)
|
||||
{
|
||||
BYTE sig[8] = WINPR_C_ARRAY_INIT;
|
||||
int status = 1;
|
||||
long offset = 0;
|
||||
|
||||
WINPR_ASSERT(persistent);
|
||||
persistent->fp = winpr_fopen(persistent->filename, "rb");
|
||||
|
||||
if (!persistent->fp)
|
||||
return -1;
|
||||
|
||||
if (fread(sig, 8, 1, persistent->fp) != 1)
|
||||
return -1;
|
||||
|
||||
if (memcmp(sig, sig_str, sizeof(sig_str)) == 0)
|
||||
persistent->version = 3;
|
||||
else
|
||||
persistent->version = 2;
|
||||
|
||||
(void)fseek(persistent->fp, 0, SEEK_SET);
|
||||
|
||||
if (persistent->version == 3)
|
||||
{
|
||||
PERSISTENT_CACHE_HEADER_V3 header;
|
||||
|
||||
if (fread(&header, sizeof(header), 1, persistent->fp) != 1)
|
||||
return -1;
|
||||
|
||||
status = persistent_cache_read_v3(persistent);
|
||||
offset = sizeof(header);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = persistent_cache_read_v2(persistent);
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
(void)fseek(persistent->fp, offset, SEEK_SET);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int persistent_cache_open_write(rdpPersistentCache* persistent)
|
||||
{
|
||||
WINPR_ASSERT(persistent);
|
||||
|
||||
persistent->fp = winpr_fopen(persistent->filename, "w+b");
|
||||
|
||||
if (!persistent->fp)
|
||||
return -1;
|
||||
|
||||
if (persistent->version == 3)
|
||||
{
|
||||
PERSISTENT_CACHE_HEADER_V3 header = WINPR_C_ARRAY_INIT;
|
||||
memcpy(header.sig, sig_str, MIN(sizeof(header.sig), sizeof(sig_str)));
|
||||
header.flags = 0x00000006;
|
||||
|
||||
if (fwrite(&header, sizeof(header), 1, persistent->fp) != 1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
ZeroMemory(persistent->bmpData, persistent->bmpSize);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int persistent_cache_open(rdpPersistentCache* persistent, const char* filename, BOOL write,
|
||||
UINT32 version)
|
||||
{
|
||||
WINPR_ASSERT(persistent);
|
||||
WINPR_ASSERT(filename);
|
||||
persistent->write = write;
|
||||
|
||||
persistent->filename = _strdup(filename);
|
||||
|
||||
if (!persistent->filename)
|
||||
return -1;
|
||||
|
||||
if (persistent->write)
|
||||
{
|
||||
WINPR_ASSERT(version <= INT32_MAX);
|
||||
persistent->version = (int)version;
|
||||
return persistent_cache_open_write(persistent);
|
||||
}
|
||||
|
||||
return persistent_cache_open_read(persistent);
|
||||
}
|
||||
|
||||
int persistent_cache_close(rdpPersistentCache* persistent)
|
||||
{
|
||||
WINPR_ASSERT(persistent);
|
||||
if (persistent->fp)
|
||||
{
|
||||
(void)fclose(persistent->fp);
|
||||
persistent->fp = nullptr;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
rdpPersistentCache* persistent_cache_new(void)
|
||||
{
|
||||
rdpPersistentCache* persistent = calloc(1, sizeof(rdpPersistentCache));
|
||||
|
||||
if (!persistent)
|
||||
return nullptr;
|
||||
|
||||
persistent->bmpSize = 0x4000;
|
||||
persistent->bmpData = calloc(1, persistent->bmpSize);
|
||||
|
||||
if (!persistent->bmpData)
|
||||
{
|
||||
free(persistent);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return persistent;
|
||||
}
|
||||
|
||||
void persistent_cache_free(rdpPersistentCache* persistent)
|
||||
{
|
||||
if (!persistent)
|
||||
return;
|
||||
|
||||
persistent_cache_close(persistent);
|
||||
|
||||
free(persistent->filename);
|
||||
|
||||
winpr_aligned_free(persistent->bmpData);
|
||||
|
||||
free(persistent);
|
||||
}
|
||||
597
third_party/FreeRDP/libfreerdp/cache/pointer.c
vendored
Normal file
597
third_party/FreeRDP/libfreerdp/cache/pointer.c
vendored
Normal file
@@ -0,0 +1,597 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Glyph Cache
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#include "pointer.h"
|
||||
#include "cache.h"
|
||||
|
||||
#define TAG FREERDP_TAG("cache.pointer")
|
||||
|
||||
static BOOL pointer_cache_put(rdpPointerCache* pointer_cache, UINT32 index, rdpPointer* pointer,
|
||||
BOOL colorCache);
|
||||
static rdpPointer* pointer_cache_get(rdpPointerCache* pointer_cache, UINT32 index);
|
||||
|
||||
static void pointer_clear(rdpPointer* pointer)
|
||||
{
|
||||
if (pointer)
|
||||
{
|
||||
pointer->lengthAndMask = 0;
|
||||
free(pointer->andMaskData);
|
||||
pointer->andMaskData = nullptr;
|
||||
|
||||
pointer->lengthXorMask = 0;
|
||||
free(pointer->xorMaskData);
|
||||
pointer->xorMaskData = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void pointer_free(rdpContext* context, rdpPointer* pointer)
|
||||
{
|
||||
if (pointer)
|
||||
{
|
||||
IFCALL(pointer->Free, context, pointer);
|
||||
pointer_clear(pointer);
|
||||
}
|
||||
free(pointer);
|
||||
}
|
||||
|
||||
static BOOL update_pointer_position(rdpContext* context,
|
||||
const POINTER_POSITION_UPDATE* pointer_position)
|
||||
{
|
||||
if (!context || !context->graphics || !context->graphics->Pointer_Prototype ||
|
||||
!pointer_position)
|
||||
return FALSE;
|
||||
|
||||
const BOOL GrabMouse = freerdp_settings_get_bool(context->settings, FreeRDP_GrabMouse);
|
||||
if (!GrabMouse)
|
||||
return TRUE;
|
||||
|
||||
const rdpPointer* pointer = context->graphics->Pointer_Prototype;
|
||||
WINPR_ASSERT(pointer);
|
||||
|
||||
return IFCALLRESULT(TRUE, pointer->SetPosition, context, pointer_position->xPos,
|
||||
pointer_position->yPos);
|
||||
}
|
||||
|
||||
static BOOL update_pointer_system(rdpContext* context, const POINTER_SYSTEM_UPDATE* pointer_system)
|
||||
{
|
||||
rdpPointer* pointer = nullptr;
|
||||
|
||||
if (!context || !context->graphics || !context->graphics->Pointer_Prototype || !pointer_system)
|
||||
return FALSE;
|
||||
|
||||
pointer = context->graphics->Pointer_Prototype;
|
||||
|
||||
switch (pointer_system->type)
|
||||
{
|
||||
case SYSPTR_NULL:
|
||||
return IFCALLRESULT(TRUE, pointer->SetNull, context);
|
||||
|
||||
case SYSPTR_DEFAULT:
|
||||
return IFCALLRESULT(TRUE, pointer->SetDefault, context);
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "Unknown system pointer type (0x%08" PRIX32 ")", pointer_system->type);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL upate_pointer_copy_andxor(rdpPointer* pointer, const BYTE* andMaskData,
|
||||
size_t lengthAndMask, const BYTE* xorMaskData,
|
||||
size_t lengthXorMask)
|
||||
{
|
||||
WINPR_ASSERT(pointer);
|
||||
|
||||
pointer_clear(pointer);
|
||||
if (lengthAndMask && andMaskData)
|
||||
{
|
||||
if (lengthAndMask > UINT32_MAX)
|
||||
return FALSE;
|
||||
pointer->lengthAndMask = (UINT32)lengthAndMask;
|
||||
pointer->andMaskData = (BYTE*)malloc(lengthAndMask);
|
||||
if (!pointer->andMaskData)
|
||||
return FALSE;
|
||||
|
||||
CopyMemory(pointer->andMaskData, andMaskData, lengthAndMask);
|
||||
}
|
||||
|
||||
if (lengthXorMask && xorMaskData)
|
||||
{
|
||||
if (lengthXorMask > UINT32_MAX)
|
||||
return FALSE;
|
||||
pointer->lengthXorMask = (UINT32)lengthXorMask;
|
||||
pointer->xorMaskData = (BYTE*)malloc(lengthXorMask);
|
||||
if (!pointer->xorMaskData)
|
||||
return FALSE;
|
||||
|
||||
CopyMemory(pointer->xorMaskData, xorMaskData, lengthXorMask);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL update_pointer_color(rdpContext* context, const POINTER_COLOR_UPDATE* pointer_color)
|
||||
{
|
||||
rdpPointer* pointer = nullptr;
|
||||
rdpCache* cache = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(pointer_color);
|
||||
|
||||
cache = context->cache;
|
||||
WINPR_ASSERT(cache);
|
||||
|
||||
pointer = Pointer_Alloc(context);
|
||||
|
||||
if (pointer == nullptr)
|
||||
return FALSE;
|
||||
pointer->xorBpp = 24;
|
||||
pointer->xPos = pointer_color->hotSpotX;
|
||||
pointer->yPos = pointer_color->hotSpotY;
|
||||
pointer->width = pointer_color->width;
|
||||
pointer->height = pointer_color->height;
|
||||
|
||||
if (!upate_pointer_copy_andxor(pointer, pointer_color->andMaskData,
|
||||
pointer_color->lengthAndMask, pointer_color->xorMaskData,
|
||||
pointer_color->lengthXorMask))
|
||||
goto out_fail;
|
||||
|
||||
if (!IFCALLRESULT(TRUE, pointer->New, context, pointer))
|
||||
goto out_fail;
|
||||
|
||||
if (!pointer_cache_put(cache->pointer, pointer_color->cacheIndex, pointer, TRUE))
|
||||
goto out_fail;
|
||||
|
||||
return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
|
||||
|
||||
out_fail:
|
||||
pointer_free(context, pointer);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL update_pointer_large(rdpContext* context, const POINTER_LARGE_UPDATE* pointer_large)
|
||||
{
|
||||
rdpPointer* pointer = nullptr;
|
||||
rdpCache* cache = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(pointer_large);
|
||||
|
||||
cache = context->cache;
|
||||
WINPR_ASSERT(cache);
|
||||
|
||||
pointer = Pointer_Alloc(context);
|
||||
if (pointer == nullptr)
|
||||
return FALSE;
|
||||
pointer->xorBpp = pointer_large->xorBpp;
|
||||
pointer->xPos = pointer_large->hotSpotX;
|
||||
pointer->yPos = pointer_large->hotSpotY;
|
||||
pointer->width = pointer_large->width;
|
||||
pointer->height = pointer_large->height;
|
||||
|
||||
if (!upate_pointer_copy_andxor(pointer, pointer_large->andMaskData,
|
||||
pointer_large->lengthAndMask, pointer_large->xorMaskData,
|
||||
pointer_large->lengthXorMask))
|
||||
goto out_fail;
|
||||
|
||||
if (!IFCALLRESULT(TRUE, pointer->New, context, pointer))
|
||||
goto out_fail;
|
||||
|
||||
if (!pointer_cache_put(cache->pointer, pointer_large->cacheIndex, pointer, FALSE))
|
||||
goto out_fail;
|
||||
|
||||
return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
|
||||
|
||||
out_fail:
|
||||
pointer_free(context, pointer);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL update_pointer_new(rdpContext* context, const POINTER_NEW_UPDATE* pointer_new)
|
||||
{
|
||||
if (!context || !pointer_new)
|
||||
return FALSE;
|
||||
|
||||
rdpCache* cache = context->cache;
|
||||
rdpPointer* pointer = Pointer_Alloc(context);
|
||||
|
||||
if (!pointer)
|
||||
return FALSE;
|
||||
|
||||
pointer->xorBpp = pointer_new->xorBpp;
|
||||
pointer->xPos = pointer_new->colorPtrAttr.hotSpotX;
|
||||
pointer->yPos = pointer_new->colorPtrAttr.hotSpotY;
|
||||
pointer->width = pointer_new->colorPtrAttr.width;
|
||||
pointer->height = pointer_new->colorPtrAttr.height;
|
||||
if (!upate_pointer_copy_andxor(
|
||||
pointer, pointer_new->colorPtrAttr.andMaskData, pointer_new->colorPtrAttr.lengthAndMask,
|
||||
pointer_new->colorPtrAttr.xorMaskData, pointer_new->colorPtrAttr.lengthXorMask))
|
||||
goto out_fail;
|
||||
|
||||
if (!IFCALLRESULT(TRUE, pointer->New, context, pointer))
|
||||
goto out_fail;
|
||||
|
||||
if (!pointer_cache_put(cache->pointer, pointer_new->colorPtrAttr.cacheIndex, pointer, FALSE))
|
||||
goto out_fail;
|
||||
|
||||
return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
|
||||
|
||||
out_fail:
|
||||
pointer_free(context, pointer);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL update_pointer_cached(rdpContext* context, const POINTER_CACHED_UPDATE* pointer_cached)
|
||||
{
|
||||
rdpPointer* pointer = nullptr;
|
||||
rdpCache* cache = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
WINPR_ASSERT(pointer_cached);
|
||||
|
||||
cache = context->cache;
|
||||
WINPR_ASSERT(cache);
|
||||
|
||||
pointer = pointer_cache_get(cache->pointer, pointer_cached->cacheIndex);
|
||||
|
||||
if (pointer != nullptr)
|
||||
return IFCALLRESULT(TRUE, pointer->Set, context, pointer);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rdpPointer* pointer_cache_get(rdpPointerCache* pointer_cache, UINT32 index)
|
||||
{
|
||||
rdpPointer* pointer = nullptr;
|
||||
|
||||
WINPR_ASSERT(pointer_cache);
|
||||
|
||||
if (index >= pointer_cache->cacheSize)
|
||||
{
|
||||
WLog_ERR(TAG, "invalid pointer index:%" PRIu32 " [%" PRIu32 "]", index,
|
||||
pointer_cache->cacheSize);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINPR_ASSERT(pointer_cache->entries);
|
||||
pointer = pointer_cache->entries[index];
|
||||
return pointer;
|
||||
}
|
||||
|
||||
BOOL pointer_cache_put(rdpPointerCache* pointer_cache, UINT32 index, rdpPointer* pointer,
|
||||
BOOL colorCache)
|
||||
{
|
||||
rdpPointer* prevPointer = nullptr;
|
||||
const FreeRDP_Settings_Keys_UInt32 id =
|
||||
colorCache ? FreeRDP_ColorPointerCacheSize : FreeRDP_PointerCacheSize;
|
||||
|
||||
WINPR_ASSERT(pointer_cache);
|
||||
WINPR_ASSERT(pointer_cache->context);
|
||||
|
||||
const UINT32 size = freerdp_settings_get_uint32(pointer_cache->context->settings, id);
|
||||
if (index >= pointer_cache->cacheSize)
|
||||
{
|
||||
WLog_ERR(TAG,
|
||||
"invalid pointer index:%" PRIu32 " [allocated %" PRIu32 ", %s size %" PRIu32 "]",
|
||||
index, pointer_cache->cacheSize,
|
||||
colorCache ? "color-pointer-cache" : "pointer-cache", size);
|
||||
return FALSE;
|
||||
}
|
||||
if (index >= size)
|
||||
{
|
||||
WLog_WARN(TAG,
|
||||
"suspicious pointer index:%" PRIu32 " [allocated %" PRIu32 ", %s size %" PRIu32
|
||||
"]",
|
||||
index, pointer_cache->cacheSize,
|
||||
colorCache ? "color-pointer-cache" : "pointer-cache", size);
|
||||
}
|
||||
|
||||
WINPR_ASSERT(pointer_cache->entries);
|
||||
prevPointer = pointer_cache->entries[index];
|
||||
pointer_free(pointer_cache->context, prevPointer);
|
||||
pointer_cache->entries[index] = pointer;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void pointer_cache_register_callbacks(rdpUpdate* update)
|
||||
{
|
||||
rdpPointerUpdate* pointer = nullptr;
|
||||
|
||||
WINPR_ASSERT(update);
|
||||
WINPR_ASSERT(update->context);
|
||||
|
||||
pointer = update->pointer;
|
||||
WINPR_ASSERT(pointer);
|
||||
|
||||
if (!freerdp_settings_get_bool(update->context->settings, FreeRDP_DeactivateClientDecoding))
|
||||
{
|
||||
pointer->PointerPosition = update_pointer_position;
|
||||
pointer->PointerSystem = update_pointer_system;
|
||||
pointer->PointerColor = update_pointer_color;
|
||||
pointer->PointerLarge = update_pointer_large;
|
||||
pointer->PointerNew = update_pointer_new;
|
||||
pointer->PointerCached = update_pointer_cached;
|
||||
}
|
||||
}
|
||||
|
||||
rdpPointerCache* pointer_cache_new(rdpContext* context)
|
||||
{
|
||||
rdpPointerCache* pointer_cache = nullptr;
|
||||
rdpSettings* settings = nullptr;
|
||||
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
settings = context->settings;
|
||||
WINPR_ASSERT(settings);
|
||||
|
||||
pointer_cache = (rdpPointerCache*)calloc(1, sizeof(rdpPointerCache));
|
||||
|
||||
if (!pointer_cache)
|
||||
return nullptr;
|
||||
|
||||
pointer_cache->context = context;
|
||||
|
||||
/* seen invalid pointer cache requests by mstsc (off by 1) so we ensure the cache entry size
|
||||
* matches */
|
||||
const UINT32 size = freerdp_settings_get_uint32(settings, FreeRDP_PointerCacheSize);
|
||||
const UINT32 colorSize = freerdp_settings_get_uint32(settings, FreeRDP_ColorPointerCacheSize);
|
||||
pointer_cache->cacheSize = MAX(size, colorSize) + 1;
|
||||
|
||||
pointer_cache->entries = (rdpPointer**)calloc(pointer_cache->cacheSize, sizeof(rdpPointer*));
|
||||
|
||||
if (!pointer_cache->entries)
|
||||
{
|
||||
free(pointer_cache);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pointer_cache;
|
||||
}
|
||||
|
||||
void pointer_cache_free(rdpPointerCache* pointer_cache)
|
||||
{
|
||||
if (pointer_cache != nullptr)
|
||||
{
|
||||
if (pointer_cache->entries)
|
||||
{
|
||||
for (UINT32 i = 0; i < pointer_cache->cacheSize; i++)
|
||||
{
|
||||
rdpPointer* pointer = pointer_cache->entries[i];
|
||||
pointer_free(pointer_cache->context, pointer);
|
||||
}
|
||||
}
|
||||
|
||||
free((void*)pointer_cache->entries);
|
||||
free(pointer_cache);
|
||||
}
|
||||
}
|
||||
|
||||
POINTER_COLOR_UPDATE* copy_pointer_color_update(rdpContext* context,
|
||||
const POINTER_COLOR_UPDATE* pointer)
|
||||
{
|
||||
POINTER_COLOR_UPDATE* dst = calloc(1, sizeof(POINTER_COLOR_UPDATE));
|
||||
|
||||
if (!dst || !pointer)
|
||||
goto fail;
|
||||
|
||||
*dst = *pointer;
|
||||
|
||||
if (pointer->lengthAndMask > 0)
|
||||
{
|
||||
dst->andMaskData = calloc(pointer->lengthAndMask, sizeof(BYTE));
|
||||
|
||||
if (!dst->andMaskData)
|
||||
goto fail;
|
||||
|
||||
memcpy(dst->andMaskData, pointer->andMaskData, pointer->lengthAndMask);
|
||||
}
|
||||
|
||||
if (pointer->lengthXorMask > 0)
|
||||
{
|
||||
dst->xorMaskData = calloc(pointer->lengthXorMask, sizeof(BYTE));
|
||||
|
||||
if (!dst->xorMaskData)
|
||||
goto fail;
|
||||
|
||||
memcpy(dst->xorMaskData, pointer->xorMaskData, pointer->lengthXorMask);
|
||||
}
|
||||
|
||||
return dst;
|
||||
fail:
|
||||
free_pointer_color_update(context, dst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void free_pointer_color_update(rdpContext* context, POINTER_COLOR_UPDATE* pointer)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
|
||||
if (!pointer)
|
||||
return;
|
||||
|
||||
free(pointer->xorMaskData);
|
||||
free(pointer->andMaskData);
|
||||
free(pointer);
|
||||
}
|
||||
|
||||
POINTER_LARGE_UPDATE* copy_pointer_large_update(rdpContext* context,
|
||||
const POINTER_LARGE_UPDATE* pointer)
|
||||
{
|
||||
POINTER_LARGE_UPDATE* dst = calloc(1, sizeof(POINTER_LARGE_UPDATE));
|
||||
|
||||
if (!dst || !pointer)
|
||||
goto fail;
|
||||
|
||||
*dst = *pointer;
|
||||
|
||||
if (pointer->lengthAndMask > 0)
|
||||
{
|
||||
dst->andMaskData = calloc(pointer->lengthAndMask, sizeof(BYTE));
|
||||
|
||||
if (!dst->andMaskData)
|
||||
goto fail;
|
||||
|
||||
memcpy(dst->andMaskData, pointer->andMaskData, pointer->lengthAndMask);
|
||||
}
|
||||
|
||||
if (pointer->lengthXorMask > 0)
|
||||
{
|
||||
dst->xorMaskData = calloc(pointer->lengthXorMask, sizeof(BYTE));
|
||||
|
||||
if (!dst->xorMaskData)
|
||||
goto fail;
|
||||
|
||||
memcpy(dst->xorMaskData, pointer->xorMaskData, pointer->lengthXorMask);
|
||||
}
|
||||
|
||||
return dst;
|
||||
fail:
|
||||
free_pointer_large_update(context, dst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void free_pointer_large_update(rdpContext* context, POINTER_LARGE_UPDATE* pointer)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
if (!pointer)
|
||||
return;
|
||||
|
||||
free(pointer->xorMaskData);
|
||||
free(pointer->andMaskData);
|
||||
free(pointer);
|
||||
}
|
||||
|
||||
POINTER_NEW_UPDATE* copy_pointer_new_update(rdpContext* context, const POINTER_NEW_UPDATE* pointer)
|
||||
{
|
||||
POINTER_NEW_UPDATE* dst = calloc(1, sizeof(POINTER_NEW_UPDATE));
|
||||
|
||||
if (!dst || !pointer)
|
||||
goto fail;
|
||||
|
||||
*dst = *pointer;
|
||||
|
||||
if (pointer->colorPtrAttr.lengthAndMask > 0)
|
||||
{
|
||||
dst->colorPtrAttr.andMaskData = calloc(pointer->colorPtrAttr.lengthAndMask, sizeof(BYTE));
|
||||
|
||||
if (!dst->colorPtrAttr.andMaskData)
|
||||
goto fail;
|
||||
|
||||
memcpy(dst->colorPtrAttr.andMaskData, pointer->colorPtrAttr.andMaskData,
|
||||
pointer->colorPtrAttr.lengthAndMask);
|
||||
}
|
||||
|
||||
if (pointer->colorPtrAttr.lengthXorMask > 0)
|
||||
{
|
||||
dst->colorPtrAttr.xorMaskData = calloc(pointer->colorPtrAttr.lengthXorMask, sizeof(BYTE));
|
||||
|
||||
if (!dst->colorPtrAttr.xorMaskData)
|
||||
goto fail;
|
||||
|
||||
memcpy(dst->colorPtrAttr.xorMaskData, pointer->colorPtrAttr.xorMaskData,
|
||||
pointer->colorPtrAttr.lengthXorMask);
|
||||
}
|
||||
|
||||
return dst;
|
||||
fail:
|
||||
free_pointer_new_update(context, dst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void free_pointer_new_update(WINPR_ATTR_UNUSED rdpContext* context, POINTER_NEW_UPDATE* pointer)
|
||||
{
|
||||
if (!pointer)
|
||||
return;
|
||||
|
||||
free(pointer->colorPtrAttr.xorMaskData);
|
||||
free(pointer->colorPtrAttr.andMaskData);
|
||||
free(pointer);
|
||||
}
|
||||
|
||||
POINTER_CACHED_UPDATE* copy_pointer_cached_update(rdpContext* context,
|
||||
const POINTER_CACHED_UPDATE* pointer)
|
||||
{
|
||||
POINTER_CACHED_UPDATE* dst = calloc(1, sizeof(POINTER_CACHED_UPDATE));
|
||||
|
||||
if (!dst)
|
||||
goto fail;
|
||||
|
||||
*dst = *pointer;
|
||||
return dst;
|
||||
fail:
|
||||
free_pointer_cached_update(context, dst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void free_pointer_cached_update(rdpContext* context, POINTER_CACHED_UPDATE* pointer)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
free(pointer);
|
||||
}
|
||||
|
||||
void free_pointer_position_update(rdpContext* context, POINTER_POSITION_UPDATE* pointer)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
free(pointer);
|
||||
}
|
||||
|
||||
POINTER_POSITION_UPDATE* copy_pointer_position_update(rdpContext* context,
|
||||
const POINTER_POSITION_UPDATE* pointer)
|
||||
{
|
||||
POINTER_POSITION_UPDATE* dst = calloc(1, sizeof(POINTER_POSITION_UPDATE));
|
||||
|
||||
if (!dst || !pointer)
|
||||
goto fail;
|
||||
|
||||
*dst = *pointer;
|
||||
return dst;
|
||||
fail:
|
||||
free_pointer_position_update(context, dst);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void free_pointer_system_update(rdpContext* context, POINTER_SYSTEM_UPDATE* pointer)
|
||||
{
|
||||
WINPR_UNUSED(context);
|
||||
free(pointer);
|
||||
}
|
||||
|
||||
POINTER_SYSTEM_UPDATE* copy_pointer_system_update(rdpContext* context,
|
||||
const POINTER_SYSTEM_UPDATE* pointer)
|
||||
{
|
||||
POINTER_SYSTEM_UPDATE* dst = calloc(1, sizeof(POINTER_SYSTEM_UPDATE));
|
||||
|
||||
if (!dst || !pointer)
|
||||
goto fail;
|
||||
|
||||
*dst = *pointer;
|
||||
return dst;
|
||||
fail:
|
||||
free_pointer_system_update(context, dst);
|
||||
return nullptr;
|
||||
}
|
||||
102
third_party/FreeRDP/libfreerdp/cache/pointer.h
vendored
Normal file
102
third_party/FreeRDP/libfreerdp/cache/pointer.h
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
|
||||
* Copyright 2018 Thincast Technologies GmbH
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_LIB_CACHE_POINTER_H
|
||||
#define FREERDP_LIB_CACHE_POINTER_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/pointer.h>
|
||||
|
||||
typedef struct rdp_pointer_cache rdpPointerCache;
|
||||
|
||||
struct rdp_pointer_cache
|
||||
{
|
||||
UINT32 cacheSize; /* 0 */
|
||||
rdpPointer** entries; /* 1 */
|
||||
|
||||
/* internal */
|
||||
rdpContext* context;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
FREERDP_LOCAL void pointer_cache_register_callbacks(rdpUpdate* update);
|
||||
|
||||
FREERDP_LOCAL void pointer_cache_free(rdpPointerCache* pointer_cache);
|
||||
|
||||
WINPR_ATTR_MALLOC(pointer_cache_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL rdpPointerCache* pointer_cache_new(rdpContext* context);
|
||||
|
||||
FREERDP_LOCAL void free_pointer_color_update(rdpContext* context,
|
||||
POINTER_COLOR_UPDATE* pointer);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_pointer_color_update, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL POINTER_COLOR_UPDATE*
|
||||
copy_pointer_color_update(rdpContext* context, const POINTER_COLOR_UPDATE* pointer);
|
||||
|
||||
FREERDP_LOCAL void free_pointer_large_update(rdpContext* context,
|
||||
POINTER_LARGE_UPDATE* pointer);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_pointer_large_update, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL POINTER_LARGE_UPDATE*
|
||||
copy_pointer_large_update(rdpContext* context, const POINTER_LARGE_UPDATE* pointer);
|
||||
|
||||
FREERDP_LOCAL void free_pointer_new_update(rdpContext* context, POINTER_NEW_UPDATE* pointer);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_pointer_new_update, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL POINTER_NEW_UPDATE* copy_pointer_new_update(rdpContext* context,
|
||||
const POINTER_NEW_UPDATE* pointer);
|
||||
|
||||
FREERDP_LOCAL void free_pointer_cached_update(rdpContext* context,
|
||||
POINTER_CACHED_UPDATE* pointer);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_pointer_cached_update, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL POINTER_CACHED_UPDATE*
|
||||
copy_pointer_cached_update(rdpContext* context, const POINTER_CACHED_UPDATE* pointer);
|
||||
|
||||
FREERDP_LOCAL void free_pointer_position_update(rdpContext* context,
|
||||
POINTER_POSITION_UPDATE* pointer);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_pointer_position_update, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL POINTER_POSITION_UPDATE*
|
||||
copy_pointer_position_update(rdpContext* context, const POINTER_POSITION_UPDATE* pointer);
|
||||
|
||||
FREERDP_LOCAL void free_pointer_system_update(rdpContext* context,
|
||||
POINTER_SYSTEM_UPDATE* pointer);
|
||||
|
||||
WINPR_ATTR_MALLOC(free_pointer_system_update, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL POINTER_SYSTEM_UPDATE*
|
||||
copy_pointer_system_update(rdpContext* context, const POINTER_SYSTEM_UPDATE* pointer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_LIB_CACHE_POINTER_H */
|
||||
Reference in New Issue
Block a user