xenocara/xserver/render/filter.c

360 lines
9.1 KiB
C
Raw Normal View History

2006-11-26 11:13:41 -07:00
/*
* Copyright © 2002 Keith Packard
*
* 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 Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD 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.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include "misc.h"
#include "scrnintstr.h"
#include "os.h"
#include "regionstr.h"
#include "validate.h"
#include "windowstr.h"
#include "input.h"
#include "resource.h"
#include "colormapst.h"
#include "cursorstr.h"
#include "dixstruct.h"
#include "gcstruct.h"
#include "servermd.h"
#include "picturestr.h"
static char **filterNames;
static int nfilterNames;
/*
* standard but not required filters don't have constant indices
*/
int
PictureGetFilterId (char *filter, int len, Bool makeit)
{
int i;
char *name;
char **names;
if (len < 0)
len = strlen (filter);
for (i = 0; i < nfilterNames; i++)
if (!CompareISOLatin1Lowered ((unsigned char *) filterNames[i], -1, (unsigned char *) filter, len))
return i;
if (!makeit)
return -1;
name = malloc(len + 1);
2006-11-26 11:13:41 -07:00
if (!name)
return -1;
memcpy (name, filter, len);
name[len] = '\0';
if (filterNames)
names = realloc(filterNames, (nfilterNames + 1) * sizeof (char *));
2006-11-26 11:13:41 -07:00
else
names = malloc(sizeof (char *));
2006-11-26 11:13:41 -07:00
if (!names)
{
free(name);
2006-11-26 11:13:41 -07:00
return -1;
}
filterNames = names;
i = nfilterNames++;
filterNames[i] = name;
return i;
}
static Bool
PictureSetDefaultIds (void)
{
/* careful here -- this list must match the #define values */
if (PictureGetFilterId (FilterNearest, -1, TRUE) != PictFilterNearest)
return FALSE;
if (PictureGetFilterId (FilterBilinear, -1, TRUE) != PictFilterBilinear)
return FALSE;
if (PictureGetFilterId (FilterFast, -1, TRUE) != PictFilterFast)
return FALSE;
if (PictureGetFilterId (FilterGood, -1, TRUE) != PictFilterGood)
return FALSE;
if (PictureGetFilterId (FilterBest, -1, TRUE) != PictFilterBest)
return FALSE;
if (PictureGetFilterId (FilterConvolution, -1, TRUE) != PictFilterConvolution)
return FALSE;
return TRUE;
}
char *
PictureGetFilterName (int id)
{
if (0 <= id && id < nfilterNames)
return filterNames[id];
else
return 0;
}
static void
PictureFreeFilterIds (void)
{
int i;
for (i = 0; i < nfilterNames; i++)
free(filterNames[i]);
free(filterNames);
2006-11-26 11:13:41 -07:00
nfilterNames = 0;
filterNames = 0;
}
int
2006-11-26 11:13:41 -07:00
PictureAddFilter (ScreenPtr pScreen,
char *filter,
PictFilterValidateParamsProcPtr ValidateParams,
int width,
int height)
2006-11-26 11:13:41 -07:00
{
PictureScreenPtr ps = GetPictureScreen(pScreen);
int id = PictureGetFilterId (filter, -1, TRUE);
int i;
PictFilterPtr filters;
if (id < 0)
return -1;
/*
* It's an error to attempt to reregister a filter
*/
for (i = 0; i < ps->nfilters; i++)
if (ps->filters[i].id == id)
return -1;
if (ps->filters)
filters = realloc(ps->filters, (ps->nfilters + 1) * sizeof (PictFilterRec));
2006-11-26 11:13:41 -07:00
else
filters = malloc(sizeof (PictFilterRec));
2006-11-26 11:13:41 -07:00
if (!filters)
return -1;
ps->filters = filters;
i = ps->nfilters++;
ps->filters[i].name = PictureGetFilterName (id);
ps->filters[i].id = id;
ps->filters[i].ValidateParams = ValidateParams;
ps->filters[i].width = width;
ps->filters[i].height = height;
2006-11-26 11:13:41 -07:00
return id;
}
Bool
2006-11-26 11:13:41 -07:00
PictureSetFilterAlias (ScreenPtr pScreen, char *filter, char *alias)
{
PictureScreenPtr ps = GetPictureScreen(pScreen);
int filter_id = PictureGetFilterId (filter, -1, FALSE);
int alias_id = PictureGetFilterId (alias, -1, TRUE);
int i;
if (filter_id < 0 || alias_id < 0)
return FALSE;
for (i = 0; i < ps->nfilterAliases; i++)
if (ps->filterAliases[i].alias_id == alias_id)
break;
if (i == ps->nfilterAliases)
{
PictFilterAliasPtr aliases;
if (ps->filterAliases)
aliases = realloc(ps->filterAliases,
2006-11-26 11:13:41 -07:00
(ps->nfilterAliases + 1) *
sizeof (PictFilterAliasRec));
else
aliases = malloc(sizeof (PictFilterAliasRec));
2006-11-26 11:13:41 -07:00
if (!aliases)
return FALSE;
ps->filterAliases = aliases;
ps->filterAliases[i].alias = PictureGetFilterName (alias_id);
ps->filterAliases[i].alias_id = alias_id;
ps->nfilterAliases++;
}
ps->filterAliases[i].filter_id = filter_id;
return TRUE;
}
PictFilterPtr
PictureFindFilter (ScreenPtr pScreen, char *name, int len)
{
PictureScreenPtr ps = GetPictureScreen(pScreen);
int id = PictureGetFilterId (name, len, FALSE);
int i;
if (id < 0)
return 0;
/* Check for an alias, allow them to recurse */
for (i = 0; i < ps->nfilterAliases; i++)
if (ps->filterAliases[i].alias_id == id)
{
id = ps->filterAliases[i].filter_id;
i = 0;
}
/* find the filter */
for (i = 0; i < ps->nfilters; i++)
if (ps->filters[i].id == id)
return &ps->filters[i];
return 0;
}
static Bool
convolutionFilterValidateParams (ScreenPtr pScreen,
2006-11-26 11:13:41 -07:00
int filter,
xFixed *params,
int nparams,
int *width,
int *height)
2006-11-26 11:13:41 -07:00
{
int w, h;
2006-11-26 11:13:41 -07:00
if (nparams < 3)
return FALSE;
if (xFixedFrac (params[0]) || xFixedFrac (params[1]))
return FALSE;
w = xFixedToInt (params[0]);
h = xFixedToInt (params[1]);
2006-11-26 11:13:41 -07:00
nparams -= 2;
if (w * h > nparams)
2006-11-26 11:13:41 -07:00
return FALSE;
*width = w;
*height = h;
2006-11-26 11:13:41 -07:00
return TRUE;
}
Bool
PictureSetDefaultFilters (ScreenPtr pScreen)
{
if (!filterNames)
if (!PictureSetDefaultIds ())
return FALSE;
if (PictureAddFilter (pScreen, FilterNearest, 0, 1, 1) < 0)
2006-11-26 11:13:41 -07:00
return FALSE;
if (PictureAddFilter (pScreen, FilterBilinear, 0, 2, 2) < 0)
2006-11-26 11:13:41 -07:00
return FALSE;
if (!PictureSetFilterAlias (pScreen, FilterNearest, FilterFast))
return FALSE;
if (!PictureSetFilterAlias (pScreen, FilterBilinear, FilterGood))
return FALSE;
if (!PictureSetFilterAlias (pScreen, FilterBilinear, FilterBest))
return FALSE;
if (PictureAddFilter (pScreen, FilterConvolution, convolutionFilterValidateParams, 0, 0) < 0)
2006-11-26 11:13:41 -07:00
return FALSE;
return TRUE;
}
void
PictureResetFilters (ScreenPtr pScreen)
{
PictureScreenPtr ps = GetPictureScreen(pScreen);
free(ps->filters);
free(ps->filterAliases);
2006-11-26 11:13:41 -07:00
PictureFreeFilterIds ();
}
int
SetPictureFilter (PicturePtr pPicture, char *name, int len, xFixed *params, int nparams)
{
PictFilterPtr pFilter;
ScreenPtr pScreen;
if (pPicture->pDrawable != NULL)
pScreen = pPicture->pDrawable->pScreen;
else
pScreen = screenInfo.screens[0];
2006-11-26 11:13:41 -07:00
pFilter = PictureFindFilter (pScreen, name, len);
2006-11-26 11:13:41 -07:00
if (!pFilter)
return BadName;
if (pPicture->pDrawable == NULL)
{
int s;
2006-11-26 11:13:41 -07:00
/* For source pictures, the picture isn't tied to a screen. So, ensure
* that all screens can handle a filter we set for the picture.
*/
for (s = 1; s < screenInfo.numScreens; s++)
{
PictFilterPtr pScreenFilter;
pScreenFilter = PictureFindFilter (screenInfo.screens[s],
name, len);
if (!pScreenFilter || pScreenFilter->id != pFilter->id)
2006-11-26 11:13:41 -07:00
return BadMatch;
}
}
return SetPicturePictFilter (pPicture, pFilter, params, nparams);
}
int
SetPicturePictFilter (PicturePtr pPicture, PictFilterPtr pFilter,
xFixed *params, int nparams)
{
ScreenPtr pScreen;
int i;
if (pPicture->pDrawable)
pScreen = pPicture->pDrawable->pScreen;
else
pScreen = screenInfo.screens[0];
2006-11-26 11:13:41 -07:00
if (pFilter->ValidateParams)
{
int width, height;
if (!(*pFilter->ValidateParams) (pScreen, pFilter->id, params, nparams, &width, &height))
2006-11-26 11:13:41 -07:00
return BadMatch;
}
else if (nparams)
return BadMatch;
if (nparams != pPicture->filter_nparams)
{
xFixed *new_params = malloc(nparams * sizeof (xFixed));
if (!new_params && nparams)
2006-11-26 11:13:41 -07:00
return BadAlloc;
free(pPicture->filter_params);
2006-11-26 11:13:41 -07:00
pPicture->filter_params = new_params;
pPicture->filter_nparams = nparams;
}
for (i = 0; i < nparams; i++)
pPicture->filter_params[i] = params[i];
pPicture->filter = pFilter->id;
if (pPicture->pDrawable)
{
PictureScreenPtr ps = GetPictureScreen(pScreen);
int result;
2006-11-26 11:13:41 -07:00
result = (*ps->ChangePictureFilter) (pPicture, pPicture->filter,
params, nparams);
return result;
}
return Success;
}