Blame libfreerdp/cache/glyph.c

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