3 Copyright 2006-2008 Taco Hoekwater <taco@luatex.org>
5 This file is part of LuaTeX.
7 LuaTeX is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2 of the License, or (at your
10 option) any later version.
12 LuaTeX is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License along
18 with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
24 #include <math.h> /* temporary */
31 # include <../lua51/lua.h>
32 # include <../lua51/lauxlib.h>
33 # include <../lua51/lualib.h>
39 /*@unused@*/ static const char _svn_version[] =
40 "$Id: lmplib.c 1364 2008-07-04 16:09:46Z taco $ $URL: http://scm.foundry.supelec.fr/svn/luatex/trunk/src/texk/web2c/luatexdir/lua/lmplib.c $";
42 /* metatable identifiers and tests */
44 #define MPLIB_METATABLE "MPlib"
45 #define MPLIB_FIG_METATABLE "MPlib.fig"
46 #define MPLIB_GR_METATABLE "MPlib.gr"
48 #define is_mp(L,b) (MP *)luaL_checkudata(L,b,MPLIB_METATABLE)
49 #define is_fig(L,b) (struct mp_edge_object **)luaL_checkudata(L,b,MPLIB_FIG_METATABLE)
50 #define is_gr_object(L,b) (struct mp_graphic_object **)luaL_checkudata(L,b,MPLIB_GR_METATABLE)
52 /* Lua string pre-hashing */
54 #define mplib_init_S(a) do { \
55 lua_pushliteral(L,#a); \
56 mplib_##a##_ptr = (char *)lua_tostring(L,-1); \
57 mplib_##a##_index = luaL_ref (L,LUA_REGISTRYINDEX); \
60 #define mplib_push_S(a) do { \
61 lua_rawgeti(L,LUA_REGISTRYINDEX,mplib_##a##_index); \
64 #define mplib_is_S(a,i) (mplib_##a##_ptr==(char *)lua_tostring(L,i))
66 #define mplib_make_S(a) \
67 static int mplib_##a##_index = 0; \
68 static char *mplib_##a##_ptr = NULL
70 static int mplib_type_Ses[mp_special_code + 1] = { 0 }; /* [0] is not used */
73 mplib_make_S(outline);
75 mplib_make_S(special);
76 mplib_make_S(start_bounds);
77 mplib_make_S(stop_bounds);
78 mplib_make_S(start_clip);
79 mplib_make_S(stop_clip);
81 mplib_make_S(left_type);
82 mplib_make_S(right_type);
83 mplib_make_S(x_coord);
84 mplib_make_S(y_coord);
87 mplib_make_S(right_x);
88 mplib_make_S(right_y);
97 mplib_make_S(linecap);
98 mplib_make_S(linejoin);
99 mplib_make_S(miterlimit);
102 mplib_make_S(postscript);
103 mplib_make_S(prescript);
104 mplib_make_S(transform);
108 static void mplib_init_Ses(lua_State * L)
111 mplib_init_S(outline);
113 mplib_init_S(start_bounds);
114 mplib_init_S(stop_bounds);
115 mplib_init_S(start_clip);
116 mplib_init_S(stop_clip);
117 mplib_init_S(special);
119 mplib_type_Ses[mp_fill_code] = mplib_fill_index;
120 mplib_type_Ses[mp_stroked_code] = mplib_outline_index;
121 mplib_type_Ses[mp_text_code] = mplib_text_index;
122 mplib_type_Ses[mp_start_bounds_code] = mplib_start_bounds_index;
123 mplib_type_Ses[mp_stop_bounds_code] = mplib_stop_bounds_index;
124 mplib_type_Ses[mp_start_clip_code] = mplib_start_clip_index;
125 mplib_type_Ses[mp_stop_clip_code] = mplib_stop_clip_index;
126 mplib_type_Ses[mp_special_code] = mplib_special_index;
128 mplib_init_S(left_type);
129 mplib_init_S(right_type);
130 mplib_init_S(x_coord);
131 mplib_init_S(y_coord);
132 mplib_init_S(left_x);
133 mplib_init_S(left_y);
134 mplib_init_S(right_x);
135 mplib_init_S(right_y);
142 mplib_init_S(height);
144 mplib_init_S(linecap);
145 mplib_init_S(linejoin);
146 mplib_init_S(miterlimit);
149 mplib_init_S(postscript);
150 mplib_init_S(prescript);
151 mplib_init_S(transform);
157 /* Enumeration arrays to map MPlib enums to Lua strings */
159 static const char *interaction_options[] =
160 { "unknown", "batch", "nonstop", "scroll", "errorstop", NULL };
162 static const char *mplib_filetype_names[] =
163 { "term", "error", "mp", "log", "ps", "mem", "tfm", "map", "pfb", "enc", NULL };
165 static const char *knot_type_enum[] =
166 { "endpoint", "explicit", "given", "curl", "open", "end_cycle" };
168 static const char *fill_fields[] =
169 { "type", "path", "htap", "pen", "color", "linejoin", "miterlimit",
170 "prescript", "postscript", NULL };
172 static const char *stroked_fields[] =
173 { "type", "path", "pen", "color", "linejoin", "miterlimit", "linecap",
174 "dash", "prescript", "postscript", NULL };
176 static const char *text_fields[] =
177 { "type", "text", "dsize", "font", "color", "width", "height", "depth",
178 "transform", "prescript", "postscript", NULL };
180 static const char *special_fields[] =
181 { "type", "prescript", NULL };
183 static const char *start_bounds_fields[] =
184 { "type", "path", NULL };
186 static const char *start_clip_fields[] =
187 { "type", "path", NULL };
189 static const char *stop_bounds_fields[] =
192 static const char *stop_clip_fields[] =
195 static const char *no_fields[] =
199 /* The list of supported MPlib options (not all make sense) */
202 P_ERROR_LINE, P_MAX_LINE,
203 P_MAIN_MEMORY, P_HASH_SIZE, P_PARAM_SIZE, P_IN_OPEN, P_RANDOM_SEED,
204 P_INTERACTION, P_INI_VERSION, P_MEM_NAME, P_JOB_NAME, P_FIND_FILE,
205 P__SENTINEL } mplib_parm_idx;
208 const char *name; /* parameter name */
209 mplib_parm_idx idx; /* parameter index */
212 static mplib_parm_struct mplib_parms[] = {
213 {"error_line", P_ERROR_LINE },
214 {"print_line", P_MAX_LINE },
215 {"main_memory", P_MAIN_MEMORY },
216 {"hash_size", P_HASH_SIZE },
217 {"param_size", P_PARAM_SIZE },
218 {"max_in_open", P_IN_OPEN },
219 {"random_seed", P_RANDOM_SEED },
220 {"interaction", P_INTERACTION },
221 {"ini_version", P_INI_VERSION },
222 {"mem_name", P_MEM_NAME },
223 {"job_name", P_JOB_NAME },
224 {"find_file", P_FIND_FILE },
229 /* Start by defining the needed callback routines for the library */
231 static char *mplib_find_file(MP mp, const char *fname, const char *fmode, int ftype)
233 lua_State *L = (lua_State *)mp_userdata(mp);
234 lua_checkstack(L, 4);
235 lua_getfield(L, LUA_REGISTRYINDEX, "mplib_file_finder");
236 if (lua_isfunction(L, -1)) {
237 char *s = NULL, *x = NULL;
238 lua_pushstring(L, fname);
239 lua_pushstring(L, fmode);
240 if (ftype >= mp_filetype_text) {
241 lua_pushnumber(L, (lua_Number)(ftype - mp_filetype_text));
243 lua_pushstring(L, mplib_filetype_names[ftype]);
245 if (lua_pcall(L, 3, 1, 0) != 0) {
246 fprintf(stdout, "Error in mp.find_file: %s\n",
247 (char *) lua_tostring(L, -1));
250 x = (char *) lua_tostring(L, -1);
253 lua_pop(L, 1); /* pop the string */
258 if (fmode[0] != 'r' || (!access(fname, R_OK)) || ftype) {
259 return strdup(fname);
264 static int mplib_find_file_function(lua_State * L)
266 if (!(lua_isfunction(L, -1) || lua_isnil(L, -1))) {
267 return 1; /* error */
269 lua_pushstring(L, "mplib_file_finder");
270 lua_pushvalue(L, -2);
271 lua_rawset(L, LUA_REGISTRYINDEX);
275 #define xfree(A) if ((A)!=NULL) { free((A)); A = NULL; }
277 static int mplib_new(lua_State * L)
280 mp_ptr = lua_newuserdata(L, sizeof(MP *));
283 struct MP_options *options = mp_options();
284 options->userdata = (void *) L;
285 options->noninteractive = 1; /* required ! */
286 options->find_file = mplib_find_file;
287 options->print_found_names = 1;
288 if (lua_type(L, 1) == LUA_TTABLE) {
289 for (i = 0; mplib_parms[i].name != NULL; i++) {
290 lua_getfield(L, 1, mplib_parms[i].name);
291 if (lua_isnil(L, -1)) {
293 continue; /* skip unset */
295 switch (mplib_parms[i].idx) {
297 options->error_line = (int)lua_tointeger(L, -1);
298 if (options->error_line<60) options->error_line =60;
299 if (options->error_line>250) options->error_line = 250;
300 options->half_error_line = (options->error_line/2)+10;
303 options->max_print_line = (int)lua_tointeger(L, -1);
304 if (options->max_print_line<60) options->max_print_line = 60;
307 options->main_memory = (int)lua_tointeger(L, -1);
310 options->hash_size = (unsigned)lua_tointeger(L, -1);
313 options->param_size = (int)lua_tointeger(L, -1);
316 options->max_in_open = (int)lua_tointeger(L, -1);
319 options->random_seed = (int)lua_tointeger(L, -1);
322 options->interaction =
323 luaL_checkoption(L, -1, "errorstopmode",
324 interaction_options);
327 options->ini_version = lua_toboolean(L, -1);
330 options->mem_name = strdup((char *) lua_tostring(L, -1));
333 options->job_name = strdup((char *) lua_tostring(L, -1));
336 if (mplib_find_file_function(L)) { /* error here */
338 "Invalid arguments to mp.new({find_file=...})\n");
347 *mp_ptr = mp_initialize(options);
348 xfree(options->command_line);
349 xfree(options->mem_name);
352 luaL_getmetatable(L, MPLIB_METATABLE);
353 lua_setmetatable(L, -2);
361 static int mplib_collect(lua_State * L)
363 MP *mp_ptr = is_mp(L, 1);
364 if (*mp_ptr != NULL) {
365 (void)mp_finish(*mp_ptr);
371 static int mplib_tostring(lua_State * L)
373 MP *mp_ptr = is_mp(L, 1);
374 if (*mp_ptr != NULL) {
375 (void)lua_pushfstring(L, "<MP %p>", *mp_ptr);
381 static int mplib_wrapresults(lua_State * L, mp_run_data *res, int status)
383 lua_checkstack(L, 5);
385 if (res->term_out.size != 0) {
386 lua_pushstring(L, res->term_out.data);
387 lua_setfield(L, -2, "term");
389 if (res->error_out.size != 0) {
390 lua_pushstring(L, res->error_out.data);
391 lua_setfield(L, -2, "error");
393 if (res->log_out.size != 0) {
394 lua_pushstring(L, res->log_out.data);
395 lua_setfield(L, -2, "log");
397 if (res->edges != NULL) {
398 struct mp_edge_object **v;
399 struct mp_edge_object *p = res->edges;
403 v = lua_newuserdata(L, sizeof(struct mp_edge_object *));
405 luaL_getmetatable(L, MPLIB_FIG_METATABLE);
406 lua_setmetatable(L, -2);
407 lua_rawseti(L, -2, i);
411 lua_setfield(L, -2, "fig");
414 lua_pushnumber(L, (lua_Number)status);
415 lua_setfield(L, -2, "status");
419 static int mplib_execute(lua_State * L)
421 MP *mp_ptr = is_mp(L, 1);
422 if (*mp_ptr != NULL && lua_isstring(L, 2)) {
424 char *s = (char *) lua_tolstring(L, 2, &l);
425 int h = mp_execute(*mp_ptr, s, l);
426 mp_run_data *res = mp_rundata(*mp_ptr);
427 return mplib_wrapresults(L, res, h);
434 static int mplib_finish(lua_State * L)
436 MP *mp_ptr = is_mp(L, 1);
437 if (*mp_ptr != NULL) {
439 int h = mp_execute(*mp_ptr,NULL,0);
440 mp_run_data *res = mp_rundata(*mp_ptr);
441 i = mplib_wrapresults(L, res, h);
442 (void)mp_finish(*mp_ptr);
451 static int mplib_char_dimension(lua_State * L, int t)
453 MP *mp_ptr = is_mp(L, 1);
454 if (*mp_ptr != NULL) {
455 char *fname = (char *)luaL_checkstring(L,2);
456 int charnum = (int)luaL_checkinteger(L,3);
457 if (charnum<0 || charnum>255) {
458 lua_pushnumber(L, (lua_Number)0);
460 lua_pushnumber(L,(lua_Number)mp_get_char_dimension(*mp_ptr,fname,charnum,t));
463 lua_pushnumber(L, (lua_Number)0);
468 static int mplib_charwidth(lua_State * L)
470 return mplib_char_dimension(L, 'w');
473 static int mplib_chardepth(lua_State * L)
475 return mplib_char_dimension(L, 'd');
478 static int mplib_charheight(lua_State * L)
480 return mplib_char_dimension(L, 'h');
483 static int mplib_version(lua_State * L)
485 char *s = mp_metapost_version();
486 lua_pushstring(L, s);
491 static int mplib_statistics(lua_State * L)
493 MP *mp_ptr = is_mp(L, 1);
494 if (*mp_ptr != NULL) {
496 lua_pushnumber(L, (lua_Number)mp_memory_usage(*mp_ptr));
497 lua_setfield(L, -2, "main_memory");
498 lua_pushnumber(L, (lua_Number)mp_hash_usage(*mp_ptr));
499 lua_setfield(L, -2, "hash_size");
500 lua_pushnumber(L, (lua_Number)mp_param_usage(*mp_ptr));
501 lua_setfield(L, -2, "param_size");
502 lua_pushnumber(L, (lua_Number)mp_open_usage(*mp_ptr));
503 lua_setfield(L, -2, "max_in_open");
513 static int mplib_fig_collect(lua_State * L)
515 struct mp_edge_object **hh = is_fig(L, 1);
517 mp_gr_toss_objects(*hh);
523 static int mplib_fig_body(lua_State * L)
526 struct mp_graphic_object **v;
527 struct mp_graphic_object *p;
528 struct mp_edge_object **hh = is_fig(L, 1);
532 v = lua_newuserdata(L, sizeof(struct mp_graphic_object *));
534 luaL_getmetatable(L, MPLIB_GR_METATABLE);
535 lua_setmetatable(L, -2);
536 lua_rawseti(L, -2, i);
540 (*hh)->body = NULL; /* prevent double free */
544 static int mplib_fig_copy_body(lua_State * L)
547 struct mp_graphic_object **v;
548 struct mp_graphic_object *p;
549 struct mp_edge_object **hh = is_fig(L, 1);
553 v = lua_newuserdata(L, sizeof(struct mp_graphic_object *));
554 *v = mp_gr_copy_object((*hh)->parent, p);
555 luaL_getmetatable(L, MPLIB_GR_METATABLE);
556 lua_setmetatable(L, -2);
557 lua_rawseti(L, -2, i);
565 static int mplib_fig_tostring(lua_State * L)
567 struct mp_edge_object **hh = is_fig(L, 1);
568 (void)lua_pushfstring(L, "<figure %p>", *hh);
572 static int mplib_fig_postscript(lua_State * L)
575 struct mp_edge_object **hh = is_fig(L, 1);
576 int prologues = (int)luaL_optnumber(L, 2, (lua_Number)-1);
577 int procset = (int)luaL_optnumber(L, 3, (lua_Number)-1);
578 if (mp_ps_ship_out(*hh, prologues, procset)
579 && (res = mp_rundata((*hh)->parent))
580 && (res->ps_out.size != 0)) {
581 lua_pushstring(L, res->ps_out.data);
588 static int mplib_fig_filename(lua_State * L)
590 struct mp_edge_object **hh = is_fig(L, 1);
592 char *s = (*hh)->filename;
593 lua_pushstring(L, s);
600 static int mplib_fig_width(lua_State * L)
602 struct mp_edge_object **hh = is_fig(L, 1);
604 lua_pushnumber(L, (double) (*hh)->width / 65536.0);
611 static int mplib_fig_height(lua_State * L)
613 struct mp_edge_object **hh = is_fig(L, 1);
615 lua_pushnumber(L, (double) (*hh)->height / 65536.0);
622 static int mplib_fig_depth(lua_State * L)
624 struct mp_edge_object **hh = is_fig(L, 1);
626 lua_pushnumber(L, (double) (*hh)->depth / 65536.0);
633 static int mplib_fig_italcorr(lua_State * L)
635 struct mp_edge_object **hh = is_fig(L, 1);
637 lua_pushnumber(L, (double) (*hh)->ital_corr / 65536.0);
644 static int mplib_fig_charcode(lua_State * L)
646 struct mp_edge_object **hh = is_fig(L, 1);
648 lua_pushnumber(L, (lua_Number)(*hh)->charcode);
657 static int mplib_fig_bb(lua_State * L)
659 struct mp_edge_object **hh = is_fig(L, 1);
661 lua_pushnumber(L, (double) (*hh)->minx / 65536.0);
662 lua_rawseti(L, -2, 1);
663 lua_pushnumber(L, (double) (*hh)->miny / 65536.0);
664 lua_rawseti(L, -2, 2);
665 lua_pushnumber(L, (double) (*hh)->maxx / 65536.0);
666 lua_rawseti(L, -2, 3);
667 lua_pushnumber(L, (double) (*hh)->maxy / 65536.0);
668 lua_rawseti(L, -2, 4);
674 static int mplib_gr_collect(lua_State * L)
676 struct mp_graphic_object **hh = is_gr_object(L, 1);
678 mp_gr_toss_object(*hh);
684 static int mplib_gr_tostring(lua_State * L)
686 struct mp_graphic_object **hh = is_gr_object(L, 1);
687 (void)lua_pushfstring(L, "<object %p>", *hh);
691 #define pyth(a,b) (sqrt((a)*(a) + (b)*(b)))
693 #define aspect_bound (10.0/65536.0)
694 #define aspect_default (1.0/65536.0)
696 static double eps = 0.0001;
698 static double coord_range_x (mp_knot *h, double dz) {
700 double zlo = 0.0, zhi = 0.0;
703 z = (double)h->x_coord;
704 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
705 z = (double)h->right_x;
706 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
707 z = (double)h->left_x;
708 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
713 return (zhi - zlo <= dz ? aspect_bound : aspect_default);
716 static double coord_range_y (mp_knot *h, double dz) {
718 double zlo = 0.0, zhi = 0.0;
721 z = (double)h->y_coord;
722 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
723 z = (double)h->right_y;
724 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
725 z = (double)h->left_y;
726 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
731 return (zhi - zlo <= dz ? aspect_bound : aspect_default);
735 static int mplib_gr_peninfo(lua_State * L) {
736 double x_coord, y_coord, left_x, left_y, right_x, right_y;
738 double rx = 1.0, sx = 0.0, sy = 0.0, ry = 1.0, tx = 0.0, ty = 0.0;
739 double divider = 1.0;
741 mp_knot *p = NULL, *path = NULL;
742 struct mp_graphic_object **hh = is_gr_object(L, -1);
747 if ((*hh)->type == mp_fill_code) {
748 p = ((mp_fill_object *)(*hh))->pen_p;
749 path = ((mp_fill_object *)(*hh))->path_p;
750 } else if ((*hh)->type == mp_stroked_code) {
751 p = ((mp_stroked_object *)(*hh))->pen_p;
752 path = ((mp_stroked_object *)(*hh))->path_p;
754 if (p==NULL || path == NULL) {
758 x_coord = p->x_coord/65536.0;
759 y_coord = p->y_coord/65536.0;
760 left_x = p->left_x/65536.0;
761 left_y = p->left_y/65536.0;
762 right_x = p->right_x/65536.0;
763 right_y = p->right_y/65536.0;
764 if ((right_x == x_coord) && (left_y == y_coord)) {
765 wx = fabs(left_x - x_coord);
766 wy = fabs(right_y - y_coord);
768 wx = pyth(left_x - x_coord, right_x - x_coord);
769 wy = pyth(left_y - y_coord, right_y - y_coord);
771 if ((wy/coord_range_x(path, wx)) >= (wx/coord_range_y(path, wy)))
785 rx/=width; ry/=width; sx/=width; sy/=width;
788 if (fabs(sx) < eps) sx = eps;
789 if (fabs(sy) < eps) sy = eps;
790 divider = sx*sy - rx*ry;
792 lua_pushnumber(L,width); lua_setfield(L,-2,"width");
793 lua_pushnumber(L,rx); lua_setfield(L,-2,"rx");
794 lua_pushnumber(L,sx); lua_setfield(L,-2,"sx");
795 lua_pushnumber(L,sy); lua_setfield(L,-2,"sy");
796 lua_pushnumber(L,ry); lua_setfield(L,-2,"ry");
797 lua_pushnumber(L,tx); lua_setfield(L,-2,"tx");
798 lua_pushnumber(L,ty); lua_setfield(L,-2,"ty");
803 static int mplib_gr_fields(lua_State * L)
807 struct mp_graphic_object **hh = is_gr_object(L, 1);
809 switch ((*hh)->type) {
811 fields = fill_fields;
813 case mp_stroked_code:
814 fields = stroked_fields;
817 fields = text_fields;
819 case mp_special_code:
820 fields = special_fields;
822 case mp_start_clip_code:
823 fields = start_clip_fields;
825 case mp_start_bounds_code:
826 fields = start_bounds_fields;
828 case mp_stop_clip_code:
829 fields = stop_clip_fields;
831 case mp_stop_bounds_code:
832 fields = stop_bounds_fields;
838 for (i = 0; fields[i] != NULL; i++) {
839 lua_pushstring(L, fields[i]);
840 lua_rawseti(L, -2, (i + 1));
849 #define mplib_push_number(L,x) lua_pushnumber(L,(lua_Number)(x)/65536.0)
854 static void mplib_push_path(lua_State * L, struct mp_knot *h, int is_pen)
856 struct mp_knot *p; /* for scanning the path */
862 lua_createtable(L, 0, 6);
864 if (p->left_type != mp_explicit) {
865 mplib_push_S(left_type);
866 lua_pushstring(L, knot_type_enum[p->left_type]);
869 if (p->right_type != mp_explicit) {
870 mplib_push_S(right_type);
871 lua_pushstring(L, knot_type_enum[p->right_type]);
875 mplib_push_S(x_coord);
876 mplib_push_number(L, p->x_coord);
878 mplib_push_S(y_coord);
879 mplib_push_number(L, p->y_coord);
881 mplib_push_S(left_x);
882 mplib_push_number(L, p->left_x);
884 mplib_push_S(left_y);
885 mplib_push_number(L, p->left_y);
887 mplib_push_S(right_x);
888 mplib_push_number(L, p->right_x);
890 mplib_push_S(right_y);
891 mplib_push_number(L, p->right_y);
893 lua_rawseti(L, -2, i);
895 if (p->right_type == mp_endpoint) {
905 /* this assumes that the top of the stack is a table
906 or nil already in the case
908 static void mplib_push_pentype(lua_State * L, struct mp_knot *h)
910 struct mp_knot *p; /* for scanning the path */
914 } else if (p == p->next) {
916 lua_pushstring(L, "elliptical");
922 #define set_color_objects(pq) \
923 object_color_model = pq->color_model; \
924 object_color_a = pq->color.a_val; \
925 object_color_b = pq->color.b_val; \
926 object_color_c = pq->color.c_val; \
927 object_color_d = pq->color.d_val;
930 static void mplib_push_color(lua_State * L, struct mp_graphic_object *p)
932 int object_color_model;
933 int object_color_a, object_color_b, object_color_c, object_color_d;
935 if (p->type == mp_fill_code) {
936 mp_fill_object *h = (mp_fill_object *) p;
937 set_color_objects(h);
938 } else if (p->type == mp_stroked_code) {
939 mp_stroked_object *h = (mp_stroked_object *) p;
940 set_color_objects(h);
942 mp_text_object *h = (mp_text_object *) p;
943 set_color_objects(h);
946 if (object_color_model >= mp_grey_model) {
947 mplib_push_number(L, object_color_a);
948 lua_rawseti(L, -2, 1);
949 if (object_color_model >= mp_rgb_model) {
950 mplib_push_number(L, object_color_b);
951 lua_rawseti(L, -2, 2);
952 mplib_push_number(L, object_color_c);
953 lua_rawseti(L, -2, 3);
954 if (object_color_model == mp_cmyk_model) {
955 mplib_push_number(L, object_color_d);
956 lua_rawseti(L, -2, 4);
965 /* the dash scale is not exported, the field has no external value */
966 static void mplib_push_dash(lua_State * L, struct mp_stroked_object *h)
970 if (h != NULL && h->dash_p != NULL) {
973 mplib_push_number(L, d->offset);
974 lua_setfield(L, -2, "offset");
975 if (d->array != NULL) {
978 while (*(d->array + i) != -1) {
979 ds = *(d->array + i) / 65536.0;
980 lua_pushnumber(L, ds);
982 lua_rawseti(L, -2, i);
984 lua_setfield(L, -2, "dashes");
991 static void mplib_push_transform(lua_State * L, struct mp_text_object *h)
995 lua_createtable(L, 6, 0);
996 mplib_push_number(L, h->tx);
997 lua_rawseti(L, -2, i);
999 mplib_push_number(L, h->ty);
1000 lua_rawseti(L, -2, i);
1002 mplib_push_number(L, h->txx);
1003 lua_rawseti(L, -2, i);
1005 mplib_push_number(L, h->tyx);
1006 lua_rawseti(L, -2, i);
1008 mplib_push_number(L, h->txy);
1009 lua_rawseti(L, -2, i);
1011 mplib_push_number(L, h->tyy);
1012 lua_rawseti(L, -2, i);
1019 #define FIELD(A) (mplib_is_S(A,2))
1021 static void mplib_fill(lua_State * L, struct mp_fill_object *h)
1024 mplib_push_path(L, h->path_p, MPLIB_PATH);
1025 } else if (FIELD(htap)) {
1026 mplib_push_path(L, h->htap_p, MPLIB_PATH);
1027 } else if (FIELD(pen)) {
1028 mplib_push_path(L, h->pen_p, MPLIB_PEN);
1029 mplib_push_pentype(L, h->pen_p);
1030 } else if (FIELD(color)) {
1031 mplib_push_color(L, (mp_graphic_object *) h);
1032 } else if (FIELD(linejoin)) {
1033 lua_pushnumber(L, (lua_Number)h->ljoin);
1034 } else if (FIELD(miterlimit)) {
1035 mplib_push_number(L, h->miterlim);
1036 } else if (FIELD(prescript)) {
1037 lua_pushstring(L, h->pre_script);
1038 } else if (FIELD(postscript)) {
1039 lua_pushstring(L, h->post_script);
1045 static void mplib_stroked(lua_State * L, struct mp_stroked_object *h)
1048 mplib_push_path(L, h->path_p, MPLIB_PATH);
1049 } else if (FIELD(pen)) {
1050 mplib_push_path(L, h->pen_p, MPLIB_PEN);
1051 mplib_push_pentype(L, h->pen_p);
1052 } else if (FIELD(color)) {
1053 mplib_push_color(L, (mp_graphic_object *) h);
1054 } else if (FIELD(dash)) {
1055 mplib_push_dash(L, h);
1056 } else if (FIELD(linecap)) {
1057 lua_pushnumber(L, (lua_Number)h->lcap);
1058 } else if (FIELD(linejoin)) {
1059 lua_pushnumber(L, (lua_Number)h->ljoin);
1060 } else if (FIELD(miterlimit)) {
1061 mplib_push_number(L, h->miterlim);
1062 } else if (FIELD(prescript)) {
1063 lua_pushstring(L, h->pre_script);
1064 } else if (FIELD(postscript)) {
1065 lua_pushstring(L, h->post_script);
1071 static void mplib_text(lua_State * L, struct mp_text_object *h)
1074 lua_pushstring(L, h->text_p);
1075 } else if (FIELD(dsize)) {
1076 mplib_push_number(L, (h->font_dsize / 16));
1077 } else if (FIELD(font)) {
1078 lua_pushstring(L, h->font_name);
1079 } else if (FIELD(color)) {
1080 mplib_push_color(L, (mp_graphic_object *) h);
1081 } else if (FIELD(width)) {
1082 mplib_push_number(L, h->width);
1083 } else if (FIELD(height)) {
1084 mplib_push_number(L, h->height);
1085 } else if (FIELD(depth)) {
1086 mplib_push_number(L, h->depth);
1087 } else if (FIELD(transform)) {
1088 mplib_push_transform(L, h);
1089 } else if (FIELD(prescript)) {
1090 lua_pushstring(L, h->pre_script);
1091 } else if (FIELD(postscript)) {
1092 lua_pushstring(L, h->post_script);
1098 static void mplib_special(lua_State * L, struct mp_special_object *h)
1100 if (FIELD(prescript)) {
1101 lua_pushstring(L, h->pre_script);
1107 static void mplib_start_bounds(lua_State * L, struct mp_bounds_object *h)
1110 mplib_push_path(L, h->path_p, MPLIB_PATH);
1116 static void mplib_start_clip(lua_State * L, struct mp_clip_object *h)
1119 mplib_push_path(L, h->path_p, MPLIB_PATH);
1125 static int mplib_gr_index(lua_State * L)
1127 struct mp_graphic_object **hh = is_gr_object(L, 1);
1129 struct mp_graphic_object *h = *hh;
1131 if (mplib_is_S(type, 2)) {
1132 lua_rawgeti(L, LUA_REGISTRYINDEX, mplib_type_Ses[h->type]);
1136 mplib_fill(L, (mp_fill_object *) h);
1138 case mp_stroked_code:
1139 mplib_stroked(L, (mp_stroked_object *) h);
1142 mplib_text(L, (mp_text_object *) h);
1144 case mp_special_code:
1145 mplib_special(L, (mp_special_object *) h);
1147 case mp_start_clip_code:
1148 mplib_start_clip(L, (mp_clip_object *) h);
1150 case mp_start_bounds_code:
1151 mplib_start_bounds(L, (mp_bounds_object *) h);
1153 case mp_stop_clip_code:
1154 case mp_stop_bounds_code:
1166 static const struct luaL_reg mplib_meta[] = {
1167 {"__gc", mplib_collect},
1168 {"__tostring", mplib_tostring},
1169 {NULL, NULL} /* sentinel */
1172 static const struct luaL_reg mplib_fig_meta[] = {
1173 {"__gc", mplib_fig_collect},
1174 {"__tostring", mplib_fig_tostring},
1175 {"objects", mplib_fig_body},
1176 {"copy_objects", mplib_fig_copy_body},
1177 {"filename", mplib_fig_filename},
1178 {"postscript", mplib_fig_postscript},
1179 {"boundingbox", mplib_fig_bb},
1180 {"width", mplib_fig_width},
1181 {"height", mplib_fig_height},
1182 {"depth", mplib_fig_depth},
1183 {"italcorr", mplib_fig_italcorr},
1184 {"charcode", mplib_fig_charcode},
1185 {NULL, NULL} /* sentinel */
1188 static const struct luaL_reg mplib_gr_meta[] = {
1189 {"__gc", mplib_gr_collect},
1190 {"__tostring", mplib_gr_tostring},
1191 {"__index", mplib_gr_index},
1192 {NULL, NULL} /* sentinel */
1195 static const struct luaL_reg mplib_d[] = {
1196 {"execute", mplib_execute},
1197 {"finish", mplib_finish},
1198 {"char_width", mplib_charwidth},
1199 {"char_height", mplib_charheight},
1200 {"char_depth", mplib_chardepth},
1201 {"statistics", mplib_statistics},
1202 {NULL, NULL} /* sentinel */
1206 static const struct luaL_reg mplib_m[] = {
1208 {"version", mplib_version},
1209 {"fields", mplib_gr_fields},
1210 {"pen_info", mplib_gr_peninfo},
1211 {NULL, NULL} /* sentinel */
1215 int luaopen_mplib(lua_State * L)
1219 luaL_newmetatable(L, MPLIB_GR_METATABLE);
1220 lua_pushvalue(L, -1); /* push metatable */
1221 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1222 luaL_register(L, NULL, mplib_gr_meta); /* object meta methods */
1225 luaL_newmetatable(L, MPLIB_FIG_METATABLE);
1226 lua_pushvalue(L, -1); /* push metatable */
1227 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1228 luaL_register(L, NULL, mplib_fig_meta); /* figure meta methods */
1231 luaL_newmetatable(L, MPLIB_METATABLE);
1232 lua_pushvalue(L, -1); /* push metatable */
1233 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1234 luaL_register(L, NULL, mplib_meta); /* meta methods */
1235 luaL_register(L, NULL, mplib_d); /* dict methods */
1236 luaL_register(L, "mplib", mplib_m); /* module functions */