FFmpeg
Loading...
Searching...
No Matches
drawvg.c
Go to the documentation of this file.
1/*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19
20// Prevent the `dllimport` attribute in the functions declared by Cairo when
21// the test is built on a Windows machine.
22//
23// This is needed to avoid the "redeclared without dllimport attribute after
24// being referenced with dll linkage" warnings on every function redefined by
25// the `MOCK_FN_n` macros below.
26#define CAIRO_WIN32_STATIC_BUILD
27
28#include <cairo.h>
29#include <stdarg.h>
30#include <stdio.h>
31
32#include "libavutil/log.h"
33#include "libavutil/pixdesc.h"
34
35static void mock_av_log(void *ptr, int level, const char *fmt, va_list vl) {
36 printf("av_log[%d]: ", level);
37 vprintf(fmt, vl);
38}
39
41
42// Mock for cairo functions.
43//
44// `MOCK_FN_n` macros define wrappers for functions that only receive `n`
45// arguments of type `double`.
46//
47// `MOCK_FN_I` macro wrap a function that receives a single integer value.
48
49struct _cairo {
52};
53
54static void update_current_point(cairo_t *cr, const char *func, double x, double y) {
55 // Update current point only if the function name contains `_to`.
56 if (strstr(func, "_to") == NULL) {
57 return;
58 }
59
60 if (strstr(func, "_rel_") == NULL) {
61 cr->current_point_x = x;
62 cr->current_point_y = y;
63 } else {
64 cr->current_point_x += x;
65 cr->current_point_y += y;
66 }
67}
68
69#define MOCK_FN_0(func) \
70 void func(cairo_t* cr) { \
71 puts(#func); \
72 }
73
74#define MOCK_FN_1(func) \
75 void func(cairo_t* cr, double a0) { \
76 printf(#func " %.1f\n", a0); \
77 }
78
79#define MOCK_FN_2(func) \
80 void func(cairo_t* cr, double a0, double a1) { \
81 update_current_point(cr, #func, a0, a1); \
82 printf(#func " %.1f %.1f\n", a0, a1); \
83 }
84
85#define MOCK_FN_4(func) \
86 void func(cairo_t* cr, double a0, double a1, double a2, double a3) { \
87 printf(#func " %.1f %.1f %.1f %.1f\n", a0, a1, a2, a3); \
88 }
89
90#define MOCK_FN_5(func) \
91 void func(cairo_t* cr, double a0, double a1, double a2, double a3, double a4) { \
92 printf(#func " %.1f %.1f %.1f %.1f %.1f\n", a0, a1, a2, a3, a4); \
93 }
94
95#define MOCK_FN_6(func) \
96 void func(cairo_t* cr, double a0, double a1, double a2, double a3, double a4, double a5) { \
97 update_current_point(cr, #func, a4, a5); \
98 printf(#func " %.1f %.1f %.1f %.1f %.1f %.1f\n", a0, a1, a2, a3, a4, a5); \
99 }
100
101#define MOCK_FN_I(func, type) \
102 void func(cairo_t* cr, type i) { \
103 printf(#func " %d\n", (int)i); \
104 }
105
106MOCK_FN_5(cairo_arc);
107MOCK_FN_0(cairo_clip);
108MOCK_FN_0(cairo_clip_preserve);
109MOCK_FN_0(cairo_close_path);
110MOCK_FN_6(cairo_curve_to);
111MOCK_FN_0(cairo_fill);
112MOCK_FN_0(cairo_fill_preserve);
113MOCK_FN_0(cairo_identity_matrix);
114MOCK_FN_2(cairo_line_to);
115MOCK_FN_2(cairo_move_to);
116MOCK_FN_0(cairo_new_path);
117MOCK_FN_0(cairo_new_sub_path);
118MOCK_FN_4(cairo_rectangle);
119MOCK_FN_6(cairo_rel_curve_to);
120MOCK_FN_2(cairo_rel_line_to);
121MOCK_FN_2(cairo_rel_move_to);
122MOCK_FN_0(cairo_reset_clip);
123MOCK_FN_0(cairo_restore);
124MOCK_FN_1(cairo_rotate);
125MOCK_FN_0(cairo_save);
126MOCK_FN_2(cairo_scale);
127MOCK_FN_I(cairo_set_fill_rule, cairo_fill_rule_t);
128MOCK_FN_1(cairo_set_font_size);
129MOCK_FN_I(cairo_set_line_cap, cairo_line_cap_t);
130MOCK_FN_I(cairo_set_line_join, cairo_line_join_t);
131MOCK_FN_1(cairo_set_line_width);
132MOCK_FN_1(cairo_set_miter_limit);
133MOCK_FN_4(cairo_set_source_rgba);
134MOCK_FN_0(cairo_stroke);
135MOCK_FN_0(cairo_stroke_preserve);
136MOCK_FN_2(cairo_translate);
137
138cairo_bool_t cairo_get_dash_count(cairo_t *cr) {
139 return 1;
140}
141
142cairo_status_t cairo_status(cairo_t *cr) {
143 return CAIRO_STATUS_SUCCESS;
144}
145
146void cairo_get_dash(cairo_t *cr, double *dashes, double *offset) {
147 // Return a dummy value to verify that it is included in
148 // the next call to `cairo_set_dash`.
149 *dashes = -1;
150
151 if (offset)
152 *offset = -2;
153}
154
155void cairo_set_dash(cairo_t *cr, const double *dashes, int num_dashes, double offset) {
156 printf("%s [", __func__);
157 for (int i = 0; i < num_dashes; i++)
158 printf(" %.1f", dashes[i]);
159 printf(" ] %.1f\n", offset);
160}
161
162cairo_bool_t cairo_has_current_point(cairo_t *cr) {
163 return 1;
164}
165
166void cairo_get_current_point(cairo_t *cr, double *x, double *y) {
167 *x = cr->current_point_x;
168 *y = cr->current_point_y;
169}
170
171void cairo_set_source(cairo_t *cr, cairo_pattern_t *source) {
172 int count;
173 double r, g, b, a;
174 double x0, y0, x1, y1, r0, r1;
175
176 printf("%s", __func__);
177
178#define PRINT_COLOR(prefix) \
179 printf(prefix "#%02lx%02lx%02lx%02lx", lround(r*255), lround(g*255), lround(b*255), lround(a*255))
180
181 switch (cairo_pattern_get_type(source)) {
182 case CAIRO_PATTERN_TYPE_SOLID:
183 cairo_pattern_get_rgba(source, &r, &g, &b, &a);
184 PRINT_COLOR(" ");
185 break;
186
187 case CAIRO_PATTERN_TYPE_LINEAR:
188 cairo_pattern_get_linear_points(source, &x0, &y0, &x1, &y1);
189 printf(" lineargrad(%.1f %.1f %.1f %.1f)", x0, y0, x1, y1);
190 break;
191
192 case CAIRO_PATTERN_TYPE_RADIAL:
193 cairo_pattern_get_radial_circles(source, &x0, &y0, &r0, &x1, &y1, &r1);
194 printf(" radialgrad(%.1f %.1f %.1f %.1f %.1f %.1f)", x0, y0, r0, x1, y1, r1);
195 break;
196 }
197
198 if (cairo_pattern_get_color_stop_count(source, &count) == CAIRO_STATUS_SUCCESS) {
199 for (int i = 0; i < count; i++) {
200 cairo_pattern_get_color_stop_rgba(source, i, &x0, &r, &g, &b, &a);
201 printf(" %.1f/", x0);
202 PRINT_COLOR("");
203 }
204 }
205
206 printf("\n");
207}
208
209// Verify that the `vgs_commands` array is sorted, so it can
210// be used with `bsearch(3)`.
211static void check_sorted_cmds_array(void) {
212 int failures = 0;
213
214 for (int i = 0; i < FF_ARRAY_ELEMS(vgs_commands) - 1; i++) {
216 printf("%s: comparator must return 0 for item %d\n", __func__, i);
217 failures++;
218 }
219
221 printf("%s: entry for '%s' must appear after '%s', at index %d\n",
222 __func__, vgs_commands[i].name, vgs_commands[i + 1].name, i);
223 failures++;
224 }
225 }
226
227 printf("%s: %d failures\n", __func__, failures);
228}
229
230// Compile and run a script.
231static void check_script(int is_file, const char* source) {
232 int ret;
233
235
236 struct VGSEvalState state;
237 struct VGSParser parser;
238 struct VGSProgram program;
239
240 struct _cairo cairo_ctx = { 0, 0 };
241
242 if (is_file) {
243 uint8_t *s = NULL;
244
245 printf("\n--- %s: %s\n", __func__, av_basename(source));
246
247 ret = ff_load_textfile(NULL, source, &s, NULL);
248 if (ret != 0) {
249 printf("Failed to read %s: %d\n", source, ret);
250 return;
251 }
252
253 source = s;
254 } else {
255 printf("\n--- %s: %s\n", __func__, source);
256 }
257
258 ret = av_dict_parse_string(&metadata, "m.a=1:m.b=2", "=", ":", 0);
259 av_assert0(ret == 0);
260
261 vgs_parser_init(&parser, source);
262
263 ret = vgs_parse(NULL, &parser, &program, 0);
264
265 int init_ret = vgs_eval_state_init(&state, &program, NULL, NULL);
266 av_assert0(init_ret == 0);
267
268 for (int i = 0; i < VAR_COUNT; i++)
269 state.vars[i] = 1 << i;
270
271 vgs_parser_free(&parser);
272
273 if (ret != 0) {
274 printf("%s: vgs_parse = %d\n", __func__, ret);
275 goto exit;
276 }
277
278 state.metadata = metadata;
279 state.cairo_ctx = &cairo_ctx;
280
281 ret = vgs_eval(&state, &program, 0);
283
284 if (ret != 0)
285 printf("%s: vgs_eval = %d\n", __func__, ret);
286
287exit:
289
290 if (is_file)
291 av_free((void*)source);
292
293 vgs_free(&program);
294}
295
296int main(int argc, const char **argv)
297{
298 char buf[512];
299
301
303
304 for (int i = 1; i < argc; i++)
305 check_script(1, argv[i]);
306
307 // Detect unclosed expressions.
308 check_script(0, "M 0 (1*(t+1)");
309
310 // Invalid command.
311 check_script(0, "save invalid 1 2");
312
313 // Invalid constant.
314 check_script(0, "setlinecap unknown m 10 20");
315
316 // Missing arguments.
317 check_script(0, "M 0 1 2");
318
319 // Invalid variable names.
320 check_script(0, "setvar ba^d 0");
321
322 // Reserved names.
323 check_script(0, "setvar cx 0");
324
325 // Max number of user variables.
326 memset(buf, 0, sizeof(buf));
327 for (int i = 0; i < USER_VAR_COUNT; i++) {
328 av_strlcatf(buf, sizeof(buf), " setvar v%d %d", i, i);
329 }
330 av_strlcatf(buf, sizeof(buf), " M (v0) (v%d) 1 (unknown_var)", USER_VAR_COUNT - 1);
331 check_script(0, buf);
332
333 // Too many variables.
334 memset(buf, 0, sizeof(buf));
335 for (int i = 0; i < USER_VAR_COUNT + 1; i++) {
336 av_strlcatf(buf, sizeof(buf), " setvar v%d %d", i + 1, i);
337 }
338 check_script(0, buf);
339
340 // Invalid procedure names.
341 check_script(0, "call a");
342 check_script(0, "proc a { call b } call a");
343
344 // Invalid arguments list.
345 check_script(0, "proc p0 a1 a2 a3 a4 a5 a6 a7 a8 { break }");
346 check_script(0, "proc p0 a1 a2 { break } call p0 break");
347 check_script(0, "proc p0 a1 a2 { break } call p0 1 2 3");
348
349 // Long expressions.
350 memset(buf, 0, sizeof(buf));
351 strncat(buf, "M 0 (1", sizeof(buf) - 1);
352 for (int i = 0; i < 100; i++) {
353 strncat(buf, " + n", sizeof(buf) - 1);
354 }
355 strncat(buf, ")", sizeof(buf) - 1);
356 check_script(0, buf);
357
358 return 0;
359}
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
size_t av_strlcatf(char *dst, size_t size, const char *fmt,...)
Definition avstring.c:103
static int FUNC metadata(CodedBitstreamContext *ctx, RWContext *rw, APVRawMetadata *current)
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
__device__ int printf(const char *,...)
int main
Definition dovi_rpuenc.c:38
cairo_status_t cairo_status(cairo_t *cr)
Definition drawvg.c:142
#define MOCK_FN_5(func)
Definition drawvg.c:90
static void mock_av_log(void *ptr, int level, const char *fmt, va_list vl)
Definition drawvg.c:35
#define MOCK_FN_4(func)
Definition drawvg.c:85
cairo_bool_t cairo_has_current_point(cairo_t *cr)
Definition drawvg.c:162
#define MOCK_FN_0(func)
Definition drawvg.c:69
cairo_bool_t cairo_get_dash_count(cairo_t *cr)
Definition drawvg.c:138
#define MOCK_FN_2(func)
Definition drawvg.c:79
static void check_sorted_cmds_array(void)
Definition drawvg.c:211
#define PRINT_COLOR(prefix)
#define MOCK_FN_I(func, type)
Definition drawvg.c:101
void cairo_set_source(cairo_t *cr, cairo_pattern_t *source)
Definition drawvg.c:171
static void update_current_point(cairo_t *cr, const char *func, double x, double y)
Definition drawvg.c:54
void cairo_get_current_point(cairo_t *cr, double *x, double *y)
Definition drawvg.c:166
void cairo_get_dash(cairo_t *cr, double *dashes, double *offset)
Definition drawvg.c:146
static void check_script(int is_file, const char *source)
Definition drawvg.c:231
#define MOCK_FN_1(func)
Definition drawvg.c:74
#define MOCK_FN_6(func)
Definition drawvg.c:95
void cairo_set_dash(cairo_t *cr, const double *dashes, int num_dashes, double offset)
Definition drawvg.c:155
static struct @346255127015250356166251341105367306144006377143 state
void av_dict_free(AVDictionary **pm)
Free all the memory allocated for an AVDictionary struct and all keys and values.
Definition dict.c:233
int av_dict_parse_string(AVDictionary **pm, const char *str, const char *key_val_sep, const char *pairs_sep, int flags)
Parse the key/value pairs list and add the parsed entries to a dictionary.
Definition dict.c:210
void av_log_set_callback(void(*callback)(void *, int, const char *, va_list))
Set the logging callback.
Definition log.c:491
const char * av_basename(const char *path)
Thread safe basename.
Definition avstring.c:253
int a
#define r
Definition input.c:42
#define b
Definition input.c:43
unsigned offset
Definition libaomenc.c:763
int(* func)(AVBPrint *dst, const char *in, const char *arg)
Definition jacosubdec.c:66
static int failures
Definition probetest.c:33
const char * name
Definition qsvenc.c:142
#define FF_ARRAY_ELEMS(a)
double current_point_y
Definition drawvg.c:51
double current_point_x
Definition drawvg.c:50
uint8_t level
Definition svq3.c:208
#define av_free(p)
int ff_load_textfile(void *log_ctx, const char *textfile, unsigned char **text, size_t *text_size)
Definition textutils.c:354
const char * g
Definition vf_curves.c:128
drawvg filter, draw vector graphics with cairo.
static void vgs_eval_state_free(struct VGSEvalState *state)
Definition vf_drawvg.c:1676
static int vgs_eval_state_init(struct VGSEvalState *state, const struct VGSProgram *program, void *log_ctx, AVFrame *frame)
Definition vf_drawvg.c:1645
#define USER_VAR_COUNT
Number of user variables that can be created with setvar.
Definition vf_drawvg.c:77
static int vgs_eval(struct VGSEvalState *state, const struct VGSProgram *program, int stack_level)
Interpreter for VGSProgram.
Definition vf_drawvg.c:1901
static void vgs_parser_init(struct VGSParser *parser, const char *source)
Definition vf_drawvg.c:1298
static int vgs_comp_command_spec(const void *cs1, const void *cs2)
Comparator for VGSCommandDecl, to be used with bsearch(3).
Definition vf_drawvg.c:352
static void vgs_free(struct VGSProgram *program)
Release the memory allocated by the program.
Definition vf_drawvg.c:731
static const struct VGSCommandSpec vgs_commands[]
Definition vf_drawvg.c:273
static void vgs_parser_free(struct VGSParser *parser)
Definition vf_drawvg.c:1311
static int vgs_parse(void *log_ctx, struct VGSParser *parser, struct VGSProgram *program, int subprogram)
Build a program by parsing a script.
Definition vf_drawvg.c:1330
#define VAR_COUNT
Total number of variables (default- and user-variables).
Definition vf_drawvg.c:80
static double cr(void *priv, double x, double y)
Definition vf_geq.c:248