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/>. */
23 #include <math.h> /* temporary */
30 # include <../lua51/lua.h>
31 # include <../lua51/lauxlib.h>
32 # include <../lua51/lualib.h>
38 /*@unused@*/ static const char _svn_version[] =
39 "$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 $";
41 /* metatable identifiers and tests */
43 #define MPLIB_METATABLE "MPlib"
44 #define MPLIB_FIG_METATABLE "MPlib.fig"
45 #define MPLIB_GR_METATABLE "MPlib.gr"
47 #define is_mp(L,b) (MP *)luaL_checkudata(L,b,MPLIB_METATABLE)
48 #define is_fig(L,b) (struct mp_edge_object **)luaL_checkudata(L,b,MPLIB_FIG_METATABLE)
49 #define is_gr_object(L,b) (struct mp_graphic_object **)luaL_checkudata(L,b,MPLIB_GR_METATABLE)
51 /* Lua string pre-hashing */
53 #define mplib_init_S(a) do { \
54 lua_pushliteral(L,#a); \
55 mplib_##a##_ptr = (char *)lua_tostring(L,-1); \
56 mplib_##a##_index = luaL_ref (L,LUA_REGISTRYINDEX); \
59 #define mplib_push_S(a) do { \
60 lua_rawgeti(L,LUA_REGISTRYINDEX,mplib_##a##_index); \
63 #define mplib_is_S(a,i) (mplib_##a##_ptr==(char *)lua_tostring(L,i))
65 #define mplib_make_S(a) \
66 static int mplib_##a##_index = 0; \
67 static char *mplib_##a##_ptr = NULL
69 static int mplib_type_Ses[mp_special_code + 1] = { 0 }; /* [0] is not used */
72 mplib_make_S(outline);
74 mplib_make_S(special);
75 mplib_make_S(start_bounds);
76 mplib_make_S(stop_bounds);
77 mplib_make_S(start_clip);
78 mplib_make_S(stop_clip);
80 mplib_make_S(left_type);
81 mplib_make_S(right_type);
82 mplib_make_S(x_coord);
83 mplib_make_S(y_coord);
86 mplib_make_S(right_x);
87 mplib_make_S(right_y);
96 mplib_make_S(linecap);
97 mplib_make_S(linejoin);
98 mplib_make_S(miterlimit);
101 mplib_make_S(postscript);
102 mplib_make_S(prescript);
103 mplib_make_S(transform);
107 static void mplib_init_Ses(lua_State * L)
110 mplib_init_S(outline);
112 mplib_init_S(start_bounds);
113 mplib_init_S(stop_bounds);
114 mplib_init_S(start_clip);
115 mplib_init_S(stop_clip);
116 mplib_init_S(special);
118 mplib_type_Ses[mp_fill_code] = mplib_fill_index;
119 mplib_type_Ses[mp_stroked_code] = mplib_outline_index;
120 mplib_type_Ses[mp_text_code] = mplib_text_index;
121 mplib_type_Ses[mp_start_bounds_code] = mplib_start_bounds_index;
122 mplib_type_Ses[mp_stop_bounds_code] = mplib_stop_bounds_index;
123 mplib_type_Ses[mp_start_clip_code] = mplib_start_clip_index;
124 mplib_type_Ses[mp_stop_clip_code] = mplib_stop_clip_index;
125 mplib_type_Ses[mp_special_code] = mplib_special_index;
127 mplib_init_S(left_type);
128 mplib_init_S(right_type);
129 mplib_init_S(x_coord);
130 mplib_init_S(y_coord);
131 mplib_init_S(left_x);
132 mplib_init_S(left_y);
133 mplib_init_S(right_x);
134 mplib_init_S(right_y);
141 mplib_init_S(height);
143 mplib_init_S(linecap);
144 mplib_init_S(linejoin);
145 mplib_init_S(miterlimit);
148 mplib_init_S(postscript);
149 mplib_init_S(prescript);
150 mplib_init_S(transform);
156 /* Enumeration arrays to map MPlib enums to Lua strings */
158 static const char *interaction_options[] =
159 { "unknown", "batch", "nonstop", "scroll", "errorstop", NULL };
161 static const char *mplib_filetype_names[] =
162 { "term", "error", "mp", "log", "ps", "mem", "tfm", "map", "pfb", "enc", NULL };
164 static const char *knot_type_enum[] =
165 { "endpoint", "explicit", "given", "curl", "open", "end_cycle" };
167 static const char *fill_fields[] =
168 { "type", "path", "htap", "pen", "color", "linejoin", "miterlimit",
169 "prescript", "postscript", NULL };
171 static const char *stroked_fields[] =
172 { "type", "path", "pen", "color", "linejoin", "miterlimit", "linecap",
173 "dash", "prescript", "postscript", NULL };
175 static const char *text_fields[] =
176 { "type", "text", "dsize", "font", "color", "width", "height", "depth",
177 "transform", "prescript", "postscript", NULL };
179 static const char *special_fields[] =
180 { "type", "prescript", NULL };
182 static const char *start_bounds_fields[] =
183 { "type", "path", NULL };
185 static const char *start_clip_fields[] =
186 { "type", "path", NULL };
188 static const char *stop_bounds_fields[] =
191 static const char *stop_clip_fields[] =
194 static const char *no_fields[] =
198 /* The list of supported MPlib options (not all make sense) */
201 P_ERROR_LINE, P_MAX_LINE,
202 P_MAIN_MEMORY, P_HASH_SIZE, P_PARAM_SIZE, P_IN_OPEN, P_RANDOM_SEED,
203 P_INTERACTION, P_INI_VERSION, P_MEM_NAME, P_JOB_NAME, P_FIND_FILE,
204 P__SENTINEL } mplib_parm_idx;
207 const char *name; /* parameter name */
208 mplib_parm_idx idx; /* parameter index */
211 static mplib_parm_struct mplib_parms[] = {
212 {"error_line", P_ERROR_LINE },
213 {"print_line", P_MAX_LINE },
214 {"main_memory", P_MAIN_MEMORY },
215 {"hash_size", P_HASH_SIZE },
216 {"param_size", P_PARAM_SIZE },
217 {"max_in_open", P_IN_OPEN },
218 {"random_seed", P_RANDOM_SEED },
219 {"interaction", P_INTERACTION },
220 {"ini_version", P_INI_VERSION },
221 {"mem_name", P_MEM_NAME },
222 {"job_name", P_JOB_NAME },
223 {"find_file", P_FIND_FILE },
228 /* Start by defining the needed callback routines for the library */
230 static char *mplib_find_file(MP mp, const char *fname, const char *fmode, int ftype)
232 lua_State *L = (lua_State *)mp_userdata(mp);
233 lua_checkstack(L, 4);
234 lua_getfield(L, LUA_REGISTRYINDEX, "mplib_file_finder");
235 if (lua_isfunction(L, -1)) {
236 char *s = NULL, *x = NULL;
237 lua_pushstring(L, fname);
238 lua_pushstring(L, fmode);
239 if (ftype >= mp_filetype_text) {
240 lua_pushnumber(L, (lua_Number)(ftype - mp_filetype_text));
242 lua_pushstring(L, mplib_filetype_names[ftype]);
244 if (lua_pcall(L, 3, 1, 0) != 0) {
245 fprintf(stdout, "Error in mp.find_file: %s\n",
246 (char *) lua_tostring(L, -1));
249 x = (char *) lua_tostring(L, -1);
252 lua_pop(L, 1); /* pop the string */
257 if (fmode[0] != 'r' || (!access(fname, R_OK)) || ftype) {
258 return strdup(fname);
263 static int mplib_find_file_function(lua_State * L)
265 if (!(lua_isfunction(L, -1) || lua_isnil(L, -1))) {
266 return 1; /* error */
268 lua_pushstring(L, "mplib_file_finder");
269 lua_pushvalue(L, -2);
270 lua_rawset(L, LUA_REGISTRYINDEX);
274 #define xfree(A) if ((A)!=NULL) { free((A)); A = NULL; }
276 static int mplib_new(lua_State * L)
279 mp_ptr = lua_newuserdata(L, sizeof(MP *));
282 struct MP_options *options = mp_options();
283 options->userdata = (void *) L;
284 options->noninteractive = 1; /* required ! */
285 options->find_file = mplib_find_file;
286 options->print_found_names = 1;
287 if (lua_type(L, 1) == LUA_TTABLE) {
288 for (i = 0; mplib_parms[i].name != NULL; i++) {
289 lua_getfield(L, 1, mplib_parms[i].name);
290 if (lua_isnil(L, -1)) {
292 continue; /* skip unset */
294 switch (mplib_parms[i].idx) {
296 options->error_line = (int)lua_tointeger(L, -1);
297 if (options->error_line<60) options->error_line =60;
298 if (options->error_line>250) options->error_line = 250;
299 options->half_error_line = (options->error_line/2)+10;
302 options->max_print_line = (int)lua_tointeger(L, -1);
303 if (options->max_print_line<60) options->max_print_line = 60;
306 options->main_memory = (int)lua_tointeger(L, -1);
309 options->hash_size = (unsigned)lua_tointeger(L, -1);
312 options->param_size = (int)lua_tointeger(L, -1);
315 options->max_in_open = (int)lua_tointeger(L, -1);
318 options->random_seed = (int)lua_tointeger(L, -1);
321 options->interaction =
322 luaL_checkoption(L, -1, "errorstopmode",
323 interaction_options);
326 options->ini_version = lua_toboolean(L, -1);
329 options->mem_name = strdup((char *) lua_tostring(L, -1));
332 options->job_name = strdup((char *) lua_tostring(L, -1));
335 if (mplib_find_file_function(L)) { /* error here */
337 "Invalid arguments to mp.new({find_file=...})\n");
346 *mp_ptr = mp_initialize(options);
347 xfree(options->command_line);
348 xfree(options->mem_name);
351 luaL_getmetatable(L, MPLIB_METATABLE);
352 lua_setmetatable(L, -2);
360 static int mplib_collect(lua_State * L)
362 MP *mp_ptr = is_mp(L, 1);
363 if (*mp_ptr != NULL) {
364 (void)mp_finish(*mp_ptr);
370 static int mplib_tostring(lua_State * L)
372 MP *mp_ptr = is_mp(L, 1);
373 if (*mp_ptr != NULL) {
374 (void)lua_pushfstring(L, "<MP %p>", *mp_ptr);
380 static int mplib_wrapresults(lua_State * L, mp_run_data *res, int status)
382 lua_checkstack(L, 5);
384 if (res->term_out.size != 0) {
385 lua_pushstring(L, res->term_out.data);
386 lua_setfield(L, -2, "term");
388 if (res->error_out.size != 0) {
389 lua_pushstring(L, res->error_out.data);
390 lua_setfield(L, -2, "error");
392 if (res->log_out.size != 0) {
393 lua_pushstring(L, res->log_out.data);
394 lua_setfield(L, -2, "log");
396 if (res->edges != NULL) {
397 struct mp_edge_object **v;
398 struct mp_edge_object *p = res->edges;
402 v = lua_newuserdata(L, sizeof(struct mp_edge_object *));
404 luaL_getmetatable(L, MPLIB_FIG_METATABLE);
405 lua_setmetatable(L, -2);
406 lua_rawseti(L, -2, i);
410 lua_setfield(L, -2, "fig");
413 lua_pushnumber(L, (lua_Number)status);
414 lua_setfield(L, -2, "status");
418 static int mplib_execute(lua_State * L)
420 MP *mp_ptr = is_mp(L, 1);
421 if (*mp_ptr != NULL && lua_isstring(L, 2)) {
423 char *s = (char *) lua_tolstring(L, 2, &l);
424 int h = mp_execute(*mp_ptr, s, l);
425 mp_run_data *res = mp_rundata(*mp_ptr);
426 return mplib_wrapresults(L, res, h);
433 static int mplib_finish(lua_State * L)
435 MP *mp_ptr = is_mp(L, 1);
436 if (*mp_ptr != NULL) {
438 int h = mp_execute(*mp_ptr,NULL,0);
439 mp_run_data *res = mp_rundata(*mp_ptr);
440 i = mplib_wrapresults(L, res, h);
441 (void)mp_finish(*mp_ptr);
450 static int mplib_char_dimension(lua_State * L, int t)
452 MP *mp_ptr = is_mp(L, 1);
453 if (*mp_ptr != NULL) {
454 char *fname = (char *)luaL_checkstring(L,2);
455 int charnum = (int)luaL_checkinteger(L,3);
456 if (charnum<0 || charnum>255) {
457 lua_pushnumber(L, (lua_Number)0);
459 lua_pushnumber(L,(lua_Number)mp_get_char_dimension(*mp_ptr,fname,charnum,t));
462 lua_pushnumber(L, (lua_Number)0);
467 static int mplib_charwidth(lua_State * L)
469 return mplib_char_dimension(L, 'w');
472 static int mplib_chardepth(lua_State * L)
474 return mplib_char_dimension(L, 'd');
477 static int mplib_charheight(lua_State * L)
479 return mplib_char_dimension(L, 'h');
482 static int mplib_version(lua_State * L)
484 char *s = mp_metapost_version();
485 lua_pushstring(L, s);
490 static int mplib_statistics(lua_State * L)
492 MP *mp_ptr = is_mp(L, 1);
493 if (*mp_ptr != NULL) {
495 lua_pushnumber(L, (lua_Number)mp_memory_usage(*mp_ptr));
496 lua_setfield(L, -2, "main_memory");
497 lua_pushnumber(L, (lua_Number)mp_hash_usage(*mp_ptr));
498 lua_setfield(L, -2, "hash_size");
499 lua_pushnumber(L, (lua_Number)mp_param_usage(*mp_ptr));
500 lua_setfield(L, -2, "param_size");
501 lua_pushnumber(L, (lua_Number)mp_open_usage(*mp_ptr));
502 lua_setfield(L, -2, "max_in_open");
512 static int mplib_fig_collect(lua_State * L)
514 struct mp_edge_object **hh = is_fig(L, 1);
516 mp_gr_toss_objects(*hh);
522 static int mplib_fig_body(lua_State * L)
525 struct mp_graphic_object **v;
526 struct mp_graphic_object *p;
527 struct mp_edge_object **hh = is_fig(L, 1);
531 v = lua_newuserdata(L, sizeof(struct mp_graphic_object *));
533 luaL_getmetatable(L, MPLIB_GR_METATABLE);
534 lua_setmetatable(L, -2);
535 lua_rawseti(L, -2, i);
539 (*hh)->body = NULL; /* prevent double free */
543 static int mplib_fig_copy_body(lua_State * L)
546 struct mp_graphic_object **v;
547 struct mp_graphic_object *p;
548 struct mp_edge_object **hh = is_fig(L, 1);
552 v = lua_newuserdata(L, sizeof(struct mp_graphic_object *));
553 *v = mp_gr_copy_object((*hh)->parent, p);
554 luaL_getmetatable(L, MPLIB_GR_METATABLE);
555 lua_setmetatable(L, -2);
556 lua_rawseti(L, -2, i);
564 static int mplib_fig_tostring(lua_State * L)
566 struct mp_edge_object **hh = is_fig(L, 1);
567 (void)lua_pushfstring(L, "<figure %p>", *hh);
571 static int mplib_fig_postscript(lua_State * L)
574 struct mp_edge_object **hh = is_fig(L, 1);
575 int prologues = (int)luaL_optnumber(L, 2, (lua_Number)-1);
576 int procset = (int)luaL_optnumber(L, 3, (lua_Number)-1);
577 if (mp_ps_ship_out(*hh, prologues, procset)
578 && (res = mp_rundata((*hh)->parent))
579 && (res->ps_out.size != 0)) {
580 lua_pushstring(L, res->ps_out.data);
587 static int mplib_fig_filename(lua_State * L)
589 struct mp_edge_object **hh = is_fig(L, 1);
591 char *s = (*hh)->filename;
592 lua_pushstring(L, s);
599 static int mplib_fig_width(lua_State * L)
601 struct mp_edge_object **hh = is_fig(L, 1);
603 lua_pushnumber(L, (double) (*hh)->width / 65536.0);
610 static int mplib_fig_height(lua_State * L)
612 struct mp_edge_object **hh = is_fig(L, 1);
614 lua_pushnumber(L, (double) (*hh)->height / 65536.0);
621 static int mplib_fig_depth(lua_State * L)
623 struct mp_edge_object **hh = is_fig(L, 1);
625 lua_pushnumber(L, (double) (*hh)->depth / 65536.0);
632 static int mplib_fig_italcorr(lua_State * L)
634 struct mp_edge_object **hh = is_fig(L, 1);
636 lua_pushnumber(L, (double) (*hh)->ital_corr / 65536.0);
643 static int mplib_fig_charcode(lua_State * L)
645 struct mp_edge_object **hh = is_fig(L, 1);
647 lua_pushnumber(L, (lua_Number)(*hh)->charcode);
656 static int mplib_fig_bb(lua_State * L)
658 struct mp_edge_object **hh = is_fig(L, 1);
660 lua_pushnumber(L, (double) (*hh)->minx / 65536.0);
661 lua_rawseti(L, -2, 1);
662 lua_pushnumber(L, (double) (*hh)->miny / 65536.0);
663 lua_rawseti(L, -2, 2);
664 lua_pushnumber(L, (double) (*hh)->maxx / 65536.0);
665 lua_rawseti(L, -2, 3);
666 lua_pushnumber(L, (double) (*hh)->maxy / 65536.0);
667 lua_rawseti(L, -2, 4);
673 static int mplib_gr_collect(lua_State * L)
675 struct mp_graphic_object **hh = is_gr_object(L, 1);
677 mp_gr_toss_object(*hh);
683 static int mplib_gr_tostring(lua_State * L)
685 struct mp_graphic_object **hh = is_gr_object(L, 1);
686 (void)lua_pushfstring(L, "<object %p>", *hh);
690 #define pyth(a,b) (sqrt((a)*(a) + (b)*(b)))
692 #define aspect_bound (10.0/65536.0)
693 #define aspect_default (1.0/65536.0)
695 static double eps = 0.0001;
697 static double coord_range_x (mp_knot *h, double dz) {
699 double zlo = 0.0, zhi = 0.0;
702 z = (double)h->x_coord;
703 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
704 z = (double)h->right_x;
705 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
706 z = (double)h->left_x;
707 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
712 return (zhi - zlo <= dz ? aspect_bound : aspect_default);
715 static double coord_range_y (mp_knot *h, double dz) {
717 double zlo = 0.0, zhi = 0.0;
720 z = (double)h->y_coord;
721 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
722 z = (double)h->right_y;
723 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
724 z = (double)h->left_y;
725 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
730 return (zhi - zlo <= dz ? aspect_bound : aspect_default);
734 static int mplib_gr_peninfo(lua_State * L) {
735 double x_coord, y_coord, left_x, left_y, right_x, right_y;
737 double rx = 1.0, sx = 0.0, sy = 0.0, ry = 1.0, tx = 0.0, ty = 0.0;
738 double divider = 1.0;
740 mp_knot *p = NULL, *path = NULL;
741 struct mp_graphic_object **hh = is_gr_object(L, -1);
746 if ((*hh)->type == mp_fill_code) {
747 p = ((mp_fill_object *)(*hh))->pen_p;
748 path = ((mp_fill_object *)(*hh))->path_p;
749 } else if ((*hh)->type == mp_stroked_code) {
750 p = ((mp_stroked_object *)(*hh))->pen_p;
751 path = ((mp_stroked_object *)(*hh))->path_p;
753 if (p==NULL || path == NULL) {
757 x_coord = p->x_coord/65536.0;
758 y_coord = p->y_coord/65536.0;
759 left_x = p->left_x/65536.0;
760 left_y = p->left_y/65536.0;
761 right_x = p->right_x/65536.0;
762 right_y = p->right_y/65536.0;
763 if ((right_x == x_coord) && (left_y == y_coord)) {
764 wx = fabs(left_x - x_coord);
765 wy = fabs(right_y - y_coord);
767 wx = pyth(left_x - x_coord, right_x - x_coord);
768 wy = pyth(left_y - y_coord, right_y - y_coord);
770 if ((wy/coord_range_x(path, wx)) >= (wx/coord_range_y(path, wy)))
784 rx/=width; ry/=width; sx/=width; sy/=width;
787 if (fabs(sx) < eps) sx = eps;
788 if (fabs(sy) < eps) sy = eps;
789 divider = sx*sy - rx*ry;
791 lua_pushnumber(L,width); lua_setfield(L,-2,"width");
792 lua_pushnumber(L,rx); lua_setfield(L,-2,"rx");
793 lua_pushnumber(L,sx); lua_setfield(L,-2,"sx");
794 lua_pushnumber(L,sy); lua_setfield(L,-2,"sy");
795 lua_pushnumber(L,ry); lua_setfield(L,-2,"ry");
796 lua_pushnumber(L,tx); lua_setfield(L,-2,"tx");
797 lua_pushnumber(L,ty); lua_setfield(L,-2,"ty");
802 static int mplib_gr_fields(lua_State * L)
806 struct mp_graphic_object **hh = is_gr_object(L, 1);
808 switch ((*hh)->type) {
810 fields = fill_fields;
812 case mp_stroked_code:
813 fields = stroked_fields;
816 fields = text_fields;
818 case mp_special_code:
819 fields = special_fields;
821 case mp_start_clip_code:
822 fields = start_clip_fields;
824 case mp_start_bounds_code:
825 fields = start_bounds_fields;
827 case mp_stop_clip_code:
828 fields = stop_clip_fields;
830 case mp_stop_bounds_code:
831 fields = stop_bounds_fields;
837 for (i = 0; fields[i] != NULL; i++) {
838 lua_pushstring(L, fields[i]);
839 lua_rawseti(L, -2, (i + 1));
848 #define mplib_push_number(L,x) lua_pushnumber(L,(lua_Number)(x)/65536.0)
853 static void mplib_push_path(lua_State * L, struct mp_knot *h, int is_pen)
855 struct mp_knot *p; /* for scanning the path */
861 lua_createtable(L, 0, 6);
863 if (p->left_type != mp_explicit) {
864 mplib_push_S(left_type);
865 lua_pushstring(L, knot_type_enum[p->left_type]);
868 if (p->right_type != mp_explicit) {
869 mplib_push_S(right_type);
870 lua_pushstring(L, knot_type_enum[p->right_type]);
874 mplib_push_S(x_coord);
875 mplib_push_number(L, p->x_coord);
877 mplib_push_S(y_coord);
878 mplib_push_number(L, p->y_coord);
880 mplib_push_S(left_x);
881 mplib_push_number(L, p->left_x);
883 mplib_push_S(left_y);
884 mplib_push_number(L, p->left_y);
886 mplib_push_S(right_x);
887 mplib_push_number(L, p->right_x);
889 mplib_push_S(right_y);
890 mplib_push_number(L, p->right_y);
892 lua_rawseti(L, -2, i);
894 if (p->right_type == mp_endpoint) {
904 /* this assumes that the top of the stack is a table
905 or nil already in the case
907 static void mplib_push_pentype(lua_State * L, struct mp_knot *h)
909 struct mp_knot *p; /* for scanning the path */
913 } else if (p == p->next) {
915 lua_pushstring(L, "elliptical");
921 #define set_color_objects(pq) \
922 object_color_model = pq->color_model; \
923 object_color_a = pq->color.a_val; \
924 object_color_b = pq->color.b_val; \
925 object_color_c = pq->color.c_val; \
926 object_color_d = pq->color.d_val;
929 static void mplib_push_color(lua_State * L, struct mp_graphic_object *p)
931 int object_color_model;
932 int object_color_a, object_color_b, object_color_c, object_color_d;
934 if (p->type == mp_fill_code) {
935 mp_fill_object *h = (mp_fill_object *) p;
936 set_color_objects(h);
937 } else if (p->type == mp_stroked_code) {
938 mp_stroked_object *h = (mp_stroked_object *) p;
939 set_color_objects(h);
941 mp_text_object *h = (mp_text_object *) p;
942 set_color_objects(h);
945 if (object_color_model >= mp_grey_model) {
946 mplib_push_number(L, object_color_a);
947 lua_rawseti(L, -2, 1);
948 if (object_color_model >= mp_rgb_model) {
949 mplib_push_number(L, object_color_b);
950 lua_rawseti(L, -2, 2);
951 mplib_push_number(L, object_color_c);
952 lua_rawseti(L, -2, 3);
953 if (object_color_model == mp_cmyk_model) {
954 mplib_push_number(L, object_color_d);
955 lua_rawseti(L, -2, 4);
964 /* the dash scale is not exported, the field has no external value */
965 static void mplib_push_dash(lua_State * L, struct mp_stroked_object *h)
969 if (h != NULL && h->dash_p != NULL) {
972 mplib_push_number(L, d->offset);
973 lua_setfield(L, -2, "offset");
974 if (d->array != NULL) {
977 while (*(d->array + i) != -1) {
978 ds = *(d->array + 1) / 65536.0;
979 lua_pushnumber(L, ds);
981 lua_rawseti(L, -2, i);
983 lua_setfield(L, -2, "dashes");
990 static void mplib_push_transform(lua_State * L, struct mp_text_object *h)
994 lua_createtable(L, 6, 0);
995 mplib_push_number(L, h->tx);
996 lua_rawseti(L, -2, i);
998 mplib_push_number(L, h->ty);
999 lua_rawseti(L, -2, i);
1001 mplib_push_number(L, h->txx);
1002 lua_rawseti(L, -2, i);
1004 mplib_push_number(L, h->tyx);
1005 lua_rawseti(L, -2, i);
1007 mplib_push_number(L, h->txy);
1008 lua_rawseti(L, -2, i);
1010 mplib_push_number(L, h->tyy);
1011 lua_rawseti(L, -2, i);
1018 #define FIELD(A) (mplib_is_S(A,2))
1020 static void mplib_fill(lua_State * L, struct mp_fill_object *h)
1023 mplib_push_path(L, h->path_p, MPLIB_PATH);
1024 } else if (FIELD(htap)) {
1025 mplib_push_path(L, h->htap_p, MPLIB_PATH);
1026 } else if (FIELD(pen)) {
1027 mplib_push_path(L, h->pen_p, MPLIB_PEN);
1028 mplib_push_pentype(L, h->pen_p);
1029 } else if (FIELD(color)) {
1030 mplib_push_color(L, (mp_graphic_object *) h);
1031 } else if (FIELD(linejoin)) {
1032 lua_pushnumber(L, (lua_Number)h->ljoin);
1033 } else if (FIELD(miterlimit)) {
1034 mplib_push_number(L, h->miterlim);
1035 } else if (FIELD(prescript)) {
1036 lua_pushstring(L, h->pre_script);
1037 } else if (FIELD(postscript)) {
1038 lua_pushstring(L, h->post_script);
1044 static void mplib_stroked(lua_State * L, struct mp_stroked_object *h)
1047 mplib_push_path(L, h->path_p, MPLIB_PATH);
1048 } else if (FIELD(pen)) {
1049 mplib_push_path(L, h->pen_p, MPLIB_PEN);
1050 mplib_push_pentype(L, h->pen_p);
1051 } else if (FIELD(color)) {
1052 mplib_push_color(L, (mp_graphic_object *) h);
1053 } else if (FIELD(dash)) {
1054 mplib_push_dash(L, h);
1055 } else if (FIELD(linecap)) {
1056 lua_pushnumber(L, (lua_Number)h->lcap);
1057 } else if (FIELD(linejoin)) {
1058 lua_pushnumber(L, (lua_Number)h->ljoin);
1059 } else if (FIELD(miterlimit)) {
1060 mplib_push_number(L, h->miterlim);
1061 } else if (FIELD(prescript)) {
1062 lua_pushstring(L, h->pre_script);
1063 } else if (FIELD(postscript)) {
1064 lua_pushstring(L, h->post_script);
1070 static void mplib_text(lua_State * L, struct mp_text_object *h)
1073 lua_pushstring(L, h->text_p);
1074 } else if (FIELD(dsize)) {
1075 mplib_push_number(L, (h->font_dsize / 16));
1076 } else if (FIELD(font)) {
1077 lua_pushstring(L, h->font_name);
1078 } else if (FIELD(color)) {
1079 mplib_push_color(L, (mp_graphic_object *) h);
1080 } else if (FIELD(width)) {
1081 mplib_push_number(L, h->width);
1082 } else if (FIELD(height)) {
1083 mplib_push_number(L, h->height);
1084 } else if (FIELD(depth)) {
1085 mplib_push_number(L, h->depth);
1086 } else if (FIELD(transform)) {
1087 mplib_push_transform(L, h);
1088 } else if (FIELD(prescript)) {
1089 lua_pushstring(L, h->pre_script);
1090 } else if (FIELD(postscript)) {
1091 lua_pushstring(L, h->post_script);
1097 static void mplib_special(lua_State * L, struct mp_special_object *h)
1099 if (FIELD(prescript)) {
1100 lua_pushstring(L, h->pre_script);
1106 static void mplib_start_bounds(lua_State * L, struct mp_bounds_object *h)
1109 mplib_push_path(L, h->path_p, MPLIB_PATH);
1115 static void mplib_start_clip(lua_State * L, struct mp_clip_object *h)
1118 mplib_push_path(L, h->path_p, MPLIB_PATH);
1124 static int mplib_gr_index(lua_State * L)
1126 struct mp_graphic_object **hh = is_gr_object(L, 1);
1128 struct mp_graphic_object *h = *hh;
1130 if (mplib_is_S(type, 2)) {
1131 lua_rawgeti(L, LUA_REGISTRYINDEX, mplib_type_Ses[h->type]);
1135 mplib_fill(L, (mp_fill_object *) h);
1137 case mp_stroked_code:
1138 mplib_stroked(L, (mp_stroked_object *) h);
1141 mplib_text(L, (mp_text_object *) h);
1143 case mp_special_code:
1144 mplib_special(L, (mp_special_object *) h);
1146 case mp_start_clip_code:
1147 mplib_start_clip(L, (mp_clip_object *) h);
1149 case mp_start_bounds_code:
1150 mplib_start_bounds(L, (mp_bounds_object *) h);
1152 case mp_stop_clip_code:
1153 case mp_stop_bounds_code:
1165 static const struct luaL_reg mplib_meta[] = {
1166 {"__gc", mplib_collect},
1167 {"__tostring", mplib_tostring},
1168 {NULL, NULL} /* sentinel */
1171 static const struct luaL_reg mplib_fig_meta[] = {
1172 {"__gc", mplib_fig_collect},
1173 {"__tostring", mplib_fig_tostring},
1174 {"objects", mplib_fig_body},
1175 {"copy_objects", mplib_fig_copy_body},
1176 {"filename", mplib_fig_filename},
1177 {"postscript", mplib_fig_postscript},
1178 {"boundingbox", mplib_fig_bb},
1179 {"width", mplib_fig_width},
1180 {"height", mplib_fig_height},
1181 {"depth", mplib_fig_depth},
1182 {"italcorr", mplib_fig_italcorr},
1183 {"charcode", mplib_fig_charcode},
1184 {NULL, NULL} /* sentinel */
1187 static const struct luaL_reg mplib_gr_meta[] = {
1188 {"__gc", mplib_gr_collect},
1189 {"__tostring", mplib_gr_tostring},
1190 {"__index", mplib_gr_index},
1191 {NULL, NULL} /* sentinel */
1194 static const struct luaL_reg mplib_d[] = {
1195 {"execute", mplib_execute},
1196 {"finish", mplib_finish},
1197 {"char_width", mplib_charwidth},
1198 {"char_height", mplib_charheight},
1199 {"char_depth", mplib_chardepth},
1200 {"statistics", mplib_statistics},
1201 {NULL, NULL} /* sentinel */
1205 static const struct luaL_reg mplib_m[] = {
1207 {"version", mplib_version},
1208 {"fields", mplib_gr_fields},
1209 {"pen_info", mplib_gr_peninfo},
1210 {NULL, NULL} /* sentinel */
1214 int luaopen_mplib(lua_State * L)
1218 luaL_newmetatable(L, MPLIB_GR_METATABLE);
1219 lua_pushvalue(L, -1); /* push metatable */
1220 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1221 luaL_register(L, NULL, mplib_gr_meta); /* object meta methods */
1224 luaL_newmetatable(L, MPLIB_FIG_METATABLE);
1225 lua_pushvalue(L, -1); /* push metatable */
1226 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1227 luaL_register(L, NULL, mplib_fig_meta); /* figure meta methods */
1230 luaL_newmetatable(L, MPLIB_METATABLE);
1231 lua_pushvalue(L, -1); /* push metatable */
1232 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1233 luaL_register(L, NULL, mplib_meta); /* meta methods */
1234 luaL_register(L, NULL, mplib_d); /* dict methods */
1235 luaL_register(L, "mplib", mplib_m); /* module functions */