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 
42 static char **filterNames;
43 static int nfilterNames;
44 
45 /*
46  * standard but not required filters don't have constant indices
47  */
48 
49 int
PictureGetFilterId(const char * filter,int len,Bool makeit)50 PictureGetFilterId(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 = reallocarray(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 
83 static Bool
PictureSetDefaultIds(void)84 PictureSetDefaultIds(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 
106 char *
PictureGetFilterName(int id)107 PictureGetFilterName(int id)
108 {
109     if (0 <= id && id < nfilterNames)
110         return filterNames[id];
111     else
112         return 0;
113 }
114 
115 static void
PictureFreeFilterIds(void)116 PictureFreeFilterIds(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 
127 int
PictureAddFilter(ScreenPtr pScreen,const char * filter,PictFilterValidateParamsProcPtr ValidateParams,int width,int height)128 PictureAddFilter(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             reallocarray(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 
163 Bool
PictureSetFilterAlias(ScreenPtr pScreen,const char * filter,const char * alias)164 PictureSetFilterAlias(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 = reallocarray(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 
196 PictFilterPtr
PictureFindFilter(ScreenPtr pScreen,char * name,int len)197 PictureFindFilter(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 
218 static Bool
convolutionFilterValidateParams(ScreenPtr pScreen,int filter,xFixed * params,int nparams,int * width,int * height)219 convolutionFilterValidateParams(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 
244 Bool
PictureSetDefaultFilters(ScreenPtr pScreen)245 PictureSetDefaultFilters(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 
269 void
PictureResetFilters(ScreenPtr pScreen)270 PictureResetFilters(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 
282 int
SetPictureFilter(PicturePtr pPicture,char * name,int len,xFixed * params,int nparams)283 SetPictureFilter(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 
316 int
SetPicturePictFilter(PicturePtr pPicture,PictFilterPtr pFilter,xFixed * params,int nparams)317 SetPicturePictFilter(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 = xallocarray(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 }
361