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');
483 static int mplib_statistics(lua_State * L)
485 MP *mp_ptr = is_mp(L, 1);
486 if (*mp_ptr != NULL) {
488 lua_pushnumber(L, (lua_Number)mp_memory_usage(*mp_ptr));
489 lua_setfield(L, -2, "main_memory");
490 lua_pushnumber(L, (lua_Number)mp_hash_usage(*mp_ptr));
491 lua_setfield(L, -2, "hash_size");
492 lua_pushnumber(L, (lua_Number)mp_param_usage(*mp_ptr));
493 lua_setfield(L, -2, "param_size");
494 lua_pushnumber(L, (lua_Number)mp_open_usage(*mp_ptr));
495 lua_setfield(L, -2, "max_in_open");
505 static int mplib_fig_collect(lua_State * L)
507 struct mp_edge_object **hh = is_fig(L, 1);
509 mp_gr_toss_objects(*hh);
515 static int mplib_fig_body(lua_State * L)
518 struct mp_graphic_object **v;
519 struct mp_graphic_object *p;
520 struct mp_edge_object **hh = is_fig(L, 1);
524 v = lua_newuserdata(L, sizeof(struct mp_graphic_object *));
526 luaL_getmetatable(L, MPLIB_GR_METATABLE);
527 lua_setmetatable(L, -2);
528 lua_rawseti(L, -2, i);
532 (*hh)->body = NULL; /* prevent double free */
536 static int mplib_fig_copy_body(lua_State * L)
539 struct mp_graphic_object **v;
540 struct mp_graphic_object *p;
541 struct mp_edge_object **hh = is_fig(L, 1);
545 v = lua_newuserdata(L, sizeof(struct mp_graphic_object *));
546 *v = mp_gr_copy_object((*hh)->parent, p);
547 luaL_getmetatable(L, MPLIB_GR_METATABLE);
548 lua_setmetatable(L, -2);
549 lua_rawseti(L, -2, i);
557 static int mplib_fig_tostring(lua_State * L)
559 struct mp_edge_object **hh = is_fig(L, 1);
560 (void)lua_pushfstring(L, "<figure %p>", *hh);
564 static int mplib_fig_postscript(lua_State * L)
567 struct mp_edge_object **hh = is_fig(L, 1);
568 int prologues = (int)luaL_optnumber(L, 2, (lua_Number)-1);
569 int procset = (int)luaL_optnumber(L, 3, (lua_Number)-1);
570 if (mp_ps_ship_out(*hh, prologues, procset)
571 && (res = mp_rundata((*hh)->parent))
572 && (res->ps_out.size != 0)) {
573 lua_pushstring(L, res->ps_out.data);
580 static int mplib_fig_filename(lua_State * L)
582 struct mp_edge_object **hh = is_fig(L, 1);
584 char *s = (*hh)->filename;
585 lua_pushstring(L, s);
592 static int mplib_fig_width(lua_State * L)
594 struct mp_edge_object **hh = is_fig(L, 1);
596 lua_pushnumber(L, (double) (*hh)->width / 65536.0);
603 static int mplib_fig_height(lua_State * L)
605 struct mp_edge_object **hh = is_fig(L, 1);
607 lua_pushnumber(L, (double) (*hh)->height / 65536.0);
614 static int mplib_fig_depth(lua_State * L)
616 struct mp_edge_object **hh = is_fig(L, 1);
618 lua_pushnumber(L, (double) (*hh)->depth / 65536.0);
625 static int mplib_fig_italcorr(lua_State * L)
627 struct mp_edge_object **hh = is_fig(L, 1);
629 lua_pushnumber(L, (double) (*hh)->ital_corr / 65536.0);
636 static int mplib_fig_charcode(lua_State * L)
638 struct mp_edge_object **hh = is_fig(L, 1);
640 lua_pushnumber(L, (lua_Number)(*hh)->charcode);
649 static int mplib_fig_bb(lua_State * L)
651 struct mp_edge_object **hh = is_fig(L, 1);
653 lua_pushnumber(L, (double) (*hh)->minx / 65536.0);
654 lua_rawseti(L, -2, 1);
655 lua_pushnumber(L, (double) (*hh)->miny / 65536.0);
656 lua_rawseti(L, -2, 2);
657 lua_pushnumber(L, (double) (*hh)->maxx / 65536.0);
658 lua_rawseti(L, -2, 3);
659 lua_pushnumber(L, (double) (*hh)->maxy / 65536.0);
660 lua_rawseti(L, -2, 4);
666 static int mplib_gr_collect(lua_State * L)
668 struct mp_graphic_object **hh = is_gr_object(L, 1);
670 mp_gr_toss_object(*hh);
676 static int mplib_gr_tostring(lua_State * L)
678 struct mp_graphic_object **hh = is_gr_object(L, 1);
679 (void)lua_pushfstring(L, "<object %p>", *hh);
683 #define pyth(a,b) (sqrt((a)*(a) + (b)*(b)))
685 #define aspect_bound (10.0/65536.0)
686 #define aspect_default (1.0/65536.0)
688 static double eps = 0.0001;
690 static double coord_range_x (mp_knot *h, double dz) {
692 double zlo = 0.0, zhi = 0.0;
695 z = (double)h->x_coord;
696 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
697 z = (double)h->right_x;
698 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
699 z = (double)h->left_x;
700 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
705 return (zhi - zlo <= dz ? aspect_bound : aspect_default);
708 static double coord_range_y (mp_knot *h, double dz) {
710 double zlo = 0.0, zhi = 0.0;
713 z = (double)h->y_coord;
714 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
715 z = (double)h->right_y;
716 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
717 z = (double)h->left_y;
718 if (z < zlo) zlo = z; else if (z > zhi) zhi = z;
723 return (zhi - zlo <= dz ? aspect_bound : aspect_default);
727 static int mplib_gr_peninfo(lua_State * L) {
728 double x_coord, y_coord, left_x, left_y, right_x, right_y;
730 double rx = 1.0, sx = 0.0, sy = 0.0, ry = 1.0, tx = 0.0, ty = 0.0;
731 double divider = 1.0;
733 mp_knot *p = NULL, *path = NULL;
734 struct mp_graphic_object **hh = is_gr_object(L, -1);
739 if ((*hh)->type == mp_fill_code) {
740 p = ((mp_fill_object *)(*hh))->pen_p;
741 path = ((mp_fill_object *)(*hh))->path_p;
742 } else if ((*hh)->type == mp_stroked_code) {
743 p = ((mp_stroked_object *)(*hh))->pen_p;
744 path = ((mp_stroked_object *)(*hh))->path_p;
746 if (p==NULL || path == NULL) {
750 x_coord = p->x_coord/65536.0;
751 y_coord = p->y_coord/65536.0;
752 left_x = p->left_x/65536.0;
753 left_y = p->left_y/65536.0;
754 right_x = p->right_x/65536.0;
755 right_y = p->right_y/65536.0;
756 if ((right_x == x_coord) && (left_y == y_coord)) {
757 wx = fabs(left_x - x_coord);
758 wy = fabs(right_y - y_coord);
760 wx = pyth(left_x - x_coord, right_x - x_coord);
761 wy = pyth(left_y - y_coord, right_y - y_coord);
763 if ((wy/coord_range_x(path, wx)) >= (wx/coord_range_y(path, wy)))
777 rx/=width; ry/=width; sx/=width; sy/=width;
780 if (fabs(sx) < eps) sx = eps;
781 if (fabs(sy) < eps) sy = eps;
782 divider = sx*sy - rx*ry;
784 lua_pushnumber(L,width); lua_setfield(L,-2,"width");
785 lua_pushnumber(L,rx); lua_setfield(L,-2,"rx");
786 lua_pushnumber(L,sx); lua_setfield(L,-2,"sx");
787 lua_pushnumber(L,sy); lua_setfield(L,-2,"sy");
788 lua_pushnumber(L,ry); lua_setfield(L,-2,"ry");
789 lua_pushnumber(L,tx); lua_setfield(L,-2,"tx");
790 lua_pushnumber(L,ty); lua_setfield(L,-2,"ty");
795 static int mplib_gr_fields(lua_State * L)
799 struct mp_graphic_object **hh = is_gr_object(L, 1);
801 switch ((*hh)->type) {
803 fields = fill_fields;
805 case mp_stroked_code:
806 fields = stroked_fields;
809 fields = text_fields;
811 case mp_special_code:
812 fields = special_fields;
814 case mp_start_clip_code:
815 fields = start_clip_fields;
817 case mp_start_bounds_code:
818 fields = start_bounds_fields;
820 case mp_stop_clip_code:
821 fields = stop_clip_fields;
823 case mp_stop_bounds_code:
824 fields = stop_bounds_fields;
830 for (i = 0; fields[i] != NULL; i++) {
831 lua_pushstring(L, fields[i]);
832 lua_rawseti(L, -2, (i + 1));
841 #define mplib_push_number(L,x) lua_pushnumber(L,(lua_Number)(x)/65536.0)
846 static void mplib_push_path(lua_State * L, struct mp_knot *h, int is_pen)
848 struct mp_knot *p; /* for scanning the path */
854 lua_createtable(L, 0, 6);
856 if (p->left_type != mp_explicit) {
857 mplib_push_S(left_type);
858 lua_pushstring(L, knot_type_enum[p->left_type]);
861 if (p->right_type != mp_explicit) {
862 mplib_push_S(right_type);
863 lua_pushstring(L, knot_type_enum[p->right_type]);
867 mplib_push_S(x_coord);
868 mplib_push_number(L, p->x_coord);
870 mplib_push_S(y_coord);
871 mplib_push_number(L, p->y_coord);
873 mplib_push_S(left_x);
874 mplib_push_number(L, p->left_x);
876 mplib_push_S(left_y);
877 mplib_push_number(L, p->left_y);
879 mplib_push_S(right_x);
880 mplib_push_number(L, p->right_x);
882 mplib_push_S(right_y);
883 mplib_push_number(L, p->right_y);
885 lua_rawseti(L, -2, i);
887 if (p->right_type == mp_endpoint) {
897 /* this assumes that the top of the stack is a table
898 or nil already in the case
900 static void mplib_push_pentype(lua_State * L, struct mp_knot *h)
902 struct mp_knot *p; /* for scanning the path */
906 } else if (p == p->next) {
908 lua_pushstring(L, "elliptical");
914 #define set_color_objects(pq) \
915 object_color_model = pq->color_model; \
916 object_color_a = pq->color.a_val; \
917 object_color_b = pq->color.b_val; \
918 object_color_c = pq->color.c_val; \
919 object_color_d = pq->color.d_val;
922 static void mplib_push_color(lua_State * L, struct mp_graphic_object *p)
924 int object_color_model;
925 int object_color_a, object_color_b, object_color_c, object_color_d;
927 if (p->type == mp_fill_code) {
928 mp_fill_object *h = (mp_fill_object *) p;
929 set_color_objects(h);
930 } else if (p->type == mp_stroked_code) {
931 mp_stroked_object *h = (mp_stroked_object *) p;
932 set_color_objects(h);
934 mp_text_object *h = (mp_text_object *) p;
935 set_color_objects(h);
938 if (object_color_model >= mp_grey_model) {
939 mplib_push_number(L, object_color_a);
940 lua_rawseti(L, -2, 1);
941 if (object_color_model >= mp_rgb_model) {
942 mplib_push_number(L, object_color_b);
943 lua_rawseti(L, -2, 2);
944 mplib_push_number(L, object_color_c);
945 lua_rawseti(L, -2, 3);
946 if (object_color_model == mp_cmyk_model) {
947 mplib_push_number(L, object_color_d);
948 lua_rawseti(L, -2, 4);
957 /* the dash scale is not exported, the field has no external value */
958 static void mplib_push_dash(lua_State * L, struct mp_stroked_object *h)
962 if (h != NULL && h->dash_p != NULL) {
965 mplib_push_number(L, d->offset);
966 lua_setfield(L, -2, "offset");
967 if (d->array != NULL) {
970 while (*(d->array + i) != -1) {
971 ds = *(d->array + 1) / 65536.0;
972 lua_pushnumber(L, ds);
974 lua_rawseti(L, -2, i);
976 lua_setfield(L, -2, "dashes");
983 static void mplib_push_transform(lua_State * L, struct mp_text_object *h)
987 lua_createtable(L, 6, 0);
988 mplib_push_number(L, h->tx);
989 lua_rawseti(L, -2, i);
991 mplib_push_number(L, h->ty);
992 lua_rawseti(L, -2, i);
994 mplib_push_number(L, h->txx);
995 lua_rawseti(L, -2, i);
997 mplib_push_number(L, h->tyx);
998 lua_rawseti(L, -2, i);
1000 mplib_push_number(L, h->txy);
1001 lua_rawseti(L, -2, i);
1003 mplib_push_number(L, h->tyy);
1004 lua_rawseti(L, -2, i);
1011 #define FIELD(A) (mplib_is_S(A,2))
1013 static void mplib_fill(lua_State * L, struct mp_fill_object *h)
1016 mplib_push_path(L, h->path_p, MPLIB_PATH);
1017 } else if (FIELD(htap)) {
1018 mplib_push_path(L, h->htap_p, MPLIB_PATH);
1019 } else if (FIELD(pen)) {
1020 mplib_push_path(L, h->pen_p, MPLIB_PEN);
1021 mplib_push_pentype(L, h->pen_p);
1022 } else if (FIELD(color)) {
1023 mplib_push_color(L, (mp_graphic_object *) h);
1024 } else if (FIELD(linejoin)) {
1025 lua_pushnumber(L, (lua_Number)h->ljoin);
1026 } else if (FIELD(miterlimit)) {
1027 mplib_push_number(L, h->miterlim);
1028 } else if (FIELD(prescript)) {
1029 lua_pushstring(L, h->pre_script);
1030 } else if (FIELD(postscript)) {
1031 lua_pushstring(L, h->post_script);
1037 static void mplib_stroked(lua_State * L, struct mp_stroked_object *h)
1040 mplib_push_path(L, h->path_p, MPLIB_PATH);
1041 } else if (FIELD(pen)) {
1042 mplib_push_path(L, h->pen_p, MPLIB_PEN);
1043 mplib_push_pentype(L, h->pen_p);
1044 } else if (FIELD(color)) {
1045 mplib_push_color(L, (mp_graphic_object *) h);
1046 } else if (FIELD(dash)) {
1047 mplib_push_dash(L, h);
1048 } else if (FIELD(linecap)) {
1049 lua_pushnumber(L, (lua_Number)h->lcap);
1050 } else if (FIELD(linejoin)) {
1051 lua_pushnumber(L, (lua_Number)h->ljoin);
1052 } else if (FIELD(miterlimit)) {
1053 mplib_push_number(L, h->miterlim);
1054 } else if (FIELD(prescript)) {
1055 lua_pushstring(L, h->pre_script);
1056 } else if (FIELD(postscript)) {
1057 lua_pushstring(L, h->post_script);
1063 static void mplib_text(lua_State * L, struct mp_text_object *h)
1066 lua_pushstring(L, h->text_p);
1067 } else if (FIELD(dsize)) {
1068 mplib_push_number(L, (h->font_dsize / 16));
1069 } else if (FIELD(font)) {
1070 lua_pushstring(L, h->font_name);
1071 } else if (FIELD(color)) {
1072 mplib_push_color(L, (mp_graphic_object *) h);
1073 } else if (FIELD(width)) {
1074 mplib_push_number(L, h->width);
1075 } else if (FIELD(height)) {
1076 mplib_push_number(L, h->height);
1077 } else if (FIELD(depth)) {
1078 mplib_push_number(L, h->depth);
1079 } else if (FIELD(transform)) {
1080 mplib_push_transform(L, h);
1081 } else if (FIELD(prescript)) {
1082 lua_pushstring(L, h->pre_script);
1083 } else if (FIELD(postscript)) {
1084 lua_pushstring(L, h->post_script);
1090 static void mplib_special(lua_State * L, struct mp_special_object *h)
1092 if (FIELD(prescript)) {
1093 lua_pushstring(L, h->pre_script);
1099 static void mplib_start_bounds(lua_State * L, struct mp_bounds_object *h)
1102 mplib_push_path(L, h->path_p, MPLIB_PATH);
1108 static void mplib_start_clip(lua_State * L, struct mp_clip_object *h)
1111 mplib_push_path(L, h->path_p, MPLIB_PATH);
1117 static int mplib_gr_index(lua_State * L)
1119 struct mp_graphic_object **hh = is_gr_object(L, 1);
1121 struct mp_graphic_object *h = *hh;
1123 if (mplib_is_S(type, 2)) {
1124 lua_rawgeti(L, LUA_REGISTRYINDEX, mplib_type_Ses[h->type]);
1128 mplib_fill(L, (mp_fill_object *) h);
1130 case mp_stroked_code:
1131 mplib_stroked(L, (mp_stroked_object *) h);
1134 mplib_text(L, (mp_text_object *) h);
1136 case mp_special_code:
1137 mplib_special(L, (mp_special_object *) h);
1139 case mp_start_clip_code:
1140 mplib_start_clip(L, (mp_clip_object *) h);
1142 case mp_start_bounds_code:
1143 mplib_start_bounds(L, (mp_bounds_object *) h);
1145 case mp_stop_clip_code:
1146 case mp_stop_bounds_code:
1158 static const struct luaL_reg mplib_meta[] = {
1159 {"__gc", mplib_collect},
1160 {"__tostring", mplib_tostring},
1161 {NULL, NULL} /* sentinel */
1164 static const struct luaL_reg mplib_fig_meta[] = {
1165 {"__gc", mplib_fig_collect},
1166 {"__tostring", mplib_fig_tostring},
1167 {"objects", mplib_fig_body},
1168 {"copy_objects", mplib_fig_copy_body},
1169 {"filename", mplib_fig_filename},
1170 {"postscript", mplib_fig_postscript},
1171 {"boundingbox", mplib_fig_bb},
1172 {"width", mplib_fig_width},
1173 {"height", mplib_fig_height},
1174 {"depth", mplib_fig_depth},
1175 {"italcorr", mplib_fig_italcorr},
1176 {"charcode", mplib_fig_charcode},
1177 {NULL, NULL} /* sentinel */
1180 static const struct luaL_reg mplib_gr_meta[] = {
1181 {"__gc", mplib_gr_collect},
1182 {"__tostring", mplib_gr_tostring},
1183 {"__index", mplib_gr_index},
1184 {NULL, NULL} /* sentinel */
1187 static const struct luaL_reg mplib_d[] = {
1188 {"execute", mplib_execute},
1189 {"finish", mplib_finish},
1190 {"char_width", mplib_charwidth},
1191 {"char_height", mplib_charheight},
1192 {"char_depth", mplib_chardepth},
1193 {"statistics", mplib_statistics},
1194 {NULL, NULL} /* sentinel */
1198 static const struct luaL_reg mplib_m[] = {
1200 {"fields", mplib_gr_fields},
1201 {"pen_info", mplib_gr_peninfo},
1202 {NULL, NULL} /* sentinel */
1206 int luaopen_mplib(lua_State * L)
1210 luaL_newmetatable(L, MPLIB_GR_METATABLE);
1211 lua_pushvalue(L, -1); /* push metatable */
1212 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1213 luaL_register(L, NULL, mplib_gr_meta); /* object meta methods */
1216 luaL_newmetatable(L, MPLIB_FIG_METATABLE);
1217 lua_pushvalue(L, -1); /* push metatable */
1218 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1219 luaL_register(L, NULL, mplib_fig_meta); /* figure meta methods */
1222 luaL_newmetatable(L, MPLIB_METATABLE);
1223 lua_pushvalue(L, -1); /* push metatable */
1224 lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
1225 luaL_register(L, NULL, mplib_meta); /* meta methods */
1226 luaL_register(L, NULL, mplib_d); /* dict methods */
1227 luaL_register(L, "mplib", mplib_m); /* module functions */