Commit | Line | Data |
---|---|---|
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 | ||
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 | |
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 = 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 | ||
83 | static Bool | |
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 * | |
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 | |
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 | |
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 | 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 | ||
163 | Bool | |
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 = 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 | ||
196 | PictFilterPtr | |
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 | |
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 | |
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 | |
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 | |
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 | |
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 = 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 | } |