Imported Upstream version 1.15.1
[deb_xorg-server.git] / render / filter.c
CommitLineData
a09e091a
JB
1/*
2 * Copyright © 2002 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Keith Packard makes no
11 * representations about the suitability of this software for any purpose. It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_DIX_CONFIG_H
24#include <dix-config.h>
25#endif
26
27#include "misc.h"
28#include "scrnintstr.h"
29#include "os.h"
30#include "regionstr.h"
31#include "validate.h"
32#include "windowstr.h"
33#include "input.h"
34#include "resource.h"
35#include "colormapst.h"
36#include "cursorstr.h"
37#include "dixstruct.h"
38#include "gcstruct.h"
39#include "servermd.h"
40#include "picturestr.h"
41
42static char **filterNames;
43static int nfilterNames;
44
45/*
46 * standard but not required filters don't have constant indices
47 */
48
49int
50PictureGetFilterId(const char *filter, int len, Bool makeit)
51{
52 int i;
53 char *name;
54 char **names;
55
56 if (len < 0)
57 len = strlen(filter);
58 for (i = 0; i < nfilterNames; i++)
59 if (!CompareISOLatin1Lowered((const unsigned char *) filterNames[i], -1,
60 (const unsigned char *) filter, len))
61 return i;
62 if (!makeit)
63 return -1;
64 name = malloc(len + 1);
65 if (!name)
66 return -1;
67 memcpy(name, filter, len);
68 name[len] = '\0';
69 if (filterNames)
70 names = realloc(filterNames, (nfilterNames + 1) * sizeof(char *));
71 else
72 names = malloc(sizeof(char *));
73 if (!names) {
74 free(name);
75 return -1;
76 }
77 filterNames = names;
78 i = nfilterNames++;
79 filterNames[i] = name;
80 return i;
81}
82
83static Bool
84PictureSetDefaultIds(void)
85{
86 /* careful here -- this list must match the #define values */
87
88 if (PictureGetFilterId(FilterNearest, -1, TRUE) != PictFilterNearest)
89 return FALSE;
90 if (PictureGetFilterId(FilterBilinear, -1, TRUE) != PictFilterBilinear)
91 return FALSE;
92
93 if (PictureGetFilterId(FilterFast, -1, TRUE) != PictFilterFast)
94 return FALSE;
95 if (PictureGetFilterId(FilterGood, -1, TRUE) != PictFilterGood)
96 return FALSE;
97 if (PictureGetFilterId(FilterBest, -1, TRUE) != PictFilterBest)
98 return FALSE;
99
100 if (PictureGetFilterId(FilterConvolution, -1, TRUE) !=
101 PictFilterConvolution)
102 return FALSE;
103 return TRUE;
104}
105
106char *
107PictureGetFilterName(int id)
108{
109 if (0 <= id && id < nfilterNames)
110 return filterNames[id];
111 else
112 return 0;
113}
114
115static void
116PictureFreeFilterIds(void)
117{
118 int i;
119
120 for (i = 0; i < nfilterNames; i++)
121 free(filterNames[i]);
122 free(filterNames);
123 nfilterNames = 0;
124 filterNames = 0;
125}
126
127int
128PictureAddFilter(ScreenPtr pScreen,
129 const char *filter,
130 PictFilterValidateParamsProcPtr ValidateParams,
131 int width, int height)
132{
133 PictureScreenPtr ps = GetPictureScreen(pScreen);
134 int id = PictureGetFilterId(filter, -1, TRUE);
135 int i;
136 PictFilterPtr filters;
137
138 if (id < 0)
139 return -1;
140 /*
141 * It's an error to attempt to reregister a filter
142 */
143 for (i = 0; i < ps->nfilters; i++)
144 if (ps->filters[i].id == id)
145 return -1;
146 if (ps->filters)
147 filters =
148 realloc(ps->filters, (ps->nfilters + 1) * sizeof(PictFilterRec));
149 else
150 filters = malloc(sizeof(PictFilterRec));
151 if (!filters)
152 return -1;
153 ps->filters = filters;
154 i = ps->nfilters++;
155 ps->filters[i].name = PictureGetFilterName(id);
156 ps->filters[i].id = id;
157 ps->filters[i].ValidateParams = ValidateParams;
158 ps->filters[i].width = width;
159 ps->filters[i].height = height;
160 return id;
161}
162
163Bool
164PictureSetFilterAlias(ScreenPtr pScreen, const char *filter, const char *alias)
165{
166 PictureScreenPtr ps = GetPictureScreen(pScreen);
167 int filter_id = PictureGetFilterId(filter, -1, FALSE);
168 int alias_id = PictureGetFilterId(alias, -1, TRUE);
169 int i;
170
171 if (filter_id < 0 || alias_id < 0)
172 return FALSE;
173 for (i = 0; i < ps->nfilterAliases; i++)
174 if (ps->filterAliases[i].alias_id == alias_id)
175 break;
176 if (i == ps->nfilterAliases) {
177 PictFilterAliasPtr aliases;
178
179 if (ps->filterAliases)
180 aliases = realloc(ps->filterAliases,
181 (ps->nfilterAliases + 1) *
182 sizeof(PictFilterAliasRec));
183 else
184 aliases = malloc(sizeof(PictFilterAliasRec));
185 if (!aliases)
186 return FALSE;
187 ps->filterAliases = aliases;
188 ps->filterAliases[i].alias = PictureGetFilterName(alias_id);
189 ps->filterAliases[i].alias_id = alias_id;
190 ps->nfilterAliases++;
191 }
192 ps->filterAliases[i].filter_id = filter_id;
193 return TRUE;
194}
195
196PictFilterPtr
197PictureFindFilter(ScreenPtr pScreen, char *name, int len)
198{
199 PictureScreenPtr ps = GetPictureScreen(pScreen);
200 int id = PictureGetFilterId(name, len, FALSE);
201 int i;
202
203 if (id < 0)
204 return 0;
205 /* Check for an alias, allow them to recurse */
206 for (i = 0; i < ps->nfilterAliases; i++)
207 if (ps->filterAliases[i].alias_id == id) {
208 id = ps->filterAliases[i].filter_id;
209 i = 0;
210 }
211 /* find the filter */
212 for (i = 0; i < ps->nfilters; i++)
213 if (ps->filters[i].id == id)
214 return &ps->filters[i];
215 return 0;
216}
217
218static Bool
219convolutionFilterValidateParams(ScreenPtr pScreen,
220 int filter,
221 xFixed * params,
222 int nparams, int *width, int *height)
223{
224 int w, h;
225
226 if (nparams < 3)
227 return FALSE;
228
229 if (xFixedFrac(params[0]) || xFixedFrac(params[1]))
230 return FALSE;
231
232 w = xFixedToInt(params[0]);
233 h = xFixedToInt(params[1]);
234
235 nparams -= 2;
236 if (w * h > nparams)
237 return FALSE;
238
239 *width = w;
240 *height = h;
241 return TRUE;
242}
243
244Bool
245PictureSetDefaultFilters(ScreenPtr pScreen)
246{
247 if (!filterNames)
248 if (!PictureSetDefaultIds())
249 return FALSE;
250 if (PictureAddFilter(pScreen, FilterNearest, 0, 1, 1) < 0)
251 return FALSE;
252 if (PictureAddFilter(pScreen, FilterBilinear, 0, 2, 2) < 0)
253 return FALSE;
254
255 if (!PictureSetFilterAlias(pScreen, FilterNearest, FilterFast))
256 return FALSE;
257 if (!PictureSetFilterAlias(pScreen, FilterBilinear, FilterGood))
258 return FALSE;
259 if (!PictureSetFilterAlias(pScreen, FilterBilinear, FilterBest))
260 return FALSE;
261
262 if (PictureAddFilter
263 (pScreen, FilterConvolution, convolutionFilterValidateParams, 0, 0) < 0)
264 return FALSE;
265
266 return TRUE;
267}
268
269void
270PictureResetFilters(ScreenPtr pScreen)
271{
272 PictureScreenPtr ps = GetPictureScreen(pScreen);
273
274 free(ps->filters);
275 free(ps->filterAliases);
276
277 /* Free the filters when the last screen is closed */
278 if (pScreen->myNum == 0)
279 PictureFreeFilterIds();
280}
281
282int
283SetPictureFilter(PicturePtr pPicture, char *name, int len, xFixed * params,
284 int nparams)
285{
286 PictFilterPtr pFilter;
287 ScreenPtr pScreen;
288
289 if (pPicture->pDrawable != NULL)
290 pScreen = pPicture->pDrawable->pScreen;
291 else
292 pScreen = screenInfo.screens[0];
293
294 pFilter = PictureFindFilter(pScreen, name, len);
295
296 if (!pFilter)
297 return BadName;
298
299 if (pPicture->pDrawable == NULL) {
300 int s;
301
302 /* For source pictures, the picture isn't tied to a screen. So, ensure
303 * that all screens can handle a filter we set for the picture.
304 */
305 for (s = 1; s < screenInfo.numScreens; s++) {
306 PictFilterPtr pScreenFilter;
307
308 pScreenFilter = PictureFindFilter(screenInfo.screens[s], name, len);
309 if (!pScreenFilter || pScreenFilter->id != pFilter->id)
310 return BadMatch;
311 }
312 }
313 return SetPicturePictFilter(pPicture, pFilter, params, nparams);
314}
315
316int
317SetPicturePictFilter(PicturePtr pPicture, PictFilterPtr pFilter,
318 xFixed * params, int nparams)
319{
320 ScreenPtr pScreen;
321 int i;
322
323 if (pPicture->pDrawable)
324 pScreen = pPicture->pDrawable->pScreen;
325 else
326 pScreen = screenInfo.screens[0];
327
328 if (pFilter->ValidateParams) {
329 int width, height;
330
331 if (!(*pFilter->ValidateParams)
332 (pScreen, pFilter->id, params, nparams, &width, &height))
333 return BadMatch;
334 }
335 else if (nparams)
336 return BadMatch;
337
338 if (nparams != pPicture->filter_nparams) {
339 xFixed *new_params = malloc(nparams * sizeof(xFixed));
340
341 if (!new_params && nparams)
342 return BadAlloc;
343 free(pPicture->filter_params);
344 pPicture->filter_params = new_params;
345 pPicture->filter_nparams = nparams;
346 }
347 for (i = 0; i < nparams; i++)
348 pPicture->filter_params[i] = params[i];
349 pPicture->filter = pFilter->id;
350
351 if (pPicture->pDrawable) {
352 PictureScreenPtr ps = GetPictureScreen(pScreen);
353 int result;
354
355 result = (*ps->ChangePictureFilter) (pPicture, pPicture->filter,
356 params, nparams);
357 return result;
358 }
359 return Success;
360}