2025-08-08 20:00:36 +02:00

456 lines
12 KiB
C

/**************************************************************************/
/* */
/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */
/* Copyright (c) 2008-2017 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */
/* Copyright (c) 2011-2022 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
/* Copyright (c) 2014-2019 Mihai Moldovan <ionic@ionic.de> */
/* Copyright (c) 2014-2022 Ulrich Sibiller <uli42@gmx.de> */
/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */
/* */
/* NXAGENT, NX protocol compression and NX extensions to this software */
/* are copyright of the aforementioned persons and companies. */
/* */
/* Redistribution and use of the present software is allowed according */
/* to terms specified in the file LICENSE which comes in the source */
/* distribution. */
/* */
/* All rights reserved. */
/* */
/* NOTE: This software has received contributions from various other */
/* contributors, only the core maintainers and supporters are listed as */
/* copyright holders. Please contact us, if you feel you should be listed */
/* as copyright holder, as well. */
/* */
/**************************************************************************/
/*
* Copyright © 2000 SuSE, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of SuSE not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. SuSE makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Keith Packard, SuSE, Inc.
*/
#include "../../render/glyph.c"
#ifdef NXAGENT_SERVER
#include "Render.h"
#define PANIC
#define WARNING
#undef DEBUG
#undef TEST
#endif
GlyphRefPtr
FindGlyphRef (GlyphHashPtr hash, CARD32 signature, Bool match, GlyphPtr compare)
{
CARD32 elt, step, s;
GlyphPtr glyph;
GlyphRefPtr table, gr, del;
CARD32 tableSize = hash->hashSet->size;
table = hash->table;
elt = signature % tableSize;
step = 0;
del = 0;
for (;;)
{
gr = &table[elt];
s = gr->signature;
glyph = gr->glyph;
if (!glyph)
{
if (del)
gr = del;
break;
}
if (glyph == DeletedGlyph)
{
if (!del)
del = gr;
else if (gr == del)
break;
}
#ifdef NXAGENT_SERVER
else if (s == signature && match && glyph->size != compare->size)
{
/*
* if the glyphsize is different there's no need to do a memcmp
* because it will surely report difference. And even worse:
* it will read beyond the end of glyph under some
* circumstances, which can be detected when compiling with
* -fsanitize=address.
*/
}
#endif
else if (s == signature &&
(!match ||
memcmp (&compare->info, &glyph->info, compare->size) == 0))
{
break;
}
if (!step)
{
step = signature % hash->hashSet->rehash;
if (!step)
step = 1;
}
elt += step;
if (elt >= tableSize)
elt -= tableSize;
}
return gr;
}
void
AddGlyph (GlyphSetPtr glyphSet, GlyphPtr glyph, Glyph id)
{
GlyphRefPtr gr;
CARD32 hash;
CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph top global");
/* Locate existing matching glyph */
hash = HashGlyph (glyph);
gr = FindGlyphRef (&globalGlyphs[glyphSet->fdepth], hash, TRUE, glyph);
if (gr->glyph && gr->glyph != DeletedGlyph)
{
free (glyph);
glyph = gr->glyph;
}
else
{
gr->glyph = glyph;
gr->signature = hash;
globalGlyphs[glyphSet->fdepth].tableEntries++;
}
/* Insert/replace glyphset value */
gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0);
++glyph->refcnt;
if (gr->glyph && gr->glyph != DeletedGlyph)
FreeGlyph (gr->glyph, glyphSet->fdepth);
else
glyphSet->hash.tableEntries++;
gr->glyph = glyph;
gr->signature = id;
#ifdef NXAGENT_SERVER
gr -> corruptedGlyph = 1;
#endif
CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph bottom");
}
GlyphPtr
FindGlyph (GlyphSetPtr glyphSet, Glyph id)
{
GlyphPtr glyph;
#ifdef NXAGENT_SERVER
GlyphRefPtr gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0);
glyph = gr -> glyph;
#else
glyph = FindGlyphRef (&glyphSet->hash, id, FALSE, 0)->glyph;
#endif
if (glyph == DeletedGlyph)
{
glyph = 0;
}
#ifdef NXAGENT_SERVER
else if (gr -> corruptedGlyph == 1)
{
#ifdef DEBUG
fprintf(stderr, "FindGlyphRef: Going to synchronize the glyph [%p] for glyphset [%p].\n",
(void *) glyph, (void *) glyphSet);
#endif
nxagentAddGlyphs(glyphSet, &id, &(glyph -> info), 1,
(CARD8*)(glyph + 1), glyph -> size - sizeof(xGlyphInfo));
}
#endif
return glyph;
}
Bool
ResizeGlyphHash (GlyphHashPtr hash, CARD32 change, Bool global)
{
CARD32 tableEntries;
GlyphHashSetPtr hashSet;
GlyphHashRec newHash;
GlyphRefPtr gr;
GlyphPtr glyph;
int i;
int oldSize;
CARD32 s;
tableEntries = hash->tableEntries + change;
hashSet = FindGlyphHashSet (tableEntries);
if (hashSet == hash->hashSet)
return TRUE;
if (global)
CheckDuplicates (hash, "ResizeGlyphHash top");
if (!AllocateGlyphHash (&newHash, hashSet))
return FALSE;
if (hash->table)
{
oldSize = hash->hashSet->size;
for (i = 0; i < oldSize; i++)
{
glyph = hash->table[i].glyph;
if (glyph && glyph != DeletedGlyph)
{
s = hash->table[i].signature;
#ifdef NXAGENT_SERVER
CARD32 c = hash->table[i].corruptedGlyph;
#endif
gr = FindGlyphRef (&newHash, s, global, glyph);
gr->signature = s;
gr->glyph = glyph;
#ifdef NXAGENT_SERVER
gr -> corruptedGlyph = c;
#endif
++newHash.tableEntries;
}
}
free (hash->table);
}
*hash = newHash;
if (global)
CheckDuplicates (hash, "ResizeGlyphHash bottom");
return TRUE;
}
void
miGlyphs (CARD8 op,
PicturePtr pSrc,
PicturePtr pDst,
PictFormatPtr maskFormat,
INT16 xSrc,
INT16 ySrc,
int nlist,
GlyphListPtr list,
GlyphPtr *glyphs)
{
PixmapPtr pPixmap = 0;
PicturePtr pPicture;
PixmapPtr pMaskPixmap = 0;
PicturePtr pMask;
ScreenPtr pScreen = pDst->pDrawable->pScreen;
int width = 0, height = 0;
int x, y;
int xDst = list->xOff, yDst = list->yOff;
int n;
GlyphPtr glyph;
int error;
BoxRec extents;
CARD32 component_alpha;
#ifdef NXAGENT_SERVER
/*
* Get rid of the warning.
*/
extents.x1 = 0;
extents.y1 = 0;
#endif
if (maskFormat)
{
GCPtr pGC;
xRectangle rect;
#ifdef NXAGENT_SERVER
if (nxagentGlyphsExtents != NullBox)
{
memcpy(&extents, nxagentGlyphsExtents, sizeof(BoxRec));
}
else
{
nxagentGlyphsExtents = (BoxPtr) malloc(sizeof(BoxRec));
if (!nxagentGlyphsExtents)
{
#ifdef WARNING
fprintf(stderr, "WARNING! Cannot allocate GlyphExtents\n");
#endif
return;
}
GlyphExtents (nlist, list, glyphs, &extents);
memcpy(nxagentGlyphsExtents, &extents, sizeof(BoxRec));
}
#else
GlyphExtents (nlist, list, glyphs, &extents);
#endif
if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1)
return;
width = extents.x2 - extents.x1;
height = extents.y2 - extents.y1;
pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height,
maskFormat->depth,
CREATE_PIXMAP_USAGE_SCRATCH);
if (!pMaskPixmap)
return;
component_alpha = NeedsComponent(maskFormat->format);
pMask = CreatePicture (0, &pMaskPixmap->drawable,
maskFormat, CPComponentAlpha, &component_alpha,
serverClient, &error);
if (!pMask)
{
(*pScreen->DestroyPixmap) (pMaskPixmap);
return;
}
pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen);
ValidateGC (&pMaskPixmap->drawable, pGC);
rect.x = 0;
rect.y = 0;
rect.width = width;
rect.height = height;
(*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect);
FreeScratchGC (pGC);
x = -extents.x1;
y = -extents.y1;
}
else
{
pMask = pDst;
x = 0;
y = 0;
}
pPicture = 0;
while (nlist--)
{
x += list->xOff;
y += list->yOff;
n = list->len;
while (n--)
{
glyph = *glyphs++;
if (!pPicture)
{
pPixmap = GetScratchPixmapHeader (pScreen, glyph->info.width, glyph->info.height,
list->format->depth,
list->format->depth,
0, (void *) (glyph + 1));
if (!pPixmap)
return;
component_alpha = NeedsComponent(list->format->format);
pPicture = CreatePicture (0, &pPixmap->drawable, list->format,
CPComponentAlpha, &component_alpha,
serverClient, &error);
if (!pPicture)
{
FreeScratchPixmapHeader (pPixmap);
return;
}
}
(*pScreen->ModifyPixmapHeader) (pPixmap,
glyph->info.width, glyph->info.height,
0, 0, -1, (void *) (glyph + 1));
#ifdef NXAGENT_SERVER
/*
* The following line fixes a problem with glyphs that appeared
* as clipped. It was a side effect due the validate function
* "ValidatePicture" that makes a check on the Drawable serial
* number instead of the picture serial number, failing thus
* the clip mask update.
*/
pPicture->pDrawable->serialNumber = NEXT_SERIAL_NUMBER;
#endif
pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
if (maskFormat)
{
CompositePicture (PictOpAdd,
pPicture,
None,
pMask,
0, 0,
0, 0,
x - glyph->info.x,
y - glyph->info.y,
glyph->info.width,
glyph->info.height);
}
else
{
CompositePicture (op,
pSrc,
pPicture,
pDst,
xSrc + (x - glyph->info.x) - xDst,
ySrc + (y - glyph->info.y) - yDst,
0, 0,
x - glyph->info.x,
y - glyph->info.y,
glyph->info.width,
glyph->info.height);
}
x += glyph->info.xOff;
y += glyph->info.yOff;
}
list++;
if (pPicture)
{
FreeScratchPixmapHeader (pPixmap);
FreePicture ((void *) pPicture, 0);
pPicture = 0;
pPixmap = 0;
}
}
if (maskFormat)
{
x = extents.x1;
y = extents.y1;
CompositePicture (op,
pSrc,
pMask,
pDst,
xSrc + x - xDst,
ySrc + y - yDst,
0, 0,
x, y,
width, height);
FreePicture ((void *) pMask, (XID) 0);
(*pScreen->DestroyPixmap) (pMaskPixmap);
}
}