Blame libfreerdp/cache/glyph.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 * Glyph Cache
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <stdio.h>
Packit Service fa4841
Packit Service fa4841
#include <winpr/crt.h>
Packit Service fa4841
Packit Service fa4841
#include <freerdp/freerdp.h>
Packit Service fa4841
#include <winpr/stream.h>
Packit Service fa4841
Packit Service fa4841
#include <freerdp/log.h>
Packit Service fa4841
#include <freerdp/cache/glyph.h>
Packit Service fa4841
Packit Service fa4841
#include "glyph.h"
Packit Service fa4841
Packit Service fa4841
#define TAG FREERDP_TAG("cache.glyph")
Packit Service fa4841
Packit Service b1ea74
static rdpGlyph* glyph_cache_get(rdpGlyphCache* glyph_cache, UINT32 id, UINT32 index);
Packit Service b1ea74
static BOOL glyph_cache_put(rdpGlyphCache* glyph_cache, UINT32 id, UINT32 index, rdpGlyph* entry);
Packit Service b1ea74
Packit Service b1ea74
static const void* glyph_cache_fragment_get(rdpGlyphCache* glyph, UINT32 index, UINT32* count);
Packit Service b1ea74
static BOOL glyph_cache_fragment_put(rdpGlyphCache* glyph, UINT32 index, UINT32 count,
Packit Service b1ea74
                                     const void* entry);
Packit Service b1ea74
Packit Service b1ea74
static UINT32 update_glyph_offset(const BYTE* data, size_t length, UINT32 index, INT32* x, INT32* y,
Packit Service b1ea74
                                  UINT32 ulCharInc, UINT32 flAccel)
Packit Service fa4841
{
Packit Service fa4841
	if ((ulCharInc == 0) && (!(flAccel & SO_CHAR_INC_EQUAL_BM_BASE)))
Packit Service fa4841
	{
Packit Service fa4841
		UINT32 offset = data[index++];
Packit Service fa4841
Packit Service fa4841
		if (offset & 0x80)
Packit Service fa4841
		{
Packit Service b1ea74
Packit Service b1ea74
			if (index + 1 < length)
Packit Service b1ea74
			{
Packit Service b1ea74
				offset = data[index++];
Packit Service b1ea74
				offset |= ((UINT32)data[index++]) << 8;
Packit Service b1ea74
			}
Packit Service b1ea74
			else
Packit Service b1ea74
				WLog_WARN(TAG, "[%s] glyph index out of bound %" PRIu32 " [max %" PRIuz "]", index,
Packit Service b1ea74
				          length);
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (flAccel & SO_VERTICAL)
Packit Service fa4841
			*y += offset;
Packit Service fa4841
Packit Service fa4841
		if (flAccel & SO_HORIZONTAL)
Packit Service fa4841
			*x += offset;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return index;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
static BOOL update_process_glyph(rdpContext* context, const BYTE* data, UINT32 cacheIndex, INT32* x,
Packit Service b1ea74
                                 INT32* y, UINT32 cacheId, UINT32 flAccel, BOOL fOpRedundant,
Packit Service fa4841
                                 const RDP_RECT* bound)
Packit Service fa4841
{
Packit Service fa4841
	INT32 sx = 0, sy = 0;
Packit Service fa4841
	INT32 dx, dy;
Packit Service fa4841
	rdpGlyph* glyph;
Packit Service fa4841
	rdpGlyphCache* glyph_cache;
Packit Service fa4841
Packit Service b1ea74
	if (!context || !data || !x || !y || !context->graphics || !context->cache ||
Packit Service b1ea74
	    !context->cache->glyph)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	glyph_cache = context->cache->glyph;
Packit Service fa4841
	glyph = glyph_cache_get(glyph_cache, cacheId, cacheIndex);
Packit Service fa4841
Packit Service fa4841
	if (!glyph)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	dx = glyph->x + *x;
Packit Service fa4841
	dy = glyph->y + *y;
Packit Service fa4841
Packit Service fa4841
	if (dx < bound->x)
Packit Service fa4841
	{
Packit Service fa4841
		sx = bound->x - dx;
Packit Service fa4841
		dx = bound->x;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (dy < bound->y)
Packit Service fa4841
	{
Packit Service fa4841
		sy = bound->y - dy;
Packit Service fa4841
		dy = bound->y;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if ((dx <= (bound->x + bound->width)) && (dy <= (bound->y + bound->height)))
Packit Service fa4841
	{
Packit Service fa4841
		INT32 dw = glyph->cx - sx;
Packit Service fa4841
		INT32 dh = glyph->cy - sy;
Packit Service fa4841
Packit Service fa4841
		if ((dw + dx) > (bound->x + bound->width))
Packit Service fa4841
			dw = (bound->x + bound->width) - (dw + dx);
Packit Service fa4841
Packit Service fa4841
		if ((dh + dy) > (bound->y + bound->height))
Packit Service fa4841
			dh = (bound->y + bound->height) - (dh + dy);
Packit Service fa4841
Packit Service fa4841
		if ((dh > 0) && (dw > 0))
Packit Service fa4841
		{
Packit Service fa4841
			if (!glyph->Draw(context, glyph, dx, dy, dw, dh, sx, sy, fOpRedundant))
Packit Service fa4841
				return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (flAccel & SO_CHAR_INC_EQUAL_BM_BASE)
Packit Service fa4841
		*x += glyph->cx;
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
static BOOL update_process_glyph_fragments(rdpContext* context, const BYTE* data, UINT32 length,
Packit Service b1ea74
                                           UINT32 cacheId, UINT32 ulCharInc, UINT32 flAccel,
Packit Service b1ea74
                                           UINT32 bgcolor, UINT32 fgcolor, INT32 x, INT32 y,
Packit Service b1ea74
                                           INT32 bkX, INT32 bkY, INT32 bkWidth, INT32 bkHeight,
Packit Service b1ea74
                                           INT32 opX, INT32 opY, INT32 opWidth, INT32 opHeight,
Packit Service b1ea74
                                           BOOL fOpRedundant)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 n;
Packit Service fa4841
	UINT32 id;
Packit Service fa4841
	UINT32 size;
Packit Service fa4841
	UINT32 index = 0;
Packit Service fa4841
	BYTE* fragments;
Packit Service fa4841
	rdpGraphics* graphics;
Packit Service fa4841
	rdpGlyphCache* glyph_cache;
Packit Service fa4841
	rdpGlyph* glyph;
Packit Service fa4841
	RDP_RECT bound;
Packit Service fa4841
Packit Service b1ea74
	if (!context || !data || !context->graphics || !context->cache || !context->cache->glyph)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	graphics = context->graphics;
Packit Service fa4841
	glyph_cache = context->cache->glyph;
Packit Service fa4841
	glyph = graphics->Glyph_Prototype;
Packit Service fa4841
Packit Service fa4841
	if (!glyph)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service b1ea74
	/* Limit op rectangle to visible screen. */
Packit Service fa4841
	if (opX < 0)
Packit Service fa4841
	{
Packit Service fa4841
		opWidth += opX;
Packit Service fa4841
		opX = 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (opY < 0)
Packit Service fa4841
	{
Packit Service fa4841
		opHeight += opY;
Packit Service fa4841
		opY = 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (opWidth < 0)
Packit Service fa4841
		opWidth = 0;
Packit Service fa4841
Packit Service fa4841
	if (opHeight < 0)
Packit Service fa4841
		opHeight = 0;
Packit Service fa4841
Packit Service b1ea74
	/* Limit bk rectangle to visible screen. */
Packit Service fa4841
	if (bkX < 0)
Packit Service fa4841
	{
Packit Service fa4841
		bkWidth += bkX;
Packit Service fa4841
		bkX = 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (bkY < 0)
Packit Service fa4841
	{
Packit Service fa4841
		bkHeight += bkY;
Packit Service fa4841
		bkY = 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (bkWidth < 0)
Packit Service fa4841
		bkWidth = 0;
Packit Service fa4841
Packit Service fa4841
	if (bkHeight < 0)
Packit Service fa4841
		bkHeight = 0;
Packit Service fa4841
Packit Service b1ea74
	if (opX + opWidth > (INT64)context->settings->DesktopWidth)
Packit Service fa4841
	{
Packit Service fa4841
		/**
Packit Service fa4841
		 * Some Microsoft servers send erroneous high values close to the
Packit Service fa4841
		 * sint16 maximum in the OpRight field of the GlyphIndex, FastIndex and
Packit Service fa4841
		 * FastGlyph drawing orders, probably a result of applications trying to
Packit Service fa4841
		 * clear the text line to the very right end.
Packit Service fa4841
		 * One example where this can be seen is typing in notepad.exe within
Packit Service fa4841
		 * a RDP session to Windows XP Professional SP3.
Packit Service fa4841
		 * This workaround prevents resulting problems in the UI callbacks.
Packit Service fa4841
		 */
Packit Service fa4841
		opWidth = context->settings->DesktopWidth - opX;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service b1ea74
	if (bkX + bkWidth > (INT64)context->settings->DesktopWidth)
Packit Service fa4841
	{
Packit Service fa4841
		/**
Packit Service fa4841
		 * Some Microsoft servers send erroneous high values close to the
Packit Service fa4841
		 * sint16 maximum in the OpRight field of the GlyphIndex, FastIndex and
Packit Service fa4841
		 * FastGlyph drawing orders, probably a result of applications trying to
Packit Service fa4841
		 * clear the text line to the very right end.
Packit Service fa4841
		 * One example where this can be seen is typing in notepad.exe within
Packit Service fa4841
		 * a RDP session to Windows XP Professional SP3.
Packit Service fa4841
		 * This workaround prevents resulting problems in the UI callbacks.
Packit Service fa4841
		 */
Packit Service fa4841
		bkWidth = context->settings->DesktopWidth - bkX;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	bound.x = bkX;
Packit Service fa4841
	bound.y = bkY;
Packit Service fa4841
	bound.width = bkWidth;
Packit Service fa4841
	bound.height = bkHeight;
Packit Service fa4841
Packit Service b1ea74
	if (!glyph->BeginDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor, fOpRedundant))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!IFCALLRESULT(TRUE, glyph->SetBounds, context, bkX, bkY, bkWidth, bkHeight))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	while (index < length)
Packit Service fa4841
	{
Packit Service fa4841
		const UINT32 op = data[index++];
Packit Service fa4841
Packit Service fa4841
		switch (op)
Packit Service fa4841
		{
Packit Service fa4841
			case GLYPH_FRAGMENT_USE:
Packit Service b1ea74
				if (index + 1 >= length)
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				id = data[index++];
Packit Service b1ea74
				fragments = (BYTE*)glyph_cache_fragment_get(glyph_cache, id, &size);
Packit Service fa4841
Packit Service fa4841
				if (fragments == NULL)
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				for (n = 0; n < size;)
Packit Service fa4841
				{
Packit Service fa4841
					const UINT32 fop = fragments[n++];
Packit Service b1ea74
					n = update_glyph_offset(fragments, size, n, &x, &y, ulCharInc, flAccel);
Packit Service fa4841
Packit Service b1ea74
					if (!update_process_glyph(context, fragments, fop, &x, &y, cacheId, flAccel,
Packit Service b1ea74
					                          fOpRedundant, &bound))
Packit Service fa4841
						return FALSE;
Packit Service fa4841
				}
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case GLYPH_FRAGMENT_ADD:
Packit Service fa4841
				if (index + 2 > length)
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				id = data[index++];
Packit Service fa4841
				size = data[index++];
Packit Service fa4841
				glyph_cache_fragment_put(glyph_cache, id, size, data);
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			default:
Packit Service b1ea74
				index = update_glyph_offset(data, length, index, &x, &y, ulCharInc, flAccel);
Packit Service fa4841
Packit Service b1ea74
				if (!update_process_glyph(context, data, op, &x, &y, cacheId, flAccel, fOpRedundant,
Packit Service b1ea74
				                          &bound))
Packit Service fa4841
					return FALSE;
Packit Service fa4841
Packit Service fa4841
				break;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return glyph->EndDraw(context, opX, opY, opWidth, opHeight, bgcolor, fgcolor);
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
static BOOL update_gdi_glyph_index(rdpContext* context, GLYPH_INDEX_ORDER* glyphIndex)
Packit Service fa4841
{
Packit Service fa4841
	INT32 bkWidth = 0, bkHeight = 0, opWidth = 0, opHeight = 0;
Packit Service fa4841
Packit Service fa4841
	if (!context || !glyphIndex || !context->cache)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (glyphIndex->bkRight > glyphIndex->bkLeft)
Packit Service fa4841
		bkWidth = glyphIndex->bkRight - glyphIndex->bkLeft + 1;
Packit Service fa4841
Packit Service fa4841
	if (glyphIndex->opRight > glyphIndex->opLeft)
Packit Service fa4841
		opWidth = glyphIndex->opRight - glyphIndex->opLeft + 1;
Packit Service fa4841
Packit Service fa4841
	if (glyphIndex->bkBottom > glyphIndex->bkTop)
Packit Service fa4841
		bkHeight = glyphIndex->bkBottom - glyphIndex->bkTop + 1;
Packit Service fa4841
Packit Service fa4841
	if (glyphIndex->opBottom > glyphIndex->opTop)
Packit Service fa4841
		opHeight = glyphIndex->opBottom - glyphIndex->opTop + 1;
Packit Service fa4841
Packit Service b1ea74
	return update_process_glyph_fragments(
Packit Service b1ea74
	    context, glyphIndex->data, glyphIndex->cbData, glyphIndex->cacheId, glyphIndex->ulCharInc,
Packit Service b1ea74
	    glyphIndex->flAccel, glyphIndex->backColor, glyphIndex->foreColor, glyphIndex->x,
Packit Service b1ea74
	    glyphIndex->y, glyphIndex->bkLeft, glyphIndex->bkTop, bkWidth, bkHeight, glyphIndex->opLeft,
Packit Service b1ea74
	    glyphIndex->opTop, opWidth, opHeight, glyphIndex->fOpRedundant);
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
static BOOL update_gdi_fast_index(rdpContext* context, const FAST_INDEX_ORDER* fastIndex)
Packit Service fa4841
{
Packit Service fa4841
	INT32 x, y;
Packit Service fa4841
	INT32 opLeft, opTop;
Packit Service fa4841
	INT32 opRight, opBottom;
Packit Service fa4841
	INT32 opWidth = 0, opHeight = 0;
Packit Service fa4841
	INT32 bkWidth = 0, bkHeight = 0;
Packit Service fa4841
Packit Service fa4841
	if (!context || !fastIndex || !context->cache)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	opLeft = fastIndex->opLeft;
Packit Service fa4841
	opTop = fastIndex->opTop;
Packit Service fa4841
	opRight = fastIndex->opRight;
Packit Service fa4841
	opBottom = fastIndex->opBottom;
Packit Service fa4841
	x = fastIndex->x;
Packit Service fa4841
	y = fastIndex->y;
Packit Service fa4841
Packit Service fa4841
	if (opBottom == -32768)
Packit Service fa4841
	{
Packit Service fa4841
		BYTE flags = (BYTE)(opTop & 0x0F);
Packit Service fa4841
Packit Service fa4841
		if (flags & 0x01)
Packit Service fa4841
			opBottom = fastIndex->bkBottom;
Packit Service fa4841
Packit Service fa4841
		if (flags & 0x02)
Packit Service fa4841
			opRight = fastIndex->bkRight;
Packit Service fa4841
Packit Service fa4841
		if (flags & 0x04)
Packit Service fa4841
			opTop = fastIndex->bkTop;
Packit Service fa4841
Packit Service fa4841
		if (flags & 0x08)
Packit Service fa4841
			opLeft = fastIndex->bkLeft;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (opLeft == 0)
Packit Service fa4841
		opLeft = fastIndex->bkLeft;
Packit Service fa4841
Packit Service fa4841
	if (opRight == 0)
Packit Service fa4841
		opRight = fastIndex->bkRight;
Packit Service fa4841
Packit Service fa4841
	/* Server can send a massive number (32766) which appears to be
Packit Service fa4841
	 * undocumented special behavior for "Erase all the way right".
Packit Service fa4841
	 * X11 has nondeterministic results asking for a draw that wide. */
Packit Service b1ea74
	if (opRight > (INT64)context->instance->settings->DesktopWidth)
Packit Service b1ea74
		opRight = (int)context->instance->settings->DesktopWidth;
Packit Service fa4841
Packit Service fa4841
	if (x == -32768)
Packit Service fa4841
		x = fastIndex->bkLeft;
Packit Service fa4841
Packit Service fa4841
	if (y == -32768)
Packit Service fa4841
		y = fastIndex->bkTop;
Packit Service fa4841
Packit Service fa4841
	if (fastIndex->bkRight > fastIndex->bkLeft)
Packit Service fa4841
		bkWidth = fastIndex->bkRight - fastIndex->bkLeft + 1;
Packit Service fa4841
Packit Service fa4841
	if (fastIndex->bkBottom > fastIndex->bkTop)
Packit Service fa4841
		bkHeight = fastIndex->bkBottom - fastIndex->bkTop + 1;
Packit Service fa4841
Packit Service fa4841
	if (opRight > opLeft)
Packit Service fa4841
		opWidth = opRight - opLeft + 1;
Packit Service fa4841
Packit Service fa4841
	if (opBottom > opTop)
Packit Service fa4841
		opHeight = opBottom - opTop + 1;
Packit Service fa4841
Packit Service b1ea74
	return update_process_glyph_fragments(
Packit Service b1ea74
	    context, fastIndex->data, fastIndex->cbData, fastIndex->cacheId, fastIndex->ulCharInc,
Packit Service b1ea74
	    fastIndex->flAccel, fastIndex->backColor, fastIndex->foreColor, x, y, fastIndex->bkLeft,
Packit Service b1ea74
	    fastIndex->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE);
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
static BOOL update_gdi_fast_glyph(rdpContext* context, const FAST_GLYPH_ORDER* fastGlyph)
Packit Service fa4841
{
Packit Service fa4841
	INT32 x, y;
Packit Service b1ea74
	BYTE text_data[4] = { 0 };
Packit Service fa4841
	INT32 opLeft, opTop;
Packit Service fa4841
	INT32 opRight, opBottom;
Packit Service fa4841
	INT32 opWidth = 0, opHeight = 0;
Packit Service fa4841
	INT32 bkWidth = 0, bkHeight = 0;
Packit Service fa4841
	rdpCache* cache;
Packit Service fa4841
Packit Service fa4841
	if (!context || !fastGlyph || !context->cache)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	cache = context->cache;
Packit Service fa4841
	opLeft = fastGlyph->opLeft;
Packit Service fa4841
	opTop = fastGlyph->opTop;
Packit Service fa4841
	opRight = fastGlyph->opRight;
Packit Service fa4841
	opBottom = fastGlyph->opBottom;
Packit Service fa4841
	x = fastGlyph->x;
Packit Service fa4841
	y = fastGlyph->y;
Packit Service fa4841
Packit Service fa4841
	if (opBottom == -32768)
Packit Service fa4841
	{
Packit Service fa4841
		BYTE flags = (BYTE)(opTop & 0x0F);
Packit Service fa4841
Packit Service fa4841
		if (flags & 0x01)
Packit Service fa4841
			opBottom = fastGlyph->bkBottom;
Packit Service fa4841
Packit Service fa4841
		if (flags & 0x02)
Packit Service fa4841
			opRight = fastGlyph->bkRight;
Packit Service fa4841
Packit Service fa4841
		if (flags & 0x04)
Packit Service fa4841
			opTop = fastGlyph->bkTop;
Packit Service fa4841
Packit Service fa4841
		if (flags & 0x08)
Packit Service fa4841
			opLeft = fastGlyph->bkLeft;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (opLeft == 0)
Packit Service fa4841
		opLeft = fastGlyph->bkLeft;
Packit Service fa4841
Packit Service fa4841
	if (opRight == 0)
Packit Service fa4841
		opRight = fastGlyph->bkRight;
Packit Service fa4841
Packit Service fa4841
	/* See update_gdi_fast_index opRight comment. */
Packit Service b1ea74
	if (opRight > (INT64)context->instance->settings->DesktopWidth)
Packit Service b1ea74
		opRight = (int)context->instance->settings->DesktopWidth;
Packit Service fa4841
Packit Service fa4841
	if (x == -32768)
Packit Service fa4841
		x = fastGlyph->bkLeft;
Packit Service fa4841
Packit Service fa4841
	if (y == -32768)
Packit Service fa4841
		y = fastGlyph->bkTop;
Packit Service fa4841
Packit Service fa4841
	if ((fastGlyph->cbData > 1) && (fastGlyph->glyphData.aj))
Packit Service fa4841
	{
Packit Service fa4841
		/* got option font that needs to go into cache */
Packit Service fa4841
		rdpGlyph* glyph;
Packit Service fa4841
		const GLYPH_DATA_V2* glyphData = &fastGlyph->glyphData;
Packit Service fa4841
Packit Service b1ea74
		glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx, glyphData->cy,
Packit Service fa4841
		                    glyphData->cb, glyphData->aj);
Packit Service fa4841
Packit Service fa4841
		if (!glyph)
Packit Service fa4841
			return FALSE;
Packit Service fa4841
Packit Service b1ea74
		if (!glyph_cache_put(cache->glyph, fastGlyph->cacheId, fastGlyph->data[0], glyph))
Packit Service fa4841
		{
Packit Service fa4841
			glyph->Free(context, glyph);
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	text_data[0] = fastGlyph->data[0];
Packit Service fa4841
	text_data[1] = 0;
Packit Service fa4841
Packit Service fa4841
	if (fastGlyph->bkRight > fastGlyph->bkLeft)
Packit Service fa4841
		bkWidth = fastGlyph->bkRight - fastGlyph->bkLeft + 1;
Packit Service fa4841
Packit Service fa4841
	if (fastGlyph->bkBottom > fastGlyph->bkTop)
Packit Service fa4841
		bkHeight = fastGlyph->bkBottom - fastGlyph->bkTop + 1;
Packit Service fa4841
Packit Service fa4841
	if (opRight > opLeft)
Packit Service fa4841
		opWidth = opRight - opLeft + 1;
Packit Service fa4841
Packit Service fa4841
	if (opBottom > opTop)
Packit Service fa4841
		opHeight = opBottom - opTop + 1;
Packit Service fa4841
Packit Service b1ea74
	return update_process_glyph_fragments(
Packit Service b1ea74
	    context, text_data, sizeof(text_data), fastGlyph->cacheId, fastGlyph->ulCharInc,
Packit Service b1ea74
	    fastGlyph->flAccel, fastGlyph->backColor, fastGlyph->foreColor, x, y, fastGlyph->bkLeft,
Packit Service b1ea74
	    fastGlyph->bkTop, bkWidth, bkHeight, opLeft, opTop, opWidth, opHeight, FALSE);
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
static BOOL update_gdi_cache_glyph(rdpContext* context, const CACHE_GLYPH_ORDER* cacheGlyph)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 i;
Packit Service fa4841
	rdpCache* cache;
Packit Service fa4841
Packit Service fa4841
	if (!context || !cacheGlyph || !context->cache)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	cache = context->cache;
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < cacheGlyph->cGlyphs; i++)
Packit Service fa4841
	{
Packit Service fa4841
		const GLYPH_DATA* glyph_data = &cacheGlyph->glyphData[i];
Packit Service fa4841
		rdpGlyph* glyph;
Packit Service fa4841
Packit Service fa4841
		if (!glyph_data)
Packit Service fa4841
			return FALSE;
Packit Service fa4841
Packit Service b1ea74
		if (!(glyph = Glyph_Alloc(context, glyph_data->x, glyph_data->y, glyph_data->cx,
Packit Service b1ea74
		                          glyph_data->cy, glyph_data->cb, glyph_data->aj)))
Packit Service fa4841
			return FALSE;
Packit Service fa4841
Packit Service b1ea74
		if (!glyph_cache_put(cache->glyph, cacheGlyph->cacheId, glyph_data->cacheIndex, glyph))
Packit Service fa4841
		{
Packit Service fa4841
			glyph->Free(context, glyph);
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
static BOOL update_gdi_cache_glyph_v2(rdpContext* context, const CACHE_GLYPH_V2_ORDER* cacheGlyphV2)
Packit Service fa4841
{
Packit Service fa4841
	UINT32 i;
Packit Service fa4841
	rdpCache* cache;
Packit Service fa4841
Packit Service fa4841
	if (!context || !cacheGlyphV2 || !context->cache)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	cache = context->cache;
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < cacheGlyphV2->cGlyphs; i++)
Packit Service fa4841
	{
Packit Service fa4841
		const GLYPH_DATA_V2* glyphData = &cacheGlyphV2->glyphData[i];
Packit Service fa4841
		rdpGlyph* glyph;
Packit Service fa4841
Packit Service fa4841
		if (!glyphData)
Packit Service fa4841
			return FALSE;
Packit Service fa4841
Packit Service b1ea74
		glyph = Glyph_Alloc(context, glyphData->x, glyphData->y, glyphData->cx, glyphData->cy,
Packit Service b1ea74
		                    glyphData->cb, glyphData->aj);
Packit Service fa4841
Packit Service fa4841
		if (!glyph)
Packit Service fa4841
			return FALSE;
Packit Service fa4841
Packit Service b1ea74
		if (!glyph_cache_put(cache->glyph, cacheGlyphV2->cacheId, glyphData->cacheIndex, glyph))
Packit Service fa4841
		{
Packit Service fa4841
			glyph->Free(context, glyph);
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
rdpGlyph* glyph_cache_get(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index)
Packit Service fa4841
{
Packit Service fa4841
	rdpGlyph* glyph;
Packit Service b1ea74
	WLog_Print(glyphCache->log, WLOG_DEBUG, "GlyphCacheGet: id: %" PRIu32 " index: %" PRIu32 "", id,
Packit Service fa4841
	           index);
Packit Service fa4841
Packit Service fa4841
	if (id > 9)
Packit Service fa4841
	{
Packit Service b1ea74
		WLog_ERR(TAG, "invalid glyph cache id: %" PRIu32 "", id);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (index > glyphCache->glyphCache[id].number)
Packit Service fa4841
	{
Packit Service b1ea74
		WLog_ERR(TAG, "index %" PRIu32 " out of range for cache id: %" PRIu32 "", index, id);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	glyph = glyphCache->glyphCache[id].entries[index];
Packit Service fa4841
Packit Service fa4841
	if (!glyph)
Packit Service b1ea74
		WLog_ERR(TAG, "no glyph found at cache index: %" PRIu32 " in cache id: %" PRIu32 "", index,
Packit Service b1ea74
		         id);
Packit Service fa4841
Packit Service fa4841
	return glyph;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
BOOL glyph_cache_put(rdpGlyphCache* glyphCache, UINT32 id, UINT32 index, rdpGlyph* glyph)
Packit Service fa4841
{
Packit Service fa4841
	rdpGlyph* prevGlyph;
Packit Service fa4841
Packit Service fa4841
	if (id > 9)
Packit Service fa4841
	{
Packit Service b1ea74
		WLog_ERR(TAG, "invalid glyph cache id: %" PRIu32 "", id);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service b1ea74
	if (index >= glyphCache->glyphCache[id].number)
Packit Service fa4841
	{
Packit Service b1ea74
		WLog_ERR(TAG, "invalid glyph cache index: %" PRIu32 " in cache id: %" PRIu32 "", index, id);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service b1ea74
	WLog_Print(glyphCache->log, WLOG_DEBUG, "GlyphCachePut: id: %" PRIu32 " index: %" PRIu32 "", id,
Packit Service fa4841
	           index);
Packit Service fa4841
	prevGlyph = glyphCache->glyphCache[id].entries[index];
Packit Service fa4841
Packit Service fa4841
	if (prevGlyph)
Packit Service fa4841
		prevGlyph->Free(glyphCache->context, prevGlyph);
Packit Service fa4841
Packit Service fa4841
	glyphCache->glyphCache[id].entries[index] = glyph;
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
const void* glyph_cache_fragment_get(rdpGlyphCache* glyphCache, UINT32 index, UINT32* size)
Packit Service fa4841
{
Packit Service fa4841
	void* fragment;
Packit Service fa4841
Packit Service fa4841
	if (index > 255)
Packit Service fa4841
	{
Packit Service b1ea74
		WLog_ERR(TAG, "invalid glyph cache fragment index: %" PRIu32 "", index);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	fragment = glyphCache->fragCache.entries[index].fragment;
Packit Service b1ea74
	*size = (BYTE)glyphCache->fragCache.entries[index].size;
Packit Service fa4841
	WLog_Print(glyphCache->log, WLOG_DEBUG,
Packit Service b1ea74
	           "GlyphCacheFragmentGet: index: %" PRIu32 " size: %" PRIu32 "", index, *size);
Packit Service fa4841
Packit Service fa4841
	if (!fragment)
Packit Service b1ea74
		WLog_ERR(TAG, "invalid glyph fragment at index:%" PRIu32 "", index);
Packit Service fa4841
Packit Service fa4841
	return fragment;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
BOOL glyph_cache_fragment_put(rdpGlyphCache* glyphCache, UINT32 index, UINT32 size,
Packit Service b1ea74
                              const void* fragment)
Packit Service fa4841
{
Packit Service fa4841
	void* prevFragment;
Packit Service fa4841
	void* copy;
Packit Service fa4841
Packit Service fa4841
	if (index > 255)
Packit Service fa4841
	{
Packit Service b1ea74
		WLog_ERR(TAG, "invalid glyph cache fragment index: %" PRIu32 "", index);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	copy = malloc(size);
Packit Service fa4841
Packit Service fa4841
	if (!copy)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	WLog_Print(glyphCache->log, WLOG_DEBUG,
Packit Service b1ea74
	           "GlyphCacheFragmentPut: index: %" PRIu32 " size: %" PRIu32 "", index, size);
Packit Service fa4841
	CopyMemory(copy, fragment, size);
Packit Service fa4841
	prevFragment = glyphCache->fragCache.entries[index].fragment;
Packit Service fa4841
	glyphCache->fragCache.entries[index].fragment = copy;
Packit Service fa4841
	glyphCache->fragCache.entries[index].size = size;
Packit Service fa4841
	free(prevFragment);
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void glyph_cache_register_callbacks(rdpUpdate* update)
Packit Service fa4841
{
Packit Service fa4841
	update->primary->GlyphIndex = update_gdi_glyph_index;
Packit Service fa4841
	update->primary->FastIndex = update_gdi_fast_index;
Packit Service fa4841
	update->primary->FastGlyph = update_gdi_fast_glyph;
Packit Service fa4841
	update->secondary->CacheGlyph = update_gdi_cache_glyph;
Packit Service fa4841
	update->secondary->CacheGlyphV2 = update_gdi_cache_glyph_v2;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
rdpGlyphCache* glyph_cache_new(rdpSettings* settings)
Packit Service fa4841
{
Packit Service fa4841
	int i;
Packit Service fa4841
	rdpGlyphCache* glyphCache;
Packit Service b1ea74
	glyphCache = (rdpGlyphCache*)calloc(1, sizeof(rdpGlyphCache));
Packit Service fa4841
Packit Service fa4841
	if (!glyphCache)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	glyphCache->log = WLog_Get("com.freerdp.cache.glyph");
Packit Service fa4841
	glyphCache->settings = settings;
Packit Service b1ea74
	glyphCache->context = ((freerdp*)settings->instance)->update->context;
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < 10; i++)
Packit Service fa4841
	{
Packit Service fa4841
		glyphCache->glyphCache[i].number = settings->GlyphCache[i].cacheEntries;
Packit Service b1ea74
		glyphCache->glyphCache[i].maxCellSize = settings->GlyphCache[i].cacheMaximumCellSize;
Packit Service b1ea74
		glyphCache->glyphCache[i].entries =
Packit Service b1ea74
		    (rdpGlyph**)calloc(glyphCache->glyphCache[i].number, sizeof(rdpGlyph*));
Packit Service fa4841
Packit Service fa4841
		if (!glyphCache->glyphCache[i].entries)
Packit Service fa4841
			goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	glyphCache->fragCache.entries = calloc(256, sizeof(FRAGMENT_CACHE_ENTRY));
Packit Service fa4841
Packit Service fa4841
	if (!glyphCache->fragCache.entries)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	return glyphCache;
Packit Service fa4841
fail:
Packit Service fa4841
	glyph_cache_free(glyphCache);
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void glyph_cache_free(rdpGlyphCache* glyphCache)
Packit Service fa4841
{
Packit Service fa4841
	if (glyphCache)
Packit Service fa4841
	{
Packit Service fa4841
		int i;
Packit Service fa4841
		GLYPH_CACHE* cache = glyphCache->glyphCache;
Packit Service fa4841
Packit Service b1ea74
		for (i = 0; i < 10; i++)
Packit Service fa4841
		{
Packit Service b1ea74
			UINT32 j;
Packit Service b1ea74
			rdpGlyph** entries = cache[i].entries;
Packit Service bb5c11
Packit Service b1ea74
			if (!entries)
Packit Service b1ea74
				continue;
Packit Service fa4841
Packit Service b1ea74
			for (j = 0; j < cache[i].number; j++)
Packit Service b1ea74
			{
Packit Service b1ea74
				rdpGlyph* glyph = entries[j];
Packit Service bb5c11
Packit Service b1ea74
				if (glyph)
Packit Service b1ea74
				{
Packit Service b1ea74
					glyph->Free(glyphCache->context, glyph);
Packit Service b1ea74
					entries[j] = NULL;
Packit Service fa4841
				}
Packit Service bb5c11
			}
Packit Service b1ea74
Packit Service b1ea74
			free(entries);
Packit Service b1ea74
			cache[i].entries = NULL;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (glyphCache->fragCache.entries)
Packit Service fa4841
		{
Packit Service fa4841
			for (i = 0; i < 256; i++)
Packit Service fa4841
			{
Packit Service fa4841
				free(glyphCache->fragCache.entries[i].fragment);
Packit Service fa4841
				glyphCache->fragCache.entries[i].fragment = NULL;
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		free(glyphCache->fragCache.entries);
Packit Service fa4841
		free(glyphCache);
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
CACHE_GLYPH_ORDER* copy_cache_glyph_order(rdpContext* context, const CACHE_GLYPH_ORDER* glyph)
Packit Service fa4841
{
Packit Service fa4841
	size_t x;
Packit Service fa4841
	CACHE_GLYPH_ORDER* dst = calloc(1, sizeof(CACHE_GLYPH_ORDER));
Packit Service fa4841
Packit Service fa4841
	if (!dst || !glyph)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	*dst = *glyph;
Packit Service fa4841
Packit Service fa4841
	for (x = 0; x < glyph->cGlyphs; x++)
Packit Service fa4841
	{
Packit Service fa4841
		const GLYPH_DATA* src = &glyph->glyphData[x];
Packit Service fa4841
		GLYPH_DATA* data = &dst->glyphData[x];
Packit Service fa4841
Packit Service fa4841
		if (src->aj)
Packit Service fa4841
		{
Packit Service fa4841
			const size_t size = src->cb;
Packit Service fa4841
			data->aj = malloc(size);
Packit Service fa4841
Packit Service fa4841
			if (!data->aj)
Packit Service fa4841
				goto fail;
Packit Service fa4841
Packit Service fa4841
			memcpy(data->aj, src->aj, size);
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (glyph->unicodeCharacters)
Packit Service fa4841
	{
Packit Service b1ea74
		if (glyph->cGlyphs == 0)
Packit Service b1ea74
			goto fail;
Packit Service b1ea74
Packit Service fa4841
		dst->unicodeCharacters = calloc(glyph->cGlyphs, sizeof(WCHAR));
Packit Service fa4841
Packit Service fa4841
		if (!dst->unicodeCharacters)
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		memcpy(dst->unicodeCharacters, glyph->unicodeCharacters, sizeof(WCHAR) * glyph->cGlyphs);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return dst;
Packit Service fa4841
fail:
Packit Service fa4841
	free_cache_glyph_order(context, dst);
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void free_cache_glyph_order(rdpContext* context, CACHE_GLYPH_ORDER* glyph)
Packit Service fa4841
{
Packit Service fa4841
	if (glyph)
Packit Service fa4841
	{
Packit Service fa4841
		size_t x;
Packit Service fa4841
Packit Service fa4841
		for (x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
Packit Service fa4841
			free(glyph->glyphData[x].aj);
Packit Service fa4841
Packit Service fa4841
		free(glyph->unicodeCharacters);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	free(glyph);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
CACHE_GLYPH_V2_ORDER* copy_cache_glyph_v2_order(rdpContext* context,
Packit Service b1ea74
                                                const CACHE_GLYPH_V2_ORDER* glyph)
Packit Service fa4841
{
Packit Service fa4841
	size_t x;
Packit Service fa4841
	CACHE_GLYPH_V2_ORDER* dst = calloc(1, sizeof(CACHE_GLYPH_V2_ORDER));
Packit Service fa4841
Packit Service fa4841
	if (!dst || !glyph)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	*dst = *glyph;
Packit Service fa4841
Packit Service fa4841
	for (x = 0; x < glyph->cGlyphs; x++)
Packit Service fa4841
	{
Packit Service fa4841
		const GLYPH_DATA_V2* src = &glyph->glyphData[x];
Packit Service fa4841
		GLYPH_DATA_V2* data = &dst->glyphData[x];
Packit Service fa4841
Packit Service fa4841
		if (src->aj)
Packit Service fa4841
		{
Packit Service fa4841
			const size_t size = src->cb;
Packit Service fa4841
			data->aj = malloc(size);
Packit Service fa4841
Packit Service fa4841
			if (!data->aj)
Packit Service fa4841
				goto fail;
Packit Service fa4841
Packit Service fa4841
			memcpy(data->aj, src->aj, size);
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (glyph->unicodeCharacters)
Packit Service fa4841
	{
Packit Service b1ea74
		if (glyph->cGlyphs == 0)
Packit Service b1ea74
			goto fail;
Packit Service b1ea74
Packit Service fa4841
		dst->unicodeCharacters = calloc(glyph->cGlyphs, sizeof(WCHAR));
Packit Service fa4841
Packit Service fa4841
		if (!dst->unicodeCharacters)
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		memcpy(dst->unicodeCharacters, glyph->unicodeCharacters, sizeof(WCHAR) * glyph->cGlyphs);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return dst;
Packit Service fa4841
fail:
Packit Service fa4841
	free_cache_glyph_v2_order(context, dst);
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void free_cache_glyph_v2_order(rdpContext* context, CACHE_GLYPH_V2_ORDER* glyph)
Packit Service fa4841
{
Packit Service fa4841
	if (glyph)
Packit Service fa4841
	{
Packit Service fa4841
		size_t x;
Packit Service fa4841
Packit Service fa4841
		for (x = 0; x < ARRAYSIZE(glyph->glyphData); x++)
Packit Service fa4841
			free(glyph->glyphData[x].aj);
Packit Service fa4841
Packit Service fa4841
		free(glyph->unicodeCharacters);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	free(glyph);
Packit Service fa4841
}