1 /* WEED is free software; you can redistribute it and/or
2 modify it under the terms of the GNU Lesser General Public
3 License as published by the Free Software Foundation; either
4 version 3 of the License, or (at your option) any later version.
5
6 Weed is distributed in the hope that it will be useful,
7 but WITHOUT ANY WARRANTY; without even the implied warranty of
8 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 Lesser General Public License for more details.
10
11 You should have received a copy of the GNU Lesser General Public
12 License along with this source code; if not, write to the Free Software
13 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
14
15 Weed is developed by:
16 Gabriel "Salsaman" Finch - http://lives-video.com
17
18 partly based on LiViDO, which is developed by:
19 Niels Elburg - http://veejay.sf.net
20 Denis "Jaromil" Rojo - http://freej.dyne.org
21 Tom Schouten - http://zwizwa.fartit.com
22 Andraz Tori - http://cvs.cinelerra.org
23
24 reviewed with suggestions and contributions from:
25 Silvano "Kysucix" Galliani - http://freej.dyne.org
26 Kentaro Fukuchi - http://megaui.net/fukuchi
27 Jun Iio - http://www.malib.net
28 Carlo Prelz - http://www2.fluido.as:8080/
29 */
30
31 /* (C) G. Finch, 2005 - 2020u */
32
33 #ifdef __WEED_HOST__
34 #error This file is intended only for Weed plugins
35 #endif
36
37 #ifndef __HAVE_WEED_PLUGIN_UTILS__
38 #define __HAVE_WEED_PLUGIN_UTILS__
39
40 #ifdef __WEED_PLUGIN__
41
42 #ifndef NEED_LOCAL_WEED_PLUGIN
43 #include <weed/weed.h>
44 #include <weed/weed-effects.h>
45 #include <weed/weed-palettes.h>
46 #include <weed/weed-plugin-utils.h>
47 #else
48 #include "../../libweed/weed.h"
49 #include "../../libweed/weed-effects.h"
50 #include "../../libweed/weed-palettes.h"
51 #include "../../libweed/weed-plugin-utils.h"
52 #endif
53 #endif
54
55 #include <string.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 ///////////////////////////////////////////////////////////
59 // this 90% of the API right here
60 static int wtrue = WEED_TRUE;
61 #define wlne(p,k) weed_leaf_num_elements((p),(k))
62 #define wlg(p,w,i,v) weed_leaf_get((p),(w),(i),(v))
63 #define wls(p,w,t,n,v) weed_leaf_set((p),(w),(t),(n),(v))
64 #define _leaf_has_value(p,k) ((wlne(p,k)>0)?1:0)
65 #define gg(p,w,i,v) (p?((wlg((p),(w),(i),(v))==WEED_SUCCESS)?v:0):0)
66 #define __WPFC__ WEED_PLANT_FILTER_CLASS
67 #define __WPPT__ WEED_PLANT_PARAMETER_TEMPLATE
68 #define __WPCT__ WEED_PLANT_CHANNEL_TEMPLATE
69 #define __WPP__ WEED_PLANT_PARAMETER
70 #define __WPFI__ WEED_PLANT_FILTER_INSTANCE
gg_i(weed_plant_t * p,const char * w)71 static inline int gg_i(weed_plant_t *p, const char *w)
72 {int v, *vp = (int *)gg(p, w, 0, &v); return vp ? v : 0;}
gg_p(weed_plant_t * p,const char * w,int i)73 static inline weed_plant_t *gg_p(weed_plant_t *p, const char *w, int i)
74 {weed_plant_t *v, **vp = (weed_plant_t **)gg(p, w, i, &v); return vp ? v : 0;}
gg_i64(weed_plant_t * p,const char * w)75 static inline int64_t gg_i64(weed_plant_t *p, const char *w)
76 {int64_t v, *vp = (int64_t *)gg(p, w, 0, &v); return vp ? v : 0;}
weed_plant_get_type(weed_plant_t * p)77 static inline int weed_plant_get_type(weed_plant_t *p) {return gg_i(p, WEED_LEAF_TYPE);}
_weed_get_gui(weed_plant_t * p)78 static inline weed_plant_t *_weed_get_gui(weed_plant_t *p) {
79 weed_plant_t *g = NULL; int t = weed_plant_get_type(p);
80 if (t != __WPFC__ && t != __WPPT__ && t != __WPP__ && t != __WPFI__) return NULL;
81 gg(p, WEED_LEAF_GUI, 0, (void *)&g);
82 if (!g) {
83 g = weed_plant_new(WEED_PLANT_GUI);
84 wls(p, WEED_LEAF_GUI, WEED_SEED_PLANTPTR, 1, &g);
85 } return g;
86 }
gg_dbl(weed_plant_t * p,const char * w)87 static inline double gg_dbl(weed_plant_t *p, const char *w)
88 {double v, *vp = (double *)gg(p, w, 0, &v); return vp ? v : 0;}
weed_get_api_version(weed_plant_t * pi)89 static inline int weed_get_api_version(weed_plant_t *pi)
90 {weed_plant_t *h; wlg(pi, WEED_LEAF_HOST_INFO, 0, &h); return gg_i(h, WEED_LEAF_FILTER_API_VERSION);}
_weed_plant_set_flags(weed_plant_t * p,int f)91 static inline void _weed_plant_set_flags(weed_plant_t *p, int f) {
92 int t = weed_plant_get_type(p);
93 if (t == __WPFC__ || t == __WPPT__ || t == __WPCT__ || t == WEED_PLANT_GUI)
94 wls(p, WEED_LEAF_FLAGS, WEED_SEED_INT, 1, &f);
95 }
weed_filter_set_flags(weed_plant_t * f,int fl)96 static inline void weed_filter_set_flags(weed_plant_t *f, int fl) {_weed_plant_set_flags(f, fl);}
weed_chantmpl_set_flags(weed_plant_t * c,int f)97 static inline void weed_chantmpl_set_flags(weed_plant_t *c, int f) {_weed_plant_set_flags(c, f);}
weed_paramtmpl_set_flags(weed_plant_t * p,int f)98 static inline void weed_paramtmpl_set_flags(weed_plant_t *p, int f) {_weed_plant_set_flags(p, f);}
weed_gui_set_flags(weed_plant_t * g,int f)99 static inline void weed_gui_set_flags(weed_plant_t *g, int f) {_weed_plant_set_flags(g, f);}
_weed_plant_set_name(weed_plant_t * p,const char * n)100 static inline void _weed_plant_set_name(weed_plant_t *p, const char *n) {
101 int t = weed_plant_get_type(p);
102 if (t == __WPFC__ || t == __WPPT__ || t == __WPCT__) wls(p, WEED_LEAF_NAME, WEED_SEED_STRING, 1, &n);
103 }
weed_filter_set_name(weed_plant_t * f,const char * n)104 static inline void weed_filter_set_name(weed_plant_t *f, const char *n) {_weed_plant_set_name(f, n);}
weed_chantmpl_set_name(weed_plant_t * c,const char * n)105 static inline void weed_chantmpl_set_name(weed_plant_t *c, const char *n) {_weed_plant_set_name(c, n);}
weed_paramtmpl_set_name(weed_plant_t * p,const char * n)106 static inline void weed_paramtmpl_set_name(weed_plant_t *p, const char *n) {_weed_plant_set_name(p, n);}
weed_paramtmpl_declare_transition(weed_plant_t * pt)107 static inline void weed_paramtmpl_declare_transition(weed_plant_t *pt)
108 {wls(pt, WEED_LEAF_IS_TRANSITION, WEED_SEED_BOOLEAN, 1, &wtrue);}
weed_plugin_set_package_version(weed_plant_t * pi,int v)109 static inline void weed_plugin_set_package_version(weed_plant_t *pi, int v)
110 {wls(pi, WEED_LEAF_VERSION, WEED_SEED_INT, 1, &v);}
weed_filter_get_gui(weed_plant_t * f)111 static inline weed_plant_t *weed_filter_get_gui(weed_plant_t *f) {return _weed_get_gui(f);}
weed_param_get_gui(weed_plant_t * p)112 static inline weed_plant_t *weed_param_get_gui(weed_plant_t *p) {return _weed_get_gui(p);}
weed_paramtmpl_get_gui(weed_plant_t * pt)113 static inline weed_plant_t *weed_paramtmpl_get_gui(weed_plant_t *pt) {return _weed_get_gui(pt);}
weed_instance_get_gui(weed_plant_t * i)114 static inline weed_plant_t *weed_instance_get_gui(weed_plant_t *i) {return _weed_get_gui(i);}
weed_get_host_info(weed_plant_t * pi)115 static inline weed_plant_t *weed_get_host_info(weed_plant_t *pi)
116 {weed_plant_t *hi; return *((weed_plant_t **)(gg(pi, WEED_LEAF_HOST_INFO, 0, (void *)&hi)));}
weed_get_host_verbosity(weed_plant_t * hi)117 static inline int weed_get_host_verbosity(weed_plant_t *hi) {return gg_i(hi, WEED_LEAF_VERBOSITY);}
_weed_plant_get_flags(weed_plant_t * p)118 static inline int _weed_plant_get_flags(weed_plant_t *p) {return gg_i(p, WEED_LEAF_FLAGS);}
weed_host_get_flags(weed_plant_t * h)119 static inline int weed_host_get_flags(weed_plant_t *h) {return _weed_plant_get_flags(h);}
weed_filter_get_flags(weed_plant_t * f)120 static inline int weed_filter_get_flags(weed_plant_t *f) {return _weed_plant_get_flags(f);}
weed_filter_get_version(weed_plant_t * f)121 static inline int weed_filter_get_version(weed_plant_t *f) {return gg_i(f, WEED_LEAF_VERSION);}
weed_chantmpl_get_flags(weed_plant_t * c)122 static inline int weed_chantmpl_get_flags(weed_plant_t *c) {return _weed_plant_get_flags(c);}
weed_paramtmpl_get_flags(weed_plant_t * p)123 static inline int weed_paramtmpl_get_flags(weed_plant_t *p) {return _weed_plant_get_flags(p);}
weed_instance_get_flags(weed_plant_t * i)124 static inline int weed_instance_get_flags(weed_plant_t *i) {return _weed_plant_get_flags(i);}
weed_host_supports_linear_gamma(weed_plant_t * h)125 static inline int weed_host_supports_linear_gamma(weed_plant_t *h)
126 {return (weed_host_get_flags(h) & WEED_HOST_SUPPORTS_LINEAR_GAMMA) ? 1 : 0;}
weed_host_supports_premultiplied_alpha(weed_plant_t * h)127 static inline int weed_host_supports_premultiplied_alpha(weed_plant_t *h)
128 {return (weed_host_get_flags(h) & WEED_HOST_SUPPORTS_PREMULTIPLIED_ALPHA) ? 1 : 0;}
weed_instance_get_filter(weed_plant_t * i)129 static inline weed_plant_t *weed_instance_get_filter(weed_plant_t *i)
130 {weed_plant_t *f; return *((weed_plant_t **)gg(i, WEED_LEAF_FILTER_CLASS, 0, (void *)&f));}
weed_get_in_channel(weed_plant_t * i,int x)131 static inline weed_plant_t *weed_get_in_channel(weed_plant_t *i, int x)
132 {return gg_p(i, WEED_LEAF_IN_CHANNELS, x);}
weed_get_out_channel(weed_plant_t * i,int x)133 static inline weed_plant_t *weed_get_out_channel(weed_plant_t *i, int x)
134 {return gg_p(i, WEED_LEAF_OUT_CHANNELS, x);}
weed_get_in_param(weed_plant_t * i,int x)135 static inline weed_plant_t *weed_get_in_param(weed_plant_t *i, int x)
136 {return gg_p(i, WEED_LEAF_IN_PARAMETERS, x);}
weed_get_out_param(weed_plant_t * i,int x)137 static inline weed_plant_t *weed_get_out_param(weed_plant_t *i, int x)
138 {return gg_p(i, WEED_LEAF_OUT_PARAMETERS, x);}
weed_channel_get_pixel_data(weed_plant_t * c)139 static inline void *weed_channel_get_pixel_data(weed_plant_t *c)
140 {void *pd; return *((void **)(gg(c, WEED_LEAF_PIXEL_DATA, 0, (void *)&pd)));}
weed_channel_get_width(weed_plant_t * c)141 static inline int weed_channel_get_width(weed_plant_t *c) {return gg_i(c, WEED_LEAF_WIDTH);}
weed_channel_get_height(weed_plant_t * c)142 static inline int weed_channel_get_height(weed_plant_t *c) {return gg_i(c, WEED_LEAF_HEIGHT);}
weed_channel_get_palette(weed_plant_t * c)143 static inline int weed_channel_get_palette(weed_plant_t *c) {return gg_i(c, WEED_LEAF_CURRENT_PALETTE);}
weed_channel_get_yuv_clamping(weed_plant_t * c)144 static inline int weed_channel_get_yuv_clamping(weed_plant_t *c) {return gg_i(c, WEED_LEAF_YUV_CLAMPING);}
weed_channel_get_stride(weed_plant_t * c)145 static inline int weed_channel_get_stride(weed_plant_t *c) {return gg_i(c, WEED_LEAF_ROWSTRIDES);}
weed_channel_get_offset(weed_plant_t * c)146 static inline int weed_channel_get_offset(weed_plant_t *c) {return gg_i(c, WEED_LEAF_OFFSET);}
weed_channel_get_real_height(weed_plant_t * c)147 static inline int weed_channel_get_real_height(weed_plant_t *c)
148 {int h; return *((int *)(gg(c, WEED_LEAF_HEIGHT, wlne(c, WEED_LEAF_HEIGHT) - 1, &h)));}
weed_channel_is_disabled(weed_plant_t * c)149 static inline int weed_channel_is_disabled(weed_plant_t *c) {return gg_i(c, WEED_LEAF_DISABLED);}
weed_param_get_template(weed_plant_t * p)150 static inline weed_plant_t *weed_param_get_template(weed_plant_t *p)
151 {weed_plant_t *pt; return *((weed_plant_t **)(gg(p, WEED_LEAF_TEMPLATE, 0, (void *)&pt)));}
152 ////////////////////////////////////////////////////////////////////////////////////////////////////
153
weed_plugin_info_init(weed_bootstrap_f weed_boot,int32_t weed_api_min_version,int32_t weed_api_max_version,int32_t weed_filter_api_min_version,int32_t weed_filter_api_max_version)154 static weed_plant_t *weed_plugin_info_init(weed_bootstrap_f weed_boot, int32_t weed_api_min_version,
155 int32_t weed_api_max_version,
156 int32_t weed_filter_api_min_version,
157 int32_t weed_filter_api_max_version) {
158 /////////////////////////////////////////////////////////
159 // get our bootstrap values
160
161 // every plugin should call this at the beginning of its weed_setup(), and return NULL if this function returns NULL
162 // otherwise it may add its filter classes to the returned plugin_info, and then return the plugin_info to the host
163
164 // if using the standard headers, then the plugin can use the macro WEED_SETUP_START(int weed_api_version, int filter_api_version)
165 // and this function will be called and the return if NULL will be handled
166
167 weed_default_getter_f weed_default_getp;
168
169 weed_plant_t *host_info = (*weed_boot)(&weed_default_getp, weed_api_min_version, weed_api_max_version,
170 weed_filter_api_min_version, weed_filter_api_max_version);
171
172 weed_plant_t *plugin_info = NULL;
173 int32_t weed_abi_version = WEED_ABI_VERSION;
174 int32_t filter_api_version = WEED_API_VERSION;
175 weed_error_t err;
176
177 if (!host_info) return NULL; // matching version was not found
178
179 // we must use the default getter to bootstrap our actual API functions
180
181 //////////// get weed api version /////////
182 if ((*weed_default_getp)(host_info, WEED_LEAF_WEED_API_VERSION,
183 (weed_funcptr_t *)&weed_abi_version) != WEED_SUCCESS) return NULL;
184 if ((*weed_default_getp)(host_info, WEED_LEAF_GET_FUNC, (weed_funcptr_t *)&weed_leaf_get) != WEED_SUCCESS) return NULL;
185 if ((*weed_default_getp)(host_info, WEED_LEAF_MALLOC_FUNC, (weed_funcptr_t *)&weed_malloc) != WEED_SUCCESS) return NULL;
186 if ((*weed_default_getp)(host_info, WEED_LEAF_FREE_FUNC, (weed_funcptr_t *)&weed_free) != WEED_SUCCESS) return NULL;
187 if ((*weed_default_getp)(host_info, WEED_LEAF_MEMSET_FUNC, (weed_funcptr_t *)&weed_memset) != WEED_SUCCESS) return NULL;
188 if ((*weed_default_getp)(host_info, WEED_LEAF_MEMCPY_FUNC, (weed_funcptr_t *)&weed_memcpy) != WEED_SUCCESS) return NULL;
189
190 // now we can use the normal get function (weed_leaf_get)
191
192 // get any additional functions for higher API versions ////////////
193 weed_realloc = NULL;
194 weed_plant_free = NULL;
195
196 // 2.0
197 if (weed_abi_version >= 200) {
198 if (weed_leaf_get(host_info, WEED_LEAF_REALLOC_FUNC, 0, &weed_realloc) != WEED_SUCCESS) return NULL;
199 if (weed_leaf_get(host_info, WEED_LEAF_CALLOC_FUNC, 0, &weed_calloc) != WEED_SUCCESS) return NULL;
200 if (weed_leaf_get(host_info, WEED_LEAF_MEMMOVE_FUNC, 0, &weed_memmove) != WEED_SUCCESS) return NULL;
201 }
202
203 // base functions 1.0
204 if (weed_leaf_get(host_info, WEED_LEAF_SET_FUNC, 0, &weed_leaf_set) != WEED_SUCCESS) return NULL;
205 if (weed_leaf_get(host_info, WEED_PLANT_NEW_FUNC, 0, &weed_plant_new) != WEED_SUCCESS) return NULL;
206 if (weed_leaf_get(host_info, WEED_PLANT_LIST_LEAVES_FUNC, 0, &weed_plant_list_leaves) != WEED_SUCCESS) return NULL;
207 if (weed_leaf_get(host_info, WEED_LEAF_NUM_ELEMENTS_FUNC, 0, &weed_leaf_num_elements) != WEED_SUCCESS) return NULL;
208 if (weed_leaf_get(host_info, WEED_LEAF_ELEMENT_SIZE_FUNC, 0, &weed_leaf_element_size) != WEED_SUCCESS) return NULL;
209 if (weed_leaf_get(host_info, WEED_LEAF_SEED_TYPE_FUNC, 0, &weed_leaf_seed_type) != WEED_SUCCESS) return NULL;
210 if (weed_leaf_get(host_info, WEED_LEAF_GET_FLAGS_FUNC, 0, &weed_leaf_get_flags) != WEED_SUCCESS) return NULL;
211
212 weed_leaf_get(host_info, WEED_LEAF_FILTER_API_VERSION, 0, &filter_api_version);
213
214 // base functions 2.0
215 if (filter_api_version >= 200) {
216 // added weed_plant_free for plugins
217 if (weed_leaf_get(host_info, WEED_PLANT_FREE_FUNC, 0, &weed_plant_free) != WEED_SUCCESS) return NULL;
218 // added weed_leaf_delete for plugins
219 if (weed_leaf_get(host_info, WEED_LEAF_DELETE_FUNC, 0, &weed_leaf_delete) != WEED_SUCCESS) return NULL;
220 }
221
222 //////////////////////////////////////////////////////////////////////
223
224 if (_leaf_has_value(host_info, WEED_LEAF_PLUGIN_INFO)) {
225 if ((err = weed_leaf_get(host_info, WEED_LEAF_PLUGIN_INFO, 0, &plugin_info)) == WEED_SUCCESS) {
226 int32_t type;
227 weed_leaf_get(plugin_info, WEED_LEAF_TYPE, 0, &type);
228 if (err != WEED_SUCCESS) return NULL;
229 if (type != WEED_PLANT_PLUGIN_INFO) plugin_info = NULL;
230 } else return NULL;
231 }
232
233 if (!plugin_info) if (!(plugin_info = weed_plant_new(WEED_PLANT_PLUGIN_INFO))) return NULL;
234 weed_leaf_set(plugin_info, WEED_LEAF_HOST_INFO, WEED_SEED_PLANTPTR, 1, &host_info);
235 return plugin_info;
236 }
237
weed_channel_template_init(const char * name,int flags)238 static weed_plant_t *weed_channel_template_init(const char *name, int flags) {
239 weed_plant_t *chantmpl = weed_plant_new(WEED_PLANT_CHANNEL_TEMPLATE);
240 if (!chantmpl || !name) return NULL;
241 weed_chantmpl_set_name(chantmpl, name); weed_chantmpl_set_flags(chantmpl, flags);
242 return chantmpl;
243 }
244
weed_filter_class_init(const char * name,const char * author,int version,int flags,int * palettes,weed_init_f init_func,weed_process_f process_func,weed_deinit_f deinit_func,weed_plant_t ** in_chantmpls,weed_plant_t ** out_chantmpls,weed_plant_t ** in_paramtmpls,weed_plant_t ** out_paramtmpls)245 static weed_plant_t *weed_filter_class_init(const char *name, const char *author, int version, int flags, int *palettes,
246 weed_init_f init_func, weed_process_f process_func, weed_deinit_f deinit_func,
247 weed_plant_t **in_chantmpls, weed_plant_t **out_chantmpls,
248 weed_plant_t **in_paramtmpls, weed_plant_t **out_paramtmpls) {
249 int i;
250 weed_plant_t *filter_class = NULL;
251 if (name) filter_class = weed_plant_new(WEED_PLANT_FILTER_CLASS);
252 if (!filter_class) return NULL;
253 weed_filter_set_name(filter_class, name);
254 weed_leaf_set(filter_class, WEED_LEAF_AUTHOR, WEED_SEED_STRING, 1, &author);
255 weed_leaf_set(filter_class, WEED_LEAF_VERSION, WEED_SEED_INT, 1, &version);
256 weed_filter_set_flags(filter_class, flags);
257
258 if (init_func) weed_leaf_set(filter_class, WEED_LEAF_INIT_FUNC, WEED_SEED_FUNCPTR, 1, &init_func);
259
260 if (process_func) weed_leaf_set(filter_class, WEED_LEAF_PROCESS_FUNC, WEED_SEED_FUNCPTR, 1, &process_func);
261
262 if (deinit_func) weed_leaf_set(filter_class, WEED_LEAF_DEINIT_FUNC, WEED_SEED_FUNCPTR, 1, &deinit_func);
263
264 if (!in_chantmpls || !in_chantmpls[0])
265 weed_leaf_set(filter_class, WEED_LEAF_IN_CHANNEL_TEMPLATES, WEED_SEED_PLANTPTR, 0, NULL);
266 else {
267 for (i = 0; in_chantmpls[i] != NULL; i++);
268 weed_leaf_set(filter_class, WEED_LEAF_IN_CHANNEL_TEMPLATES, WEED_SEED_PLANTPTR, i, in_chantmpls);
269 }
270 if (!out_chantmpls || !out_chantmpls[0])
271 weed_leaf_set(filter_class, WEED_LEAF_OUT_CHANNEL_TEMPLATES, WEED_SEED_PLANTPTR, 0, NULL);
272 else {
273 for (i = 0; out_chantmpls[i] != NULL; i++);
274 weed_leaf_set(filter_class, WEED_LEAF_OUT_CHANNEL_TEMPLATES, WEED_SEED_PLANTPTR, i, out_chantmpls);
275 }
276 if (!in_paramtmpls || !in_paramtmpls[0])
277 weed_leaf_set(filter_class, WEED_LEAF_IN_PARAMETER_TEMPLATES, WEED_SEED_PLANTPTR, 0, NULL);
278 else {
279 for (i = 0; in_paramtmpls[i] != NULL; i++);
280 weed_leaf_set(filter_class, WEED_LEAF_IN_PARAMETER_TEMPLATES, WEED_SEED_PLANTPTR, i, in_paramtmpls);
281 }
282 if (!out_paramtmpls || !out_paramtmpls[0])
283 weed_leaf_set(filter_class, WEED_LEAF_OUT_PARAMETER_TEMPLATES, WEED_SEED_PLANTPTR, 0, NULL);
284 else {
285 for (i = 0; out_paramtmpls[i] != NULL; i++);
286 weed_leaf_set(filter_class, WEED_LEAF_OUT_PARAMETER_TEMPLATES, WEED_SEED_PLANTPTR, i, out_paramtmpls);
287 }
288 if (palettes) {
289 for (i = 0; palettes[i] != WEED_PALETTE_END; i++);
290 if (i == 0) weed_leaf_set(filter_class, WEED_LEAF_PALETTE_LIST, WEED_SEED_INT, 0, NULL);
291 weed_leaf_set(filter_class, WEED_LEAF_PALETTE_LIST, WEED_SEED_INT, i, palettes);
292 }
293 return filter_class;
294 }
295
weed_plugin_info_add_filter_class(weed_plant_t * plugin_info,weed_plant_t * filter_class)296 static void weed_plugin_info_add_filter_class(weed_plant_t *plugin_info, weed_plant_t *filter_class) {
297 int num_filters = 0, i;
298 weed_plant_t **filters;
299 if (_leaf_has_value(plugin_info, WEED_LEAF_FILTERS)) num_filters = weed_leaf_num_elements(plugin_info, WEED_LEAF_FILTERS);
300 filters = (weed_plant_t **)weed_malloc((num_filters + 1) * sizeof(weed_plant_t *));
301 if (!filters) return;
302 for (i = 0; i < num_filters; i++) weed_leaf_get(plugin_info, WEED_LEAF_FILTERS, i, &filters[i]);
303 filters[i] = filter_class;
304 weed_leaf_set(plugin_info, WEED_LEAF_FILTERS, WEED_SEED_PLANTPTR, i + 1, filters);
305 weed_leaf_set(filter_class, WEED_LEAF_PLUGIN_INFO, WEED_SEED_PLANTPTR, 1, &plugin_info);
306 weed_free(filters);
307 }
308
309 //////////////////////////////////////////////////////////////////////////////////////////////
310
weed_integer_init(const char * name,const char * label,int def,int min,int max)311 static weed_plant_t *weed_integer_init(const char *name, const char *label, int def, int min, int max) {
312 weed_plant_t *paramt = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
313 int ptype = WEED_PARAM_INTEGER;
314 weed_plant_t *gui;
315 weed_paramtmpl_set_name(paramt, name);
316 weed_leaf_set(paramt, WEED_LEAF_PARAM_TYPE, WEED_SEED_INT, 1, &ptype);
317 weed_leaf_set(paramt, WEED_LEAF_DEFAULT, WEED_SEED_INT, 1, &def);
318 weed_leaf_set(paramt, WEED_LEAF_MIN, WEED_SEED_INT, 1, &min);
319 weed_leaf_set(paramt, WEED_LEAF_MAX, WEED_SEED_INT, 1, &max);
320 gui = weed_paramtmpl_get_gui(paramt);
321 weed_leaf_set(gui, WEED_LEAF_LABEL, WEED_SEED_STRING, 1, &label);
322 weed_leaf_set(gui, WEED_LEAF_USE_MNEMONIC, WEED_SEED_BOOLEAN, 1, &wtrue);
323 return paramt;
324 }
325
weed_string_list_init(const char * name,const char * label,int def,const char ** const list)326 static weed_plant_t *weed_string_list_init(const char *name, const char *label, int def, const char **const list) {
327 int i = 0;
328 weed_plant_t *paramt, *gui;
329 int min = 0;
330 while (list[i] != NULL) i++;
331 i--;
332 if (def <= -1) min = def = -1;
333 paramt = weed_integer_init(name, label, def, min, i);
334 gui = weed_paramtmpl_get_gui(paramt);
335 weed_leaf_set(gui, WEED_LEAF_CHOICES, WEED_SEED_STRING, i + 1, list);
336 return paramt;
337 }
338
weed_switch_init(const char * name,const char * label,int def)339 static weed_plant_t *weed_switch_init(const char *name, const char *label, int def) {
340 weed_plant_t *paramt = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
341 int ptype = WEED_PARAM_SWITCH;
342 weed_plant_t *gui;
343 weed_paramtmpl_set_name(paramt, name);
344 weed_leaf_set(paramt, WEED_LEAF_PARAM_TYPE, WEED_SEED_INT, 1, &ptype);
345 weed_leaf_set(paramt, WEED_LEAF_DEFAULT, WEED_SEED_BOOLEAN, 1, &def);
346 gui = weed_paramtmpl_get_gui(paramt);
347 weed_leaf_set(gui, WEED_LEAF_LABEL, WEED_SEED_STRING, 1, &label);
348 weed_leaf_set(gui, WEED_LEAF_USE_MNEMONIC, WEED_SEED_BOOLEAN, 1, &wtrue);
349 return paramt;
350 }
351
weed_radio_init(const char * name,const char * label,int def,int group)352 static weed_plant_t *weed_radio_init(const char *name, const char *label, int def, int group) {
353 weed_plant_t *paramt = weed_switch_init(name, label, def);
354 weed_leaf_set(paramt, WEED_LEAF_GROUP, WEED_SEED_INT, 1, &group);
355 return paramt;
356 }
357
weed_float_init(const char * name,const char * label,double def,double min,double max)358 static weed_plant_t *weed_float_init(const char *name, const char *label, double def, double min, double max) {
359 weed_plant_t *paramt = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
360 int ptype = WEED_PARAM_FLOAT;
361 weed_plant_t *gui;
362 weed_paramtmpl_set_name(paramt, name);
363 weed_leaf_set(paramt, WEED_LEAF_PARAM_TYPE, WEED_SEED_INT, 1, &ptype);
364 weed_leaf_set(paramt, WEED_LEAF_DEFAULT, WEED_SEED_DOUBLE, 1, &def);
365 weed_leaf_set(paramt, WEED_LEAF_MIN, WEED_SEED_DOUBLE, 1, &min);
366 weed_leaf_set(paramt, WEED_LEAF_MAX, WEED_SEED_DOUBLE, 1, &max);
367 gui = weed_paramtmpl_get_gui(paramt);
368 weed_leaf_set(gui, WEED_LEAF_LABEL, WEED_SEED_STRING, 1, &label);
369 weed_leaf_set(gui, WEED_LEAF_USE_MNEMONIC, WEED_SEED_BOOLEAN, 1, &wtrue);
370 return paramt;
371 }
372
weed_text_init(const char * name,const char * label,const char * def)373 static weed_plant_t *weed_text_init(const char *name, const char *label, const char *def) {
374 weed_plant_t *paramt = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
375 int ptype = WEED_PARAM_TEXT;
376 weed_plant_t *gui;
377 weed_paramtmpl_set_name(paramt, name);
378 weed_leaf_set(paramt, WEED_LEAF_PARAM_TYPE, WEED_SEED_INT, 1, &ptype);
379 weed_leaf_set(paramt, WEED_LEAF_DEFAULT, WEED_SEED_STRING, 1, &def);
380 gui = weed_paramtmpl_get_gui(paramt);
381 weed_leaf_set(gui, WEED_LEAF_LABEL, WEED_SEED_STRING, 1, &label);
382 weed_leaf_set(gui, WEED_LEAF_USE_MNEMONIC, WEED_SEED_BOOLEAN, 1, &wtrue);
383 return paramt;
384 }
385
weed_colRGBi_init(const char * name,const char * label,int red,int green,int blue)386 static weed_plant_t *weed_colRGBi_init(const char *name, const char *label, int red, int green, int blue) {
387 weed_plant_t *paramt = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
388 int ptype = WEED_PARAM_COLOR;
389 int cspace = WEED_COLORSPACE_RGB;
390 int def[3] = {red, green, blue}, min = 0, max = 255;
391 weed_plant_t *gui;
392 weed_paramtmpl_set_name(paramt, name);
393 weed_leaf_set(paramt, WEED_LEAF_PARAM_TYPE, WEED_SEED_INT, 1, &ptype);
394 weed_leaf_set(paramt, WEED_LEAF_COLORSPACE, WEED_SEED_INT, 1, &cspace);
395 weed_leaf_set(paramt, WEED_LEAF_DEFAULT, WEED_SEED_INT, 3, def);
396 weed_leaf_set(paramt, WEED_LEAF_MIN, WEED_SEED_INT, 1, &min);
397 weed_leaf_set(paramt, WEED_LEAF_MAX, WEED_SEED_INT, 1, &max);
398 gui = weed_paramtmpl_get_gui(paramt);
399 weed_leaf_set(gui, WEED_LEAF_LABEL, WEED_SEED_STRING, 1, &label);
400 weed_leaf_set(gui, WEED_LEAF_USE_MNEMONIC, WEED_SEED_BOOLEAN, 1, &wtrue);
401 return paramt;
402 }
403
weed_colRGBd_init(const char * name,const char * label,double red,double green,double blue)404 static weed_plant_t *weed_colRGBd_init(const char *name, const char *label, double red, double green, double blue) {
405 weed_plant_t *paramt = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
406 int ptype = WEED_PARAM_COLOR;
407 int cspace = WEED_COLORSPACE_RGB;
408 double def[3] = {red, green, blue}, min = 0., max = 1.;
409 weed_plant_t *gui;
410 weed_paramtmpl_set_name(paramt, name);
411 weed_leaf_set(paramt, WEED_LEAF_PARAM_TYPE, WEED_SEED_INT, 1, &ptype);
412 weed_leaf_set(paramt, WEED_LEAF_COLORSPACE, WEED_SEED_INT, 1, &cspace);
413 weed_leaf_set(paramt, WEED_LEAF_DEFAULT, WEED_SEED_DOUBLE, 3, def);
414 weed_leaf_set(paramt, WEED_LEAF_MIN, WEED_SEED_DOUBLE, 1, &min);
415 weed_leaf_set(paramt, WEED_LEAF_MAX, WEED_SEED_DOUBLE, 1, &max);
416 gui = weed_paramtmpl_get_gui(paramt);
417 weed_leaf_set(gui, WEED_LEAF_LABEL, WEED_SEED_STRING, 1, &label);
418 weed_leaf_set(gui, WEED_LEAF_USE_MNEMONIC, WEED_SEED_BOOLEAN, 1, &wtrue);
419 return paramt;
420 }
421
weed_out_param_integer_init(const char * name,int def,int min,int max)422 static weed_plant_t *weed_out_param_integer_init(const char *name, int def, int min, int max) {
423 weed_plant_t *paramt = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
424 int ptype = WEED_PARAM_INTEGER;
425 weed_paramtmpl_set_name(paramt, name);
426 weed_leaf_set(paramt, WEED_LEAF_PARAM_TYPE, WEED_SEED_INT, 1, &ptype);
427 weed_leaf_set(paramt, WEED_LEAF_DEFAULT, WEED_SEED_INT, 1, &def);
428 weed_leaf_set(paramt, WEED_LEAF_MIN, WEED_SEED_INT, 1, &min);
429 weed_leaf_set(paramt, WEED_LEAF_MAX, WEED_SEED_INT, 1, &max);
430 return paramt;
431 }
432
weed_out_param_integer_init_nominmax(const char * name,int def)433 static weed_plant_t *weed_out_param_integer_init_nominmax(const char *name, int def) {
434 weed_plant_t *paramt = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
435 int ptype = WEED_PARAM_INTEGER;
436 weed_paramtmpl_set_name(paramt, name);
437 weed_leaf_set(paramt, WEED_LEAF_PARAM_TYPE, WEED_SEED_INT, 1, &ptype);
438 weed_leaf_set(paramt, WEED_LEAF_DEFAULT, WEED_SEED_INT, 1, &def);
439 return paramt;
440 }
441
weed_out_param_switch_init(const char * name,int def)442 static weed_plant_t *weed_out_param_switch_init(const char *name, int def) {
443 weed_plant_t *paramt = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
444 int ptype = WEED_PARAM_SWITCH;
445 weed_paramtmpl_set_name(paramt, name);
446 weed_leaf_set(paramt, WEED_LEAF_PARAM_TYPE, WEED_SEED_INT, 1, &ptype);
447 weed_leaf_set(paramt, WEED_LEAF_DEFAULT, WEED_SEED_BOOLEAN, 1, &def);
448 return paramt;
449 }
450
weed_out_param_float_init(const char * name,double def,double min,double max)451 static weed_plant_t *weed_out_param_float_init(const char *name, double def, double min, double max) {
452 weed_plant_t *paramt = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
453 int ptype = WEED_PARAM_FLOAT;
454 weed_paramtmpl_set_name(paramt, name);
455 weed_leaf_set(paramt, WEED_LEAF_PARAM_TYPE, WEED_SEED_INT, 1, &ptype);
456 weed_leaf_set(paramt, WEED_LEAF_DEFAULT, WEED_SEED_DOUBLE, 1, &def);
457 weed_leaf_set(paramt, WEED_LEAF_MIN, WEED_SEED_DOUBLE, 1, &min);
458 weed_leaf_set(paramt, WEED_LEAF_MAX, WEED_SEED_DOUBLE, 1, &max);
459 return paramt;
460 }
461
weed_out_param_float_init_nominmax(const char * name,double def)462 static weed_plant_t *weed_out_param_float_init_nominmax(const char *name, double def) {
463 weed_plant_t *paramt = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
464 int ptype = WEED_PARAM_FLOAT;
465 weed_paramtmpl_set_name(paramt, name);
466 weed_leaf_set(paramt, WEED_LEAF_PARAM_TYPE, WEED_SEED_INT, 1, &ptype);
467 weed_leaf_set(paramt, WEED_LEAF_DEFAULT, WEED_SEED_DOUBLE, 1, &def);
468 return paramt;
469 }
470
weed_out_param_text_init(const char * name,const char * def)471 static weed_plant_t *weed_out_param_text_init(const char *name, const char *def) {
472 weed_plant_t *paramt = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
473 int ptype = WEED_PARAM_TEXT;
474 weed_paramtmpl_set_name(paramt, name);
475 weed_leaf_set(paramt, WEED_LEAF_PARAM_TYPE, WEED_SEED_INT, 1, &ptype);
476 weed_leaf_set(paramt, WEED_LEAF_DEFAULT, WEED_SEED_STRING, 1, &def);
477 return paramt;
478 }
479
weed_out_param_colRGBi_init(const char * name,int red,int green,int blue)480 static weed_plant_t *weed_out_param_colRGBi_init(const char *name, int red, int green, int blue) {
481 weed_plant_t *paramt = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
482 int ptype = WEED_PARAM_COLOR;
483 int cspace = WEED_COLORSPACE_RGB;
484 int def[3] = {red, green, blue}, min = 0, max = 255;
485 weed_paramtmpl_set_name(paramt, name);
486 weed_leaf_set(paramt, WEED_LEAF_PARAM_TYPE, WEED_SEED_INT, 1, &ptype);
487 weed_leaf_set(paramt, WEED_LEAF_COLORSPACE, WEED_SEED_INT, 1, &cspace);
488 weed_leaf_set(paramt, WEED_LEAF_DEFAULT, WEED_SEED_INT, 3, def);
489 weed_leaf_set(paramt, WEED_LEAF_MIN, WEED_SEED_INT, 1, &min);
490 weed_leaf_set(paramt, WEED_LEAF_MAX, WEED_SEED_INT, 1, &max);
491 return paramt;
492 }
493
weed_out_param_colRGBd_init(const char * name,double red,double green,double blue)494 static weed_plant_t *weed_out_param_colRGBd_init(const char *name, double red, double green, double blue) {
495 weed_plant_t *paramt = weed_plant_new(WEED_PLANT_PARAMETER_TEMPLATE);
496 int ptype = WEED_PARAM_COLOR;
497 int cspace = WEED_COLORSPACE_RGB;
498 double def[3] = {red, green, blue}, min = 0, max = 1.;
499 weed_paramtmpl_set_name(paramt, name);
500 weed_leaf_set(paramt, WEED_LEAF_PARAM_TYPE, WEED_SEED_INT, 1, &ptype);
501 weed_leaf_set(paramt, WEED_LEAF_COLORSPACE, WEED_SEED_INT, 1, &cspace);
502 weed_leaf_set(paramt, WEED_LEAF_DEFAULT, WEED_SEED_DOUBLE, 3, def);
503 weed_leaf_set(paramt, WEED_LEAF_MIN, WEED_SEED_DOUBLE, 1, &min);
504 weed_leaf_set(paramt, WEED_LEAF_MAX, WEED_SEED_DOUBLE, 1, &max);
505 return paramt;
506 }
507
508 ///////////////////////////////////////////////////////////////////////
509
510 #ifdef NEED_AUDIO
weed_channel_get_audio_rate(weed_plant_t * channel)511 static inline int weed_channel_get_audio_rate(weed_plant_t *channel) {return gg_i(channel, WEED_LEAF_AUDIO_RATE);}
weed_channel_get_naudchans(weed_plant_t * channel)512 static inline int weed_channel_get_naudchans(weed_plant_t *channel) {return gg_i(channel, WEED_LEAF_AUDIO_CHANNELS);}
weed_channel_get_audio_length(weed_plant_t * channel)513 static inline int weed_channel_get_audio_length(weed_plant_t *channel) {return gg_i(channel, WEED_LEAF_AUDIO_DATA_LENGTH);}
weed_paramtmpl_declare_volume_mastern(weed_plant_t * pt)514 static inline void weed_paramtmpl_declare_volume_mastern(weed_plant_t *pt) {
515 weed_leaf_set(pt, WEED_LEAF_IS_VOLUME_MASTER, WEED_SEED_BOOLEAN, 1, &wtrue);
516 }
517 static weed_plant_t *weed_audio_channel_template_init(const char *name, int flags);
518 #ifdef __WEED_UTILS_H__
weed_channel_get_audio_data(weed_plant_t * channel,int * naudchans)519 static inline float **weed_channel_get_audio_data(weed_plant_t *channel, int *naudchans) {
520 if (naudchans) *naudchans = 0;
521 return (float **)weed_get_voidptr_array_counted(channel, WEED_LEAF_AUDIO_DATA, naudchans);
522 }
523 #endif
weed_audio_channel_template_init(const char * name,int flags)524 static weed_plant_t *weed_audio_channel_template_init(const char *name, int flags) {
525 weed_plant_t *chantmpl = weed_channel_template_init(name, flags);
526 if (chantmpl) weed_leaf_set(chantmpl, WEED_LEAF_IS_AUDIO, WEED_SEED_BOOLEAN, 1, &wtrue);
527 return chantmpl;
528 }
529 #endif
530
weed_is_threading(weed_plant_t * inst)531 static inline int weed_is_threading(weed_plant_t *inst) {
532 if (inst) {
533 weed_plant_t *ochan = weed_get_out_channel(inst, 0);
534 return (ochan && _leaf_has_value(ochan, WEED_LEAF_OFFSET)) ? WEED_TRUE : WEED_FALSE;
535 } return WEED_FALSE;
536 }
537
538 #ifdef __WEED_UTILS_H__
weed_param_get_array_int(weed_plant_t * param,int * nvalues)539 static inline int *weed_param_get_array_int(weed_plant_t *param, int *nvalues) {
540 return (int *)(weed_get_int_array_counted(param, WEED_LEAF_VALUE, nvalues));
541 }
weed_param_get_array_boolean(weed_plant_t * param,int * nvalues)542 static inline int *weed_param_get_array_boolean(weed_plant_t *param, int *nvalues) {
543 return weed_get_boolean_array_counted(param, WEED_LEAF_VALUE, nvalues);
544 }
weed_param_get_array_double(weed_plant_t * param,int * nvalues)545 static inline double *weed_param_get_array_double(weed_plant_t *param, int *nvalues) {
546 return weed_get_double_array_counted(param, WEED_LEAF_VALUE, nvalues);
547 }
weed_param_get_array_int64(weed_plant_t * param,int * nvalues)548 static inline int64_t *weed_param_get_array_int64(weed_plant_t *param, int *nvalues) {
549 return weed_get_int64_array_counted(param, WEED_LEAF_VALUE, nvalues);
550 }
weed_param_get_array_string(weed_plant_t * param,int * nvalues)551 static inline char **weed_param_get_array_string(weed_plant_t *param, int *nvalues) {
552 return weed_get_string_array_counted(param, WEED_LEAF_VALUE, nvalues);
553 }
weed_get_in_channels(weed_plant_t * instance,int * nchans)554 static inline weed_plant_t **weed_get_in_channels(weed_plant_t *instance, int *nchans) {
555 return weed_get_plantptr_array_counted(instance, WEED_LEAF_IN_CHANNELS, nchans);
556 }
weed_get_out_channels(weed_plant_t * instance,int * nchans)557 static inline weed_plant_t **weed_get_out_channels(weed_plant_t *instance, int *nchans) {
558 return weed_get_plantptr_array_counted(instance, WEED_LEAF_OUT_CHANNELS, nchans);
559 }
weed_get_in_params(weed_plant_t * instance,int * nparams)560 static inline weed_plant_t **weed_get_in_params(weed_plant_t *instance, int *nparams) {
561 return weed_get_plantptr_array_counted(instance, WEED_LEAF_IN_PARAMETERS, nparams);
562 }
weed_get_out_params(weed_plant_t * instance,int * nparams)563 static inline weed_plant_t **weed_get_out_params(weed_plant_t *instance, int *nparams) {
564 return weed_get_plantptr_array_counted(instance, WEED_LEAF_OUT_PARAMETERS, nparams);
565 }
weed_channel_get_rowstrides(weed_plant_t * channel,int * nplanes)566 static inline int *weed_channel_get_rowstrides(weed_plant_t *channel, int *nplanes) {
567 return weed_get_int_array_counted(channel, WEED_LEAF_ROWSTRIDES, nplanes);
568 }
weed_channel_get_pixel_data_planar(weed_plant_t * channel,int * nplanes)569 static inline void **weed_channel_get_pixel_data_planar(weed_plant_t *channel, int *nplanes) {
570 return weed_get_voidptr_array_counted(channel, WEED_LEAF_PIXEL_DATA, nplanes);
571 }
572 #endif
573
weed_param_get_value_int(weed_plant_t * param)574 static inline int weed_param_get_value_int(weed_plant_t *param) {return gg_i(param, WEED_LEAF_VALUE);}
weed_param_get_value_boolean(weed_plant_t * param)575 static inline int weed_param_get_value_boolean(weed_plant_t *param) {return weed_param_get_value_int(param);}
weed_param_get_value_double(weed_plant_t * param)576 static inline double weed_param_get_value_double(weed_plant_t *param) {return gg_dbl(param, WEED_LEAF_VALUE);}
weed_param_get_value_int64(weed_plant_t * param)577 static inline int64_t weed_param_get_value_int64(weed_plant_t *param) {return gg_i64(param, WEED_LEAF_VALUE);}
weed_param_get_value_string(weed_plant_t * param)578 static inline char *weed_param_get_value_string(weed_plant_t *param) {
579 char *value;
580 return (!weed_leaf_num_elements(param, WEED_LEAF_VALUE)
581 || !(value = (char *)weed_malloc(weed_leaf_element_size(param, WEED_LEAF_VALUE, 0) + 1))) ? NULL
582 : *((char **)gg(param, WEED_LEAF_VALUE, 0, (void *)&value));
583 }
584
585 ///////////////////////////////////////////////////////////////////////////////////////////////
586
_weed_clone_leaf(weed_plant_t * from,const char * key,weed_plant_t * to)587 static void _weed_clone_leaf(weed_plant_t *from, const char *key, weed_plant_t *to) {
588 int i, *datai;
589 double *datad;
590 char **datac;
591 int64_t *datai6;
592 void **datav;
593 weed_funcptr_t *dataf;
594 weed_plant_t **datap;
595 int32_t seed_type = weed_leaf_seed_type(from, key);
596 weed_size_t stlen, num = wlne(from, key);
597 if (num == 0) weed_leaf_set(to, key, seed_type, 0, NULL);
598 else {
599 switch (seed_type) {
600 case WEED_SEED_BOOLEAN:
601 case WEED_SEED_INT:
602 datai = (int *)weed_malloc(num * sizeof(int));
603 for (i = 0; (weed_size_t)i < num; i++) weed_leaf_get(from, key, i, &datai[i]);
604 weed_leaf_set(to, key, seed_type, num, datai);
605 weed_free(datai);
606 break;
607 case WEED_SEED_INT64:
608 datai6 = (int64_t *)weed_malloc(num * sizeof(int64_t));
609 for (i = 0; (weed_size_t)i < num; i++) weed_leaf_get(from, key, i, &datai6[i]);
610 weed_leaf_set(to, key, WEED_SEED_INT64, num, datai6);
611 weed_free(datai6);
612 break;
613 case WEED_SEED_DOUBLE:
614 datad = (double *)weed_malloc(num * sizeof(double));
615 for (i = 0; (weed_size_t)i < num; i++) weed_leaf_get(from, key, i, &datad[i]);
616 weed_leaf_set(to, key, WEED_SEED_DOUBLE, num, datad);
617 weed_free(datad);
618 break;
619 case WEED_SEED_FUNCPTR:
620 dataf = (weed_funcptr_t *)weed_malloc(num * sizeof(weed_funcptr_t));
621 for (i = 0; (weed_size_t)i < num; i++) weed_leaf_get(from, key, i, &dataf[i]);
622 weed_leaf_set(to, key, WEED_SEED_FUNCPTR, num, dataf);
623 weed_free(dataf);
624 break;
625 case WEED_SEED_VOIDPTR:
626 datav = (void **)weed_malloc(num * sizeof(void *));
627 for (i = 0; (weed_size_t)i < num; i++) weed_leaf_get(from, key, i, &datav[i]);
628 weed_leaf_set(to, key, WEED_SEED_VOIDPTR, num, datav);
629 weed_free(datav);
630 break;
631 case WEED_SEED_PLANTPTR:
632 datap = (weed_plant_t **)weed_malloc(num * sizeof(weed_plant_t *));
633 for (i = 0; (weed_size_t)i < num; i++) weed_leaf_get(from, key, i, &datap[i]);
634 weed_leaf_set(to, key, WEED_SEED_PLANTPTR, num, datap);
635 weed_free(datap);
636 break;
637 case WEED_SEED_STRING:
638 datac = (char **)weed_malloc(num * sizeof(char *));
639 for (i = 0; (weed_size_t)i < num; i++) {
640 stlen = weed_leaf_element_size(from, key, i);
641 datac[i] = (char *)weed_malloc(stlen + 1);
642 weed_leaf_get(from, key, i, &datac[i]);
643 }
644 weed_leaf_set(to, key, WEED_SEED_STRING, num, datac);
645 for (i = 0; (weed_size_t)i < num; i++) weed_free(datac[i]);
646 weed_free(datac);
647 break;
648 }
649 }
650 }
651
weed_clone_plants(weed_plant_t ** plants)652 static weed_plant_t **weed_clone_plants(weed_plant_t **plants) {
653 //plants must be a NULL terminated array
654 int i, j, k, type, num_plants;
655 weed_plant_t **ret, *gui, *gui2;
656 char **leaves, **leaves2;
657 for (i = 0; plants[i]; i++);
658 num_plants = i;
659 ret = (weed_plant_t **)weed_malloc((num_plants + 1) * sizeof(weed_plant_t *));
660 if (!ret) return NULL;
661
662 for (i = 0; i < num_plants; i++) {
663 weed_leaf_get(plants[i], WEED_LEAF_TYPE, 0, &type);
664 ret[i] = weed_plant_new(type);
665 if (!ret[i]) return NULL;
666
667 leaves = weed_plant_list_leaves(plants[i], NULL);
668 for (j = 0; leaves[j]; j++) {
669 if (!strcmp(leaves[j], WEED_LEAF_GUI)) {
670 weed_leaf_get(plants[i], WEED_LEAF_GUI, 0, &gui);
671 gui2 = weed_plant_new(WEED_PLANT_GUI);
672 weed_leaf_set(ret[i], WEED_LEAF_GUI, WEED_SEED_PLANTPTR, 1, &gui2);
673 leaves2 = weed_plant_list_leaves(gui, NULL);
674 for (k = 0; leaves2[k] != NULL; k++) {
675 _weed_clone_leaf(gui, leaves2[k], gui2);
676 free(leaves2[k]);
677 }
678 free(leaves2);
679 } else _weed_clone_leaf(plants[i], leaves[j], ret[i]);
680 free(leaves[j]);
681 }
682 free(leaves);
683 }
684 ret[i] = NULL;
685 return ret;
686 }
687
688 #if defined (NEED_ALPHA_SORT) // for wrappers, use this to sort filters alphabetically
689 typedef struct dlink_list dlink_list_t;
690 struct dlink_list {
691 weed_plant_t *filter;
692 const char *name;
693 dlink_list_t *next;
694 };
695
add_to_list_sorted(dlink_list_t * list,weed_plant_t * filter,const char * name)696 static dlink_list_t *add_to_list_sorted(dlink_list_t *list, weed_plant_t *filter, const char *name) {
697 dlink_list_t *entry = (dlink_list_t *)weed_malloc(sizeof(dlink_list_t));
698 if (!entry) return list;
699 entry->filter = filter;
700 entry->name = strdup(name);
701 entry->next = list;
702 return entry;
703 }
704
dlink_list_cmp(const void * p1,const void * p2)705 static int dlink_list_cmp(const void *p1, const void *p2) {
706 dlink_list_t *l1 = *((dlink_list_t **)p1);
707 dlink_list_t *l2 = *((dlink_list_t **)p2);
708 return strcmp(l1->name, l2->name);
709 }
710
add_filters_from_list(weed_plant_t * plugin_info,dlink_list_t * list)711 static int add_filters_from_list(weed_plant_t *plugin_info, dlink_list_t *list) {
712 int count = 0, ocount;
713 dlink_list_t **dll, *xlist;
714 // map list to flat array so we can qsort it. The original list was prepended, so adding in reverse restores original order.
715 for (xlist = list; xlist; xlist = xlist->next) count++;
716 dll = (dlink_list_t **)weed_malloc((ocount = count) * sizeof(dlink_list_t *));
717 for (xlist = list; xlist; xlist = xlist->next) {
718 dll[--count] = xlist;
719 }
720 qsort(dll, ocount, sizeof(dlink_list_t *), dlink_list_cmp);
721 for (count = 0; count < ocount; count++) {
722 weed_plugin_info_add_filter_class(plugin_info, dll[count]->filter);
723 free((void *)dll[count]->name); weed_free(dll[count]);
724 }
725 weed_free(dll);
726 return count;
727 }
728 #endif
729
730 #if defined(NEED_RANDOM)
731
732 #if defined _WIN32 || defined __CYGWIN__ || defined IS_MINGW
733 #ifndef _CRT_RAND_S
734 #define _CRT_RAND_S
735 #endif
736 #else
737 #include <sys/time.h>
738 #endif
739 #include <stdlib.h>
740
drand(double max)741 static inline double drand(double max)
742 #if defined _WIN32 || defined __CYGWIN__ || defined IS_MINGW
743 {uint32_t rval; rand_s(&rval); return ((double)rval / (double)UINT_MAX * max);}
744 #else
745 {return (double)(drand48() * max);}
746 #endif
747
xorshift(uint64_t x)748 static inline uint64_t xorshift(uint64_t x) {x ^= x << 13; x ^= x >> 7; return x ^ (x << 17);}
749
fastrand(uint64_t oldval)750 static inline uint64_t fastrand(uint64_t oldval) {
751 // pseudo-random number generator
752 static uint64_t val = 0;
753 if (!val) {
754 #if defined _WIN32 || defined __CYGWIN__ || defined IS_MINGW
755 uint32_t rval, rval2; val++; rand_s(&rval); rand_s(&rval2); val = fastrand(((uint64_t)rval << 32) | (uint64_t)rval2) + 1;
756 #else
757 struct timeval t; gettimeofday(&t, NULL); srand48(t.tv_sec & 0xFFFFFFFFFFFF);
758 val = ((uint64_t)(lrand48() << 32) ^ (uint64_t)(lrand48())) + 1;
759 #endif
760 }
761 return (val = xorshift(val));
762 }
763
fastrand_dbl(double range)764 static inline double fastrand_dbl(double range) {
765 static const double divd = (double)(0xFFFFFFFF);
766 double val = (double)fastrand(1) / divd;
767 return val / divd * range;
768 }
769
fastrand_int(uint32_t range)770 static inline uint32_t fastrand_int(uint32_t range) {
771 return (uint32_t)(fastrand_dbl((double)(++range)));
772 }
773
774 #endif
775
776 //utilities
is_big_endian(void)777 static inline int is_big_endian(void) {
778 union memtest {int32_t num; char chr[4];} mm;
779 mm.num = 0x12345678; return (mm.chr[0] == 0x78) ? WEED_FALSE : WEED_TRUE;
780 }
781
782 #if defined(NEED_PALETTE_UTILS)
weed_palette_is_alpha(int pal)783 static inline int weed_palette_is_alpha(int pal) {return (pal >= 1024 && pal < 2048) ? WEED_TRUE : WEED_FALSE;}
weed_palette_is_rgb(int pal)784 static inline int weed_palette_is_rgb(int pal) {return (pal < 512) ? WEED_TRUE : WEED_FALSE;}
weed_palette_is_yuv(int pal)785 static inline int weed_palette_is_yuv(int pal) {return (pal >= 512 && pal < 1024) ? WEED_TRUE : WEED_FALSE;}
weed_palette_get_nplanes(int pal)786 static inline int weed_palette_get_nplanes(int pal) {
787 if (pal == WEED_PALETTE_RGB24 || pal == WEED_PALETTE_BGR24 || pal == WEED_PALETTE_RGBA32
788 || pal == WEED_PALETTE_BGRA32 ||
789 pal == WEED_PALETTE_ARGB32 || pal == WEED_PALETTE_UYVY8888 || pal == WEED_PALETTE_YUYV8888
790 || pal == WEED_PALETTE_YUV411 ||
791 pal == WEED_PALETTE_YUV888 || pal == WEED_PALETTE_YUVA8888 || pal == WEED_PALETTE_AFLOAT
792 || pal == WEED_PALETTE_A8 ||
793 pal == WEED_PALETTE_A1 || pal == WEED_PALETTE_RGBFLOAT || pal == WEED_PALETTE_RGBAFLOAT) return 1;
794 if (pal == WEED_PALETTE_YUV420P || pal == WEED_PALETTE_YVU420P || pal == WEED_PALETTE_YUV422P ||
795 pal == WEED_PALETTE_YUV444P) return 3;
796 if (pal == WEED_PALETTE_YUVA4444P) return 4;
797 return 0;
798 }
799
weed_palette_is_valid(int pal)800 static inline int weed_palette_is_valid(int pal) {return weed_palette_get_nplanes(pal) ? WEED_TRUE : WEED_FALSE;}
801
weed_palette_is_float_palette(int pal)802 static inline int weed_palette_is_float_palette(int pal) {
803 return (pal == WEED_PALETTE_RGBAFLOAT || pal == WEED_PALETTE_AFLOAT
804 || pal == WEED_PALETTE_RGBFLOAT) ? WEED_TRUE : WEED_FALSE;
805 }
806
weed_palette_has_alpha_channel(int pal)807 static inline int weed_palette_has_alpha_channel(int pal) {
808 return (pal == WEED_PALETTE_RGBA32 || pal == WEED_PALETTE_BGRA32 || pal == WEED_PALETTE_ARGB32 ||
809 pal == WEED_PALETTE_YUVA4444P || pal == WEED_PALETTE_YUVA8888 || pal == WEED_PALETTE_RGBAFLOAT ||
810 weed_palette_is_alpha(pal)) ? WEED_TRUE : WEED_FALSE;
811 }
812
weed_palette_get_plane_ratio_horizontal(int pal,int plane)813 static inline double weed_palette_get_plane_ratio_horizontal(int pal, int plane) {
814 // return ratio of plane[n] width/plane[0] width;
815 if (plane == 0) return 1.0;
816 if (plane == 1 || plane == 2) {
817 if (pal == WEED_PALETTE_YUV444P || pal == WEED_PALETTE_YUVA4444P) return 1.0;
818 if (pal == WEED_PALETTE_YUV422P || pal == WEED_PALETTE_YUV420P || pal == WEED_PALETTE_YVU420P) return 0.5;
819 }
820 if (plane == 3) if (pal == WEED_PALETTE_YUVA4444P) return 1.0;
821 return 0.0;
822 }
823
weed_palette_get_plane_ratio_vertical(int pal,int plane)824 static inline double weed_palette_get_plane_ratio_vertical(int pal, int plane) {
825 // return ratio of plane[n] height/plane[n] height
826 if (plane == 0) return 1.0;
827 if (plane == 1 || plane == 2) {
828 if (pal == WEED_PALETTE_YUV444P || pal == WEED_PALETTE_YUVA4444P || pal == WEED_PALETTE_YUV422P) return 1.0;
829 if (pal == WEED_PALETTE_YUV420P || pal == WEED_PALETTE_YVU420P) return 0.5;
830 }
831 if (plane == 3) if (pal == WEED_PALETTE_YUVA4444P) return 1.0;
832 return 0.0;
833 }
834
blank_pixel(uint8_t * dst,int pal,int yuv_clamping,uint8_t * src)835 static size_t blank_pixel(uint8_t *dst, int pal, int yuv_clamping, uint8_t *src) {
836 // set src to non-null to preserve the alpha channel (if applicable)
837 // yuv_clamping
838 // only valid for non-planar (packed) palettes
839 unsigned char *idst = dst;
840 uint8_t y_black = yuv_clamping == WEED_YUV_CLAMPING_UNCLAMPED ? 0 : 16;
841 switch (pal) {
842 case WEED_PALETTE_RGB24: case WEED_PALETTE_BGR24: dst[0] = dst[1] = dst[2] = 0; dst += 3; break;
843 case WEED_PALETTE_RGBA32: case WEED_PALETTE_BGRA32:
844 dst[0] = dst[1] = dst[2] = 0; dst[3] = src == NULL ? 255 : src[3]; dst += 4; break;
845 case WEED_PALETTE_ARGB32: dst[1] = dst[2] = dst[3] = 0; dst[0] = src == NULL ? 255 : src[0]; dst += 4; break;
846 case WEED_PALETTE_UYVY8888: dst[1] = dst[3] = y_black; dst[0] = dst[2] = 128; dst += 4; break;
847 case WEED_PALETTE_YUYV8888: dst[0] = dst[2] = y_black; dst[1] = dst[3] = 128; dst += 4; break;
848 case WEED_PALETTE_YUV888: dst[0] = y_black; dst[1] = dst[2] = 128; dst += 3; break;
849 case WEED_PALETTE_YUVA8888: dst[0] = y_black; dst[1] = dst[2] = 128; dst[3] = src == NULL ? 255 : src[3]; dst += 4; break;
850 case WEED_PALETTE_YUV411: dst[0] = dst[3] = 128; dst[1] = dst[2] = dst[4] = dst[5] = y_black; dst += 6; break;
851 default: break;
852 } return dst - idst;
853 }
854
blank_row(uint8_t ** pdst,int width,int pal,int yuv_clamping,int uvcopy,uint8_t ** psrc)855 static void blank_row(uint8_t **pdst, int width, int pal, int yuv_clamping, int uvcopy, uint8_t **psrc) {
856 // for YUV420 and YVU420, only set uvcopy for even rows, and increment pdst[1], pdst[2] on the odd rows
857 int nplanes, p, mpsize;
858 uint8_t *dst = *pdst, *src = NULL, black[3];
859 if (pal == WEED_PALETTE_RGB24 || pal == WEED_PALETTE_BGR24) {weed_memset(dst, 0, width * 3); return;}
860 if (!uvcopy && (pal == WEED_PALETTE_YUV420P || pal == WEED_PALETTE_YVU420P)) nplanes = 1;
861 else nplanes = weed_palette_get_nplanes(pal);
862 black[0] = yuv_clamping == WEED_YUV_CLAMPING_UNCLAMPED ? 0 : 16; black[1] = black[2] = 128;
863 for (p = 0; p < nplanes; p++) {
864 dst = pdst[p];
865 if (psrc != NULL) src = psrc[p];
866 if (p == 3) {if (!src) weed_memset(dst, 255, width); else weed_memcpy(dst, src, width); break;}
867 if (pal == WEED_PALETTE_YUV420P || pal == WEED_PALETTE_YVU420P || pal == WEED_PALETTE_YUV422P
868 || pal == WEED_PALETTE_YUV444P || pal == WEED_PALETTE_YUVA4444P) weed_memset(dst, black[p], width);
869 else {
870 // RGBA, BGRA, ARGB, YUV888, YUVA8888, UYVY, YUYV, YUV411
871 for (int i = 0; i < width; i++) {mpsize = blank_pixel(dst, pal, yuv_clamping, src); dst += mpsize; if (src != NULL) src += mpsize;}
872 break;
873 } if (p == 0 && (pal == WEED_PALETTE_YUV420P || pal == WEED_PALETTE_YVU420P || pal == WEED_PALETTE_YUV422P))
874 width >>= 1;
875 }
876 }
877
blank_frame(void ** pdata,int width,int height,int * rs,int pal,int yuv_clamping)878 static void blank_frame(void **pdata, int width, int height, int *rs, int pal, int yuv_clamping) {
879 uint8_t *pd2[4];
880 int nplanes = weed_palette_get_nplanes(pal), odd, is_420 = (pal == WEED_PALETTE_YUV420P || pal == WEED_PALETTE_YVU420P);
881 int i, j;
882 for (j = 0; j < nplanes; j++) pd2[j] = (uint8_t *)pdata[j];
883 for (i = 0; i < height; i++) {
884 blank_row(pd2, width, pal, yuv_clamping, !(odd = i ^ 1), NULL);
885 for (j = 0; j < nplanes; j++) {pd2[j] += rs[j]; if (is_420 && !odd) break;}
886 }
887 }
888 #endif
889
890 #if defined(NEED_PALETTE_CONVERSIONS)
891
892 #ifndef myround
893 #define myround(n) ((n >= 0.) ? (int)(n + 0.5) : (int)(n - 0.5))
894 #endif
895
896 static int alpha_inited = 0;
897 static int unal[256][256], al[256][256];
898
init_unal(void)899 static inline void init_unal(void) {
900 // premult to postmult and vice-versa
901 for (int i = 0; i < 256; i++)
902 for (int j = 0; j < 256; j++) {
903 unal[i][j] = (float)j * 255. / (float)i; al[i][j] = (float)j * (float)i / 255.;
904 }
905 }
906
alpha_premult(unsigned char * ptr,int width,int height,int rowstride,int pal,int un)907 static void alpha_premult(unsigned char *ptr, int width, int height, int rowstride, int pal, int un) {
908 int aoffs = 3, coffs = 0, psizel = 3, alpha, psize = 4;
909 int i, j, p;
910 switch (pal) {
911 case WEED_PALETTE_BGRA32: break;
912 case WEED_PALETTE_ARGB32: psizel = 4; coffs = 1; aoffs = 0; break;
913 default: return;
914 }
915 if (!alpha_inited) init_unal();
916 if (un == WEED_TRUE) {
917 for (i = 0; i < height; i++) {
918 for (j = 0; j < width; j += psize)
919 {alpha = ptr[j + aoffs]; for (p = coffs; p < psizel; p++) ptr[j + p] = unal[alpha][ptr[j + p]];}
920 ptr += rowstride;
921 }
922 } else {
923 for (i = 0; i < height; i++) for (j = 0; j < width; j += psize) {
924 alpha = ptr[j + aoffs];
925 for (p = coffs; p < psizel; p++) ptr[j + p] = al[alpha][ptr[j + p]];
926 }
927 ptr += rowstride;
928 }
929 }
930
931 /* precomputed tables */
932 #define FP_BITS 16
933 static int Y_Ru[256], Y_Gu[256], Y_Bu[256];
934 static int Cb_Ru[256], Cb_Gu[256], Cb_Bu[256];
935 static int Cr_Ru[256], Cr_Gu[256], Cr_Bu[256];
936 static int YCL_YUCL[256], UVCL_UVUCL[256], YUCL_YCL[256];
937 static int yuv_rgb_inited = 0, y_y_inited = 0;
938
init_RGB_to_YCbCr_tables(void)939 static void init_RGB_to_YCbCr_tables(void) {
940 for (int i = 0; i < 256; i++) {
941 Y_Ru[i] = myround(0.299 * (double)i * (1 << FP_BITS)); Y_Gu[i] = myround(0.587 * (double)i * (1 << FP_BITS));
942 Y_Bu[i] = myround(0.114 * (double)i * (1 << FP_BITS)); Cb_Bu[i] = myround(-0.168736 * (double)i * (1 << FP_BITS));
943 Cb_Gu[i] = myround(-0.331264 * (double)i * (1 << FP_BITS)); Cb_Ru[i] = myround((0.500 * (double)i + 128.) * (1 << FP_BITS));
944 Cr_Bu[i] = myround(0.500 * (double)i * (1 << FP_BITS)); Cr_Gu[i] = myround(-0.418688 * (double)i * (1 << FP_BITS));
945 Cr_Ru[i] = myround((-0.081312 * (double)i + 128.) * (1 << FP_BITS));
946 } yuv_rgb_inited = 1;
947 }
948
949 // unclamped values
950 #define RGB_2_YIQ(a, b, c) do {short x; for (int i = 0; i < NUM_PIXELS_SQUARED; i++) { \
951 Unit Y, I, Q; \
952 if ((x = ((Y_Ru[(int)a[i]] + Y_Gu[(int)b[i]] + Y_Bu[(int)(int)c[i]]) >> FP_BITS)) > 255) x = 255; \
953 Y = x < 0 ? 0 : x; \
954 if ((x = ((Cr_Ru[(int)a[i]] + Cr_Gu[(int)b[i]] + Cr_Bu[(int)c[i]]) >> FP_BITS)) > 255) x = 255; \
955 I = x < 0 ? 0 : x; \
956 if ((x = ((Cb_Ru[(int)a[i]] + Cb_Gu[(int)b[i]] + Cb_Bu[(int)c[i]] ) >> FP_BITS)) > 255) x = 255; \
957 Q = x < 0 ? 0 : x; a[i] = Y; b[i] = I; c[i] = Q; \
958 }} while(0)
959
init_Y_to_Y_tables(void)960 static void init_Y_to_Y_tables(void) {
961 int i;
962 for (i = 0; i < 17; i++) {UVCL_UVUCL[i] = YCL_YUCL[i] = 0; YUCL_YCL[i] = (uint8_t)((float)i / 255. * 219. + .5) + 16;}
963 for (; i < 235; i++) {
964 YCL_YUCL[i] = (int)((float)(i - 16.) / 219. * 255. + .5); UVCL_UVUCL[i] = (int)((float)(i - 16.) / 224. * 255. + .5);
965 YUCL_YCL[i] = (uint8_t)((float)i / 255. * 219. + .5) + 16;
966 }
967 for (; i < 256; i++) {UVCL_UVUCL[i] = YCL_YUCL[i] = 255; YUCL_YCL[i] = (uint8_t)((float)i / 255. * 219. + .5) + 16;}
968 y_y_inited = 1;
969 }
970
y_unclamped_to_clamped(uint8_t y)971 static inline uint8_t y_unclamped_to_clamped(uint8_t y) {if (!y_y_inited) init_Y_to_Y_tables(); return YUCL_YCL[y];}
y_clamped_to_unclamped(uint8_t y)972 static inline uint8_t y_clamped_to_unclamped(uint8_t y) {if (!y_y_inited) init_Y_to_Y_tables(); return YCL_YUCL[y];}
uv_clamped_to_unclamped(uint8_t u)973 static inline uint8_t uv_clamped_to_unclamped(uint8_t u) {if (!y_y_inited) init_Y_to_Y_tables(); return UVCL_UVUCL[u];}
974
calc_luma(uint8_t * pixel,int palette,int yuv_clamping)975 static uint8_t calc_luma(uint8_t *pixel, int palette, int yuv_clamping) {
976 if (!yuv_rgb_inited) init_RGB_to_YCbCr_tables();
977 switch (palette) {
978 case WEED_PALETTE_RGB24: case WEED_PALETTE_RGBA32: return (Y_Ru[pixel[0]] + Y_Gu[pixel[1]] + Y_Bu[pixel[2]]) >> FP_BITS;
979 case WEED_PALETTE_BGR24: case WEED_PALETTE_BGRA32: return (Y_Ru[pixel[2]] + Y_Gu[pixel[1]] + Y_Bu[pixel[0]]) >> FP_BITS;
980 case WEED_PALETTE_ARGB32: return (Y_Ru[pixel[1]] + Y_Gu[pixel[2]] + Y_Bu[pixel[3]]) >> FP_BITS;
981 default:
982 if (yuv_clamping == WEED_YUV_CLAMPING_UNCLAMPED) return pixel[0];
983 else {if (!y_y_inited) init_Y_to_Y_tables(); return YCL_YUCL[pixel[0]];}
984 } return 0;
985 }
986
987 #endif
988
989 #ifdef NEED_FONT_UTILS
990 #include <wchar.h>
991 static const wchar_t *fstretches[] = {L"UltraCondensed", L"ExtraCondensed", L"Condensed", L"SemiCondensed",
992 L"SemiExpanded", L"Expanded", L"ExtraExpanded", L"UltraExpanded", NULL
993 };
994
995 static const wchar_t *fweights[] = {L"Thin", L"UltraLight", L"ExtraLight", L"Light", L"SemiLight", L"DemiLight",
996 L"Book", L"Regular", L"Medium",
997 L"DemiBold", L"SemiBold", L"Bold", L"ExtraBold", L"UltraBold", L"Black", L"Heavy",
998 L"UltraHeavy", L"UltraBlack", L"ExtraBlack", NULL
999 };
1000
1001 static const wchar_t *fstyles[] = {L"Roman", L"Italic", L"Oblique", NULL};
1002
weed_parse_font_string(const char * fontstr,char ** family,char ** fstretch,char ** fweight,char ** fstyle,int * size)1003 void weed_parse_font_string(const char *fontstr, char **family, char **fstretch, char **fweight,
1004 char **fstyle, int *size) {
1005 wchar_t *token, *state, *next_token;
1006 wchar_t *xfamily = L"\0";
1007 wchar_t *xfstretch = L"\0";
1008 wchar_t *xfweight = L"\0";
1009 wchar_t *xfstyle = L"\0";
1010 wchar_t *xfontstr = NULL;;
1011 size_t wcs_len;
1012 int i;
1013
1014 if (size) *size = 0;
1015 if (!fontstr) goto fontdone;
1016
1017 wcs_len = mbstowcs(NULL, fontstr, 0) + 1;
1018 xfontstr = weed_calloc(wcs_len, sizeof(wchar_t));
1019 mbstowcs(xfontstr, fontstr, wcs_len);
1020
1021 for (token = wcstok(xfontstr, L" ", &state); token; token = next_token) {
1022 if (*token == L'\0') {
1023 next_token = wcstok(NULL, L" ", &state);
1024 continue;
1025 }
1026 do {
1027 next_token = wcstok(NULL, L" ", &state);
1028 } while (next_token && *next_token == L'\0');
1029 if (!next_token) {
1030 wchar_t *endptr;
1031 uintmax_t umax = wcstoumax(token, &endptr, 10);
1032 if (umax > 0 && *endptr == L'\0') {
1033 if (size) *size = (int)(umax & 0x80FFFFFF);
1034 goto fontdone;
1035 }
1036 }
1037 if (*xfstretch == L'\0') {
1038 for (i = 0; fstretches[i]; i++) {
1039 if (!wcscasecmp(token, fstretches[i])) {
1040 xfstretch = (wchar_t *)fstretches[i];
1041 break;
1042 }
1043 }
1044 if (*xfstyle != L'\0') continue;
1045 }
1046 if (*xfweight == L'\0') {
1047 for (i = 0; fweights[i]; i++) {
1048 if (!wcscasecmp(token, fweights[i])) {
1049 xfweight = (wchar_t *)fweights[i];
1050 break;
1051 }
1052 }
1053 if (*xfweight != L'\0') continue;
1054 }
1055 if (*xfstyle == L'\0') {
1056 for (i = 0; fstyles[i]; i++) {
1057 if (!wcscasecmp(token, fstyles[i])) {
1058 xfstyle = (wchar_t *)fstyles[i];
1059 break;
1060 }
1061 }
1062 if (*xfstyle != L'\0') continue;
1063 }
1064 if (*xfstretch == L'\0' && *xfweight == L'\0' && *xfstyle == L'\0') {
1065 if (*xfamily != L'\0') {
1066 wchar_t tmp[256];
1067 swprintf(tmp, 256, L"%ls %ls", xfamily, token);
1068 free(xfamily);
1069 xfamily = wcsdup(tmp);
1070 } else xfamily = wcsdup(token);
1071 }
1072 }
1073 fontdone:
1074 if (family) {
1075 wcs_len = wcstombs(NULL, xfamily, 0) + 1;
1076 *family = weed_calloc(wcs_len, 1);
1077 wcstombs(*family, xfamily, wcs_len);
1078 }
1079 if (fstretch) {
1080 wcs_len = wcstombs(NULL, xfstretch, 0) + 1;
1081 *fstretch = weed_calloc(wcs_len, 1);
1082 wcstombs(*fstretch, xfstretch, wcs_len);
1083 }
1084 if (fweight) {
1085 wcs_len = wcstombs(NULL, xfweight, 0) + 1;
1086 *fweight = weed_calloc(wcs_len, 1);
1087 wcstombs(*fweight, xfweight, wcs_len);
1088 }
1089 if (fstyle) {
1090 wcs_len = wcstombs(NULL, xfstyle, 0) + 1;
1091 *fstyle = weed_calloc(wcs_len, 1);
1092 wcstombs(*fstyle, xfstyle, wcs_len);
1093 }
1094
1095 if (*xfamily != L'\0') weed_free(xfamily);
1096 if (xfontstr) weed_free(xfontstr);
1097 }
1098 #endif
1099
1100 #endif // __HAVE_WEED_PLUGIN_UTILS__
1101