1 #include "mupdf/fitz.h"
2 
3 #if FZ_ENABLE_PDF
4 #include "mupdf/pdf.h"
5 #include "mupdf/helpers/pkcs7-openssl.h"
6 #endif
7 
8 #if FZ_ENABLE_JS
9 
10 #include "mujs.h"
11 
12 #include <string.h>
13 #include <stdlib.h>
14 #include <stdio.h>
15 
16 #define PS1 "> "
17 
rethrow(js_State * J)18 FZ_NORETURN static void rethrow(js_State *J)
19 {
20 	js_newerror(J, fz_caught_message(js_getcontext(J)));
21 	js_throw(J);
22 }
23 
rethrow_as_fz(js_State * J)24 FZ_NORETURN static void rethrow_as_fz(js_State *J)
25 {
26 	fz_throw(js_getcontext(J), FZ_ERROR_GENERIC, "%s", js_tostring(J, -1));
27 }
28 
alloc(void * actx,void * ptr,int n)29 static void *alloc(void *actx, void *ptr, int n)
30 {
31 	return fz_realloc_no_throw(actx, ptr, n);
32 }
33 
eval_print(js_State * J,const char * source)34 static int eval_print(js_State *J, const char *source)
35 {
36 	if (js_ploadstring(J, "[string]", source)) {
37 		fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
38 		js_pop(J, 1);
39 		return 1;
40 	}
41 	js_pushundefined(J);
42 	if (js_pcall(J, 0)) {
43 		fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
44 		js_pop(J, 1);
45 		return 1;
46 	}
47 	if (js_isdefined(J, -1)) {
48 		printf("%s\n", js_tryrepr(J, -1, "can't convert to string"));
49 	}
50 	js_pop(J, 1);
51 	return 0;
52 }
53 
jsB_propfun(js_State * J,const char * name,js_CFunction cfun,int n)54 static void jsB_propfun(js_State *J, const char *name, js_CFunction cfun, int n)
55 {
56 	const char *realname = strchr(name, '.');
57 	realname = realname ? realname + 1 : name;
58 	js_newcfunction(J, cfun, name, n);
59 	js_defproperty(J, -2, realname, JS_DONTENUM);
60 }
61 
jsB_propcon(js_State * J,const char * tag,const char * name,js_CFunction cfun,int n)62 static void jsB_propcon(js_State *J, const char *tag, const char *name, js_CFunction cfun, int n)
63 {
64 	const char *realname = strchr(name, '.');
65 	realname = realname ? realname + 1 : name;
66 	js_getregistry(J, tag);
67 	js_newcconstructor(J, cfun, cfun, name, n);
68 	js_defproperty(J, -2, realname, JS_DONTENUM);
69 }
70 
jsB_gc(js_State * J)71 static void jsB_gc(js_State *J)
72 {
73 	int report = js_toboolean(J, 1);
74 	js_gc(J, report);
75 	js_pushundefined(J);
76 }
77 
jsB_load(js_State * J)78 static void jsB_load(js_State *J)
79 {
80 	const char *filename = js_tostring(J, 1);
81 	int rv = js_dofile(J, filename);
82 	js_pushboolean(J, !rv);
83 }
84 
jsB_print(js_State * J)85 static void jsB_print(js_State *J)
86 {
87 	unsigned int i, top = js_gettop(J);
88 	for (i = 1; i < top; ++i) {
89 		const char *s = js_tostring(J, i);
90 		if (i > 1) putchar(' ');
91 		fputs(s, stdout);
92 	}
93 	putchar('\n');
94 	js_pushundefined(J);
95 }
96 
jsB_write(js_State * J)97 static void jsB_write(js_State *J)
98 {
99 	unsigned int i, top = js_gettop(J);
100 	for (i = 1; i < top; ++i) {
101 		const char *s = js_tostring(J, i);
102 		if (i > 1) putchar(' ');
103 		fputs(s, stdout);
104 	}
105 	js_pushundefined(J);
106 }
107 
jsB_read(js_State * J)108 static void jsB_read(js_State *J)
109 {
110 	fz_context *ctx = js_getcontext(J);
111 	const char *filename = js_tostring(J, 1);
112 	FILE *f;
113 	char *s;
114 	long n;
115 	size_t t;
116 
117 	f = fopen(filename, "rb");
118 	if (!f) {
119 		js_error(J, "cannot open file: '%s'", filename);
120 	}
121 
122 	if (fseek(f, 0, SEEK_END) < 0) {
123 		fclose(f);
124 		js_error(J, "cannot seek in file: '%s'", filename);
125 	}
126 
127 	n = ftell(f);
128 	if (n < 0) {
129 		fclose(f);
130 		js_error(J, "cannot tell in file: '%s'", filename);
131 	}
132 
133 	if (fseek(f, 0, SEEK_SET) < 0) {
134 		fclose(f);
135 		js_error(J, "cannot seek in file: '%s'", filename);
136 	}
137 
138 	s = fz_malloc(ctx, n + 1);
139 	if (!s) {
140 		fclose(f);
141 		js_error(J, "cannot allocate storage for file contents: '%s'", filename);
142 	}
143 
144 	t = fread(s, 1, n, f);
145 	if (t != (size_t) n) {
146 		fz_free(ctx, s);
147 		fclose(f);
148 		js_error(J, "cannot read data from file: '%s'", filename);
149 	}
150 	s[n] = 0;
151 
152 	js_pushstring(J, s);
153 	fz_free(ctx, s);
154 	fclose(f);
155 }
156 
jsB_readline(js_State * J)157 static void jsB_readline(js_State *J)
158 {
159 	char line[256];
160 	size_t n;
161 	if (!fgets(line, sizeof line, stdin))
162 		js_error(J, "cannot read line from stdin");
163 	n = strlen(line);
164 	if (n > 0 && line[n-1] == '\n')
165 		line[n-1] = 0;
166 	js_pushstring(J, line);
167 }
168 
jsB_repr(js_State * J)169 static void jsB_repr(js_State *J)
170 {
171 	js_repr(J, 1);
172 }
173 
jsB_quit(js_State * J)174 static void jsB_quit(js_State *J)
175 {
176 	exit(js_tonumber(J, 1));
177 }
178 
179 static const char *require_js =
180 	"function require(name) {\n"
181 	"var cache = require.cache;\n"
182 	"if (name in cache) return cache[name];\n"
183 	"var exports = {};\n"
184 	"cache[name] = exports;\n"
185 	"Function('exports', read(name+'.js'))(exports);\n"
186 	"return exports;\n"
187 	"}\n"
188 	"require.cache = Object.create(null);\n"
189 ;
190 
191 static const char *stacktrace_js =
192 	"Error.prototype.toString = function() {\n"
193 	"if (this.stackTrace) return this.name + ': ' + this.message + this.stackTrace;\n"
194 	"return this.name + ': ' + this.message;\n"
195 	"};\n"
196 ;
197 
198 /* destructors */
199 
ffi_gc_fz_buffer(js_State * J,void * buf)200 static void ffi_gc_fz_buffer(js_State *J, void *buf)
201 {
202 	fz_context *ctx = js_getcontext(J);
203 	fz_try(ctx)
204 		fz_drop_buffer(ctx, buf);
205 	fz_catch(ctx)
206 		rethrow(J);
207 }
208 
ffi_gc_fz_document(js_State * J,void * doc)209 static void ffi_gc_fz_document(js_State *J, void *doc)
210 {
211 	fz_context *ctx = js_getcontext(J);
212 	fz_drop_document(ctx, doc);
213 }
214 
ffi_gc_pdf_pkcs7_signer(js_State * J,void * signer_)215 static void ffi_gc_pdf_pkcs7_signer(js_State *J, void *signer_)
216 {
217 	fz_context *ctx = js_getcontext(J);
218 	pdf_pkcs7_signer *signer = (pdf_pkcs7_signer *)signer_;
219 	if (signer)
220 		signer->drop(ctx, signer);
221 }
222 
ffi_gc_fz_page(js_State * J,void * page)223 static void ffi_gc_fz_page(js_State *J, void *page)
224 {
225 	fz_context *ctx = js_getcontext(J);
226 	fz_drop_page(ctx, page);
227 }
228 
ffi_gc_fz_colorspace(js_State * J,void * colorspace)229 static void ffi_gc_fz_colorspace(js_State *J, void *colorspace)
230 {
231 	fz_context *ctx = js_getcontext(J);
232 	fz_drop_colorspace(ctx, colorspace);
233 }
234 
ffi_gc_fz_pixmap(js_State * J,void * pixmap)235 static void ffi_gc_fz_pixmap(js_State *J, void *pixmap)
236 {
237 	fz_context *ctx = js_getcontext(J);
238 	fz_drop_pixmap(ctx, pixmap);
239 }
240 
ffi_gc_fz_path(js_State * J,void * path)241 static void ffi_gc_fz_path(js_State *J, void *path)
242 {
243 	fz_context *ctx = js_getcontext(J);
244 	fz_drop_path(ctx, path);
245 }
246 
ffi_gc_fz_text(js_State * J,void * text)247 static void ffi_gc_fz_text(js_State *J, void *text)
248 {
249 	fz_context *ctx = js_getcontext(J);
250 	fz_drop_text(ctx, text);
251 }
252 
ffi_gc_fz_font(js_State * J,void * font)253 static void ffi_gc_fz_font(js_State *J, void *font)
254 {
255 	fz_context *ctx = js_getcontext(J);
256 	fz_drop_font(ctx, font);
257 }
258 
ffi_gc_fz_shade(js_State * J,void * shade)259 static void ffi_gc_fz_shade(js_State *J, void *shade)
260 {
261 	fz_context *ctx = js_getcontext(J);
262 	fz_drop_shade(ctx, shade);
263 }
264 
ffi_gc_fz_image(js_State * J,void * image)265 static void ffi_gc_fz_image(js_State *J, void *image)
266 {
267 	fz_context *ctx = js_getcontext(J);
268 	fz_drop_image(ctx, image);
269 }
270 
ffi_gc_fz_display_list(js_State * J,void * list)271 static void ffi_gc_fz_display_list(js_State *J, void *list)
272 {
273 	fz_context *ctx = js_getcontext(J);
274 	fz_drop_display_list(ctx, list);
275 }
276 
ffi_gc_fz_stext_page(js_State * J,void * text)277 static void ffi_gc_fz_stext_page(js_State *J, void *text)
278 {
279 	fz_context *ctx = js_getcontext(J);
280 	fz_drop_stext_page(ctx, text);
281 }
282 
ffi_gc_fz_device(js_State * J,void * device)283 static void ffi_gc_fz_device(js_State *J, void *device)
284 {
285 	fz_context *ctx = js_getcontext(J);
286 	fz_drop_device(ctx, device);
287 }
288 
ffi_gc_fz_document_writer(js_State * J,void * wri)289 static void ffi_gc_fz_document_writer(js_State *J, void *wri)
290 {
291 	fz_context *ctx = js_getcontext(J);
292 	fz_drop_document_writer(ctx, wri);
293 }
294 
295 #if FZ_ENABLE_PDF
296 
297 static void ffi_pushobj(js_State *J, pdf_obj *obj);
298 
ffi_gc_pdf_widget(js_State * J,void * widget)299 static void ffi_gc_pdf_widget(js_State *J, void *widget)
300 {
301 	fz_context *ctx = js_getcontext(J);
302 	pdf_drop_widget(ctx, widget);
303 }
304 
ffi_gc_pdf_annot(js_State * J,void * annot)305 static void ffi_gc_pdf_annot(js_State *J, void *annot)
306 {
307 	fz_context *ctx = js_getcontext(J);
308 	pdf_drop_annot(ctx, annot);
309 }
310 
ffi_gc_pdf_document(js_State * J,void * doc)311 static void ffi_gc_pdf_document(js_State *J, void *doc)
312 {
313 	fz_context *ctx = js_getcontext(J);
314 	pdf_drop_document(ctx, doc);
315 }
316 
ffi_gc_pdf_obj(js_State * J,void * obj)317 static void ffi_gc_pdf_obj(js_State *J, void *obj)
318 {
319 	fz_context *ctx = js_getcontext(J);
320 	pdf_drop_obj(ctx, obj);
321 }
322 
ffi_gc_pdf_graft_map(js_State * J,void * map)323 static void ffi_gc_pdf_graft_map(js_State *J, void *map)
324 {
325 	fz_context *ctx = js_getcontext(J);
326 	pdf_drop_graft_map(ctx, map);
327 }
328 
ffi_todocument(js_State * J,int idx)329 static fz_document *ffi_todocument(js_State *J, int idx)
330 {
331 	if (js_isuserdata(J, idx, "pdf_document"))
332 		return js_touserdata(J, idx, "pdf_document");
333 	return js_touserdata(J, idx, "fz_document");
334 }
335 
ffi_pushdocument(js_State * J,fz_document * document)336 static void ffi_pushdocument(js_State *J, fz_document *document)
337 {
338 	fz_context *ctx = js_getcontext(J);
339 	pdf_document *pdocument = pdf_document_from_fz_document(ctx, document);
340 	if (pdocument) {
341 		js_getregistry(J, "pdf_document");
342 		js_newuserdata(J, "pdf_document", document, ffi_gc_fz_document);
343 	} else {
344 		js_getregistry(J, "fz_document");
345 		js_newuserdata(J, "fz_document", document, ffi_gc_fz_document);
346 	}
347 }
348 
ffi_pushsigner(js_State * J,pdf_pkcs7_signer * signer)349 static void ffi_pushsigner(js_State *J, pdf_pkcs7_signer *signer)
350 {
351 	js_getregistry(J, "pdf_pkcs7_signer");
352 	js_newuserdata(J, "pdf_pkcs7_signer", signer, ffi_gc_pdf_pkcs7_signer);
353 }
354 
ffi_topage(js_State * J,int idx)355 static fz_page *ffi_topage(js_State *J, int idx)
356 {
357 	if (js_isuserdata(J, idx, "pdf_page"))
358 		return js_touserdata(J, idx, "pdf_page");
359 	return js_touserdata(J, idx, "fz_page");
360 }
361 
ffi_pushpage(js_State * J,fz_page * page)362 static void ffi_pushpage(js_State *J, fz_page *page)
363 {
364 	fz_context *ctx = js_getcontext(J);
365 	pdf_page *ppage = pdf_page_from_fz_page(ctx, page);
366 	if (ppage) {
367 		js_getregistry(J, "pdf_page");
368 		js_newuserdata(J, "pdf_page", page, ffi_gc_fz_page);
369 	} else {
370 		js_getregistry(J, "fz_page");
371 		js_newuserdata(J, "fz_page", page, ffi_gc_fz_page);
372 	}
373 }
374 
375 #else
376 
ffi_todocument(js_State * J,int idx)377 static fz_document *ffi_todocument(js_State *J, int idx)
378 {
379 	return js_touserdata(J, idx, "fz_document");
380 }
381 
ffi_pushdocument(js_State * J,fz_document * document)382 static void ffi_pushdocument(js_State *J, fz_document *document)
383 {
384 	js_getregistry(J, "fz_document");
385 	js_newuserdata(J, "fz_document", doc, ffi_gc_fz_document);
386 }
387 
ffi_topage(js_State * J,int idx)388 static fz_page *ffi_topage(js_State *J, int idx)
389 {
390 	return js_touserdata(J, idx, "fz_page");
391 }
392 
ffi_pushpage(js_State * J,fz_page * page)393 static void ffi_pushpage(js_State *J, fz_page *page)
394 {
395 	js_getregistry(J, "fz_page");
396 	js_newuserdata(J, "fz_page", page, ffi_gc_fz_page);
397 }
398 
399 #endif /* FZ_ENABLE_PDF */
400 
401 /* type conversions */
402 
403 struct color {
404 	fz_colorspace *colorspace;
405 	float color[FZ_MAX_COLORS];
406 	float alpha;
407 };
408 
ffi_tomatrix(js_State * J,int idx)409 static fz_matrix ffi_tomatrix(js_State *J, int idx)
410 {
411 	if (js_iscoercible(J, idx))
412 	{
413 		fz_matrix matrix;
414 		js_getindex(J, idx, 0); matrix.a = js_tonumber(J, -1); js_pop(J, 1);
415 		js_getindex(J, idx, 1); matrix.b = js_tonumber(J, -1); js_pop(J, 1);
416 		js_getindex(J, idx, 2); matrix.c = js_tonumber(J, -1); js_pop(J, 1);
417 		js_getindex(J, idx, 3); matrix.d = js_tonumber(J, -1); js_pop(J, 1);
418 		js_getindex(J, idx, 4); matrix.e = js_tonumber(J, -1); js_pop(J, 1);
419 		js_getindex(J, idx, 5); matrix.f = js_tonumber(J, -1); js_pop(J, 1);
420 		return matrix;
421 	}
422 	return fz_identity;
423 }
424 
ffi_pushmatrix(js_State * J,fz_matrix matrix)425 static void ffi_pushmatrix(js_State *J, fz_matrix matrix)
426 {
427 	js_newarray(J);
428 	js_pushnumber(J, matrix.a); js_setindex(J, -2, 0);
429 	js_pushnumber(J, matrix.b); js_setindex(J, -2, 1);
430 	js_pushnumber(J, matrix.c); js_setindex(J, -2, 2);
431 	js_pushnumber(J, matrix.d); js_setindex(J, -2, 3);
432 	js_pushnumber(J, matrix.e); js_setindex(J, -2, 4);
433 	js_pushnumber(J, matrix.f); js_setindex(J, -2, 5);
434 }
435 
ffi_topoint(js_State * J,int idx)436 static fz_point ffi_topoint(js_State *J, int idx)
437 {
438 	fz_point point;
439 	js_getindex(J, idx, 0); point.x = js_tonumber(J, -1); js_pop(J, 1);
440 	js_getindex(J, idx, 1); point.y = js_tonumber(J, -1); js_pop(J, 1);
441 	return point;
442 }
443 
ffi_pushpoint(js_State * J,fz_point point)444 static void ffi_pushpoint(js_State *J, fz_point point)
445 {
446 	js_newarray(J);
447 	js_pushnumber(J, point.x); js_setindex(J, -2, 0);
448 	js_pushnumber(J, point.y); js_setindex(J, -2, 1);
449 }
450 
ffi_torect(js_State * J,int idx)451 static fz_rect ffi_torect(js_State *J, int idx)
452 {
453 	fz_rect rect;
454 	js_getindex(J, idx, 0); rect.x0 = js_tonumber(J, -1); js_pop(J, 1);
455 	js_getindex(J, idx, 1); rect.y0 = js_tonumber(J, -1); js_pop(J, 1);
456 	js_getindex(J, idx, 2); rect.x1 = js_tonumber(J, -1); js_pop(J, 1);
457 	js_getindex(J, idx, 3); rect.y1 = js_tonumber(J, -1); js_pop(J, 1);
458 	return rect;
459 }
460 
ffi_pushrect(js_State * J,fz_rect rect)461 static void ffi_pushrect(js_State *J, fz_rect rect)
462 {
463 	js_newarray(J);
464 	js_pushnumber(J, rect.x0); js_setindex(J, -2, 0);
465 	js_pushnumber(J, rect.y0); js_setindex(J, -2, 1);
466 	js_pushnumber(J, rect.x1); js_setindex(J, -2, 2);
467 	js_pushnumber(J, rect.y1); js_setindex(J, -2, 3);
468 }
469 
ffi_toquad(js_State * J,int idx)470 static fz_quad ffi_toquad(js_State *J, int idx)
471 {
472 	fz_quad quad;
473 	js_getindex(J, idx, 0); quad.ul.x = js_tonumber(J, -1); js_pop(J, 1);
474 	js_getindex(J, idx, 1); quad.ul.y = js_tonumber(J, -1); js_pop(J, 1);
475 	js_getindex(J, idx, 2); quad.ur.x = js_tonumber(J, -1); js_pop(J, 1);
476 	js_getindex(J, idx, 3); quad.ur.y = js_tonumber(J, -1); js_pop(J, 1);
477 	js_getindex(J, idx, 4); quad.ll.x = js_tonumber(J, -1); js_pop(J, 1);
478 	js_getindex(J, idx, 5); quad.ll.y = js_tonumber(J, -1); js_pop(J, 1);
479 	js_getindex(J, idx, 6); quad.lr.x = js_tonumber(J, -1); js_pop(J, 1);
480 	js_getindex(J, idx, 7); quad.lr.y = js_tonumber(J, -1); js_pop(J, 1);
481 	return quad;
482 }
483 
ffi_pushquad(js_State * J,fz_quad quad)484 static void ffi_pushquad(js_State *J, fz_quad quad)
485 {
486 	js_newarray(J);
487 	js_pushnumber(J, quad.ul.x); js_setindex(J, -2, 0);
488 	js_pushnumber(J, quad.ul.y); js_setindex(J, -2, 1);
489 	js_pushnumber(J, quad.ur.x); js_setindex(J, -2, 2);
490 	js_pushnumber(J, quad.ur.y); js_setindex(J, -2, 3);
491 	js_pushnumber(J, quad.ll.x); js_setindex(J, -2, 4);
492 	js_pushnumber(J, quad.ll.y); js_setindex(J, -2, 5);
493 	js_pushnumber(J, quad.lr.x); js_setindex(J, -2, 6);
494 	js_pushnumber(J, quad.lr.y); js_setindex(J, -2, 7);
495 }
496 
ffi_toirect(js_State * J,int idx)497 static fz_irect ffi_toirect(js_State *J, int idx)
498 {
499 	fz_irect irect;
500 	js_getindex(J, idx, 0); irect.x0 = js_tonumber(J, -1); js_pop(J, 1);
501 	js_getindex(J, idx, 1); irect.y0 = js_tonumber(J, -1); js_pop(J, 1);
502 	js_getindex(J, idx, 2); irect.x1 = js_tonumber(J, -1); js_pop(J, 1);
503 	js_getindex(J, idx, 3); irect.y1 = js_tonumber(J, -1); js_pop(J, 1);
504 	return irect;
505 }
506 
ffi_pusharray(js_State * J,const float * v,int n)507 static void ffi_pusharray(js_State *J, const float *v, int n)
508 {
509 	int i;
510 	js_newarray(J);
511 	for (i = 0; i < n; ++i) {
512 		js_pushnumber(J, v[i]);
513 		js_setindex(J, -2, i);
514 	}
515 }
516 
ffi_pushcolorspace(js_State * J,fz_colorspace * colorspace)517 static void ffi_pushcolorspace(js_State *J, fz_colorspace *colorspace)
518 {
519 	fz_context *ctx = js_getcontext(J);
520 	if (colorspace == fz_device_rgb(ctx))
521 		js_getregistry(J, "DeviceRGB");
522 	else if (colorspace == fz_device_bgr(ctx))
523 		js_getregistry(J, "DeviceBGR");
524 	else if (colorspace == fz_device_gray(ctx))
525 		js_getregistry(J, "DeviceGray");
526 	else if (colorspace == fz_device_cmyk(ctx))
527 		js_getregistry(J, "DeviceCMYK");
528 	else {
529 		js_getregistry(J, "fz_colorspace");
530 		js_newuserdata(J, "fz_colorspace", fz_keep_colorspace(ctx, colorspace), ffi_gc_fz_colorspace);
531 	}
532 }
533 
ffi_pushcolor(js_State * J,fz_colorspace * colorspace,const float * color,float alpha)534 static void ffi_pushcolor(js_State *J, fz_colorspace *colorspace, const float *color, float alpha)
535 {
536 	fz_context *ctx = js_getcontext(J);
537 	if (colorspace) {
538 		ffi_pushcolorspace(J, colorspace);
539 		ffi_pusharray(J, color, fz_colorspace_n(ctx, colorspace));
540 	} else {
541 		js_pushnull(J);
542 		js_pushnull(J);
543 	}
544 	js_pushnumber(J, alpha);
545 }
546 
ffi_tocolor(js_State * J,int idx)547 static struct color ffi_tocolor(js_State *J, int idx)
548 {
549 	struct color c;
550 	int n, i;
551 	fz_context *ctx = js_getcontext(J);
552 	c.colorspace = js_touserdata(J, idx, "fz_colorspace");
553 	if (c.colorspace) {
554 		n = fz_colorspace_n(ctx, c.colorspace);
555 		for (i=0; i < n; ++i) {
556 			js_getindex(J, idx + 1, i);
557 			c.color[i] = js_tonumber(J, -1);
558 			js_pop(J, 1);
559 		}
560 	}
561 	c.alpha = js_tonumber(J, idx + 2);
562 	return c;
563 }
564 
ffi_tocolorparams(js_State * J,int idx)565 static fz_color_params ffi_tocolorparams(js_State *J, int idx)
566 {
567 	/* TODO */
568 	return fz_default_color_params;
569 }
570 
ffi_pushcolorparams(js_State * J,fz_color_params color_params)571 static void ffi_pushcolorparams(js_State *J, fz_color_params color_params)
572 {
573 	/* TODO */
574 	js_pushnull(J);
575 }
576 
string_from_cap(fz_linecap cap)577 static const char *string_from_cap(fz_linecap cap)
578 {
579 	switch (cap) {
580 	default:
581 	case FZ_LINECAP_BUTT: return "Butt";
582 	case FZ_LINECAP_ROUND: return "Round";
583 	case FZ_LINECAP_SQUARE: return "Square";
584 	case FZ_LINECAP_TRIANGLE: return "Triangle";
585 	}
586 }
587 
string_from_join(fz_linejoin join)588 static const char *string_from_join(fz_linejoin join)
589 {
590 	switch (join) {
591 	default:
592 	case FZ_LINEJOIN_MITER: return "Miter";
593 	case FZ_LINEJOIN_ROUND: return "Round";
594 	case FZ_LINEJOIN_BEVEL: return "Bevel";
595 	case FZ_LINEJOIN_MITER_XPS: return "MiterXPS";
596 	}
597 }
598 
string_from_line_ending(enum pdf_line_ending style)599 static const char *string_from_line_ending(enum pdf_line_ending style)
600 {
601 	switch (style) {
602 	default:
603 	case PDF_ANNOT_LE_NONE: return "None";
604 	case PDF_ANNOT_LE_SQUARE: return "Square";
605 	case PDF_ANNOT_LE_CIRCLE: return "Circle";
606 	case PDF_ANNOT_LE_DIAMOND: return "Diamond";
607 	case PDF_ANNOT_LE_OPEN_ARROW: return "OpenArrow";
608 	case PDF_ANNOT_LE_CLOSED_ARROW: return "ClosedArrow";
609 	case PDF_ANNOT_LE_BUTT: return "Butt";
610 	case PDF_ANNOT_LE_R_OPEN_ARROW: return "ROpenArrow";
611 	case PDF_ANNOT_LE_R_CLOSED_ARROW: return "RCloseArrow";
612 	case PDF_ANNOT_LE_SLASH: return "Slash";
613 	}
614 }
615 
cap_from_string(const char * str)616 static fz_linecap cap_from_string(const char *str)
617 {
618 	if (!strcmp(str, "Round")) return FZ_LINECAP_ROUND;
619 	if (!strcmp(str, "Square")) return FZ_LINECAP_SQUARE;
620 	if (!strcmp(str, "Triangle")) return FZ_LINECAP_TRIANGLE;
621 	return FZ_LINECAP_BUTT;
622 }
623 
join_from_string(const char * str)624 static fz_linejoin join_from_string(const char *str)
625 {
626 	if (!strcmp(str, "Round")) return FZ_LINEJOIN_ROUND;
627 	if (!strcmp(str, "Bevel")) return FZ_LINEJOIN_BEVEL;
628 	if (!strcmp(str, "MiterXPS")) return FZ_LINEJOIN_MITER_XPS;
629 	return FZ_LINEJOIN_MITER;
630 }
631 
line_ending_from_string(const char * str)632 static enum pdf_line_ending line_ending_from_string(const char *str)
633 {
634 	if (!strcmp(str, "None")) return PDF_ANNOT_LE_NONE;
635 	if (!strcmp(str, "Square")) return PDF_ANNOT_LE_SQUARE;
636 	if (!strcmp(str, "Circle")) return PDF_ANNOT_LE_CIRCLE;
637 	if (!strcmp(str, "Diamond")) return PDF_ANNOT_LE_DIAMOND;
638 	if (!strcmp(str, "OpenArrow")) return PDF_ANNOT_LE_OPEN_ARROW;
639 	if (!strcmp(str, "ClosedArrow")) return PDF_ANNOT_LE_CLOSED_ARROW;
640 	if (!strcmp(str, "Butt")) return PDF_ANNOT_LE_BUTT;
641 	if (!strcmp(str, "ROpenArrow")) return PDF_ANNOT_LE_R_OPEN_ARROW;
642 	if (!strcmp(str, "RClosedArrow")) return PDF_ANNOT_LE_R_CLOSED_ARROW;
643 	if (!strcmp(str, "Slash")) return PDF_ANNOT_LE_SLASH;
644 	return PDF_ANNOT_LE_NONE;
645 }
646 
ffi_pushstroke(js_State * J,const fz_stroke_state * stroke)647 static void ffi_pushstroke(js_State *J, const fz_stroke_state *stroke)
648 {
649 	js_newobject(J);
650 	js_pushliteral(J, string_from_cap(stroke->start_cap));
651 	js_setproperty(J, -2, "startCap");
652 	js_pushliteral(J, string_from_cap(stroke->dash_cap));
653 	js_setproperty(J, -2, "dashCap");
654 	js_pushliteral(J, string_from_cap(stroke->end_cap));
655 	js_setproperty(J, -2, "endCap");
656 	js_pushliteral(J, string_from_join(stroke->linejoin));
657 	js_setproperty(J, -2, "lineJoin");
658 	js_pushnumber(J, stroke->linewidth);
659 	js_setproperty(J, -2, "lineWidth");
660 	js_pushnumber(J, stroke->miterlimit);
661 	js_setproperty(J, -2, "miterLimit");
662 	js_pushnumber(J, stroke->dash_phase);
663 	js_setproperty(J, -2, "dashPhase");
664 	ffi_pusharray(J, stroke->dash_list, stroke->dash_len);
665 	js_setproperty(J, -2, "dashes");
666 }
667 
ffi_tostroke(js_State * J,int idx)668 static fz_stroke_state ffi_tostroke(js_State *J, int idx)
669 {
670 	fz_stroke_state stroke = fz_default_stroke_state;
671 	if (js_hasproperty(J, idx, "lineCap")) {
672 		stroke.start_cap = cap_from_string(js_tostring(J, -1));
673 		stroke.dash_cap = stroke.start_cap;
674 		stroke.end_cap = stroke.start_cap;
675 	}
676 	if (js_hasproperty(J, idx, "startCap")) {
677 		stroke.start_cap = cap_from_string(js_tostring(J, -1));
678 		js_pop(J, 1);
679 	}
680 	if (js_hasproperty(J, idx, "dashCap")) {
681 		stroke.dash_cap = cap_from_string(js_tostring(J, -1));
682 		js_pop(J, 1);
683 	}
684 	if (js_hasproperty(J, idx, "endCap")) {
685 		stroke.end_cap = cap_from_string(js_tostring(J, -1));
686 		js_pop(J, 1);
687 	}
688 	if (js_hasproperty(J, idx, "lineJoin")) {
689 		stroke.linejoin = join_from_string(js_tostring(J, -1));
690 		js_pop(J, 1);
691 	}
692 	if (js_hasproperty(J, idx, "lineWidth")) {
693 		stroke.linewidth = js_tonumber(J, -1);
694 		js_pop(J, 1);
695 	}
696 	if (js_hasproperty(J, idx, "miterLimit")) {
697 		stroke.miterlimit = js_tonumber(J, -1);
698 		js_pop(J, 1);
699 	}
700 	if (js_hasproperty(J, idx, "dashPhase")) {
701 		stroke.dash_phase = js_tonumber(J, -1);
702 		js_pop(J, 1);
703 	}
704 	if (js_hasproperty(J, idx, "dashes")) {
705 		int i, n = js_getlength(J, -1);
706 		if (n > (int)nelem(stroke.dash_list))
707 			n = nelem(stroke.dash_list);
708 		stroke.dash_len = n;
709 		for (i = 0; i < n; ++i) {
710 			js_getindex(J, -1, i);
711 			stroke.dash_list[i] = js_tonumber(J, -1);
712 			js_pop(J, 1);
713 		}
714 	}
715 	return stroke;
716 }
717 
ffi_pushtext(js_State * J,const fz_text * text)718 static void ffi_pushtext(js_State *J, const fz_text *text)
719 {
720 	fz_context *ctx = js_getcontext(J);
721 	js_getregistry(J, "fz_text");
722 	js_newuserdata(J, "fz_text", fz_keep_text(ctx, text), ffi_gc_fz_text);
723 }
724 
ffi_pushpath(js_State * J,const fz_path * path)725 static void ffi_pushpath(js_State *J, const fz_path *path)
726 {
727 	fz_context *ctx = js_getcontext(J);
728 	js_getregistry(J, "fz_path");
729 	js_newuserdata(J, "fz_path", fz_keep_path(ctx, path), ffi_gc_fz_path);
730 }
731 
ffi_pushfont(js_State * J,fz_font * font)732 static void ffi_pushfont(js_State *J, fz_font *font)
733 {
734 	fz_context *ctx = js_getcontext(J);
735 	js_getregistry(J, "fz_font");
736 	js_newuserdata(J, "fz_font", fz_keep_font(ctx, font), ffi_gc_fz_font);
737 }
738 
ffi_pushshade(js_State * J,fz_shade * shade)739 static void ffi_pushshade(js_State *J, fz_shade *shade)
740 {
741 	fz_context *ctx = js_getcontext(J);
742 	js_getregistry(J, "fz_shade");
743 	js_newuserdata(J, "fz_shade", fz_keep_shade(ctx, shade), ffi_gc_fz_shade);
744 }
745 
ffi_pushimage(js_State * J,fz_image * image)746 static void ffi_pushimage(js_State *J, fz_image *image)
747 {
748 	fz_context *ctx = js_getcontext(J);
749 	js_getregistry(J, "fz_image");
750 	js_newuserdata(J, "fz_image", fz_keep_image(ctx, image), ffi_gc_fz_image);
751 }
752 
ffi_pushimage_own(js_State * J,fz_image * image)753 static void ffi_pushimage_own(js_State *J, fz_image *image)
754 {
755 	js_getregistry(J, "fz_image");
756 	js_newuserdata(J, "fz_image", image, ffi_gc_fz_image);
757 }
758 
is_number(const char * key,int * idx)759 static int is_number(const char *key, int *idx)
760 {
761 	char *end;
762 	*idx = strtol(key, &end, 10);
763 	return *end == 0;
764 }
765 
ffi_buffer_has(js_State * J,void * buf_,const char * key)766 static int ffi_buffer_has(js_State *J, void *buf_, const char *key)
767 {
768 	fz_buffer *buf = buf_;
769 	int idx;
770 	unsigned char *data;
771 	size_t len = fz_buffer_storage(js_getcontext(J), buf, &data);
772 	if (is_number(key, &idx)) {
773 		if (idx < 0 || (size_t)idx >= len)
774 			js_rangeerror(J, "index out of bounds");
775 		js_pushnumber(J, data[idx]);
776 		return 1;
777 	}
778 	if (!strcmp(key, "length")) {
779 		js_pushnumber(J, len);
780 		return 1;
781 	}
782 	return 0;
783 }
784 
ffi_buffer_put(js_State * J,void * buf_,const char * key)785 static int ffi_buffer_put(js_State *J, void *buf_, const char *key)
786 {
787 	fz_buffer *buf = buf_;
788 	int idx;
789 	unsigned char *data;
790 	size_t len = fz_buffer_storage(js_getcontext(J), buf, &data);
791 	if (is_number(key, &idx)) {
792 		if (idx < 0 || (size_t)idx >= len)
793 			js_rangeerror(J, "index out of bounds");
794 		data[idx] = js_tonumber(J, -1);
795 		return 1;
796 	}
797 	if (!strcmp(key, "length"))
798 		js_typeerror(J, "buffer length is read-only");
799 	return 0;
800 }
801 
ffi_pushbuffer(js_State * J,fz_buffer * buf)802 static void ffi_pushbuffer(js_State *J, fz_buffer *buf)
803 {
804 	js_getregistry(J, "fz_buffer");
805 	js_newuserdatax(J, "fz_buffer", buf,
806 			ffi_buffer_has, ffi_buffer_put, NULL,
807 			ffi_gc_fz_buffer);
808 }
809 
810 #if FZ_ENABLE_PDF
811 
ffi_tobuffer(js_State * J,int idx)812 static fz_buffer *ffi_tobuffer(js_State *J, int idx)
813 {
814 	fz_context *ctx = js_getcontext(J);
815 	fz_buffer *buf = NULL;
816 
817 	if (js_isuserdata(J, idx, "fz_buffer"))
818 		buf = fz_keep_buffer(ctx, js_touserdata(J, idx, "fz_buffer"));
819 	else {
820 		const char *str = js_tostring(J, idx);
821 		fz_try(ctx)
822 			buf = fz_new_buffer_from_copied_data(ctx, (const unsigned char *)str, strlen(str));
823 		fz_catch(ctx)
824 			rethrow(J);
825 	}
826 
827 	return buf;
828 }
829 
830 #endif /* FZ_ENABLE_PDF */
831 
832 /* device calling into js from c */
833 
834 typedef struct
835 {
836 	fz_device super;
837 	js_State *J;
838 } js_device;
839 
840 static void
js_dev_fill_path(fz_context * ctx,fz_device * dev,const fz_path * path,int even_odd,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)841 js_dev_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, fz_matrix ctm,
842 	fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
843 {
844 	js_State *J = ((js_device*)dev)->J;
845 	if (js_try(J))
846 		rethrow_as_fz(J);
847 	if (js_hasproperty(J, -1, "fillPath")) {
848 		js_copy(J, -2);
849 		ffi_pushpath(J, path);
850 		js_pushboolean(J, even_odd);
851 		ffi_pushmatrix(J, ctm);
852 		ffi_pushcolor(J, colorspace, color, alpha);
853 		ffi_pushcolorparams(J, color_params);
854 		js_call(J, 7);
855 		js_pop(J, 1);
856 	}
857 	js_endtry(J);
858 }
859 
860 static void
js_dev_clip_path(fz_context * ctx,fz_device * dev,const fz_path * path,int even_odd,fz_matrix ctm,fz_rect scissor)861 js_dev_clip_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, fz_matrix ctm,
862 	fz_rect scissor)
863 {
864 	js_State *J = ((js_device*)dev)->J;
865 	if (js_try(J))
866 		rethrow_as_fz(J);
867 	if (js_hasproperty(J, -1, "clipPath")) {
868 		js_copy(J, -2);
869 		ffi_pushpath(J, path);
870 		js_pushboolean(J, even_odd);
871 		ffi_pushmatrix(J, ctm);
872 		js_call(J, 3);
873 		js_pop(J, 1);
874 	}
875 	js_endtry(J);
876 }
877 
878 static void
js_dev_stroke_path(fz_context * ctx,fz_device * dev,const fz_path * path,const fz_stroke_state * stroke,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)879 js_dev_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path,
880 	const fz_stroke_state *stroke, fz_matrix ctm,
881 	fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
882 {
883 	js_State *J = ((js_device*)dev)->J;
884 	if (js_try(J))
885 		rethrow_as_fz(J);
886 	if (js_hasproperty(J, -1, "strokePath")) {
887 		js_copy(J, -2);
888 		ffi_pushpath(J, path);
889 		ffi_pushstroke(J, stroke);
890 		ffi_pushmatrix(J, ctm);
891 		ffi_pushcolor(J, colorspace, color, alpha);
892 		ffi_pushcolorparams(J, color_params);
893 		js_call(J, 7);
894 		js_pop(J, 1);
895 	}
896 	js_endtry(J);
897 }
898 
899 static void
js_dev_clip_stroke_path(fz_context * ctx,fz_device * dev,const fz_path * path,const fz_stroke_state * stroke,fz_matrix ctm,fz_rect scissor)900 js_dev_clip_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke,
901 	fz_matrix ctm, fz_rect scissor)
902 {
903 	js_State *J = ((js_device*)dev)->J;
904 	if (js_try(J))
905 		rethrow_as_fz(J);
906 	if (js_hasproperty(J, -1, "clipStrokePath")) {
907 		js_copy(J, -2);
908 		ffi_pushpath(J, path);
909 		ffi_pushstroke(J, stroke);
910 		ffi_pushmatrix(J, ctm);
911 		js_call(J, 3);
912 		js_pop(J, 1);
913 	}
914 	js_endtry(J);
915 }
916 
917 static void
js_dev_fill_text(fz_context * ctx,fz_device * dev,const fz_text * text,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)918 js_dev_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm,
919 	fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
920 {
921 	js_State *J = ((js_device*)dev)->J;
922 	if (js_try(J))
923 		rethrow_as_fz(J);
924 	if (js_hasproperty(J, -1, "fillText")) {
925 		js_copy(J, -2);
926 		ffi_pushtext(J, text);
927 		ffi_pushmatrix(J, ctm);
928 		ffi_pushcolor(J, colorspace, color, alpha);
929 		ffi_pushcolorparams(J, color_params);
930 		js_call(J, 6);
931 		js_pop(J, 1);
932 	}
933 	js_endtry(J);
934 }
935 
936 static void
js_dev_stroke_text(fz_context * ctx,fz_device * dev,const fz_text * text,const fz_stroke_state * stroke,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)937 js_dev_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke,
938 	fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
939 {
940 	js_State *J = ((js_device*)dev)->J;
941 	if (js_try(J))
942 		rethrow_as_fz(J);
943 	if (js_hasproperty(J, -1, "strokeText")) {
944 		js_copy(J, -2);
945 		ffi_pushtext(J, text);
946 		ffi_pushstroke(J, stroke);
947 		ffi_pushmatrix(J, ctm);
948 		ffi_pushcolor(J, colorspace, color, alpha);
949 		ffi_pushcolorparams(J, color_params);
950 		js_call(J, 7);
951 		js_pop(J, 1);
952 	}
953 	js_endtry(J);
954 }
955 
956 static void
js_dev_clip_text(fz_context * ctx,fz_device * dev,const fz_text * text,fz_matrix ctm,fz_rect scissor)957 js_dev_clip_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm, fz_rect scissor)
958 {
959 	js_State *J = ((js_device*)dev)->J;
960 	if (js_try(J))
961 		rethrow_as_fz(J);
962 	if (js_hasproperty(J, -1, "clipText")) {
963 		js_copy(J, -2);
964 		ffi_pushtext(J, text);
965 		ffi_pushmatrix(J, ctm);
966 		js_call(J, 2);
967 		js_pop(J, 1);
968 	}
969 	js_endtry(J);
970 }
971 
972 static void
js_dev_clip_stroke_text(fz_context * ctx,fz_device * dev,const fz_text * text,const fz_stroke_state * stroke,fz_matrix ctm,fz_rect scissor)973 js_dev_clip_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke,
974 	fz_matrix ctm, fz_rect scissor)
975 {
976 	js_State *J = ((js_device*)dev)->J;
977 	if (js_try(J))
978 		rethrow_as_fz(J);
979 	if (js_hasproperty(J, -1, "clipStrokeText")) {
980 		js_copy(J, -2);
981 		ffi_pushtext(J, text);
982 		ffi_pushstroke(J, stroke);
983 		ffi_pushmatrix(J, ctm);
984 		js_call(J, 3);
985 		js_pop(J, 1);
986 	}
987 	js_endtry(J);
988 }
989 
990 static void
js_dev_ignore_text(fz_context * ctx,fz_device * dev,const fz_text * text,fz_matrix ctm)991 js_dev_ignore_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm)
992 {
993 	js_State *J = ((js_device*)dev)->J;
994 	if (js_try(J))
995 		rethrow_as_fz(J);
996 	if (js_hasproperty(J, -1, "ignoreText")) {
997 		js_copy(J, -2);
998 		ffi_pushtext(J, text);
999 		ffi_pushmatrix(J, ctm);
1000 		js_call(J, 2);
1001 		js_pop(J, 1);
1002 	}
1003 	js_endtry(J);
1004 }
1005 
1006 static void
js_dev_fill_shade(fz_context * ctx,fz_device * dev,fz_shade * shade,fz_matrix ctm,float alpha,fz_color_params color_params)1007 js_dev_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha, fz_color_params color_params)
1008 {
1009 	js_State *J = ((js_device*)dev)->J;
1010 	if (js_try(J))
1011 		rethrow_as_fz(J);
1012 	if (js_hasproperty(J, -1, "fillShade")) {
1013 		js_copy(J, -2);
1014 		ffi_pushshade(J, shade);
1015 		ffi_pushmatrix(J, ctm);
1016 		js_pushnumber(J, alpha);
1017 		ffi_pushcolorparams(J, color_params);
1018 		js_call(J, 4);
1019 		js_pop(J, 1);
1020 	}
1021 	js_endtry(J);
1022 }
1023 
1024 static void
js_dev_fill_image(fz_context * ctx,fz_device * dev,fz_image * image,fz_matrix ctm,float alpha,fz_color_params color_params)1025 js_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, float alpha, fz_color_params color_params)
1026 {
1027 	js_State *J = ((js_device*)dev)->J;
1028 	if (js_try(J))
1029 		rethrow_as_fz(J);
1030 	if (js_hasproperty(J, -1, "fillImage")) {
1031 		js_copy(J, -2);
1032 		ffi_pushimage(J, image);
1033 		ffi_pushmatrix(J, ctm);
1034 		js_pushnumber(J, alpha);
1035 		ffi_pushcolorparams(J, color_params);
1036 		js_call(J, 4);
1037 		js_pop(J, 1);
1038 	}
1039 	js_endtry(J);
1040 }
1041 
1042 static void
js_dev_fill_image_mask(fz_context * ctx,fz_device * dev,fz_image * image,fz_matrix ctm,fz_colorspace * colorspace,const float * color,float alpha,fz_color_params color_params)1043 js_dev_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm,
1044 	fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
1045 {
1046 	js_State *J = ((js_device*)dev)->J;
1047 	if (js_try(J))
1048 		rethrow_as_fz(J);
1049 	if (js_hasproperty(J, -1, "fillImageMask")) {
1050 		js_copy(J, -2);
1051 		ffi_pushimage(J, image);
1052 		ffi_pushmatrix(J, ctm);
1053 		ffi_pushcolor(J, colorspace, color, alpha);
1054 		ffi_pushcolorparams(J, color_params);
1055 		js_call(J, 6);
1056 		js_pop(J, 1);
1057 	}
1058 	js_endtry(J);
1059 }
1060 
1061 static void
js_dev_clip_image_mask(fz_context * ctx,fz_device * dev,fz_image * image,fz_matrix ctm,fz_rect scissor)1062 js_dev_clip_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, fz_rect scissor)
1063 {
1064 	js_State *J = ((js_device*)dev)->J;
1065 	if (js_try(J))
1066 		rethrow_as_fz(J);
1067 	if (js_hasproperty(J, -1, "clipImageMask")) {
1068 		js_copy(J, -2);
1069 		ffi_pushimage(J, image);
1070 		ffi_pushmatrix(J, ctm);
1071 		js_call(J, 2);
1072 		js_pop(J, 1);
1073 	}
1074 	js_endtry(J);
1075 }
1076 
1077 static void
js_dev_pop_clip(fz_context * ctx,fz_device * dev)1078 js_dev_pop_clip(fz_context *ctx, fz_device *dev)
1079 {
1080 	js_State *J = ((js_device*)dev)->J;
1081 	if (js_try(J))
1082 		rethrow_as_fz(J);
1083 	if (js_hasproperty(J, -1, "popClip")) {
1084 		js_copy(J, -2);
1085 		js_call(J, 0);
1086 		js_pop(J, 1);
1087 	}
1088 	js_endtry(J);
1089 }
1090 
1091 static void
js_dev_begin_mask(fz_context * ctx,fz_device * dev,fz_rect bbox,int luminosity,fz_colorspace * colorspace,const float * color,fz_color_params color_params)1092 js_dev_begin_mask(fz_context *ctx, fz_device *dev, fz_rect bbox, int luminosity,
1093 	fz_colorspace *colorspace, const float *color, fz_color_params color_params)
1094 {
1095 	js_State *J = ((js_device*)dev)->J;
1096 	if (js_try(J))
1097 		rethrow_as_fz(J);
1098 	if (js_hasproperty(J, -1, "beginMask")) {
1099 		js_copy(J, -2);
1100 		ffi_pushrect(J, bbox);
1101 		js_pushboolean(J, luminosity);
1102 		ffi_pushcolor(J, colorspace, color, 1);
1103 		ffi_pushcolorparams(J, color_params);
1104 		js_call(J, 6);
1105 		js_pop(J, 1);
1106 	}
1107 	js_endtry(J);
1108 }
1109 
1110 static void
js_dev_end_mask(fz_context * ctx,fz_device * dev)1111 js_dev_end_mask(fz_context *ctx, fz_device *dev)
1112 {
1113 	js_State *J = ((js_device*)dev)->J;
1114 	if (js_try(J))
1115 		rethrow_as_fz(J);
1116 	if (js_hasproperty(J, -1, "endMask")) {
1117 		js_copy(J, -2);
1118 		js_call(J, 0);
1119 		js_pop(J, 1);
1120 	}
1121 	js_endtry(J);
1122 }
1123 
1124 static void
js_dev_begin_group(fz_context * ctx,fz_device * dev,fz_rect bbox,fz_colorspace * cs,int isolated,int knockout,int blendmode,float alpha)1125 js_dev_begin_group(fz_context *ctx, fz_device *dev, fz_rect bbox,
1126 	fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha)
1127 {
1128 	js_State *J = ((js_device*)dev)->J;
1129 	if (js_try(J))
1130 		rethrow_as_fz(J);
1131 	if (js_hasproperty(J, -1, "beginGroup")) {
1132 		js_copy(J, -2);
1133 		ffi_pushrect(J, bbox);
1134 		js_pushboolean(J, isolated);
1135 		js_pushboolean(J, knockout);
1136 		js_pushliteral(J, fz_blendmode_name(blendmode));
1137 		js_pushnumber(J, alpha);
1138 		js_call(J, 5);
1139 		js_pop(J, 1);
1140 	}
1141 	js_endtry(J);
1142 }
1143 
1144 static void
js_dev_end_group(fz_context * ctx,fz_device * dev)1145 js_dev_end_group(fz_context *ctx, fz_device *dev)
1146 {
1147 	js_State *J = ((js_device*)dev)->J;
1148 	if (js_try(J))
1149 		rethrow_as_fz(J);
1150 	if (js_hasproperty(J, -1, "endGroup")) {
1151 		js_copy(J, -2);
1152 		js_call(J, 0);
1153 		js_pop(J, 1);
1154 	}
1155 	js_endtry(J);
1156 }
1157 
1158 static int
js_dev_begin_tile(fz_context * ctx,fz_device * dev,fz_rect area,fz_rect view,float xstep,float ystep,fz_matrix ctm,int id)1159 js_dev_begin_tile(fz_context *ctx, fz_device *dev, fz_rect area, fz_rect view,
1160 	float xstep, float ystep, fz_matrix ctm, int id)
1161 {
1162 	js_State *J = ((js_device*)dev)->J;
1163 	if (js_try(J))
1164 		rethrow_as_fz(J);
1165 	if (js_hasproperty(J, -1, "beginTile")) {
1166 		int n;
1167 		js_copy(J, -2);
1168 		ffi_pushrect(J, area);
1169 		ffi_pushrect(J, view);
1170 		js_pushnumber(J, xstep);
1171 		js_pushnumber(J, ystep);
1172 		ffi_pushmatrix(J, ctm);
1173 		js_pushnumber(J, id);
1174 		js_call(J, 6);
1175 		n = js_tointeger(J, -1);
1176 		js_pop(J, 1);
1177 		return n;
1178 	}
1179 	js_endtry(J);
1180 	return 0;
1181 }
1182 
1183 static void
js_dev_end_tile(fz_context * ctx,fz_device * dev)1184 js_dev_end_tile(fz_context *ctx, fz_device *dev)
1185 {
1186 	js_State *J = ((js_device*)dev)->J;
1187 	if (js_try(J))
1188 		rethrow_as_fz(J);
1189 	if (js_hasproperty(J, -1, "endTile")) {
1190 		js_copy(J, -2);
1191 		js_call(J, 0);
1192 		js_pop(J, 1);
1193 	}
1194 	js_endtry(J);
1195 }
1196 
1197 static void
js_dev_begin_layer(fz_context * ctx,fz_device * dev,const char * name)1198 js_dev_begin_layer(fz_context *ctx, fz_device *dev, const char *name)
1199 {
1200 	js_State *J = ((js_device*)dev)->J;
1201 	if (js_try(J))
1202 		rethrow_as_fz(J);
1203 	if (js_hasproperty(J, -1, "beginLayer")) {
1204 		js_copy(J, -2);
1205 		js_pushstring(J, name);
1206 		js_call(J, 1);
1207 		js_pop(J, 1);
1208 	}
1209 	js_endtry(J);
1210 }
1211 
1212 static void
js_dev_end_layer(fz_context * ctx,fz_device * dev)1213 js_dev_end_layer(fz_context *ctx, fz_device *dev)
1214 {
1215 	js_State *J = ((js_device*)dev)->J;
1216 	if (js_try(J))
1217 		rethrow_as_fz(J);
1218 	if (js_hasproperty(J, -1, "endLayer")) {
1219 		js_copy(J, -2);
1220 		js_call(J, 0);
1221 		js_pop(J, 1);
1222 	}
1223 	js_endtry(J);
1224 }
1225 
new_js_device(fz_context * ctx,js_State * J)1226 static fz_device *new_js_device(fz_context *ctx, js_State *J)
1227 {
1228 	js_device *dev = fz_new_derived_device(ctx, js_device);
1229 
1230 	dev->super.fill_path = js_dev_fill_path;
1231 	dev->super.stroke_path = js_dev_stroke_path;
1232 	dev->super.clip_path = js_dev_clip_path;
1233 	dev->super.clip_stroke_path = js_dev_clip_stroke_path;
1234 
1235 	dev->super.fill_text = js_dev_fill_text;
1236 	dev->super.stroke_text = js_dev_stroke_text;
1237 	dev->super.clip_text = js_dev_clip_text;
1238 	dev->super.clip_stroke_text = js_dev_clip_stroke_text;
1239 	dev->super.ignore_text = js_dev_ignore_text;
1240 
1241 	dev->super.fill_shade = js_dev_fill_shade;
1242 	dev->super.fill_image = js_dev_fill_image;
1243 	dev->super.fill_image_mask = js_dev_fill_image_mask;
1244 	dev->super.clip_image_mask = js_dev_clip_image_mask;
1245 
1246 	dev->super.pop_clip = js_dev_pop_clip;
1247 
1248 	dev->super.begin_mask = js_dev_begin_mask;
1249 	dev->super.end_mask = js_dev_end_mask;
1250 	dev->super.begin_group = js_dev_begin_group;
1251 	dev->super.end_group = js_dev_end_group;
1252 
1253 	dev->super.begin_tile = js_dev_begin_tile;
1254 	dev->super.end_tile = js_dev_end_tile;
1255 
1256 	dev->super.begin_layer = js_dev_begin_layer;
1257 	dev->super.end_layer = js_dev_end_layer;
1258 
1259 	dev->J = J;
1260 	return (fz_device*)dev;
1261 }
1262 
1263 /* PDF operator processor */
1264 
1265 #if FZ_ENABLE_PDF
1266 
1267 typedef struct
1268 {
1269 	pdf_processor super;
1270 	js_State *J;
1271 	int extgstate;
1272 } pdf_js_processor;
1273 
1274 #define PROC_BEGIN(OP) \
1275 	{ js_State *J = ((pdf_js_processor*)proc)->J; \
1276 	if (js_try(J)) \
1277 		rethrow_as_fz(J); \
1278 	if (js_hasproperty(J, 1, OP)) { \
1279 		js_copy(J, 1);
1280 
1281 #define PROC_END(N) \
1282 		js_call(J, N); \
1283 		js_pop(J, 1); \
1284 	} \
1285 	js_endtry(J); }
1286 
js_proc_w(fz_context * ctx,pdf_processor * proc,float linewidth)1287 static void js_proc_w(fz_context *ctx, pdf_processor *proc, float linewidth)
1288 {
1289 	if (!((pdf_js_processor*)proc)->extgstate)
1290 	{
1291 		PROC_BEGIN("op_w");
1292 		js_pushnumber(J, linewidth);
1293 		PROC_END(1);
1294 	}
1295 }
1296 
js_proc_j(fz_context * ctx,pdf_processor * proc,int linejoin)1297 static void js_proc_j(fz_context *ctx, pdf_processor *proc, int linejoin)
1298 {
1299 	if (!((pdf_js_processor*)proc)->extgstate)
1300 	{
1301 		PROC_BEGIN("op_w");
1302 		js_pushnumber(J, linejoin);
1303 		PROC_END(1);
1304 	}
1305 }
1306 
js_proc_J(fz_context * ctx,pdf_processor * proc,int linecap)1307 static void js_proc_J(fz_context *ctx, pdf_processor *proc, int linecap)
1308 {
1309 	if (!((pdf_js_processor*)proc)->extgstate)
1310 	{
1311 		PROC_BEGIN("op_J");
1312 		js_pushnumber(J, linecap);
1313 		PROC_END(1);
1314 	}
1315 }
1316 
js_proc_M(fz_context * ctx,pdf_processor * proc,float miterlimit)1317 static void js_proc_M(fz_context *ctx, pdf_processor *proc, float miterlimit)
1318 {
1319 	if (!((pdf_js_processor*)proc)->extgstate)
1320 	{
1321 		PROC_BEGIN("op_M");
1322 		js_pushnumber(J, miterlimit);
1323 		PROC_END(1);
1324 	}
1325 }
1326 
js_proc_d(fz_context * ctx,pdf_processor * proc,pdf_obj * array,float phase)1327 static void js_proc_d(fz_context *ctx, pdf_processor *proc, pdf_obj *array, float phase)
1328 {
1329 	int i, n = pdf_array_len(ctx, array);
1330 	PROC_BEGIN("op_d");
1331 	{
1332 		js_newarray(J);
1333 		for (i = 0; i < n; ++i)
1334 		{
1335 			/* we know the array only holds numbers and strings, so we are safe from exceptions here */
1336 			js_pushnumber(J, pdf_array_get_real(ctx, array, i));
1337 			js_setindex(J, -2, i);
1338 		}
1339 		js_pushnumber(J, phase);
1340 	}
1341 	PROC_END(2);
1342 }
1343 
js_proc_ri(fz_context * ctx,pdf_processor * proc,const char * intent)1344 static void js_proc_ri(fz_context *ctx, pdf_processor *proc, const char *intent)
1345 {
1346 	if (!((pdf_js_processor*)proc)->extgstate)
1347 	{
1348 		PROC_BEGIN("op_ri");
1349 		js_pushstring(J, intent);
1350 		PROC_END(1);
1351 	}
1352 }
1353 
js_proc_i(fz_context * ctx,pdf_processor * proc,float flatness)1354 static void js_proc_i(fz_context *ctx, pdf_processor *proc, float flatness)
1355 {
1356 	if (!((pdf_js_processor*)proc)->extgstate)
1357 	{
1358 		PROC_BEGIN("op_i");
1359 		js_pushnumber(J, flatness);
1360 		PROC_END(1);
1361 	}
1362 }
1363 
js_proc_gs_begin(fz_context * ctx,pdf_processor * proc,const char * name,pdf_obj * extgstate)1364 static void js_proc_gs_begin(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *extgstate)
1365 {
1366 	((pdf_js_processor*)proc)->extgstate = 1;
1367 	PROC_BEGIN("op_gs");
1368 	js_pushstring(J, name);
1369 	ffi_pushobj(J, pdf_keep_obj(ctx, extgstate));
1370 	PROC_END(2);
1371 }
1372 
js_proc_gs_end(fz_context * ctx,pdf_processor * proc)1373 static void js_proc_gs_end(fz_context *ctx, pdf_processor *proc)
1374 {
1375 	((pdf_js_processor*)proc)->extgstate = 0;
1376 }
1377 
js_proc_q(fz_context * ctx,pdf_processor * proc)1378 static void js_proc_q(fz_context *ctx, pdf_processor *proc)
1379 {
1380 	PROC_BEGIN("op_q");
1381 	PROC_END(0);
1382 }
1383 
js_proc_Q(fz_context * ctx,pdf_processor * proc)1384 static void js_proc_Q(fz_context *ctx, pdf_processor *proc)
1385 {
1386 	PROC_BEGIN("op_Q");
1387 	PROC_END(0);
1388 }
1389 
js_proc_cm(fz_context * ctx,pdf_processor * proc,float a,float b,float c,float d,float e,float f)1390 static void js_proc_cm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f)
1391 {
1392 	PROC_BEGIN("op_cm");
1393 	js_pushnumber(J, a);
1394 	js_pushnumber(J, b);
1395 	js_pushnumber(J, c);
1396 	js_pushnumber(J, d);
1397 	js_pushnumber(J, e);
1398 	js_pushnumber(J, f);
1399 	PROC_END(6);
1400 }
1401 
js_proc_m(fz_context * ctx,pdf_processor * proc,float x,float y)1402 static void js_proc_m(fz_context *ctx, pdf_processor *proc, float x, float y)
1403 {
1404 	PROC_BEGIN("op_m");
1405 	js_pushnumber(J, x);
1406 	js_pushnumber(J, y);
1407 	PROC_END(2);
1408 }
1409 
js_proc_l(fz_context * ctx,pdf_processor * proc,float x,float y)1410 static void js_proc_l(fz_context *ctx, pdf_processor *proc, float x, float y)
1411 {
1412 	PROC_BEGIN("op_l");
1413 	js_pushnumber(J, x);
1414 	js_pushnumber(J, y);
1415 	PROC_END(2);
1416 }
1417 
js_proc_c(fz_context * ctx,pdf_processor * proc,float x1,float y1,float x2,float y2,float x3,float y3)1418 static void js_proc_c(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x2, float y2, float x3, float y3)
1419 {
1420 	PROC_BEGIN("op_c");
1421 	js_pushnumber(J, x1);
1422 	js_pushnumber(J, y1);
1423 	js_pushnumber(J, x2);
1424 	js_pushnumber(J, y2);
1425 	js_pushnumber(J, x3);
1426 	js_pushnumber(J, y3);
1427 	PROC_END(6);
1428 }
1429 
js_proc_v(fz_context * ctx,pdf_processor * proc,float x2,float y2,float x3,float y3)1430 static void js_proc_v(fz_context *ctx, pdf_processor *proc, float x2, float y2, float x3, float y3)
1431 {
1432 	PROC_BEGIN("op_v");
1433 	js_pushnumber(J, x2);
1434 	js_pushnumber(J, y2);
1435 	js_pushnumber(J, x3);
1436 	js_pushnumber(J, y3);
1437 	PROC_END(4);
1438 }
1439 
js_proc_y(fz_context * ctx,pdf_processor * proc,float x1,float y1,float x3,float y3)1440 static void js_proc_y(fz_context *ctx, pdf_processor *proc, float x1, float y1, float x3, float y3)
1441 {
1442 	PROC_BEGIN("op_y");
1443 	js_pushnumber(J, x1);
1444 	js_pushnumber(J, y1);
1445 	js_pushnumber(J, x3);
1446 	js_pushnumber(J, y3);
1447 	PROC_END(4);
1448 }
1449 
js_proc_h(fz_context * ctx,pdf_processor * proc)1450 static void js_proc_h(fz_context *ctx, pdf_processor *proc)
1451 {
1452 	PROC_BEGIN("op_h");
1453 	PROC_END(0);
1454 }
1455 
js_proc_re(fz_context * ctx,pdf_processor * proc,float x,float y,float w,float h)1456 static void js_proc_re(fz_context *ctx, pdf_processor *proc, float x, float y, float w, float h)
1457 {
1458 	PROC_BEGIN("op_re");
1459 	js_pushnumber(J, x);
1460 	js_pushnumber(J, y);
1461 	js_pushnumber(J, w);
1462 	js_pushnumber(J, h);
1463 	PROC_END(4);
1464 }
1465 
js_proc_S(fz_context * ctx,pdf_processor * proc)1466 static void js_proc_S(fz_context *ctx, pdf_processor *proc)
1467 {
1468 	PROC_BEGIN("op_S");
1469 	PROC_END(0);
1470 }
1471 
js_proc_s(fz_context * ctx,pdf_processor * proc)1472 static void js_proc_s(fz_context *ctx, pdf_processor *proc)
1473 {
1474 	PROC_BEGIN("op_s");
1475 	PROC_END(0);
1476 }
1477 
js_proc_F(fz_context * ctx,pdf_processor * proc)1478 static void js_proc_F(fz_context *ctx, pdf_processor *proc)
1479 {
1480 	PROC_BEGIN("op_F");
1481 	PROC_END(0);
1482 }
1483 
js_proc_f(fz_context * ctx,pdf_processor * proc)1484 static void js_proc_f(fz_context *ctx, pdf_processor *proc)
1485 {
1486 	PROC_BEGIN("op_f");
1487 	PROC_END(0);
1488 }
1489 
js_proc_fstar(fz_context * ctx,pdf_processor * proc)1490 static void js_proc_fstar(fz_context *ctx, pdf_processor *proc)
1491 {
1492 	PROC_BEGIN("op_fstar");
1493 	PROC_END(0);
1494 }
1495 
js_proc_B(fz_context * ctx,pdf_processor * proc)1496 static void js_proc_B(fz_context *ctx, pdf_processor *proc)
1497 {
1498 	PROC_BEGIN("op_B");
1499 	PROC_END(0);
1500 }
1501 
js_proc_Bstar(fz_context * ctx,pdf_processor * proc)1502 static void js_proc_Bstar(fz_context *ctx, pdf_processor *proc)
1503 {
1504 	PROC_BEGIN("op_Bstar");
1505 	PROC_END(0);
1506 }
1507 
js_proc_b(fz_context * ctx,pdf_processor * proc)1508 static void js_proc_b(fz_context *ctx, pdf_processor *proc)
1509 {
1510 	PROC_BEGIN("op_b");
1511 	PROC_END(0);
1512 }
1513 
js_proc_bstar(fz_context * ctx,pdf_processor * proc)1514 static void js_proc_bstar(fz_context *ctx, pdf_processor *proc)
1515 {
1516 	PROC_BEGIN("op_bstar");
1517 	PROC_END(0);
1518 }
1519 
js_proc_n(fz_context * ctx,pdf_processor * proc)1520 static void js_proc_n(fz_context *ctx, pdf_processor *proc)
1521 {
1522 	PROC_BEGIN("op_n");
1523 	PROC_END(0);
1524 }
1525 
js_proc_W(fz_context * ctx,pdf_processor * proc)1526 static void js_proc_W(fz_context *ctx, pdf_processor *proc)
1527 {
1528 	PROC_BEGIN("op_W");
1529 	PROC_END(0);
1530 }
1531 
js_proc_Wstar(fz_context * ctx,pdf_processor * proc)1532 static void js_proc_Wstar(fz_context *ctx, pdf_processor *proc)
1533 {
1534 	PROC_BEGIN("op_Wstar");
1535 	PROC_END(0);
1536 }
1537 
js_proc_BT(fz_context * ctx,pdf_processor * proc)1538 static void js_proc_BT(fz_context *ctx, pdf_processor *proc)
1539 {
1540 	PROC_BEGIN("op_BT");
1541 	PROC_END(0);
1542 }
1543 
js_proc_ET(fz_context * ctx,pdf_processor * proc)1544 static void js_proc_ET(fz_context *ctx, pdf_processor *proc)
1545 {
1546 	PROC_BEGIN("op_ET");
1547 	PROC_END(0);
1548 }
1549 
js_proc_Tc(fz_context * ctx,pdf_processor * proc,float charspace)1550 static void js_proc_Tc(fz_context *ctx, pdf_processor *proc, float charspace)
1551 {
1552 	PROC_BEGIN("op_Tc");
1553 	js_pushnumber(J, charspace);
1554 	PROC_END(1);
1555 }
1556 
js_proc_Tw(fz_context * ctx,pdf_processor * proc,float wordspace)1557 static void js_proc_Tw(fz_context *ctx, pdf_processor *proc, float wordspace)
1558 {
1559 	PROC_BEGIN("op_Tw");
1560 	js_pushnumber(J, wordspace);
1561 	PROC_END(1);
1562 }
1563 
js_proc_Tz(fz_context * ctx,pdf_processor * proc,float scale)1564 static void js_proc_Tz(fz_context *ctx, pdf_processor *proc, float scale)
1565 {
1566 	PROC_BEGIN("op_Tz");
1567 	js_pushnumber(J, scale);
1568 	PROC_END(1);
1569 }
1570 
js_proc_TL(fz_context * ctx,pdf_processor * proc,float leading)1571 static void js_proc_TL(fz_context *ctx, pdf_processor *proc, float leading)
1572 {
1573 	PROC_BEGIN("op_TL");
1574 	js_pushnumber(J, leading);
1575 	PROC_END(1);
1576 }
1577 
js_proc_Tf(fz_context * ctx,pdf_processor * proc,const char * name,pdf_font_desc * font,float size)1578 static void js_proc_Tf(fz_context *ctx, pdf_processor *proc, const char *name, pdf_font_desc *font, float size)
1579 {
1580 	if (!((pdf_js_processor*)proc)->extgstate)
1581 	{
1582 		PROC_BEGIN("op_Tf");
1583 		js_pushstring(J, name);
1584 		js_pushnumber(J, size);
1585 		PROC_END(2);
1586 	}
1587 }
1588 
js_proc_Tr(fz_context * ctx,pdf_processor * proc,int render)1589 static void js_proc_Tr(fz_context *ctx, pdf_processor *proc, int render)
1590 {
1591 	PROC_BEGIN("op_Tr");
1592 	js_pushnumber(J, render);
1593 	PROC_END(1);
1594 }
1595 
js_proc_Ts(fz_context * ctx,pdf_processor * proc,float rise)1596 static void js_proc_Ts(fz_context *ctx, pdf_processor *proc, float rise)
1597 {
1598 	PROC_BEGIN("op_Ts");
1599 	js_pushnumber(J, rise);
1600 	PROC_END(1);
1601 }
1602 
js_proc_Td(fz_context * ctx,pdf_processor * proc,float tx,float ty)1603 static void js_proc_Td(fz_context *ctx, pdf_processor *proc, float tx, float ty)
1604 {
1605 	PROC_BEGIN("op_Td");
1606 	js_pushnumber(J, tx);
1607 	js_pushnumber(J, ty);
1608 	PROC_END(2);
1609 }
1610 
js_proc_TD(fz_context * ctx,pdf_processor * proc,float tx,float ty)1611 static void js_proc_TD(fz_context *ctx, pdf_processor *proc, float tx, float ty)
1612 {
1613 	PROC_BEGIN("op_TD");
1614 	js_pushnumber(J, tx);
1615 	js_pushnumber(J, ty);
1616 	PROC_END(2);
1617 }
1618 
js_proc_Tm(fz_context * ctx,pdf_processor * proc,float a,float b,float c,float d,float e,float f)1619 static void js_proc_Tm(fz_context *ctx, pdf_processor *proc, float a, float b, float c, float d, float e, float f)
1620 {
1621 	PROC_BEGIN("op_Tm");
1622 	js_pushnumber(J, a);
1623 	js_pushnumber(J, b);
1624 	js_pushnumber(J, c);
1625 	js_pushnumber(J, d);
1626 	js_pushnumber(J, e);
1627 	js_pushnumber(J, f);
1628 	PROC_END(6);
1629 }
1630 
js_proc_Tstar(fz_context * ctx,pdf_processor * proc)1631 static void js_proc_Tstar(fz_context *ctx, pdf_processor *proc)
1632 {
1633 	PROC_BEGIN("op_Tstar");
1634 	PROC_END(0);
1635 }
1636 
push_byte_string(js_State * J,unsigned char * str,size_t len)1637 static void push_byte_string(js_State *J, unsigned char *str, size_t len)
1638 {
1639 	size_t i, is_ascii = 1;
1640 	for (i = 0; i < len; ++i)
1641 		if (str[i] == 0 || str[i] > 127)
1642 			is_ascii = 0;
1643 	if (is_ascii)
1644 		js_pushstring(J, (char*)str);
1645 	else
1646 	{
1647 		js_newarray(J);
1648 		for (i = 0; i < len; ++i)
1649 		{
1650 			js_pushnumber(J, str[i]);
1651 			js_setindex(J, -2, (int)i);
1652 		}
1653 	}
1654 }
1655 
js_proc_TJ(fz_context * ctx,pdf_processor * proc,pdf_obj * array)1656 static void js_proc_TJ(fz_context *ctx, pdf_processor *proc, pdf_obj *array)
1657 {
1658 	int i, n = pdf_array_len(ctx, array);
1659 	pdf_obj *obj;
1660 	PROC_BEGIN("op_TJ");
1661 	{
1662 		/* we know the array only holds numbers and strings, so we are safe from exceptions here */
1663 		js_newarray(J);
1664 		for (i = 0; i < n; ++i)
1665 		{
1666 			obj = pdf_array_get(ctx, array, i);
1667 			if (pdf_is_number(ctx, obj))
1668 				js_pushnumber(J, pdf_to_real(ctx, obj));
1669 			else
1670 			{
1671 				push_byte_string(J, (unsigned char *)pdf_to_str_buf(ctx, obj), pdf_to_str_len(ctx, obj));
1672 			}
1673 			js_setindex(J, -2, i);
1674 		}
1675 	}
1676 	PROC_END(1);
1677 }
1678 
js_proc_Tj(fz_context * ctx,pdf_processor * proc,char * str,size_t len)1679 static void js_proc_Tj(fz_context *ctx, pdf_processor *proc, char *str, size_t len)
1680 {
1681 	PROC_BEGIN("op_Tj");
1682 	push_byte_string(J, (unsigned char *)str, len);
1683 	PROC_END(1);
1684 }
1685 
js_proc_squote(fz_context * ctx,pdf_processor * proc,char * str,size_t len)1686 static void js_proc_squote(fz_context *ctx, pdf_processor *proc, char *str, size_t len)
1687 {
1688 	PROC_BEGIN("op_squote");
1689 	push_byte_string(J, (unsigned char *)str, len);
1690 	PROC_END(1);
1691 }
1692 
js_proc_dquote(fz_context * ctx,pdf_processor * proc,float aw,float ac,char * str,size_t len)1693 static void js_proc_dquote(fz_context *ctx, pdf_processor *proc, float aw, float ac, char *str, size_t len)
1694 {
1695 	PROC_BEGIN("op_dquote");
1696 	js_pushnumber(J, aw);
1697 	js_pushnumber(J, ac);
1698 	push_byte_string(J, (unsigned char *)str, len);
1699 	PROC_END(1);
1700 }
1701 
js_proc_d0(fz_context * ctx,pdf_processor * proc,float wx,float wy)1702 static void js_proc_d0(fz_context *ctx, pdf_processor *proc, float wx, float wy)
1703 {
1704 	PROC_BEGIN("op_d0");
1705 	js_pushnumber(J, wx);
1706 	js_pushnumber(J, wy);
1707 	PROC_END(2);
1708 }
1709 
js_proc_d1(fz_context * ctx,pdf_processor * proc,float wx,float wy,float llx,float lly,float urx,float ury)1710 static void js_proc_d1(fz_context *ctx, pdf_processor *proc,
1711 	float wx, float wy, float llx, float lly, float urx, float ury)
1712 {
1713 	PROC_BEGIN("op_d1");
1714 	js_pushnumber(J, wx);
1715 	js_pushnumber(J, wy);
1716 	js_pushnumber(J, llx);
1717 	js_pushnumber(J, lly);
1718 	js_pushnumber(J, urx);
1719 	js_pushnumber(J, ury);
1720 	PROC_END(6);
1721 }
1722 
js_proc_CS(fz_context * ctx,pdf_processor * proc,const char * name,fz_colorspace * cs)1723 static void js_proc_CS(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs)
1724 {
1725 	PROC_BEGIN("op_CS");
1726 	js_pushstring(J, name);
1727 	ffi_pushcolorspace(J, cs);
1728 	PROC_END(2);
1729 }
1730 
js_proc_cs(fz_context * ctx,pdf_processor * proc,const char * name,fz_colorspace * cs)1731 static void js_proc_cs(fz_context *ctx, pdf_processor *proc, const char *name, fz_colorspace *cs)
1732 {
1733 	PROC_BEGIN("op_cs");
1734 	js_pushstring(J, name);
1735 	ffi_pushcolorspace(J, cs);
1736 	PROC_END(2);
1737 }
1738 
js_proc_SC_pattern(fz_context * ctx,pdf_processor * proc,const char * name,pdf_pattern * pat,int n,float * color)1739 static void js_proc_SC_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color)
1740 {
1741 	int i;
1742 	PROC_BEGIN("op_SC_pattern");
1743 	js_pushstring(J, name);
1744 	js_pushnumber(J, pat->id); /* TODO: pdf_obj instead! */
1745 	js_newarray(J);
1746 	for (i = 0; i < n; ++i)
1747 	{
1748 		js_pushnumber(J, color[i]);
1749 		js_setindex(J, -2, i);
1750 	}
1751 	PROC_END(3);
1752 }
1753 
js_proc_sc_pattern(fz_context * ctx,pdf_processor * proc,const char * name,pdf_pattern * pat,int n,float * color)1754 static void js_proc_sc_pattern(fz_context *ctx, pdf_processor *proc, const char *name, pdf_pattern *pat, int n, float *color)
1755 {
1756 	int i;
1757 	PROC_BEGIN("op_sc_pattern");
1758 	js_pushstring(J, name);
1759 	js_pushnumber(J, pat->id); /* TODO: pdf_obj instead! */
1760 	js_newarray(J);
1761 	for (i = 0; i < n; ++i)
1762 	{
1763 		js_pushnumber(J, color[i]);
1764 		js_setindex(J, -2, i);
1765 	}
1766 	PROC_END(3);
1767 }
1768 
js_proc_SC_shade(fz_context * ctx,pdf_processor * proc,const char * name,fz_shade * shade)1769 static void js_proc_SC_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade)
1770 {
1771 	PROC_BEGIN("op_SC_shade");
1772 	js_pushstring(J, name);
1773 	ffi_pushshade(J, shade);
1774 	PROC_END(2);
1775 }
1776 
js_proc_sc_shade(fz_context * ctx,pdf_processor * proc,const char * name,fz_shade * shade)1777 static void js_proc_sc_shade(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade)
1778 {
1779 	PROC_BEGIN("op_sc_shade");
1780 	js_pushstring(J, name);
1781 	ffi_pushshade(J, shade);
1782 	PROC_END(2);
1783 }
1784 
js_proc_SC_color(fz_context * ctx,pdf_processor * proc,int n,float * color)1785 static void js_proc_SC_color(fz_context *ctx, pdf_processor *proc, int n, float *color)
1786 {
1787 	int i;
1788 	PROC_BEGIN("op_SC_color");
1789 	js_newarray(J);
1790 	for (i = 0; i < n; ++i)
1791 	{
1792 		js_pushnumber(J, color[i]);
1793 		js_setindex(J, -2, i);
1794 	}
1795 	PROC_END(1);
1796 }
1797 
js_proc_sc_color(fz_context * ctx,pdf_processor * proc,int n,float * color)1798 static void js_proc_sc_color(fz_context *ctx, pdf_processor *proc, int n, float *color)
1799 {
1800 	int i;
1801 	PROC_BEGIN("op_sc_color");
1802 	js_newarray(J);
1803 	for (i = 0; i < n; ++i)
1804 	{
1805 		js_pushnumber(J, color[i]);
1806 		js_setindex(J, -2, i);
1807 	}
1808 	PROC_END(1);
1809 }
1810 
js_proc_G(fz_context * ctx,pdf_processor * proc,float g)1811 static void js_proc_G(fz_context *ctx, pdf_processor *proc, float g)
1812 {
1813 	PROC_BEGIN("op_G");
1814 	js_pushnumber(J, g);
1815 	PROC_END(1);
1816 }
1817 
js_proc_g(fz_context * ctx,pdf_processor * proc,float g)1818 static void js_proc_g(fz_context *ctx, pdf_processor *proc, float g)
1819 {
1820 	PROC_BEGIN("op_g");
1821 	js_pushnumber(J, g);
1822 	PROC_END(1);
1823 }
1824 
js_proc_RG(fz_context * ctx,pdf_processor * proc,float r,float g,float b)1825 static void js_proc_RG(fz_context *ctx, pdf_processor *proc, float r, float g, float b)
1826 {
1827 	PROC_BEGIN("op_RG");
1828 	js_pushnumber(J, r);
1829 	js_pushnumber(J, g);
1830 	js_pushnumber(J, b);
1831 	PROC_END(3);
1832 }
1833 
js_proc_rg(fz_context * ctx,pdf_processor * proc,float r,float g,float b)1834 static void js_proc_rg(fz_context *ctx, pdf_processor *proc, float r, float g, float b)
1835 {
1836 	PROC_BEGIN("op_rg");
1837 	js_pushnumber(J, r);
1838 	js_pushnumber(J, g);
1839 	js_pushnumber(J, b);
1840 	PROC_END(3);
1841 }
1842 
js_proc_K(fz_context * ctx,pdf_processor * proc,float c,float m,float y,float k)1843 static void js_proc_K(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k)
1844 {
1845 	PROC_BEGIN("op_K");
1846 	js_pushnumber(J, c);
1847 	js_pushnumber(J, m);
1848 	js_pushnumber(J, y);
1849 	js_pushnumber(J, k);
1850 	PROC_END(4);
1851 }
1852 
js_proc_k(fz_context * ctx,pdf_processor * proc,float c,float m,float y,float k)1853 static void js_proc_k(fz_context *ctx, pdf_processor *proc, float c, float m, float y, float k)
1854 {
1855 	PROC_BEGIN("op_k");
1856 	js_pushnumber(J, c);
1857 	js_pushnumber(J, m);
1858 	js_pushnumber(J, y);
1859 	js_pushnumber(J, k);
1860 	PROC_END(4);
1861 }
1862 
js_proc_BI(fz_context * ctx,pdf_processor * proc,fz_image * img,const char * colorspace)1863 static void js_proc_BI(fz_context *ctx, pdf_processor *proc, fz_image *img, const char *colorspace)
1864 {
1865 	PROC_BEGIN("op_BI");
1866 	ffi_pushimage(J, img);
1867 	js_pushstring(J, colorspace);
1868 	PROC_END(2);
1869 }
1870 
js_proc_sh(fz_context * ctx,pdf_processor * proc,const char * name,fz_shade * shade)1871 static void js_proc_sh(fz_context *ctx, pdf_processor *proc, const char *name, fz_shade *shade)
1872 {
1873 	PROC_BEGIN("op_sh");
1874 	js_pushstring(J, name);
1875 	ffi_pushshade(J, shade);
1876 	PROC_END(2);
1877 }
1878 
js_proc_Do_image(fz_context * ctx,pdf_processor * proc,const char * name,fz_image * image)1879 static void js_proc_Do_image(fz_context *ctx, pdf_processor *proc, const char *name, fz_image *image)
1880 {
1881 	PROC_BEGIN("op_Do_image");
1882 	js_pushstring(J, name);
1883 	ffi_pushimage(J, image);
1884 	PROC_END(2);
1885 }
1886 
js_proc_Do_form(fz_context * ctx,pdf_processor * proc,const char * name,pdf_obj * xobj,pdf_obj * page_resources)1887 static void js_proc_Do_form(fz_context *ctx, pdf_processor *proc, const char *name, pdf_obj *xobj, pdf_obj *page_resources)
1888 {
1889 	PROC_BEGIN("op_Do_form");
1890 	js_pushstring(J, name);
1891 	ffi_pushobj(J, pdf_keep_obj(ctx, xobj));
1892 	ffi_pushobj(J, pdf_keep_obj(ctx, page_resources));
1893 	PROC_END(3);
1894 }
1895 
js_proc_MP(fz_context * ctx,pdf_processor * proc,const char * tag)1896 static void js_proc_MP(fz_context *ctx, pdf_processor *proc, const char *tag)
1897 {
1898 	PROC_BEGIN("op_MP");
1899 	js_pushstring(J, tag);
1900 	PROC_END(1);
1901 }
1902 
js_proc_DP(fz_context * ctx,pdf_processor * proc,const char * tag,pdf_obj * raw,pdf_obj * cooked)1903 static void js_proc_DP(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked)
1904 {
1905 	PROC_BEGIN("op_DP");
1906 	js_pushstring(J, tag);
1907 	ffi_pushobj(J, pdf_keep_obj(ctx, raw));
1908 	PROC_END(2);
1909 }
1910 
js_proc_BMC(fz_context * ctx,pdf_processor * proc,const char * tag)1911 static void js_proc_BMC(fz_context *ctx, pdf_processor *proc, const char *tag)
1912 {
1913 	PROC_BEGIN("op_BMC");
1914 	js_pushstring(J, tag);
1915 	PROC_END(1);
1916 }
1917 
js_proc_BDC(fz_context * ctx,pdf_processor * proc,const char * tag,pdf_obj * raw,pdf_obj * cooked)1918 static void js_proc_BDC(fz_context *ctx, pdf_processor *proc, const char *tag, pdf_obj *raw, pdf_obj *cooked)
1919 {
1920 	PROC_BEGIN("op_BDC");
1921 	js_pushstring(J, tag);
1922 	ffi_pushobj(J, pdf_keep_obj(ctx, raw));
1923 	PROC_END(2);
1924 }
1925 
js_proc_EMC(fz_context * ctx,pdf_processor * proc)1926 static void js_proc_EMC(fz_context *ctx, pdf_processor *proc)
1927 {
1928 	PROC_BEGIN("op_EMC");
1929 	PROC_END(0);
1930 }
1931 
js_proc_BX(fz_context * ctx,pdf_processor * proc)1932 static void js_proc_BX(fz_context *ctx, pdf_processor *proc)
1933 {
1934 	PROC_BEGIN("op_BX");
1935 	PROC_END(0);
1936 }
1937 
js_proc_EX(fz_context * ctx,pdf_processor * proc)1938 static void js_proc_EX(fz_context *ctx, pdf_processor *proc)
1939 {
1940 	PROC_BEGIN("op_EX");
1941 	PROC_END(0);
1942 }
1943 
new_js_processor(fz_context * ctx,js_State * J)1944 static pdf_processor *new_js_processor(fz_context *ctx, js_State *J)
1945 {
1946 	pdf_js_processor *proc = pdf_new_processor(ctx, sizeof *proc);
1947 
1948 	proc->super.close_processor = NULL;
1949 	proc->super.drop_processor = NULL;
1950 
1951 	/* general graphics state */
1952 	proc->super.op_w = js_proc_w;
1953 	proc->super.op_j = js_proc_j;
1954 	proc->super.op_J = js_proc_J;
1955 	proc->super.op_M = js_proc_M;
1956 	proc->super.op_d = js_proc_d;
1957 	proc->super.op_ri = js_proc_ri;
1958 	proc->super.op_i = js_proc_i;
1959 	proc->super.op_gs_begin = js_proc_gs_begin;
1960 	proc->super.op_gs_end = js_proc_gs_end;
1961 
1962 	/* transparency graphics state */
1963 	proc->super.op_gs_BM = NULL;
1964 	proc->super.op_gs_CA = NULL;
1965 	proc->super.op_gs_ca = NULL;
1966 	proc->super.op_gs_SMask = NULL;
1967 
1968 	/* special graphics state */
1969 	proc->super.op_q = js_proc_q;
1970 	proc->super.op_Q = js_proc_Q;
1971 	proc->super.op_cm = js_proc_cm;
1972 
1973 	/* path construction */
1974 	proc->super.op_m = js_proc_m;
1975 	proc->super.op_l = js_proc_l;
1976 	proc->super.op_c = js_proc_c;
1977 	proc->super.op_v = js_proc_v;
1978 	proc->super.op_y = js_proc_y;
1979 	proc->super.op_h = js_proc_h;
1980 	proc->super.op_re = js_proc_re;
1981 
1982 	/* path painting */
1983 	proc->super.op_S = js_proc_S;
1984 	proc->super.op_s = js_proc_s;
1985 	proc->super.op_F = js_proc_F;
1986 	proc->super.op_f = js_proc_f;
1987 	proc->super.op_fstar = js_proc_fstar;
1988 	proc->super.op_B = js_proc_B;
1989 	proc->super.op_Bstar = js_proc_Bstar;
1990 	proc->super.op_b = js_proc_b;
1991 	proc->super.op_bstar = js_proc_bstar;
1992 	proc->super.op_n = js_proc_n;
1993 
1994 	/* clipping paths */
1995 	proc->super.op_W = js_proc_W;
1996 	proc->super.op_Wstar = js_proc_Wstar;
1997 
1998 	/* text objects */
1999 	proc->super.op_BT = js_proc_BT;
2000 	proc->super.op_ET = js_proc_ET;
2001 
2002 	/* text state */
2003 	proc->super.op_Tc = js_proc_Tc;
2004 	proc->super.op_Tw = js_proc_Tw;
2005 	proc->super.op_Tz = js_proc_Tz;
2006 	proc->super.op_TL = js_proc_TL;
2007 	proc->super.op_Tf = js_proc_Tf;
2008 	proc->super.op_Tr = js_proc_Tr;
2009 	proc->super.op_Ts = js_proc_Ts;
2010 
2011 	/* text positioning */
2012 	proc->super.op_Td = js_proc_Td;
2013 	proc->super.op_TD = js_proc_TD;
2014 	proc->super.op_Tm = js_proc_Tm;
2015 	proc->super.op_Tstar = js_proc_Tstar;
2016 
2017 	/* text showing */
2018 	proc->super.op_TJ = js_proc_TJ;
2019 	proc->super.op_Tj = js_proc_Tj;
2020 	proc->super.op_squote = js_proc_squote;
2021 	proc->super.op_dquote = js_proc_dquote;
2022 
2023 	/* type 3 fonts */
2024 	proc->super.op_d0 = js_proc_d0;
2025 	proc->super.op_d1 = js_proc_d1;
2026 
2027 	/* color */
2028 	proc->super.op_CS = js_proc_CS;
2029 	proc->super.op_cs = js_proc_cs;
2030 	proc->super.op_SC_color = js_proc_SC_color;
2031 	proc->super.op_sc_color = js_proc_sc_color;
2032 	proc->super.op_SC_pattern = js_proc_SC_pattern;
2033 	proc->super.op_sc_pattern = js_proc_sc_pattern;
2034 	proc->super.op_SC_shade = js_proc_SC_shade;
2035 	proc->super.op_sc_shade = js_proc_sc_shade;
2036 
2037 	proc->super.op_G = js_proc_G;
2038 	proc->super.op_g = js_proc_g;
2039 	proc->super.op_RG = js_proc_RG;
2040 	proc->super.op_rg = js_proc_rg;
2041 	proc->super.op_K = js_proc_K;
2042 	proc->super.op_k = js_proc_k;
2043 
2044 	/* shadings, images, xobjects */
2045 	proc->super.op_BI = js_proc_BI;
2046 	proc->super.op_sh = js_proc_sh;
2047 	proc->super.op_Do_image = js_proc_Do_image;
2048 	proc->super.op_Do_form = js_proc_Do_form;
2049 
2050 	/* marked content */
2051 	proc->super.op_MP = js_proc_MP;
2052 	proc->super.op_DP = js_proc_DP;
2053 	proc->super.op_BMC = js_proc_BMC;
2054 	proc->super.op_BDC = js_proc_BDC;
2055 	proc->super.op_EMC = js_proc_EMC;
2056 
2057 	/* compatibility */
2058 	proc->super.op_BX = js_proc_BX;
2059 	proc->super.op_EX = js_proc_EX;
2060 
2061 	/* extgstate */
2062 	proc->super.op_gs_OP = NULL;
2063 	proc->super.op_gs_op = NULL;
2064 	proc->super.op_gs_OPM = NULL;
2065 	proc->super.op_gs_UseBlackPtComp = NULL;
2066 
2067 	proc->J = J;
2068 
2069 	return (pdf_processor*)proc;
2070 }
2071 
2072 #endif /* FZ_ENABLE_PDF */
2073 
2074 /* device calling into c from js */
2075 
ffi_Device_close(js_State * J)2076 static void ffi_Device_close(js_State *J)
2077 {
2078 	fz_context *ctx = js_getcontext(J);
2079 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2080 	fz_try(ctx)
2081 		fz_close_device(ctx, dev);
2082 	fz_catch(ctx)
2083 		rethrow(J);
2084 }
2085 
ffi_Device_fillPath(js_State * J)2086 static void ffi_Device_fillPath(js_State *J)
2087 {
2088 	fz_context *ctx = js_getcontext(J);
2089 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2090 	fz_path *path = js_touserdata(J, 1, "fz_path");
2091 	int even_odd = js_toboolean(J, 2);
2092 	fz_matrix ctm = ffi_tomatrix(J, 3);
2093 	struct color c = ffi_tocolor(J, 4);
2094 	fz_color_params color_params = ffi_tocolorparams(J, 7);
2095 	fz_try(ctx)
2096 		fz_fill_path(ctx, dev, path, even_odd, ctm, c.colorspace, c.color, c.alpha, color_params);
2097 	fz_catch(ctx)
2098 		rethrow(J);
2099 }
2100 
ffi_Device_strokePath(js_State * J)2101 static void ffi_Device_strokePath(js_State *J)
2102 {
2103 	fz_context *ctx = js_getcontext(J);
2104 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2105 	fz_path *path = js_touserdata(J, 1, "fz_path");
2106 	fz_stroke_state stroke = ffi_tostroke(J, 2);
2107 	fz_matrix ctm = ffi_tomatrix(J, 3);
2108 	struct color c = ffi_tocolor(J, 4);
2109 	fz_color_params color_params = ffi_tocolorparams(J, 7);
2110 	fz_try(ctx)
2111 		fz_stroke_path(ctx, dev, path, &stroke, ctm, c.colorspace, c.color, c.alpha, color_params);
2112 	fz_catch(ctx)
2113 		rethrow(J);
2114 }
2115 
ffi_Device_clipPath(js_State * J)2116 static void ffi_Device_clipPath(js_State *J)
2117 {
2118 	fz_context *ctx = js_getcontext(J);
2119 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2120 	fz_path *path = js_touserdata(J, 1, "fz_path");
2121 	int even_odd = js_toboolean(J, 2);
2122 	fz_matrix ctm = ffi_tomatrix(J, 3);
2123 	fz_try(ctx)
2124 		fz_clip_path(ctx, dev, path, even_odd, ctm, fz_infinite_rect);
2125 	fz_catch(ctx)
2126 		rethrow(J);
2127 }
2128 
ffi_Device_clipStrokePath(js_State * J)2129 static void ffi_Device_clipStrokePath(js_State *J)
2130 {
2131 	fz_context *ctx = js_getcontext(J);
2132 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2133 	fz_path *path = js_touserdata(J, 1, "fz_path");
2134 	fz_stroke_state stroke = ffi_tostroke(J, 2);
2135 	fz_matrix ctm = ffi_tomatrix(J, 3);
2136 	fz_try(ctx)
2137 		fz_clip_stroke_path(ctx, dev, path, &stroke, ctm, fz_infinite_rect);
2138 	fz_catch(ctx)
2139 		rethrow(J);
2140 }
2141 
ffi_Device_fillText(js_State * J)2142 static void ffi_Device_fillText(js_State *J)
2143 {
2144 	fz_context *ctx = js_getcontext(J);
2145 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2146 	fz_text *text = js_touserdata(J, 1, "fz_text");
2147 	fz_matrix ctm = ffi_tomatrix(J, 2);
2148 	struct color c = ffi_tocolor(J, 3);
2149 	fz_color_params color_params = ffi_tocolorparams(J, 6);
2150 	fz_try(ctx)
2151 		fz_fill_text(ctx, dev, text, ctm, c.colorspace, c.color, c.alpha, color_params);
2152 	fz_catch(ctx)
2153 		rethrow(J);
2154 }
2155 
ffi_Device_strokeText(js_State * J)2156 static void ffi_Device_strokeText(js_State *J)
2157 {
2158 	fz_context *ctx = js_getcontext(J);
2159 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2160 	fz_text *text = js_touserdata(J, 1, "fz_text");
2161 	fz_stroke_state stroke = ffi_tostroke(J, 2);
2162 	fz_matrix ctm = ffi_tomatrix(J, 3);
2163 	struct color c = ffi_tocolor(J, 4);
2164 	fz_color_params color_params = ffi_tocolorparams(J, 7);
2165 	fz_try(ctx)
2166 		fz_stroke_text(ctx, dev, text, &stroke, ctm, c.colorspace, c.color, c.alpha, color_params);
2167 	fz_catch(ctx)
2168 		rethrow(J);
2169 }
2170 
ffi_Device_clipText(js_State * J)2171 static void ffi_Device_clipText(js_State *J)
2172 {
2173 	fz_context *ctx = js_getcontext(J);
2174 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2175 	fz_text *text = js_touserdata(J, 1, "fz_text");
2176 	fz_matrix ctm = ffi_tomatrix(J, 2);
2177 	fz_try(ctx)
2178 		fz_clip_text(ctx, dev, text, ctm, fz_infinite_rect);
2179 	fz_catch(ctx)
2180 		rethrow(J);
2181 }
2182 
ffi_Device_clipStrokeText(js_State * J)2183 static void ffi_Device_clipStrokeText(js_State *J)
2184 {
2185 	fz_context *ctx = js_getcontext(J);
2186 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2187 	fz_text *text = js_touserdata(J, 1, "fz_text");
2188 	fz_stroke_state stroke = ffi_tostroke(J, 2);
2189 	fz_matrix ctm = ffi_tomatrix(J, 3);
2190 	fz_try(ctx)
2191 		fz_clip_stroke_text(ctx, dev, text, &stroke, ctm, fz_infinite_rect);
2192 	fz_catch(ctx)
2193 		rethrow(J);
2194 }
2195 
ffi_Device_ignoreText(js_State * J)2196 static void ffi_Device_ignoreText(js_State *J)
2197 {
2198 	fz_context *ctx = js_getcontext(J);
2199 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2200 	fz_text *text = js_touserdata(J, 1, "fz_text");
2201 	fz_matrix ctm = ffi_tomatrix(J, 2);
2202 	fz_try(ctx)
2203 		fz_ignore_text(ctx, dev, text, ctm);
2204 	fz_catch(ctx)
2205 		rethrow(J);
2206 }
2207 
ffi_Device_fillShade(js_State * J)2208 static void ffi_Device_fillShade(js_State *J)
2209 {
2210 	fz_context *ctx = js_getcontext(J);
2211 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2212 	fz_shade *shade = js_touserdata(J, 1, "fz_shade");
2213 	fz_matrix ctm = ffi_tomatrix(J, 2);
2214 	float alpha = js_tonumber(J, 3);
2215 	fz_color_params color_params = ffi_tocolorparams(J, 4);
2216 	fz_try(ctx)
2217 		fz_fill_shade(ctx, dev, shade, ctm, alpha, color_params);
2218 	fz_catch(ctx)
2219 		rethrow(J);
2220 }
2221 
ffi_Device_fillImage(js_State * J)2222 static void ffi_Device_fillImage(js_State *J)
2223 {
2224 	fz_context *ctx = js_getcontext(J);
2225 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2226 	fz_image *image = js_touserdata(J, 1, "fz_image");
2227 	fz_matrix ctm = ffi_tomatrix(J, 2);
2228 	float alpha = js_tonumber(J, 3);
2229 	fz_color_params color_params = ffi_tocolorparams(J, 4);
2230 	fz_try(ctx)
2231 		fz_fill_image(ctx, dev, image, ctm, alpha, color_params);
2232 	fz_catch(ctx)
2233 		rethrow(J);
2234 }
2235 
ffi_Device_fillImageMask(js_State * J)2236 static void ffi_Device_fillImageMask(js_State *J)
2237 {
2238 	fz_context *ctx = js_getcontext(J);
2239 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2240 	fz_image *image = js_touserdata(J, 1, "fz_image");
2241 	fz_matrix ctm = ffi_tomatrix(J, 2);
2242 	struct color c = ffi_tocolor(J, 3);
2243 	fz_color_params color_params = ffi_tocolorparams(J, 6);
2244 	fz_try(ctx)
2245 		fz_fill_image_mask(ctx, dev, image, ctm, c.colorspace, c.color, c.alpha, color_params);
2246 	fz_catch(ctx)
2247 		rethrow(J);
2248 }
2249 
ffi_Device_clipImageMask(js_State * J)2250 static void ffi_Device_clipImageMask(js_State *J)
2251 {
2252 	fz_context *ctx = js_getcontext(J);
2253 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2254 	fz_image *image = js_touserdata(J, 1, "fz_image");
2255 	fz_matrix ctm = ffi_tomatrix(J, 2);
2256 	fz_try(ctx)
2257 		fz_clip_image_mask(ctx, dev, image, ctm, fz_infinite_rect);
2258 	fz_catch(ctx)
2259 		rethrow(J);
2260 }
2261 
ffi_Device_popClip(js_State * J)2262 static void ffi_Device_popClip(js_State *J)
2263 {
2264 	fz_context *ctx = js_getcontext(J);
2265 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2266 	fz_try(ctx)
2267 		fz_pop_clip(ctx, dev);
2268 	fz_catch(ctx)
2269 		rethrow(J);
2270 }
2271 
ffi_Device_beginMask(js_State * J)2272 static void ffi_Device_beginMask(js_State *J)
2273 {
2274 	fz_context *ctx = js_getcontext(J);
2275 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2276 	fz_rect area = ffi_torect(J, 1);
2277 	int luminosity = js_toboolean(J, 2);
2278 	struct color c = ffi_tocolor(J, 3);
2279 	fz_color_params color_params = ffi_tocolorparams(J, 6);
2280 	fz_try(ctx)
2281 		fz_begin_mask(ctx, dev, area, luminosity, c.colorspace, c.color, color_params);
2282 	fz_catch(ctx)
2283 		rethrow(J);
2284 }
2285 
ffi_Device_endMask(js_State * J)2286 static void ffi_Device_endMask(js_State *J)
2287 {
2288 	fz_context *ctx = js_getcontext(J);
2289 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2290 	fz_try(ctx)
2291 		fz_end_mask(ctx, dev);
2292 	fz_catch(ctx)
2293 		rethrow(J);
2294 }
2295 
ffi_Device_beginGroup(js_State * J)2296 static void ffi_Device_beginGroup(js_State *J)
2297 {
2298 	fz_context *ctx = js_getcontext(J);
2299 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2300 	fz_rect area = ffi_torect(J, 1);
2301 	int isolated = js_toboolean(J, 2);
2302 	int knockout = js_toboolean(J, 3);
2303 	int blendmode = fz_lookup_blendmode(js_tostring(J, 4));
2304 	float alpha = js_tonumber(J, 5);
2305 	fz_try(ctx)
2306 		fz_begin_group(ctx, dev, area, NULL, isolated, knockout, blendmode, alpha);
2307 	fz_catch(ctx)
2308 		rethrow(J);
2309 }
2310 
ffi_Device_endGroup(js_State * J)2311 static void ffi_Device_endGroup(js_State *J)
2312 {
2313 	fz_context *ctx = js_getcontext(J);
2314 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2315 	fz_try(ctx)
2316 		fz_end_group(ctx, dev);
2317 	fz_catch(ctx)
2318 		rethrow(J);
2319 }
2320 
ffi_Device_beginTile(js_State * J)2321 static void ffi_Device_beginTile(js_State *J)
2322 {
2323 	fz_context *ctx = js_getcontext(J);
2324 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2325 	fz_rect area = ffi_torect(J, 1);
2326 	fz_rect view = ffi_torect(J, 2);
2327 	float xstep = js_tonumber(J, 3);
2328 	float ystep = js_tonumber(J, 4);
2329 	fz_matrix ctm = ffi_tomatrix(J, 5);
2330 	int id = js_tonumber(J, 6);
2331 	int n = 0;
2332 	fz_try(ctx)
2333 		n = fz_begin_tile_id(ctx, dev, area, view, xstep, ystep, ctm, id);
2334 	fz_catch(ctx)
2335 		rethrow(J);
2336 	js_pushnumber(J, n);
2337 }
2338 
ffi_Device_endTile(js_State * J)2339 static void ffi_Device_endTile(js_State *J)
2340 {
2341 	fz_context *ctx = js_getcontext(J);
2342 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2343 	fz_try(ctx)
2344 		fz_end_tile(ctx, dev);
2345 	fz_catch(ctx)
2346 		rethrow(J);
2347 }
2348 
ffi_Device_beginLayer(js_State * J)2349 static void ffi_Device_beginLayer(js_State *J)
2350 {
2351 	fz_context *ctx = js_getcontext(J);
2352 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2353 	const char *name = js_tostring(J, 1);
2354 	fz_try(ctx)
2355 		fz_begin_layer(ctx, dev, name);
2356 	fz_catch(ctx)
2357 		rethrow(J);
2358 }
2359 
ffi_Device_endLayer(js_State * J)2360 static void ffi_Device_endLayer(js_State *J)
2361 {
2362 	fz_context *ctx = js_getcontext(J);
2363 	fz_device *dev = js_touserdata(J, 0, "fz_device");
2364 	fz_try(ctx)
2365 		fz_end_layer(ctx, dev);
2366 	fz_catch(ctx)
2367 		rethrow(J);
2368 }
2369 
2370 /* mupdf module */
2371 
ffi_readFile(js_State * J)2372 static void ffi_readFile(js_State *J)
2373 {
2374 	fz_context *ctx = js_getcontext(J);
2375 	const char *filename = js_tostring(J, 1);
2376 	fz_buffer *buf = NULL;
2377 	fz_try(ctx)
2378 		buf = fz_read_file(ctx, filename);
2379 	fz_catch(ctx)
2380 		rethrow(J);
2381 	ffi_pushbuffer(J, buf);
2382 }
2383 
ffi_setUserCSS(js_State * J)2384 static void ffi_setUserCSS(js_State *J)
2385 {
2386 	fz_context *ctx = js_getcontext(J);
2387 	const char *user_css = js_tostring(J, 1);
2388 	int use_doc_css = js_iscoercible(J, 2) ? js_toboolean(J, 2) : 1;
2389 	fz_try(ctx) {
2390 		fz_set_user_css(ctx, user_css);
2391 		fz_set_use_document_css(ctx, use_doc_css);
2392 	} fz_catch(ctx)
2393 		rethrow(J);
2394 }
2395 
ffi_new_Buffer(js_State * J)2396 static void ffi_new_Buffer(js_State *J)
2397 {
2398 	fz_context *ctx = js_getcontext(J);
2399 	int n = js_isdefined(J, 1) ? js_tonumber(J, 1) : 0;
2400 	fz_buffer *buf = NULL;
2401 	fz_try(ctx)
2402 		buf = fz_new_buffer(ctx, n);
2403 	fz_catch(ctx)
2404 		rethrow(J);
2405 	ffi_pushbuffer(J, buf);
2406 }
2407 
ffi_Buffer_writeByte(js_State * J)2408 static void ffi_Buffer_writeByte(js_State *J)
2409 {
2410 	fz_context *ctx = js_getcontext(J);
2411 	fz_buffer *buf = js_touserdata(J, 0, "fz_buffer");
2412 	unsigned char val = js_tonumber(J, 1);
2413 	fz_try(ctx)
2414 		fz_append_byte(ctx, buf, val);
2415 	fz_catch(ctx)
2416 		rethrow(J);
2417 }
2418 
ffi_Buffer_writeRune(js_State * J)2419 static void ffi_Buffer_writeRune(js_State *J)
2420 {
2421 	fz_context *ctx = js_getcontext(J);
2422 	fz_buffer *buf = js_touserdata(J, 0, "fz_buffer");
2423 	int val = js_tonumber(J, 1);
2424 	fz_try(ctx)
2425 		fz_append_rune(ctx, buf, val);
2426 	fz_catch(ctx)
2427 		rethrow(J);
2428 }
2429 
ffi_Buffer_write(js_State * J)2430 static void ffi_Buffer_write(js_State *J)
2431 {
2432 	fz_context *ctx = js_getcontext(J);
2433 	fz_buffer *buf = js_touserdata(J, 0, "fz_buffer");
2434 	int i, n = js_gettop(J);
2435 
2436 	for (i = 1; i < n; ++i) {
2437 		const char *s = js_tostring(J, i);
2438 		fz_try(ctx) {
2439 			if (i > 1)
2440 				fz_append_byte(ctx, buf, ' ');
2441 			fz_append_string(ctx, buf, s);
2442 		} fz_catch(ctx)
2443 			rethrow(J);
2444 	}
2445 }
2446 
ffi_Buffer_writeLine(js_State * J)2447 static void ffi_Buffer_writeLine(js_State *J)
2448 {
2449 	fz_context *ctx = js_getcontext(J);
2450 	fz_buffer *buf = js_touserdata(J, 0, "fz_buffer");
2451 	ffi_Buffer_write(J);
2452 	fz_try(ctx)
2453 		fz_append_byte(ctx, buf, '\n');
2454 	fz_catch(ctx)
2455 		rethrow(J);
2456 }
2457 
ffi_Buffer_writeBuffer(js_State * J)2458 static void ffi_Buffer_writeBuffer(js_State *J)
2459 {
2460 	fz_context *ctx = js_getcontext(J);
2461 	fz_buffer *buf = js_touserdata(J, 0, "fz_buffer");
2462 	fz_buffer *cat = js_touserdata(J, 1, "fz_buffer");
2463 	fz_try(ctx)
2464 		fz_append_buffer(ctx, buf, cat);
2465 	fz_catch(ctx)
2466 		rethrow(J);
2467 }
2468 
ffi_Buffer_save(js_State * J)2469 static void ffi_Buffer_save(js_State *J)
2470 {
2471 	fz_context *ctx = js_getcontext(J);
2472 	fz_buffer *buf = js_touserdata(J, 0, "fz_buffer");
2473 	const char *filename = js_tostring(J, 1);
2474 	fz_try(ctx)
2475 		fz_save_buffer(ctx, buf, filename);
2476 	fz_catch(ctx)
2477 		rethrow(J);
2478 }
2479 
ffi_new_Document(js_State * J)2480 static void ffi_new_Document(js_State *J)
2481 {
2482 	fz_context *ctx = js_getcontext(J);
2483 	const char *filename = js_tostring(J, 1);
2484 	fz_document *doc = NULL;
2485 
2486 	fz_try(ctx)
2487 		doc = fz_open_document(ctx, filename);
2488 	fz_catch(ctx)
2489 		rethrow(J);
2490 
2491 	ffi_pushdocument(J, doc);
2492 }
2493 
ffi_Document_isPDF(js_State * J)2494 static void ffi_Document_isPDF(js_State *J)
2495 {
2496 	js_pushboolean(J, js_isuserdata(J, 0, "pdf_document"));
2497 }
2498 
ffi_Document_countPages(js_State * J)2499 static void ffi_Document_countPages(js_State *J)
2500 {
2501 	fz_context *ctx = js_getcontext(J);
2502 	fz_document *doc = ffi_todocument(J, 0);
2503 	int count = 0;
2504 
2505 	fz_try(ctx)
2506 		count = fz_count_pages(ctx, doc);
2507 	fz_catch(ctx)
2508 		rethrow(J);
2509 
2510 	js_pushnumber(J, count);
2511 }
2512 
ffi_Document_loadPage(js_State * J)2513 static void ffi_Document_loadPage(js_State *J)
2514 {
2515 	fz_context *ctx = js_getcontext(J);
2516 	fz_document *doc = ffi_todocument(J, 0);
2517 	int number = js_tointeger(J, 1);
2518 	fz_page *page = NULL;
2519 
2520 	fz_try(ctx)
2521 		page = fz_load_page(ctx, doc, number);
2522 	fz_catch(ctx)
2523 		rethrow(J);
2524 
2525 	ffi_pushpage(J, page);
2526 }
2527 
ffi_Document_needsPassword(js_State * J)2528 static void ffi_Document_needsPassword(js_State *J)
2529 {
2530 	fz_context *ctx = js_getcontext(J);
2531 	fz_document *doc = ffi_todocument(J, 0);
2532 	int b = 0;
2533 
2534 	fz_try(ctx)
2535 		b = fz_needs_password(ctx, doc);
2536 	fz_catch(ctx)
2537 		rethrow(J);
2538 
2539 	js_pushboolean(J, b);
2540 }
2541 
ffi_Document_authenticatePassword(js_State * J)2542 static void ffi_Document_authenticatePassword(js_State *J)
2543 {
2544 	fz_context *ctx = js_getcontext(J);
2545 	fz_document *doc = ffi_todocument(J, 0);
2546 	const char *password = js_tostring(J, 1);
2547 	int b = 0;
2548 
2549 	fz_try(ctx)
2550 		b = fz_authenticate_password(ctx, doc, password);
2551 	fz_catch(ctx)
2552 		rethrow(J);
2553 
2554 	js_pushboolean(J, b);
2555 }
2556 
ffi_Document_hasPermission(js_State * J)2557 static void ffi_Document_hasPermission(js_State *J)
2558 {
2559 	fz_context *ctx = js_getcontext(J);
2560 	fz_document *doc = ffi_todocument(J, 0);
2561 	const char *perm = js_tostring(J, 1);
2562 	int flag = 0;
2563 	int result = 0;
2564 
2565 	if (!strcmp(perm, "print")) flag = FZ_PERMISSION_PRINT;
2566 	else if (!strcmp(perm, "annotate")) flag = FZ_PERMISSION_ANNOTATE;
2567 	else if (!strcmp(perm, "edit")) flag = FZ_PERMISSION_EDIT;
2568 	else if (!strcmp(perm, "copy")) flag = FZ_PERMISSION_COPY;
2569 	else js_error(J, "invalid permission name");
2570 
2571 	fz_try(ctx)
2572 		result = fz_has_permission(ctx, doc, flag);
2573 	fz_catch(ctx)
2574 		rethrow(J);
2575 
2576 	js_pushboolean(J, result);
2577 }
2578 
ffi_Document_getMetaData(js_State * J)2579 static void ffi_Document_getMetaData(js_State *J)
2580 {
2581 	fz_context *ctx = js_getcontext(J);
2582 	fz_document *doc = ffi_todocument(J, 0);
2583 	const char *key = js_tostring(J, 1);
2584 	char info[256];
2585 	int found;
2586 
2587 	fz_try(ctx)
2588 		found = fz_lookup_metadata(ctx, doc, key, info, sizeof info);
2589 	fz_catch(ctx)
2590 		rethrow(J);
2591 
2592 	if (found)
2593 		js_pushstring(J, info);
2594 	else
2595 		js_pushundefined(J);
2596 }
2597 
ffi_Document_isReflowable(js_State * J)2598 static void ffi_Document_isReflowable(js_State *J)
2599 {
2600 	fz_context *ctx = js_getcontext(J);
2601 	fz_document *doc = ffi_todocument(J, 0);
2602 	int is_reflowable = 0;
2603 
2604 	fz_try(ctx)
2605 		is_reflowable = fz_is_document_reflowable(ctx, doc);
2606 	fz_catch(ctx)
2607 		rethrow(J);
2608 
2609 	js_pushboolean(J, is_reflowable);
2610 }
2611 
ffi_Document_layout(js_State * J)2612 static void ffi_Document_layout(js_State *J)
2613 {
2614 	fz_context *ctx = js_getcontext(J);
2615 	fz_document *doc = ffi_todocument(J, 0);
2616 	float w = js_tonumber(J, 1);
2617 	float h = js_tonumber(J, 2);
2618 	float em = js_tonumber(J, 3);
2619 
2620 	fz_try(ctx)
2621 		fz_layout_document(ctx, doc, w, h, em);
2622 	fz_catch(ctx)
2623 		rethrow(J);
2624 }
2625 
to_outline(js_State * J,fz_outline * outline)2626 static void to_outline(js_State *J, fz_outline *outline)
2627 {
2628 	int i = 0;
2629 	js_newarray(J);
2630 	while (outline) {
2631 		js_newobject(J);
2632 
2633 		if (outline->title)
2634 			js_pushstring(J, outline->title);
2635 		else
2636 			js_pushundefined(J);
2637 		js_setproperty(J, -2, "title");
2638 
2639 		if (outline->uri)
2640 			js_pushstring(J, outline->uri);
2641 		else
2642 			js_pushundefined(J);
2643 		js_setproperty(J, -2, "uri");
2644 
2645 		if (outline->page >= 0)
2646 			js_pushnumber(J, outline->page);
2647 		else
2648 			js_pushundefined(J);
2649 		js_setproperty(J, -2, "page");
2650 
2651 		if (outline->down) {
2652 			to_outline(J, outline->down);
2653 			js_setproperty(J, -2, "down");
2654 		}
2655 
2656 		js_setindex(J, -2, i++);
2657 		outline = outline->next;
2658 	}
2659 }
2660 
ffi_Document_loadOutline(js_State * J)2661 static void ffi_Document_loadOutline(js_State *J)
2662 {
2663 	fz_context *ctx = js_getcontext(J);
2664 	fz_document *doc = ffi_todocument(J, 0);
2665 	fz_outline *outline = NULL;
2666 
2667 	fz_try(ctx)
2668 		outline = fz_load_outline(ctx, doc);
2669 	fz_catch(ctx)
2670 		rethrow(J);
2671 
2672 	to_outline(J, outline);
2673 
2674 	fz_drop_outline(ctx, outline);
2675 }
2676 
ffi_Page_isPDF(js_State * J)2677 static void ffi_Page_isPDF(js_State *J)
2678 {
2679 	js_pushboolean(J, js_isuserdata(J, 0, "pdf_page"));
2680 }
2681 
ffi_Page_bound(js_State * J)2682 static void ffi_Page_bound(js_State *J)
2683 {
2684 	fz_context *ctx = js_getcontext(J);
2685 	fz_page *page = ffi_topage(J, 0);
2686 	fz_rect bounds;
2687 
2688 	fz_try(ctx)
2689 		bounds = fz_bound_page(ctx, page);
2690 	fz_catch(ctx)
2691 		rethrow(J);
2692 
2693 	ffi_pushrect(J, bounds);
2694 }
2695 
ffi_Page_run(js_State * J)2696 static void ffi_Page_run(js_State *J)
2697 {
2698 	fz_context *ctx = js_getcontext(J);
2699 	fz_page *page = ffi_topage(J, 0);
2700 	fz_device *device = NULL;
2701 	fz_matrix ctm = ffi_tomatrix(J, 2);
2702 	int no_annots = js_isdefined(J, 3) ? js_toboolean(J, 3) : 0;
2703 
2704 	if (js_isuserdata(J, 1, "fz_device")) {
2705 		device = js_touserdata(J, 1, "fz_device");
2706 		fz_try(ctx)
2707 			if (no_annots)
2708 				fz_run_page_contents(ctx, page, device, ctm, NULL);
2709 			else
2710 				fz_run_page(ctx, page, device, ctm, NULL);
2711 		fz_catch(ctx)
2712 			rethrow(J);
2713 	} else {
2714 		device = new_js_device(ctx, J);
2715 		js_copy(J, 1); /* put the js device on the top so the callbacks know where to get it */
2716 		fz_try(ctx) {
2717 			if (no_annots)
2718 				fz_run_page_contents(ctx, page, device, ctm, NULL);
2719 			else
2720 				fz_run_page(ctx, page, device, ctm, NULL);
2721 			fz_close_device(ctx, device);
2722 		}
2723 		fz_always(ctx)
2724 			fz_drop_device(ctx, device);
2725 		fz_catch(ctx)
2726 			rethrow(J);
2727 	}
2728 }
2729 
ffi_Page_toDisplayList(js_State * J)2730 static void ffi_Page_toDisplayList(js_State *J)
2731 {
2732 	fz_context *ctx = js_getcontext(J);
2733 	fz_page *page = ffi_topage(J, 0);
2734 	int no_annots = js_isdefined(J, 1) ? js_toboolean(J, 1) : 0;
2735 	fz_display_list *list = NULL;
2736 
2737 	fz_try(ctx)
2738 		if (no_annots)
2739 			list = fz_new_display_list_from_page_contents(ctx, page);
2740 		else
2741 			list = fz_new_display_list_from_page(ctx, page);
2742 	fz_catch(ctx)
2743 		rethrow(J);
2744 
2745 	js_getregistry(J, "fz_display_list");
2746 	js_newuserdata(J, "fz_display_list", list, ffi_gc_fz_display_list);
2747 }
2748 
ffi_Page_toPixmap(js_State * J)2749 static void ffi_Page_toPixmap(js_State *J)
2750 {
2751 	fz_context *ctx = js_getcontext(J);
2752 	fz_page *page = ffi_topage(J, 0);
2753 	fz_matrix ctm = ffi_tomatrix(J, 1);
2754 	fz_colorspace *colorspace = js_touserdata(J, 2, "fz_colorspace");
2755 	int alpha = js_toboolean(J, 3);
2756 	int no_annots = js_isdefined(J, 4) ? js_toboolean(J, 4) : 0;
2757 	fz_pixmap *pixmap = NULL;
2758 
2759 	fz_try(ctx)
2760 		if (no_annots)
2761 			pixmap = fz_new_pixmap_from_page_contents(ctx, page, ctm, colorspace, alpha);
2762 		else
2763 			pixmap = fz_new_pixmap_from_page(ctx, page, ctm, colorspace, alpha);
2764 	fz_catch(ctx)
2765 		rethrow(J);
2766 
2767 	js_getregistry(J, "fz_pixmap");
2768 	js_newuserdata(J, "fz_pixmap", pixmap, ffi_gc_fz_pixmap);
2769 }
2770 
ffi_Page_toStructuredText(js_State * J)2771 static void ffi_Page_toStructuredText(js_State *J)
2772 {
2773 	fz_context *ctx = js_getcontext(J);
2774 	fz_page *page = ffi_topage(J, 0);
2775 	const char *options = js_iscoercible(J, 1) ? js_tostring(J, 1) : NULL;
2776 	fz_stext_options so;
2777 	fz_stext_page *text = NULL;
2778 
2779 	fz_try(ctx) {
2780 		fz_parse_stext_options(ctx, &so, options);
2781 		text = fz_new_stext_page_from_page(ctx, page, &so);
2782 	}
2783 	fz_catch(ctx)
2784 		rethrow(J);
2785 
2786 	js_getregistry(J, "fz_stext_page");
2787 	js_newuserdata(J, "fz_stext_page", text, ffi_gc_fz_stext_page);
2788 }
2789 
ffi_Page_search(js_State * J)2790 static void ffi_Page_search(js_State *J)
2791 {
2792 	fz_context *ctx = js_getcontext(J);
2793 	fz_page *page = ffi_topage(J, 0);
2794 	const char *needle = js_tostring(J, 1);
2795 	fz_quad hits[256];
2796 	int i, n = 0;
2797 
2798 	fz_try(ctx)
2799 		n = fz_search_page(ctx, page, needle, hits, nelem(hits));
2800 	fz_catch(ctx)
2801 		rethrow(J);
2802 
2803 	js_newarray(J);
2804 	for (i = 0; i < n; ++i) {
2805 		ffi_pushquad(J, hits[i]);
2806 		js_setindex(J, -2, i);
2807 	}
2808 }
2809 
ffi_Page_getLinks(js_State * J)2810 static void ffi_Page_getLinks(js_State *J)
2811 {
2812 	fz_context *ctx = js_getcontext(J);
2813 	fz_page *page = ffi_topage(J, 0);
2814 	fz_link *link, *links = NULL;
2815 	int i = 0;
2816 
2817 	js_newarray(J);
2818 
2819 	fz_try(ctx)
2820 		links = fz_load_links(ctx, page);
2821 	fz_catch(ctx)
2822 		rethrow(J);
2823 
2824 	js_newarray(J);
2825 	for (link = links; link; link = link->next) {
2826 		js_newobject(J);
2827 
2828 		ffi_pushrect(J, link->rect);
2829 		js_setproperty(J, -2, "bounds");
2830 
2831 		js_pushstring(J, link->uri);
2832 		js_setproperty(J, -2, "uri");
2833 
2834 		js_setindex(J, -2, i++);
2835 	}
2836 
2837 	fz_drop_link(ctx, links);
2838 }
2839 
ffi_ColorSpace_getNumberOfComponents(js_State * J)2840 static void ffi_ColorSpace_getNumberOfComponents(js_State *J)
2841 {
2842 	fz_colorspace *colorspace = js_touserdata(J, 0, "fz_colorspace");
2843 	fz_context *ctx = js_getcontext(J);
2844 	js_pushnumber(J, fz_colorspace_n(ctx, colorspace));
2845 }
2846 
ffi_ColorSpace_toString(js_State * J)2847 static void ffi_ColorSpace_toString(js_State *J)
2848 {
2849 	fz_colorspace *colorspace = js_touserdata(J, 0, "fz_colorspace");
2850 	fz_context *ctx = js_getcontext(J);
2851 	js_pushstring(J, fz_colorspace_name(ctx, colorspace));
2852 }
2853 
ffi_new_Pixmap(js_State * J)2854 static void ffi_new_Pixmap(js_State *J)
2855 {
2856 	fz_context *ctx = js_getcontext(J);
2857 	fz_colorspace *colorspace = js_touserdata(J, 1, "fz_colorspace");
2858 	fz_irect bounds = ffi_toirect(J, 2);
2859 	int alpha = js_toboolean(J, 3);
2860 	fz_pixmap *pixmap = NULL;
2861 
2862 	fz_try(ctx)
2863 		pixmap = fz_new_pixmap_with_bbox(ctx, colorspace, bounds, 0, alpha);
2864 	fz_catch(ctx)
2865 		rethrow(J);
2866 
2867 	js_getregistry(J, "fz_pixmap");
2868 	js_newuserdata(J, "fz_pixmap", pixmap, ffi_gc_fz_pixmap);
2869 }
2870 
ffi_Pixmap_warp(js_State * J)2871 static void ffi_Pixmap_warp(js_State *J)
2872 {
2873 	fz_context *ctx = js_getcontext(J);
2874 	fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2875 	/* 1 = array of 8 floats for points */
2876 	int w = js_tonumber(J, 2);
2877 	int h = js_tonumber(J, 3);
2878 	fz_pixmap *dest = NULL;
2879 	fz_point points[4];
2880 	int i;
2881 
2882 	if (w < 0 || h < 0 || !js_isarray(J, 1) || js_getlength(J, 1) != 8)
2883 		js_throw(J);
2884 
2885 	for (i = 0; i < 8; i++)
2886 	{
2887 		float *f = i&1 ? &points[i>>1].y : &points[i>>1].x;
2888 		js_getindex(J, 1, i);
2889 		*f = js_tonumber(J, -1);
2890 		js_pop(J, 1);
2891 	}
2892 
2893 	fz_try(ctx)
2894 		dest = fz_warp_pixmap(ctx, pixmap, points, w, h);
2895 	fz_catch(ctx)
2896 		rethrow(J);
2897 
2898 	js_getregistry(J, "fz_pixmap");
2899 	js_newuserdata(J, "fz_pixmap", dest, ffi_gc_fz_pixmap);
2900 }
2901 
ffi_Pixmap_saveAsPNG(js_State * J)2902 static void ffi_Pixmap_saveAsPNG(js_State *J)
2903 {
2904 	fz_context *ctx = js_getcontext(J);
2905 	fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2906 	const char *filename = js_tostring(J, 1);
2907 
2908 	fz_try(ctx)
2909 		fz_save_pixmap_as_png(ctx, pixmap, filename);
2910 	fz_catch(ctx)
2911 		rethrow(J);
2912 }
2913 
ffi_Pixmap_bound(js_State * J)2914 static void ffi_Pixmap_bound(js_State *J)
2915 {
2916 	fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2917 	fz_rect bounds;
2918 
2919 	// fz_irect and fz_pixmap_bbox instead
2920 	bounds.x0 = pixmap->x;
2921 	bounds.y0 = pixmap->y;
2922 	bounds.x1 = pixmap->x + pixmap->w;
2923 	bounds.y1 = pixmap->y + pixmap->h;
2924 
2925 	ffi_pushrect(J, bounds);
2926 }
2927 
ffi_Pixmap_clear(js_State * J)2928 static void ffi_Pixmap_clear(js_State *J)
2929 {
2930 	fz_context *ctx = js_getcontext(J);
2931 	fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2932 	if (js_isdefined(J, 1)) {
2933 		int value = js_tonumber(J, 1);
2934 		fz_try(ctx)
2935 			fz_clear_pixmap_with_value(ctx, pixmap, value);
2936 		fz_catch(ctx)
2937 			rethrow(J);
2938 	} else {
2939 		fz_try(ctx)
2940 			fz_clear_pixmap(ctx, pixmap);
2941 		fz_catch(ctx)
2942 			rethrow(J);
2943 	}
2944 }
2945 
ffi_Pixmap_getX(js_State * J)2946 static void ffi_Pixmap_getX(js_State *J)
2947 {
2948 	fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2949 	js_pushnumber(J, pixmap->x);
2950 }
2951 
ffi_Pixmap_getY(js_State * J)2952 static void ffi_Pixmap_getY(js_State *J)
2953 {
2954 	fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2955 	js_pushnumber(J, pixmap->y);
2956 }
2957 
ffi_Pixmap_getWidth(js_State * J)2958 static void ffi_Pixmap_getWidth(js_State *J)
2959 {
2960 	fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2961 	js_pushnumber(J, pixmap->w);
2962 }
2963 
ffi_Pixmap_getHeight(js_State * J)2964 static void ffi_Pixmap_getHeight(js_State *J)
2965 {
2966 	fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2967 	js_pushnumber(J, pixmap->h);
2968 }
2969 
ffi_Pixmap_getNumberOfComponents(js_State * J)2970 static void ffi_Pixmap_getNumberOfComponents(js_State *J)
2971 {
2972 	fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2973 	js_pushnumber(J, pixmap->n);
2974 }
2975 
ffi_Pixmap_getAlpha(js_State * J)2976 static void ffi_Pixmap_getAlpha(js_State *J)
2977 {
2978 	fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2979 	js_pushnumber(J, pixmap->alpha);
2980 }
2981 
ffi_Pixmap_getStride(js_State * J)2982 static void ffi_Pixmap_getStride(js_State *J)
2983 {
2984 	fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2985 	js_pushnumber(J, pixmap->stride);
2986 }
2987 
ffi_Pixmap_getSample(js_State * J)2988 static void ffi_Pixmap_getSample(js_State *J)
2989 {
2990 	fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2991 	int x = js_tointeger(J, 1);
2992 	int y = js_tointeger(J, 2);
2993 	int k = js_tointeger(J, 3);
2994 	if (x < 0 || x >= pixmap->w) js_rangeerror(J, "X out of range");
2995 	if (y < 0 || y >= pixmap->h) js_rangeerror(J, "Y out of range");
2996 	if (k < 0 || k >= pixmap->n) js_rangeerror(J, "N out of range");
2997 	js_pushnumber(J, pixmap->samples[(x + y * pixmap->w) * pixmap->n + k]);
2998 }
2999 
ffi_Pixmap_getXResolution(js_State * J)3000 static void ffi_Pixmap_getXResolution(js_State *J)
3001 {
3002 	fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
3003 	js_pushnumber(J, pixmap->xres);
3004 }
3005 
ffi_Pixmap_getYResolution(js_State * J)3006 static void ffi_Pixmap_getYResolution(js_State *J)
3007 {
3008 	fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
3009 	js_pushnumber(J, pixmap->yres);
3010 }
3011 
ffi_Pixmap_getColorSpace(js_State * J)3012 static void ffi_Pixmap_getColorSpace(js_State *J)
3013 {
3014 	fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
3015 	ffi_pushcolorspace(J, pixmap->colorspace);
3016 }
3017 
ffi_new_Image(js_State * J)3018 static void ffi_new_Image(js_State *J)
3019 {
3020 	fz_context *ctx = js_getcontext(J);
3021 	fz_image *image = NULL;
3022 
3023 	if (js_isuserdata(J, 1, "fz_pixmap")) {
3024 		fz_pixmap *pixmap = js_touserdata(J, 1, "fz_pixmap");
3025 		fz_image *mask = NULL;
3026 		if (js_isuserdata(J, 2, "fz_image"))
3027 			mask = js_touserdata(J, 2, "fz_image");
3028 		fz_try(ctx)
3029 			image = fz_new_image_from_pixmap(ctx, pixmap, mask);
3030 		fz_catch(ctx)
3031 			rethrow(J);
3032 	} else {
3033 		const char *name = js_tostring(J, 1);
3034 		fz_try(ctx)
3035 			image = fz_new_image_from_file(ctx, name);
3036 		fz_catch(ctx)
3037 			rethrow(J);
3038 	}
3039 
3040 	ffi_pushimage_own(J, image);
3041 }
3042 
ffi_Image_getWidth(js_State * J)3043 static void ffi_Image_getWidth(js_State *J)
3044 {
3045 	fz_image *image = js_touserdata(J, 0, "fz_image");
3046 	js_pushnumber(J, image->w);
3047 }
3048 
ffi_Image_getHeight(js_State * J)3049 static void ffi_Image_getHeight(js_State *J)
3050 {
3051 	fz_image *image = js_touserdata(J, 0, "fz_image");
3052 	js_pushnumber(J, image->h);
3053 }
3054 
ffi_Image_getXResolution(js_State * J)3055 static void ffi_Image_getXResolution(js_State *J)
3056 {
3057 	fz_image *image = js_touserdata(J, 0, "fz_image");
3058 	js_pushnumber(J, image->xres);
3059 }
3060 
ffi_Image_getYResolution(js_State * J)3061 static void ffi_Image_getYResolution(js_State *J)
3062 {
3063 	fz_image *image = js_touserdata(J, 0, "fz_image");
3064 	js_pushnumber(J, image->yres);
3065 }
3066 
ffi_Image_getNumberOfComponents(js_State * J)3067 static void ffi_Image_getNumberOfComponents(js_State *J)
3068 {
3069 	fz_image *image = js_touserdata(J, 0, "fz_image");
3070 	js_pushnumber(J, image->n);
3071 }
3072 
ffi_Image_getBitsPerComponent(js_State * J)3073 static void ffi_Image_getBitsPerComponent(js_State *J)
3074 {
3075 	fz_image *image = js_touserdata(J, 0, "fz_image");
3076 	js_pushnumber(J, image->bpc);
3077 }
3078 
ffi_Image_getInterpolate(js_State * J)3079 static void ffi_Image_getInterpolate(js_State *J)
3080 {
3081 	fz_image *image = js_touserdata(J, 0, "fz_image");
3082 	js_pushboolean(J, image->interpolate);
3083 }
3084 
ffi_Image_getImageMask(js_State * J)3085 static void ffi_Image_getImageMask(js_State *J)
3086 {
3087 	fz_image *image = js_touserdata(J, 0, "fz_image");
3088 	js_pushboolean(J, image->imagemask);
3089 }
3090 
ffi_Image_getMask(js_State * J)3091 static void ffi_Image_getMask(js_State *J)
3092 {
3093 	fz_image *image = js_touserdata(J, 0, "fz_image");
3094 	if (image->mask)
3095 		ffi_pushimage(J, image->mask);
3096 	else
3097 		js_pushnull(J);
3098 }
3099 
ffi_Image_getColorSpace(js_State * J)3100 static void ffi_Image_getColorSpace(js_State *J)
3101 {
3102 	fz_image *image = js_touserdata(J, 0, "fz_image");
3103 	ffi_pushcolorspace(J, image->colorspace);
3104 }
3105 
ffi_Image_toPixmap(js_State * J)3106 static void ffi_Image_toPixmap(js_State *J)
3107 {
3108 	fz_context *ctx = js_getcontext(J);
3109 	fz_image *image = js_touserdata(J, 0, "fz_image");
3110 	fz_matrix matrix_, *matrix = NULL;
3111 	fz_pixmap *pixmap = NULL;
3112 
3113 	if (js_isnumber(J, 1) && js_isnumber(J, 2)) {
3114 		matrix_ = fz_scale(js_tonumber(J, 1), js_tonumber(J, 2));
3115 		matrix = &matrix_;
3116 	}
3117 
3118 	fz_try(ctx)
3119 		pixmap = fz_get_pixmap_from_image(ctx, image, NULL, matrix, NULL, NULL);
3120 	fz_catch(ctx)
3121 		rethrow(J);
3122 
3123 	js_getregistry(J, "fz_pixmap");
3124 	js_newuserdata(J, "fz_pixmap", pixmap, ffi_gc_fz_pixmap);
3125 }
3126 
ffi_Shade_bound(js_State * J)3127 static void ffi_Shade_bound(js_State *J)
3128 {
3129 	fz_context *ctx = js_getcontext(J);
3130 	fz_shade *shade = js_touserdata(J, 0, "fz_shade");
3131 	fz_matrix ctm = ffi_tomatrix(J, 1);
3132 	fz_rect bounds;
3133 
3134 	fz_try(ctx)
3135 		bounds = fz_bound_shade(ctx, shade, ctm);
3136 	fz_catch(ctx)
3137 		rethrow(J);
3138 
3139 	ffi_pushrect(J, bounds);
3140 }
3141 
ffi_new_Font(js_State * J)3142 static void ffi_new_Font(js_State *J)
3143 {
3144 	fz_context *ctx = js_getcontext(J);
3145 	const char *name = js_tostring(J, 1);
3146 	int index = js_isnumber(J, 2) ? js_tonumber(J, 2) : 0;
3147 	const unsigned char *data;
3148 	int size;
3149 	fz_font *font = NULL;
3150 
3151 	fz_try(ctx) {
3152 		data = fz_lookup_base14_font(ctx, name, &size);
3153 		if (!data)
3154 			data = fz_lookup_cjk_font_by_language(ctx, name, &size, &index);
3155 		if (data)
3156 			font = fz_new_font_from_memory(ctx, name, data, size, index, 0);
3157 		else
3158 			font = fz_new_font_from_file(ctx, name, name, index, 0);
3159 	}
3160 	fz_catch(ctx)
3161 		rethrow(J);
3162 
3163 	js_getregistry(J, "fz_font");
3164 	js_newuserdata(J, "fz_font", font, ffi_gc_fz_font);
3165 }
3166 
ffi_Font_getName(js_State * J)3167 static void ffi_Font_getName(js_State *J)
3168 {
3169 	fz_context *ctx = js_getcontext(J);
3170 	fz_font *font = js_touserdata(J, 0, "fz_font");
3171 	js_pushstring(J, fz_font_name(ctx, font));
3172 }
3173 
ffi_Font_encodeCharacter(js_State * J)3174 static void ffi_Font_encodeCharacter(js_State *J)
3175 {
3176 	fz_context *ctx = js_getcontext(J);
3177 	fz_font *font = js_touserdata(J, 0, "fz_font");
3178 	int unicode = js_tonumber(J, 1);
3179 	int glyph = 0;
3180 	fz_try(ctx)
3181 		glyph = fz_encode_character(ctx, font, unicode);
3182 	fz_catch(ctx)
3183 		rethrow(J);
3184 	js_pushnumber(J, glyph);
3185 }
3186 
ffi_Font_advanceGlyph(js_State * J)3187 static void ffi_Font_advanceGlyph(js_State *J)
3188 {
3189 	fz_context *ctx = js_getcontext(J);
3190 	fz_font *font = js_touserdata(J, 0, "fz_font");
3191 	int glyph = js_tonumber(J, 1);
3192 	int wmode = js_isdefined(J, 2) ? js_toboolean(J, 2) : 0;
3193 
3194 	float advance = 0;
3195 	fz_try(ctx)
3196 		advance = fz_advance_glyph(ctx, font, glyph, wmode);
3197 	fz_catch(ctx)
3198 		rethrow(J);
3199 	js_pushnumber(J, advance);
3200 }
3201 
ffi_new_Text(js_State * J)3202 static void ffi_new_Text(js_State *J)
3203 {
3204 	fz_context *ctx = js_getcontext(J);
3205 	fz_text *text = NULL;
3206 
3207 	fz_try(ctx)
3208 		text = fz_new_text(ctx);
3209 	fz_catch(ctx)
3210 		rethrow(J);
3211 
3212 	js_getregistry(J, "fz_text");
3213 	js_newuserdata(J, "fz_text", text, ffi_gc_fz_text);
3214 }
3215 
ffi_Text_walk(js_State * J)3216 static void ffi_Text_walk(js_State *J)
3217 {
3218 	fz_text *text = js_touserdata(J, 0, "fz_text");
3219 	char buf[8];
3220 	fz_text_span *span;
3221 	fz_matrix trm;
3222 	int i;
3223 
3224 	for (span = text->head; span; span = span->next) {
3225 		ffi_pushfont(J, span->font);
3226 		trm = span->trm;
3227 		if (js_hasproperty(J, 1, "beginSpan")) {
3228 			js_copy(J, 1); // this
3229 			js_copy(J, -3); // font
3230 			ffi_pushmatrix(J, trm);
3231 			js_pushboolean(J, span->wmode);
3232 			js_pushnumber(J, span->bidi_level);
3233 			js_pushnumber(J, span->markup_dir);
3234 			js_pushstring(J, fz_string_from_text_language(buf, span->language));
3235 			js_call(J, 6);
3236 			js_pop(J, 1);
3237 		}
3238 		for (i = 0; i < span->len; ++i) {
3239 			trm.e = span->items[i].x;
3240 			trm.f = span->items[i].y;
3241 			if (js_hasproperty(J, 1, "showGlyph")) {
3242 				js_copy(J, 1); /* object for this binding */
3243 				js_copy(J, -3); /* font */
3244 				ffi_pushmatrix(J, trm);
3245 				js_pushnumber(J, span->items[i].gid);
3246 				js_pushnumber(J, span->items[i].ucs);
3247 				js_pushnumber(J, span->wmode);
3248 				js_pushnumber(J, span->bidi_level);
3249 				js_call(J, 6);
3250 				js_pop(J, 1);
3251 			}
3252 		}
3253 		js_pop(J, 1); /* pop font object */
3254 		if (js_hasproperty(J, 1, "endSpan")) {
3255 			js_copy(J, 1); // this
3256 			js_call(J, 0);
3257 			js_pop(J, 1);
3258 		}
3259 	}
3260 	js_pop(J, 1); /* pop showGlyph function */
3261 }
3262 
ffi_Text_showGlyph(js_State * J)3263 static void ffi_Text_showGlyph(js_State *J)
3264 {
3265 	fz_context *ctx = js_getcontext(J);
3266 	fz_text *text = js_touserdata(J, 0, "fz_text");
3267 	fz_font *font = js_touserdata(J, 1, "fz_font");
3268 	fz_matrix trm = ffi_tomatrix(J, 2);
3269 	int glyph = js_tointeger(J, 3);
3270 	int unicode = js_tointeger(J, 4);
3271 	int wmode = js_isdefined(J, 5) ? js_toboolean(J, 5) : 0;
3272 
3273 	fz_try(ctx)
3274 		fz_show_glyph(ctx, text, font, trm, glyph, unicode, wmode, 0, FZ_BIDI_NEUTRAL, FZ_LANG_UNSET);
3275 	fz_catch(ctx)
3276 		rethrow(J);
3277 }
3278 
ffi_Text_showString(js_State * J)3279 static void ffi_Text_showString(js_State *J)
3280 {
3281 	fz_context *ctx = js_getcontext(J);
3282 	fz_text *text = js_touserdata(J, 0, "fz_text");
3283 	fz_font *font = js_touserdata(J, 1, "fz_font");
3284 	fz_matrix trm = ffi_tomatrix(J, 2);
3285 	const char *s = js_tostring(J, 3);
3286 	int wmode = js_isdefined(J, 4) ? js_toboolean(J, 4) : 0;
3287 
3288 	fz_try(ctx)
3289 		trm = fz_show_string(ctx, text, font, trm, s, wmode, 0, FZ_BIDI_NEUTRAL, FZ_LANG_UNSET);
3290 	fz_catch(ctx)
3291 		rethrow(J);
3292 
3293 	/* update matrix with new pen position */
3294 	js_pushnumber(J, trm.e);
3295 	js_setindex(J, 2, 4);
3296 	js_pushnumber(J, trm.f);
3297 	js_setindex(J, 2, 5);
3298 }
3299 
ffi_new_Path(js_State * J)3300 static void ffi_new_Path(js_State *J)
3301 {
3302 	fz_context *ctx = js_getcontext(J);
3303 	fz_path *path = NULL;
3304 
3305 	fz_try(ctx)
3306 		path = fz_new_path(ctx);
3307 	fz_catch(ctx)
3308 		rethrow(J);
3309 
3310 	js_getregistry(J, "fz_path");
3311 	js_newuserdata(J, "fz_path", path, ffi_gc_fz_path);
3312 }
3313 
ffi_Path_walk_moveTo(fz_context * ctx,void * arg,float x,float y)3314 static void ffi_Path_walk_moveTo(fz_context *ctx, void *arg, float x, float y)
3315 {
3316 	js_State *J = arg;
3317 	if (js_try(J))
3318 		rethrow_as_fz(J);
3319 	if (js_hasproperty(J, 1, "moveTo")) {
3320 		js_copy(J, 1);
3321 		js_pushnumber(J, x);
3322 		js_pushnumber(J, y);
3323 		js_call(J, 2);
3324 		js_pop(J, 1);
3325 	}
3326 	js_endtry(J);
3327 }
3328 
ffi_Path_walk_lineTo(fz_context * ctx,void * arg,float x,float y)3329 static void ffi_Path_walk_lineTo(fz_context *ctx, void *arg, float x, float y)
3330 {
3331 	js_State *J = arg;
3332 	if (js_try(J))
3333 		rethrow_as_fz(J);
3334 	if (js_hasproperty(J, 1, "lineTo")) {
3335 		js_copy(J, 1);
3336 		js_pushnumber(J, x);
3337 		js_pushnumber(J, y);
3338 		js_call(J, 2);
3339 		js_pop(J, 1);
3340 	}
3341 	js_endtry(J);
3342 }
3343 
ffi_Path_walk_curveTo(fz_context * ctx,void * arg,float x1,float y1,float x2,float y2,float x3,float y3)3344 static void ffi_Path_walk_curveTo(fz_context *ctx, void *arg,
3345 		float x1, float y1, float x2, float y2, float x3, float y3)
3346 {
3347 	js_State *J = arg;
3348 	if (js_try(J))
3349 		rethrow_as_fz(J);
3350 	if (js_hasproperty(J, 1, "curveTo")) {
3351 		js_copy(J, 1);
3352 		js_pushnumber(J, x1);
3353 		js_pushnumber(J, y1);
3354 		js_pushnumber(J, x2);
3355 		js_pushnumber(J, y2);
3356 		js_pushnumber(J, x3);
3357 		js_pushnumber(J, y3);
3358 		js_call(J, 6);
3359 		js_pop(J, 1);
3360 	}
3361 	js_endtry(J);
3362 }
3363 
ffi_Path_walk_closePath(fz_context * ctx,void * arg)3364 static void ffi_Path_walk_closePath(fz_context *ctx, void *arg)
3365 {
3366 	js_State *J = arg;
3367 	if (js_try(J))
3368 		rethrow_as_fz(J);
3369 	if (js_hasproperty(J, 1, "closePath")) {
3370 		js_copy(J, 1);
3371 		js_call(J, 0);
3372 		js_pop(J, 1);
3373 	}
3374 	js_endtry(J);
3375 }
3376 
ffi_Path_walk(js_State * J)3377 static void ffi_Path_walk(js_State *J)
3378 {
3379 	fz_context *ctx = js_getcontext(J);
3380 	fz_path *path = js_touserdata(J, 0, "fz_path");
3381 	fz_path_walker walker = {
3382 		ffi_Path_walk_moveTo,
3383 		ffi_Path_walk_lineTo,
3384 		ffi_Path_walk_curveTo,
3385 		ffi_Path_walk_closePath,
3386 	};
3387 
3388 	fz_try(ctx)
3389 		fz_walk_path(ctx, path, &walker, J);
3390 	fz_catch(ctx)
3391 		rethrow(J);
3392 }
3393 
ffi_Path_moveTo(js_State * J)3394 static void ffi_Path_moveTo(js_State *J)
3395 {
3396 	fz_context *ctx = js_getcontext(J);
3397 	fz_path *path = js_touserdata(J, 0, "fz_path");
3398 	float x = js_tonumber(J, 1);
3399 	float y = js_tonumber(J, 2);
3400 
3401 	fz_try(ctx)
3402 		fz_moveto(ctx, path, x, y);
3403 	fz_catch(ctx)
3404 		rethrow(J);
3405 }
3406 
ffi_Path_lineTo(js_State * J)3407 static void ffi_Path_lineTo(js_State *J)
3408 {
3409 	fz_context *ctx = js_getcontext(J);
3410 	fz_path *path = js_touserdata(J, 0, "fz_path");
3411 	float x = js_tonumber(J, 1);
3412 	float y = js_tonumber(J, 2);
3413 
3414 	fz_try(ctx)
3415 		fz_lineto(ctx, path, x, y);
3416 	fz_catch(ctx)
3417 		rethrow(J);
3418 }
3419 
ffi_Path_curveTo(js_State * J)3420 static void ffi_Path_curveTo(js_State *J)
3421 {
3422 	fz_context *ctx = js_getcontext(J);
3423 	fz_path *path = js_touserdata(J, 0, "fz_path");
3424 	float x1 = js_tonumber(J, 1);
3425 	float y1 = js_tonumber(J, 2);
3426 	float x2 = js_tonumber(J, 3);
3427 	float y2 = js_tonumber(J, 4);
3428 	float x3 = js_tonumber(J, 5);
3429 	float y3 = js_tonumber(J, 6);
3430 
3431 	fz_try(ctx)
3432 		fz_curveto(ctx, path, x1, y1, x2, y2, x3, y3);
3433 	fz_catch(ctx)
3434 		rethrow(J);
3435 }
3436 
ffi_Path_curveToV(js_State * J)3437 static void ffi_Path_curveToV(js_State *J)
3438 {
3439 	fz_context *ctx = js_getcontext(J);
3440 	fz_path *path = js_touserdata(J, 0, "fz_path");
3441 	float cx = js_tonumber(J, 1);
3442 	float cy = js_tonumber(J, 2);
3443 	float ex = js_tonumber(J, 3);
3444 	float ey = js_tonumber(J, 4);
3445 
3446 	fz_try(ctx)
3447 		fz_curvetov(ctx, path, cx, cy, ex, ey);
3448 	fz_catch(ctx)
3449 		rethrow(J);
3450 }
3451 
ffi_Path_curveToY(js_State * J)3452 static void ffi_Path_curveToY(js_State *J)
3453 {
3454 	fz_context *ctx = js_getcontext(J);
3455 	fz_path *path = js_touserdata(J, 0, "fz_path");
3456 	float cx = js_tonumber(J, 1);
3457 	float cy = js_tonumber(J, 2);
3458 	float ex = js_tonumber(J, 3);
3459 	float ey = js_tonumber(J, 4);
3460 
3461 	fz_try(ctx)
3462 		fz_curvetoy(ctx, path, cx, cy, ex, ey);
3463 	fz_catch(ctx)
3464 		rethrow(J);
3465 }
3466 
ffi_Path_closePath(js_State * J)3467 static void ffi_Path_closePath(js_State *J)
3468 {
3469 	fz_context *ctx = js_getcontext(J);
3470 	fz_path *path = js_touserdata(J, 0, "fz_path");
3471 
3472 	fz_try(ctx)
3473 		fz_closepath(ctx, path);
3474 	fz_catch(ctx)
3475 		rethrow(J);
3476 }
3477 
ffi_Path_rect(js_State * J)3478 static void ffi_Path_rect(js_State *J)
3479 {
3480 	fz_context *ctx = js_getcontext(J);
3481 	fz_path *path = js_touserdata(J, 0, "fz_path");
3482 	float x1 = js_tonumber(J, 1);
3483 	float y1 = js_tonumber(J, 2);
3484 	float x2 = js_tonumber(J, 3);
3485 	float y2 = js_tonumber(J, 4);
3486 
3487 	fz_try(ctx)
3488 		fz_rectto(ctx, path, x1, y1, x2, y2);
3489 	fz_catch(ctx)
3490 		rethrow(J);
3491 }
3492 
ffi_Path_bound(js_State * J)3493 static void ffi_Path_bound(js_State *J)
3494 {
3495 	fz_context *ctx = js_getcontext(J);
3496 	fz_path *path = js_touserdata(J, 0, "fz_path");
3497 	fz_stroke_state stroke = ffi_tostroke(J, 1);
3498 	fz_matrix ctm = ffi_tomatrix(J, 2);
3499 	fz_rect bounds;
3500 
3501 	fz_try(ctx)
3502 		bounds = fz_bound_path(ctx, path, &stroke, ctm);
3503 	fz_catch(ctx)
3504 		rethrow(J);
3505 
3506 	ffi_pushrect(J, bounds);
3507 }
3508 
ffi_Path_transform(js_State * J)3509 static void ffi_Path_transform(js_State *J)
3510 {
3511 	fz_context *ctx = js_getcontext(J);
3512 	fz_path *path = js_touserdata(J, 0, "fz_path");
3513 	fz_matrix ctm = ffi_tomatrix(J, 1);
3514 
3515 	fz_try(ctx)
3516 		fz_transform_path(ctx, path, ctm);
3517 	fz_catch(ctx)
3518 		rethrow(J);
3519 }
3520 
ffi_new_DisplayList(js_State * J)3521 static void ffi_new_DisplayList(js_State *J)
3522 {
3523 	fz_context *ctx = js_getcontext(J);
3524 	fz_rect mediabox = js_iscoercible(J, 1) ? ffi_torect(J, 1) : fz_empty_rect;
3525 	fz_display_list *list = NULL;
3526 
3527 	fz_try(ctx)
3528 		list = fz_new_display_list(ctx, mediabox);
3529 	fz_catch(ctx)
3530 		rethrow(J);
3531 
3532 	js_getregistry(J, "fz_display_list");
3533 	js_newuserdata(J, "fz_display_list", list, ffi_gc_fz_display_list);
3534 }
3535 
ffi_DisplayList_run(js_State * J)3536 static void ffi_DisplayList_run(js_State *J)
3537 {
3538 	fz_context *ctx = js_getcontext(J);
3539 	fz_display_list *list = js_touserdata(J, 0, "fz_display_list");
3540 	fz_device *device = NULL;
3541 	fz_matrix ctm = ffi_tomatrix(J, 2);
3542 
3543 	if (js_isuserdata(J, 1, "fz_device")) {
3544 		device = js_touserdata(J, 1, "fz_device");
3545 		fz_try(ctx)
3546 			fz_run_display_list(ctx, list, device, ctm, fz_infinite_rect, NULL);
3547 		fz_catch(ctx)
3548 			rethrow(J);
3549 	} else {
3550 		device = new_js_device(ctx, J);
3551 		js_copy(J, 1);
3552 		fz_try(ctx) {
3553 			fz_run_display_list(ctx, list, device, ctm, fz_infinite_rect, NULL);
3554 			fz_close_device(ctx, device);
3555 		}
3556 		fz_always(ctx)
3557 			fz_drop_device(ctx, device);
3558 		fz_catch(ctx)
3559 			rethrow(J);
3560 	}
3561 }
3562 
ffi_DisplayList_toPixmap(js_State * J)3563 static void ffi_DisplayList_toPixmap(js_State *J)
3564 {
3565 	fz_context *ctx = js_getcontext(J);
3566 	fz_display_list *list = js_touserdata(J, 0, "fz_display_list");
3567 	fz_matrix ctm = ffi_tomatrix(J, 1);
3568 	fz_colorspace *colorspace = js_touserdata(J, 2, "fz_colorspace");
3569 	int alpha = js_isdefined(J, 3) ? js_toboolean(J, 3) : 0;
3570 	fz_pixmap *pixmap = NULL;
3571 
3572 	fz_try(ctx)
3573 		pixmap = fz_new_pixmap_from_display_list(ctx, list, ctm, colorspace, alpha);
3574 	fz_catch(ctx)
3575 		rethrow(J);
3576 
3577 	js_getregistry(J, "fz_pixmap");
3578 	js_newuserdata(J, "fz_pixmap", pixmap, ffi_gc_fz_pixmap);
3579 }
3580 
ffi_DisplayList_toStructuredText(js_State * J)3581 static void ffi_DisplayList_toStructuredText(js_State *J)
3582 {
3583 	fz_context *ctx = js_getcontext(J);
3584 	fz_display_list *list = js_touserdata(J, 0, "fz_display_list");
3585 	const char *options = js_iscoercible(J, 1) ? js_tostring(J, 1) : NULL;
3586 	fz_stext_options so;
3587 	fz_stext_page *text = NULL;
3588 
3589 	fz_try(ctx) {
3590 		fz_parse_stext_options(ctx, &so, options);
3591 		text = fz_new_stext_page_from_display_list(ctx, list, &so);
3592 	}
3593 	fz_catch(ctx)
3594 		rethrow(J);
3595 
3596 	js_getregistry(J, "fz_stext_page");
3597 	js_newuserdata(J, "fz_stext_page", text, ffi_gc_fz_stext_page);
3598 }
3599 
ffi_DisplayList_search(js_State * J)3600 static void ffi_DisplayList_search(js_State *J)
3601 {
3602 	fz_context *ctx = js_getcontext(J);
3603 	fz_display_list *list = js_touserdata(J, 0, "fz_display_list");
3604 	const char *needle = js_tostring(J, 1);
3605 	fz_quad hits[256];
3606 	int i, n = 0;
3607 
3608 	fz_try(ctx)
3609 		n = fz_search_display_list(ctx, list, needle, hits, nelem(hits));
3610 	fz_catch(ctx)
3611 		rethrow(J);
3612 
3613 	js_newarray(J);
3614 	for (i = 0; i < n; ++i) {
3615 		ffi_pushquad(J, hits[i]);
3616 		js_setindex(J, -2, i);
3617 	}
3618 }
3619 
ffi_StructuredText_walk(js_State * J)3620 static void ffi_StructuredText_walk(js_State *J)
3621 {
3622 	fz_stext_page *page = js_touserdata(J, 0, "fz_stext_page");
3623 	fz_stext_block *block;
3624 	fz_stext_line *line;
3625 	fz_stext_char *ch;
3626 
3627 	for (block = page->first_block; block; block = block->next)
3628 	{
3629 		if (block->type == FZ_STEXT_BLOCK_IMAGE)
3630 		{
3631 			if (js_hasproperty(J, 1, "onImageBlock"))
3632 			{
3633 				js_pushnull(J);
3634 				ffi_pushrect(J, block->bbox);
3635 				ffi_pushmatrix(J, block->u.i.transform);
3636 				ffi_pushimage(J, block->u.i.image);
3637 				js_call(J, 3);
3638 				js_pop(J, 1);
3639 			}
3640 		}
3641 		else if (block->type == FZ_STEXT_BLOCK_TEXT)
3642 		{
3643 			if (js_hasproperty(J, 1, "beginTextBlock"))
3644 			{
3645 				js_pushnull(J);
3646 				ffi_pushrect(J, block->bbox);
3647 				js_call(J, 1);
3648 				js_pop(J, 1);
3649 			}
3650 
3651 			for (line = block->u.t.first_line; line; line = line->next)
3652 			{
3653 				if (js_hasproperty(J, 1, "beginLine"))
3654 				{
3655 					js_pushnull(J);
3656 					ffi_pushrect(J, line->bbox);
3657 					js_pushboolean(J, line->wmode);
3658 					js_call(J, 2);
3659 					js_pop(J, 1);
3660 				}
3661 
3662 				for (ch = line->first_char; ch; ch = ch->next)
3663 				{
3664 					if (js_hasproperty(J, 1, "onChar"))
3665 					{
3666 						char utf[10];
3667 						js_pushnull(J);
3668 						utf[fz_runetochar(utf, ch->c)] = 0;
3669 						js_pushstring(J, utf);
3670 						ffi_pushpoint(J, ch->origin);
3671 						ffi_pushfont(J, ch->font);
3672 						js_pushnumber(J, ch->size);
3673 						ffi_pushquad(J, ch->quad);
3674 						js_call(J, 5);
3675 						js_pop(J, 1);
3676 					}
3677 				}
3678 
3679 				if (js_hasproperty(J, 1, "endLine"))
3680 				{
3681 					js_pushnull(J);
3682 					js_call(J, 0);
3683 					js_pop(J, 1);
3684 				}
3685 			}
3686 
3687 			if (js_hasproperty(J, 1, "endTextBlock"))
3688 			{
3689 				js_pushnull(J);
3690 				js_call(J, 0);
3691 				js_pop(J, 1);
3692 			}
3693 		}
3694 	}
3695 }
3696 
ffi_StructuredText_search(js_State * J)3697 static void ffi_StructuredText_search(js_State *J)
3698 {
3699 	fz_context *ctx = js_getcontext(J);
3700 	fz_stext_page *text = js_touserdata(J, 0, "fz_stext_page");
3701 	const char *needle = js_tostring(J, 1);
3702 	fz_quad hits[256];
3703 	int i, n = 0;
3704 
3705 	fz_try(ctx)
3706 		n = fz_search_stext_page(ctx, text, needle, hits, nelem(hits));
3707 	fz_catch(ctx)
3708 		rethrow(J);
3709 
3710 	js_newarray(J);
3711 	for (i = 0; i < n; ++i) {
3712 		ffi_pushquad(J, hits[i]);
3713 		js_setindex(J, -2, i);
3714 	}
3715 }
3716 
ffi_StructuredText_highlight(js_State * J)3717 static void ffi_StructuredText_highlight(js_State *J)
3718 {
3719 	fz_context *ctx = js_getcontext(J);
3720 	fz_stext_page *text = js_touserdata(J, 0, "fz_stext_page");
3721 	fz_point a = ffi_topoint(J, 1);
3722 	fz_point b = ffi_topoint(J, 2);
3723 	fz_quad hits[256];
3724 	int i, n = 0;
3725 
3726 	fz_try(ctx)
3727 		n = fz_highlight_selection(ctx, text, a, b, hits, nelem(hits));
3728 	fz_catch(ctx)
3729 		rethrow(J);
3730 
3731 	js_newarray(J);
3732 	for (i = 0; i < n; ++i) {
3733 		ffi_pushquad(J, hits[i]);
3734 		js_setindex(J, -2, i);
3735 	}
3736 }
3737 
ffi_StructuredText_copy(js_State * J)3738 static void ffi_StructuredText_copy(js_State *J)
3739 {
3740 	fz_context *ctx = js_getcontext(J);
3741 	fz_stext_page *text = js_touserdata(J, 0, "fz_stext_page");
3742 	fz_point a = ffi_topoint(J, 1);
3743 	fz_point b = ffi_topoint(J, 2);
3744 	char *s = NULL;
3745 
3746 	fz_try(ctx)
3747 		s = fz_copy_selection(ctx, text, a, b, 0);
3748 	fz_catch(ctx)
3749 		rethrow(J);
3750 
3751 	js_pushstring(J, s);
3752 
3753 	fz_try(ctx)
3754 		fz_free(ctx, s);
3755 	fz_catch(ctx)
3756 		rethrow(J);
3757 }
3758 
ffi_new_DisplayListDevice(js_State * J)3759 static void ffi_new_DisplayListDevice(js_State *J)
3760 {
3761 	fz_context *ctx = js_getcontext(J);
3762 	fz_display_list *list = js_touserdata(J, 0, "fz_display_list");
3763 	fz_device *device = NULL;
3764 
3765 	fz_try(ctx)
3766 		device = fz_new_list_device(ctx, list);
3767 	fz_catch(ctx)
3768 		rethrow(J);
3769 
3770 	js_getregistry(J, "fz_device");
3771 	js_newuserdata(J, "fz_device", device, ffi_gc_fz_device);
3772 }
3773 
ffi_new_DrawDevice(js_State * J)3774 static void ffi_new_DrawDevice(js_State *J)
3775 {
3776 	fz_context *ctx = js_getcontext(J);
3777 	fz_matrix transform = ffi_tomatrix(J, 1);
3778 	fz_pixmap *pixmap = js_touserdata(J, 2, "fz_pixmap");
3779 	fz_device *device = NULL;
3780 
3781 	fz_try(ctx)
3782 		device = fz_new_draw_device(ctx, transform, pixmap);
3783 	fz_catch(ctx)
3784 		rethrow(J);
3785 
3786 	js_getregistry(J, "fz_device");
3787 	js_newuserdata(J, "fz_device", device, ffi_gc_fz_device);
3788 }
3789 
ffi_new_DocumentWriter(js_State * J)3790 static void ffi_new_DocumentWriter(js_State *J)
3791 {
3792 	fz_context *ctx = js_getcontext(J);
3793 	const char *filename = js_tostring(J, 1);
3794 	const char *format = js_iscoercible(J, 2) ? js_tostring(J, 2) : NULL;
3795 	const char *options = js_iscoercible(J, 3) ? js_tostring(J, 3) : NULL;
3796 	fz_document_writer *wri = NULL;
3797 
3798 	fz_try(ctx)
3799 		wri = fz_new_document_writer(ctx, filename, format, options);
3800 	fz_catch(ctx)
3801 		rethrow(J);
3802 
3803 	js_getregistry(J, "fz_document_writer");
3804 	js_newuserdata(J, "fz_document_writer", wri, ffi_gc_fz_document_writer);
3805 }
3806 
ffi_DocumentWriter_beginPage(js_State * J)3807 static void ffi_DocumentWriter_beginPage(js_State *J)
3808 {
3809 	fz_context *ctx = js_getcontext(J);
3810 	fz_document_writer *wri = js_touserdata(J, 0, "fz_document_writer");
3811 	fz_rect mediabox = ffi_torect(J, 1);
3812 	fz_device *device = NULL;
3813 
3814 	fz_try(ctx)
3815 		device = fz_begin_page(ctx, wri, mediabox);
3816 	fz_catch(ctx)
3817 		rethrow(J);
3818 
3819 	js_getregistry(J, "fz_device");
3820 	js_newuserdata(J, "fz_device", fz_keep_device(ctx, device), ffi_gc_fz_device);
3821 }
3822 
ffi_DocumentWriter_endPage(js_State * J)3823 static void ffi_DocumentWriter_endPage(js_State *J)
3824 {
3825 	fz_context *ctx = js_getcontext(J);
3826 	fz_document_writer *wri = js_touserdata(J, 0, "fz_document_writer");
3827 	fz_try(ctx)
3828 		fz_end_page(ctx, wri);
3829 	fz_catch(ctx)
3830 		rethrow(J);
3831 }
3832 
ffi_DocumentWriter_close(js_State * J)3833 static void ffi_DocumentWriter_close(js_State *J)
3834 {
3835 	fz_context *ctx = js_getcontext(J);
3836 	fz_document_writer *wri = js_touserdata(J, 0, "fz_document_writer");
3837 	fz_try(ctx)
3838 		fz_close_document_writer(ctx, wri);
3839 	fz_catch(ctx)
3840 		rethrow(J);
3841 }
3842 
3843 /* PDF specifics */
3844 
3845 #if FZ_ENABLE_PDF
3846 
ffi_toobj(js_State * J,pdf_document * pdf,int idx)3847 static pdf_obj *ffi_toobj(js_State *J, pdf_document *pdf, int idx)
3848 {
3849 	fz_context *ctx = js_getcontext(J);
3850 	pdf_obj *obj = NULL;
3851 
3852 	/* make sure index is absolute */
3853 	if (idx < 0)
3854 		idx += js_gettop(J);
3855 
3856 	if (js_isuserdata(J, idx, "pdf_obj"))
3857 		return pdf_keep_obj(ctx, js_touserdata(J, idx, "pdf_obj"));
3858 
3859 	if (js_isnumber(J, idx)) {
3860 		float f = js_tonumber(J, idx);
3861 		fz_try(ctx)
3862 			if (f == (int)f)
3863 				obj = pdf_new_int(ctx, f);
3864 			else
3865 				obj = pdf_new_real(ctx, f);
3866 		fz_catch(ctx)
3867 			rethrow(J);
3868 		return obj;
3869 	}
3870 
3871 	if (js_isstring(J, idx)) {
3872 		const char *s = js_tostring(J, idx);
3873 		fz_try(ctx)
3874 			if (s[0] == '(' && s[1] != 0)
3875 				obj = pdf_new_string(ctx, s+1, strlen(s)-2);
3876 			else
3877 				obj = pdf_new_name(ctx, s);
3878 		fz_catch(ctx)
3879 			rethrow(J);
3880 		return obj;
3881 	}
3882 
3883 	if (js_isboolean(J, idx)) {
3884 		return js_toboolean(J, idx) ? PDF_TRUE : PDF_FALSE;
3885 	}
3886 
3887 	if (js_isnull(J, idx)) {
3888 		return PDF_NULL;
3889 	}
3890 
3891 	if (js_isarray(J, idx)) {
3892 		int i, n = js_getlength(J, idx);
3893 		pdf_obj *val;
3894 		fz_try(ctx)
3895 			obj = pdf_new_array(ctx, pdf, n);
3896 		fz_catch(ctx)
3897 			rethrow(J);
3898 		if (js_try(J)) {
3899 			pdf_drop_obj(ctx, obj);
3900 			js_throw(J);
3901 		}
3902 		for (i = 0; i < n; ++i) {
3903 			js_getindex(J, idx, i);
3904 			val = ffi_toobj(J, pdf, -1);
3905 			fz_try(ctx)
3906 				pdf_array_push_drop(ctx, obj, val);
3907 			fz_catch(ctx)
3908 				rethrow(J);
3909 			js_pop(J, 1);
3910 		}
3911 		js_endtry(J);
3912 		return obj;
3913 	}
3914 
3915 	if (js_isobject(J, idx)) {
3916 		const char *key;
3917 		pdf_obj *val;
3918 		fz_try(ctx)
3919 			obj = pdf_new_dict(ctx, pdf, 0);
3920 		fz_catch(ctx)
3921 			rethrow(J);
3922 		if (js_try(J)) {
3923 			pdf_drop_obj(ctx, obj);
3924 			js_throw(J);
3925 		}
3926 		js_pushiterator(J, idx, 1);
3927 		while ((key = js_nextiterator(J, -1))) {
3928 			js_getproperty(J, idx, key);
3929 			val = ffi_toobj(J, pdf, -1);
3930 			fz_try(ctx)
3931 				pdf_dict_puts_drop(ctx, obj, key, val);
3932 			fz_catch(ctx)
3933 				rethrow(J);
3934 			js_pop(J, 1);
3935 		}
3936 		js_pop(J, 1);
3937 		js_endtry(J);
3938 		return obj;
3939 	}
3940 
3941 	js_error(J, "cannot convert JS type to PDF");
3942 }
3943 
ffi_pdf_obj_has(js_State * J,void * obj,const char * key)3944 static int ffi_pdf_obj_has(js_State *J, void *obj, const char *key)
3945 {
3946 	fz_context *ctx = js_getcontext(J);
3947 	pdf_obj *val = NULL;
3948 	int idx, len = 0;
3949 
3950 	if (!strcmp(key, "length")) {
3951 		fz_try(ctx)
3952 			len = pdf_array_len(ctx, obj);
3953 		fz_catch(ctx)
3954 			rethrow(J);
3955 		js_pushnumber(J, len);
3956 		return 1;
3957 	}
3958 
3959 	if (is_number(key, &idx)) {
3960 		fz_try(ctx)
3961 			val = pdf_array_get(ctx, obj, idx);
3962 		fz_catch(ctx)
3963 			rethrow(J);
3964 	} else {
3965 		fz_try(ctx)
3966 			val = pdf_dict_gets(ctx, obj, key);
3967 		fz_catch(ctx)
3968 			rethrow(J);
3969 	}
3970 	if (val) {
3971 		ffi_pushobj(J, pdf_keep_obj(ctx, val));
3972 		return 1;
3973 	}
3974 	return 0;
3975 }
3976 
ffi_pdf_obj_put(js_State * J,void * obj,const char * key)3977 static int ffi_pdf_obj_put(js_State *J, void *obj, const char *key)
3978 {
3979 	fz_context *ctx = js_getcontext(J);
3980 	pdf_document *pdf = NULL;
3981 	pdf_obj *val;
3982 	int idx;
3983 
3984 	fz_try(ctx)
3985 		pdf = pdf_get_bound_document(ctx, obj);
3986 	fz_catch(ctx)
3987 		rethrow(J);
3988 
3989 	val = ffi_toobj(J, pdf, -1);
3990 
3991 	if (is_number(key, &idx)) {
3992 		fz_try(ctx)
3993 			pdf_array_put(ctx, obj, idx, val);
3994 		fz_always(ctx)
3995 			pdf_drop_obj(ctx, val);
3996 		fz_catch(ctx)
3997 			rethrow(J);
3998 	} else {
3999 		fz_try(ctx)
4000 			pdf_dict_puts(ctx, obj, key, val);
4001 		fz_always(ctx)
4002 			pdf_drop_obj(ctx, val);
4003 		fz_catch(ctx)
4004 			rethrow(J);
4005 	}
4006 	return 1;
4007 }
4008 
ffi_pdf_obj_delete(js_State * J,void * obj,const char * key)4009 static int ffi_pdf_obj_delete(js_State *J, void *obj, const char *key)
4010 {
4011 	fz_context *ctx = js_getcontext(J);
4012 	int idx;
4013 
4014 	if (is_number(key, &idx)) {
4015 		fz_try(ctx)
4016 			pdf_array_delete(ctx, obj, idx);
4017 		fz_catch(ctx)
4018 			rethrow(J);
4019 	} else {
4020 		fz_try(ctx)
4021 			pdf_dict_dels(ctx, obj, key);
4022 		fz_catch(ctx)
4023 			rethrow(J);
4024 	}
4025 	return 1;
4026 }
4027 
ffi_pushobj(js_State * J,pdf_obj * obj)4028 static void ffi_pushobj(js_State *J, pdf_obj *obj)
4029 {
4030 	if (obj) {
4031 		js_getregistry(J, "pdf_obj");
4032 		js_newuserdatax(J, "pdf_obj", obj,
4033 				ffi_pdf_obj_has, ffi_pdf_obj_put, ffi_pdf_obj_delete,
4034 				ffi_gc_pdf_obj);
4035 	} else {
4036 		js_pushnull(J);
4037 	}
4038 }
4039 
ffi_new_PDFDocument(js_State * J)4040 static void ffi_new_PDFDocument(js_State *J)
4041 {
4042 	fz_context *ctx = js_getcontext(J);
4043 	const char *filename = js_iscoercible(J, 1) ? js_tostring(J, 1) : NULL;
4044 	pdf_document *pdf = NULL;
4045 
4046 	fz_try(ctx)
4047 		if (filename)
4048 			pdf = pdf_open_document(ctx, filename);
4049 		else
4050 			pdf = pdf_create_document(ctx);
4051 	fz_catch(ctx)
4052 		rethrow(J);
4053 
4054 	js_getregistry(J, "pdf_document");
4055 	js_newuserdata(J, "pdf_document", pdf, ffi_gc_pdf_document);
4056 }
4057 
ffi_PDFDocument_getTrailer(js_State * J)4058 static void ffi_PDFDocument_getTrailer(js_State *J)
4059 {
4060 	fz_context *ctx = js_getcontext(J);
4061 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4062 	pdf_obj *trailer = NULL;
4063 
4064 	fz_try(ctx)
4065 		trailer = pdf_trailer(ctx, pdf);
4066 	fz_catch(ctx)
4067 		rethrow(J);
4068 
4069 	ffi_pushobj(J, pdf_keep_obj(ctx, trailer));
4070 }
4071 
ffi_PDFDocument_countObjects(js_State * J)4072 static void ffi_PDFDocument_countObjects(js_State *J)
4073 {
4074 	fz_context *ctx = js_getcontext(J);
4075 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4076 	int count = 0;
4077 
4078 	fz_try(ctx)
4079 		count = pdf_xref_len(ctx, pdf);
4080 	fz_catch(ctx)
4081 		rethrow(J);
4082 
4083 	js_pushnumber(J, count);
4084 }
4085 
ffi_PDFDocument_createObject(js_State * J)4086 static void ffi_PDFDocument_createObject(js_State *J)
4087 {
4088 	fz_context *ctx = js_getcontext(J);
4089 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4090 	pdf_obj *ind = NULL;
4091 
4092 	fz_try(ctx)
4093 		ind = pdf_new_indirect(ctx, pdf, pdf_create_object(ctx, pdf), 0);
4094 	fz_catch(ctx)
4095 		rethrow(J);
4096 
4097 	ffi_pushobj(J, ind);
4098 }
4099 
ffi_PDFDocument_deleteObject(js_State * J)4100 static void ffi_PDFDocument_deleteObject(js_State *J)
4101 {
4102 	fz_context *ctx = js_getcontext(J);
4103 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4104 	pdf_obj *ind = js_isuserdata(J, 1, "pdf_obj") ? js_touserdata(J, 1, "pdf_obj") : NULL;
4105 	int num = ind ? pdf_to_num(ctx, ind) : js_tonumber(J, 1);
4106 
4107 	fz_try(ctx)
4108 		pdf_delete_object(ctx, pdf, num);
4109 	fz_catch(ctx)
4110 		rethrow(J);
4111 }
4112 
ffi_PDFDocument_addObject(js_State * J)4113 static void ffi_PDFDocument_addObject(js_State *J)
4114 {
4115 	fz_context *ctx = js_getcontext(J);
4116 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4117 	pdf_obj *obj = ffi_toobj(J, pdf, 1);
4118 	pdf_obj *ind = NULL;
4119 
4120 	fz_try(ctx)
4121 		ind = pdf_add_object_drop(ctx, pdf, obj);
4122 	fz_catch(ctx)
4123 		rethrow(J);
4124 
4125 	ffi_pushobj(J, ind);
4126 }
4127 
ffi_PDFDocument_addStream_imp(js_State * J,int compressed)4128 static void ffi_PDFDocument_addStream_imp(js_State *J, int compressed)
4129 {
4130 	fz_context *ctx = js_getcontext(J);
4131 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4132 	fz_buffer *buf = ffi_tobuffer(J, 1); /* FIXME: leak if ffi_toobj throws */
4133 	pdf_obj *obj = js_iscoercible(J, 2) ? ffi_toobj(J, pdf, 2) : NULL;
4134 	pdf_obj *ind = NULL;
4135 
4136 	fz_try(ctx)
4137 		ind = pdf_add_stream(ctx, pdf, buf, obj, compressed);
4138 	fz_always(ctx) {
4139 		fz_drop_buffer(ctx, buf);
4140 		pdf_drop_obj(ctx, obj);
4141 	} fz_catch(ctx)
4142 		rethrow(J);
4143 
4144 	ffi_pushobj(J, ind);
4145 }
4146 
ffi_PDFDocument_addStream(js_State * J)4147 static void ffi_PDFDocument_addStream(js_State *J)
4148 {
4149 	ffi_PDFDocument_addStream_imp(J, 0);
4150 }
4151 
ffi_PDFDocument_addRawStream(js_State * J)4152 static void ffi_PDFDocument_addRawStream(js_State *J)
4153 {
4154 	ffi_PDFDocument_addStream_imp(J, 1);
4155 }
4156 
ffi_PDFDocument_addImage(js_State * J)4157 static void ffi_PDFDocument_addImage(js_State *J)
4158 {
4159 	fz_context *ctx = js_getcontext(J);
4160 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4161 	fz_image *image = js_touserdata(J, 1, "fz_image");
4162 	pdf_obj *ind = NULL;
4163 
4164 	fz_try(ctx)
4165 		ind = pdf_add_image(ctx, pdf, image);
4166 	fz_catch(ctx)
4167 		rethrow(J);
4168 
4169 	ffi_pushobj(J, ind);
4170 }
4171 
ffi_PDFDocument_loadImage(js_State * J)4172 static void ffi_PDFDocument_loadImage(js_State *J)
4173 {
4174 	fz_context *ctx = js_getcontext(J);
4175 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4176 	pdf_obj *obj = ffi_toobj(J, pdf, 1);
4177 	fz_image *img = NULL;
4178 
4179 	fz_try(ctx)
4180 		img = pdf_load_image(ctx, pdf, obj);
4181 	fz_catch(ctx)
4182 		rethrow(J);
4183 
4184 	ffi_pushimage_own(J, img);
4185 }
4186 
ffi_PDFDocument_addSimpleFont(js_State * J)4187 static void ffi_PDFDocument_addSimpleFont(js_State *J)
4188 {
4189 	fz_context *ctx = js_getcontext(J);
4190 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4191 	fz_font *font = js_touserdata(J, 1, "fz_font");
4192 	const char *encname = js_tostring(J, 2);
4193 	pdf_obj *ind = NULL;
4194 	int enc = PDF_SIMPLE_ENCODING_LATIN;
4195 
4196 	if (!strcmp(encname, "Latin") || !strcmp(encname, "Latn"))
4197 		enc = PDF_SIMPLE_ENCODING_LATIN;
4198 	else if (!strcmp(encname, "Greek") || !strcmp(encname, "Grek"))
4199 		enc = PDF_SIMPLE_ENCODING_GREEK;
4200 	else if (!strcmp(encname, "Cyrillic") || !strcmp(encname, "Cyrl"))
4201 		enc = PDF_SIMPLE_ENCODING_CYRILLIC;
4202 
4203 	fz_try(ctx)
4204 		ind = pdf_add_simple_font(ctx, pdf, font, enc);
4205 	fz_catch(ctx)
4206 		rethrow(J);
4207 
4208 	ffi_pushobj(J, ind);
4209 }
4210 
ffi_PDFDocument_addCJKFont(js_State * J)4211 static void ffi_PDFDocument_addCJKFont(js_State *J)
4212 {
4213 	fz_context *ctx = js_getcontext(J);
4214 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4215 	fz_font *font = js_touserdata(J, 1, "fz_font");
4216 	const char *lang = js_tostring(J, 2);
4217 	const char *wm = js_tostring(J, 3);
4218 	const char *ss = js_tostring(J, 4);
4219 	int ordering;
4220 	int wmode = 0;
4221 	int serif = 1;
4222 	pdf_obj *ind = NULL;
4223 
4224 	ordering = fz_lookup_cjk_ordering_by_language(lang);
4225 
4226 	if (!strcmp(wm, "V"))
4227 		wmode = 1;
4228 	if (!strcmp(ss, "sans") || !strcmp(ss, "sans-serif"))
4229 		serif = 0;
4230 
4231 	fz_try(ctx)
4232 		ind = pdf_add_cjk_font(ctx, pdf, font, ordering, wmode, serif);
4233 	fz_catch(ctx)
4234 		rethrow(J);
4235 
4236 	ffi_pushobj(J, ind);
4237 }
4238 
ffi_PDFDocument_addFont(js_State * J)4239 static void ffi_PDFDocument_addFont(js_State *J)
4240 {
4241 	fz_context *ctx = js_getcontext(J);
4242 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4243 	fz_font *font = js_touserdata(J, 1, "fz_font");
4244 	pdf_obj *ind = NULL;
4245 
4246 	fz_try(ctx)
4247 		ind = pdf_add_cid_font(ctx, pdf, font);
4248 	fz_catch(ctx)
4249 		rethrow(J);
4250 
4251 	ffi_pushobj(J, ind);
4252 }
4253 
ffi_PDFDocument_addPage(js_State * J)4254 static void ffi_PDFDocument_addPage(js_State *J)
4255 {
4256 	fz_context *ctx = js_getcontext(J);
4257 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4258 	fz_rect mediabox = ffi_torect(J, 1);
4259 	int rotate = js_tonumber(J, 2);
4260 	pdf_obj *resources = ffi_toobj(J, pdf, 3); /* FIXME: leak if ffi_tobuffer throws */
4261 	fz_buffer *contents = ffi_tobuffer(J, 4);
4262 	pdf_obj *ind = NULL;
4263 
4264 	fz_try(ctx)
4265 		ind = pdf_add_page(ctx, pdf, mediabox, rotate, resources, contents);
4266 	fz_always(ctx) {
4267 		fz_drop_buffer(ctx, contents);
4268 		pdf_drop_obj(ctx, resources);
4269 	} fz_catch(ctx)
4270 		rethrow(J);
4271 
4272 	ffi_pushobj(J, ind);
4273 }
4274 
ffi_PDFDocument_insertPage(js_State * J)4275 static void ffi_PDFDocument_insertPage(js_State *J)
4276 {
4277 	fz_context *ctx = js_getcontext(J);
4278 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4279 	int at = js_tonumber(J, 1);
4280 	pdf_obj *obj = ffi_toobj(J, pdf, 2);
4281 
4282 	fz_try(ctx)
4283 		pdf_insert_page(ctx, pdf, at, obj);
4284 	fz_always(ctx)
4285 		pdf_drop_obj(ctx, obj);
4286 	fz_catch(ctx)
4287 		rethrow(J);
4288 }
4289 
ffi_PDFDocument_deletePage(js_State * J)4290 static void ffi_PDFDocument_deletePage(js_State *J)
4291 {
4292 	fz_context *ctx = js_getcontext(J);
4293 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4294 	int at = js_tonumber(J, 1);
4295 
4296 	fz_try(ctx)
4297 		pdf_delete_page(ctx, pdf, at);
4298 	fz_catch(ctx)
4299 		rethrow(J);
4300 }
4301 
ffi_PDFDocument_countPages(js_State * J)4302 static void ffi_PDFDocument_countPages(js_State *J)
4303 {
4304 	fz_context *ctx = js_getcontext(J);
4305 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4306 	int count = 0;
4307 
4308 	fz_try(ctx)
4309 		count = pdf_count_pages(ctx, pdf);
4310 	fz_catch(ctx)
4311 		rethrow(J);
4312 
4313 	js_pushnumber(J, count);
4314 }
4315 
ffi_PDFDocument_findPage(js_State * J)4316 static void ffi_PDFDocument_findPage(js_State *J)
4317 {
4318 	fz_context *ctx = js_getcontext(J);
4319 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4320 	int at = js_tonumber(J, 1);
4321 	pdf_obj *obj = NULL;
4322 
4323 	fz_try(ctx)
4324 		obj = pdf_lookup_page_obj(ctx, pdf, at);
4325 	fz_catch(ctx)
4326 		rethrow(J);
4327 
4328 	ffi_pushobj(J, pdf_keep_obj(ctx, obj));
4329 }
4330 
ffi_PDFDocument_save(js_State * J)4331 static void ffi_PDFDocument_save(js_State *J)
4332 {
4333 	fz_context *ctx = js_getcontext(J);
4334 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4335 	const char *filename = js_tostring(J, 1);
4336 	const char *options = js_iscoercible(J, 2) ? js_tostring(J, 2) : NULL;
4337 	pdf_write_options pwo;
4338 
4339 	fz_try(ctx) {
4340 		pdf_parse_write_options(ctx, &pwo, options);
4341 		pdf_save_document(ctx, pdf, filename, &pwo);
4342 	} fz_catch(ctx)
4343 		rethrow(J);
4344 }
4345 
ffi_PDFDocument_newNull(js_State * J)4346 static void ffi_PDFDocument_newNull(js_State *J)
4347 {
4348 	ffi_pushobj(J, PDF_NULL);
4349 }
4350 
ffi_PDFDocument_newBoolean(js_State * J)4351 static void ffi_PDFDocument_newBoolean(js_State *J)
4352 {
4353 	int val = js_toboolean(J, 1);
4354 	ffi_pushobj(J, val ? PDF_TRUE : PDF_FALSE);
4355 }
4356 
ffi_PDFDocument_newInteger(js_State * J)4357 static void ffi_PDFDocument_newInteger(js_State *J)
4358 {
4359 	fz_context *ctx = js_getcontext(J);
4360 	int val = js_tointeger(J, 1);
4361 	pdf_obj *obj = NULL;
4362 	fz_try(ctx)
4363 		obj = pdf_new_int(ctx, val);
4364 	fz_catch(ctx)
4365 		rethrow(J);
4366 	ffi_pushobj(J, obj);
4367 }
4368 
ffi_PDFDocument_newReal(js_State * J)4369 static void ffi_PDFDocument_newReal(js_State *J)
4370 {
4371 	fz_context *ctx = js_getcontext(J);
4372 	float val = js_tonumber(J, 1);
4373 	pdf_obj *obj = NULL;
4374 	fz_try(ctx)
4375 		obj = pdf_new_real(ctx, val);
4376 	fz_catch(ctx)
4377 		rethrow(J);
4378 	ffi_pushobj(J, obj);
4379 }
4380 
ffi_PDFDocument_newString(js_State * J)4381 static void ffi_PDFDocument_newString(js_State *J)
4382 {
4383 	fz_context *ctx = js_getcontext(J);
4384 	const char *val = js_tostring(J, 1);
4385 	pdf_obj *obj = NULL;
4386 
4387 	fz_try(ctx)
4388 		obj = pdf_new_text_string(ctx, val);
4389 	fz_catch(ctx)
4390 		rethrow(J);
4391 	ffi_pushobj(J, obj);
4392 }
4393 
ffi_PDFDocument_newByteString(js_State * J)4394 static void ffi_PDFDocument_newByteString(js_State *J)
4395 {
4396 	fz_context *ctx = js_getcontext(J);
4397 	int n, i;
4398 	char *buf;
4399 	pdf_obj *obj = NULL;
4400 
4401 	n = js_getlength(J, 1);
4402 
4403 	fz_try(ctx)
4404 		buf = fz_malloc(ctx, n);
4405 	fz_catch(ctx)
4406 		rethrow(J);
4407 
4408 	if (js_try(J)) {
4409 		fz_free(ctx, buf);
4410 		js_throw(J);
4411 	}
4412 
4413 	for (i = 0; i < n; ++i) {
4414 		js_getindex(J, 1, i);
4415 		buf[i] = js_tonumber(J, -1);
4416 		js_pop(J, 1);
4417 	}
4418 
4419 	js_endtry(J);
4420 
4421 	fz_try(ctx)
4422 		obj = pdf_new_string(ctx, buf, n);
4423 	fz_always(ctx)
4424 		fz_free(ctx, buf);
4425 	fz_catch(ctx)
4426 		rethrow(J);
4427 	ffi_pushobj(J, obj);
4428 }
4429 
ffi_PDFDocument_newName(js_State * J)4430 static void ffi_PDFDocument_newName(js_State *J)
4431 {
4432 	fz_context *ctx = js_getcontext(J);
4433 	const char *val = js_tostring(J, 1);
4434 	pdf_obj *obj = NULL;
4435 	fz_try(ctx)
4436 		obj = pdf_new_name(ctx, val);
4437 	fz_catch(ctx)
4438 		rethrow(J);
4439 	ffi_pushobj(J, obj);
4440 }
4441 
ffi_PDFDocument_newIndirect(js_State * J)4442 static void ffi_PDFDocument_newIndirect(js_State *J)
4443 {
4444 	fz_context *ctx = js_getcontext(J);
4445 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4446 	int num = js_tointeger(J, 1);
4447 	int gen = js_tointeger(J, 2);
4448 	pdf_obj *obj = NULL;
4449 	fz_try(ctx)
4450 		obj = pdf_new_indirect(ctx, pdf, num, gen);
4451 	fz_catch(ctx)
4452 		rethrow(J);
4453 	ffi_pushobj(J, obj);
4454 }
4455 
ffi_PDFDocument_newArray(js_State * J)4456 static void ffi_PDFDocument_newArray(js_State *J)
4457 {
4458 	fz_context *ctx = js_getcontext(J);
4459 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4460 	pdf_obj *obj = NULL;
4461 	fz_try(ctx)
4462 		obj = pdf_new_array(ctx, pdf, 0);
4463 	fz_catch(ctx)
4464 		rethrow(J);
4465 	ffi_pushobj(J, obj);
4466 }
4467 
ffi_PDFDocument_newDictionary(js_State * J)4468 static void ffi_PDFDocument_newDictionary(js_State *J)
4469 {
4470 	fz_context *ctx = js_getcontext(J);
4471 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4472 	pdf_obj *obj = NULL;
4473 	fz_try(ctx)
4474 		obj = pdf_new_dict(ctx, pdf, 0);
4475 	fz_catch(ctx)
4476 		rethrow(J);
4477 	ffi_pushobj(J, obj);
4478 }
4479 
ffi_PDFDocument_enableJS(js_State * J)4480 static void ffi_PDFDocument_enableJS(js_State *J)
4481 {
4482 	fz_context *ctx = js_getcontext(J);
4483 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4484 	fz_try(ctx)
4485 		pdf_enable_js(ctx, pdf);
4486 	fz_catch(ctx)
4487 		rethrow(J);
4488 }
4489 
ffi_PDFDocument_countVersions(js_State * J)4490 static void ffi_PDFDocument_countVersions(js_State *J)
4491 {
4492 	fz_context *ctx = js_getcontext(J);
4493 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4494 	int val = 0;
4495 	fz_try(ctx)
4496 		val = pdf_count_versions(ctx, pdf);
4497 	fz_catch(ctx)
4498 		rethrow(J);
4499 	js_pushnumber(J, val);
4500 }
4501 
ffi_PDFDocument_countUnsavedVersions(js_State * J)4502 static void ffi_PDFDocument_countUnsavedVersions(js_State *J)
4503 {
4504 	fz_context *ctx = js_getcontext(J);
4505 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4506 	int val = 0;
4507 	fz_try(ctx)
4508 		val = pdf_count_unsaved_versions(ctx, pdf);
4509 	fz_catch(ctx)
4510 		rethrow(J);
4511 	js_pushnumber(J, val);
4512 }
4513 
ffi_PDFDocument_validateChangeHistory(js_State * J)4514 static void ffi_PDFDocument_validateChangeHistory(js_State *J)
4515 {
4516 	fz_context *ctx = js_getcontext(J);
4517 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4518 	int val = 0;
4519 	fz_try(ctx)
4520 		val = pdf_validate_change_history(ctx, pdf);
4521 	fz_catch(ctx)
4522 		rethrow(J);
4523 	js_pushboolean(J, val);
4524 }
4525 
ffi_PDFDocument_wasPureXFA(js_State * J)4526 static void ffi_PDFDocument_wasPureXFA(js_State *J)
4527 {
4528 	fz_context *ctx = js_getcontext(J);
4529 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4530 	int val = 0;
4531 	fz_try(ctx)
4532 		val = pdf_validate_change_history(ctx, pdf);
4533 	fz_catch(ctx)
4534 		rethrow(J);
4535 	js_pushboolean(J, val);
4536 }
4537 
ffi_PDFDocument_hasUnsavedChanges(js_State * J)4538 static void ffi_PDFDocument_hasUnsavedChanges(js_State *J)
4539 {
4540 	fz_context *ctx = js_getcontext(J);
4541 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4542 	int val = 0;
4543 	fz_try(ctx)
4544 		val = pdf_has_unsaved_changes(ctx, pdf);
4545 	fz_catch(ctx)
4546 		rethrow(J);
4547 	js_pushboolean(J, val);
4548 }
4549 
ffi_PDFDocument_wasRepaired(js_State * J)4550 static void ffi_PDFDocument_wasRepaired(js_State *J)
4551 {
4552 	fz_context *ctx = js_getcontext(J);
4553 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4554 	int val = 0;
4555 	fz_try(ctx)
4556 		val = pdf_was_repaired(ctx, pdf);
4557 	fz_catch(ctx)
4558 		rethrow(J);
4559 	js_pushboolean(J, val);
4560 }
4561 
ffi_PDFDocument_canBeSavedIncrementally(js_State * J)4562 static void ffi_PDFDocument_canBeSavedIncrementally(js_State *J)
4563 {
4564 	fz_context *ctx = js_getcontext(J);
4565 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4566 	int val = 0;
4567 	fz_try(ctx)
4568 		val = pdf_can_be_saved_incrementally(ctx, pdf);
4569 	fz_catch(ctx)
4570 		rethrow(J);
4571 	js_pushboolean(J, val);
4572 }
4573 
ffi_PDFDocument_newGraftMap(js_State * J)4574 static void ffi_PDFDocument_newGraftMap(js_State *J)
4575 {
4576 	fz_context *ctx = js_getcontext(J);
4577 	pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
4578 	pdf_graft_map *map = NULL;
4579 	fz_try(ctx)
4580 		map = pdf_new_graft_map(ctx, pdf);
4581 	fz_catch(ctx)
4582 		rethrow(J);
4583 	js_getregistry(J, "pdf_graft_map");
4584 	js_newuserdata(J, "pdf_graft_map", map, ffi_gc_pdf_graft_map);
4585 }
4586 
ffi_PDFDocument_graftObject(js_State * J)4587 static void ffi_PDFDocument_graftObject(js_State *J)
4588 {
4589 	fz_context *ctx = js_getcontext(J);
4590 	pdf_document *dst = js_touserdata(J, 0, "pdf_document");
4591 	pdf_obj *obj = js_touserdata(J, 1, "pdf_obj");
4592 	fz_try(ctx)
4593 		obj = pdf_graft_object(ctx, dst, obj);
4594 	fz_catch(ctx)
4595 		rethrow(J);
4596 	ffi_pushobj(J, obj);
4597 }
4598 
ffi_PDFDocument_graftPage(js_State * J)4599 static void ffi_PDFDocument_graftPage(js_State *J)
4600 {
4601 	fz_context *ctx = js_getcontext(J);
4602 	pdf_document *dst = js_touserdata(J, 0, "pdf_document");
4603 	int to = js_tonumber(J, 1);
4604 	pdf_document *src = js_touserdata(J, 2, "pdf_document");
4605 	int from = js_tonumber(J, 3);
4606 	fz_try(ctx)
4607 		pdf_graft_page(ctx, dst, to, src, from);
4608 	fz_catch(ctx)
4609 		rethrow(J);
4610 }
4611 
ffi_PDFGraftMap_graftObject(js_State * J)4612 static void ffi_PDFGraftMap_graftObject(js_State *J)
4613 {
4614 	fz_context *ctx = js_getcontext(J);
4615 	pdf_graft_map *map = js_touserdata(J, 0, "pdf_graft_map");
4616 	pdf_obj *obj = js_touserdata(J, 1, "pdf_obj");
4617 	fz_try(ctx)
4618 		obj = pdf_graft_mapped_object(ctx, map, obj);
4619 	fz_catch(ctx)
4620 		rethrow(J);
4621 	ffi_pushobj(J, obj);
4622 }
4623 
ffi_PDFGraftMap_graftPage(js_State * J)4624 static void ffi_PDFGraftMap_graftPage(js_State *J)
4625 {
4626 	fz_context *ctx = js_getcontext(J);
4627 	pdf_graft_map *map = js_touserdata(J, 0, "pdf_graft_map");
4628 	int to = js_tointeger(J, 1);
4629 	pdf_document *src = js_touserdata(J, 2, "pdf_document");
4630 	int from = js_tointeger(J, 3);
4631 	fz_try(ctx)
4632 		pdf_graft_mapped_page(ctx, map, to, src, from);
4633 	fz_catch(ctx)
4634 		rethrow(J);
4635 }
4636 
ffi_PDFObject_get(js_State * J)4637 static void ffi_PDFObject_get(js_State *J)
4638 {
4639 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4640 	const char *key = js_tostring(J, 1);
4641 	if (!ffi_pdf_obj_has(J, obj, key))
4642 		js_pushundefined(J);
4643 }
4644 
ffi_PDFObject_put(js_State * J)4645 static void ffi_PDFObject_put(js_State *J)
4646 {
4647 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4648 	const char *key = js_tostring(J, 1);
4649 	js_copy(J, 2);
4650 	ffi_pdf_obj_put(J, obj, key);
4651 }
4652 
ffi_PDFObject_delete(js_State * J)4653 static void ffi_PDFObject_delete(js_State *J)
4654 {
4655 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4656 	const char *key = js_tostring(J, 1);
4657 	ffi_pdf_obj_delete(J, obj, key);
4658 }
4659 
ffi_PDFObject_push(js_State * J)4660 static void ffi_PDFObject_push(js_State *J)
4661 {
4662 	fz_context *ctx = js_getcontext(J);
4663 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4664 	pdf_document *pdf = pdf_get_bound_document(ctx, obj);
4665 	pdf_obj *item = ffi_toobj(J, pdf, 1);
4666 	fz_try(ctx)
4667 		pdf_array_push(ctx, obj, item);
4668 	fz_always(ctx)
4669 		pdf_drop_obj(ctx, item);
4670 	fz_catch(ctx)
4671 		rethrow(J);
4672 }
4673 
ffi_PDFObject_resolve(js_State * J)4674 static void ffi_PDFObject_resolve(js_State *J)
4675 {
4676 	fz_context *ctx = js_getcontext(J);
4677 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4678 	pdf_obj *ind = NULL;
4679 	fz_try(ctx)
4680 		ind = pdf_resolve_indirect(ctx, obj);
4681 	fz_catch(ctx)
4682 		rethrow(J);
4683 	ffi_pushobj(J, pdf_keep_obj(ctx, ind));
4684 }
4685 
ffi_PDFObject_toString(js_State * J)4686 static void ffi_PDFObject_toString(js_State *J)
4687 {
4688 	fz_context *ctx = js_getcontext(J);
4689 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4690 	int tight = js_isdefined(J, 1) ? js_toboolean(J, 1) : 1;
4691 	int ascii = js_isdefined(J, 2) ? js_toboolean(J, 2) : 0;
4692 	char *s = NULL;
4693 	size_t n;
4694 
4695 	fz_try(ctx)
4696 		s = pdf_sprint_obj(ctx, NULL, 0, &n, obj, tight, ascii);
4697 	fz_catch(ctx)
4698 		rethrow(J);
4699 
4700 	if (js_try(J)) {
4701 		fz_free(ctx, s);
4702 		js_throw(J);
4703 	}
4704 	js_pushstring(J, s);
4705 	js_endtry(J);
4706 	fz_free(ctx, s);
4707 }
4708 
ffi_PDFObject_valueOf(js_State * J)4709 static void ffi_PDFObject_valueOf(js_State *J)
4710 {
4711 	fz_context *ctx = js_getcontext(J);
4712 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4713 	if (pdf_is_indirect(ctx, obj))
4714 		js_pushstring(J, "R");
4715 	else if (pdf_is_null(ctx, obj))
4716 		js_pushnull(J);
4717 	else if (pdf_is_bool(ctx, obj))
4718 		js_pushboolean(J, pdf_to_bool(ctx, obj));
4719 	else if (pdf_is_int(ctx, obj))
4720 		js_pushnumber(J, pdf_to_int(ctx, obj));
4721 	else if (pdf_is_real(ctx, obj))
4722 		js_pushnumber(J, pdf_to_real(ctx, obj));
4723 	else if (pdf_is_string(ctx, obj))
4724 		js_pushlstring(J, pdf_to_str_buf(ctx, obj), (int)pdf_to_str_len(ctx, obj));
4725 	else if (pdf_is_name(ctx, obj))
4726 		js_pushstring(J, pdf_to_name(ctx, obj));
4727 	else
4728 		js_copy(J, 0);
4729 }
4730 
ffi_PDFObject_isArray(js_State * J)4731 static void ffi_PDFObject_isArray(js_State *J)
4732 {
4733 	fz_context *ctx = js_getcontext(J);
4734 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4735 	int b = 0;
4736 	fz_try(ctx)
4737 		b = pdf_is_array(ctx, obj);
4738 	fz_catch(ctx)
4739 		rethrow(J);
4740 	js_pushboolean(J, b);
4741 }
4742 
ffi_PDFObject_isDictionary(js_State * J)4743 static void ffi_PDFObject_isDictionary(js_State *J)
4744 {
4745 	fz_context *ctx = js_getcontext(J);
4746 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4747 	int b = 0;
4748 	fz_try(ctx)
4749 		b = pdf_is_dict(ctx, obj);
4750 	fz_catch(ctx)
4751 		rethrow(J);
4752 	js_pushboolean(J, b);
4753 }
4754 
ffi_PDFObject_isIndirect(js_State * J)4755 static void ffi_PDFObject_isIndirect(js_State *J)
4756 {
4757 	fz_context *ctx = js_getcontext(J);
4758 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4759 	int b = 0;
4760 	fz_try(ctx)
4761 		b = pdf_is_indirect(ctx, obj);
4762 	fz_catch(ctx)
4763 		rethrow(J);
4764 	js_pushboolean(J, b);
4765 }
4766 
ffi_PDFObject_asIndirect(js_State * J)4767 static void ffi_PDFObject_asIndirect(js_State *J)
4768 {
4769 	fz_context *ctx = js_getcontext(J);
4770 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4771 	int num = 0;
4772 	fz_try(ctx)
4773 		num = pdf_to_num(ctx, obj);
4774 	fz_catch(ctx)
4775 		rethrow(J);
4776 	js_pushnumber(J, num);
4777 }
4778 
ffi_PDFObject_isNull(js_State * J)4779 static void ffi_PDFObject_isNull(js_State *J)
4780 {
4781 	fz_context *ctx = js_getcontext(J);
4782 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4783 	int b = 0;
4784 	fz_try(ctx)
4785 		b = pdf_is_null(ctx, obj);
4786 	fz_catch(ctx)
4787 		rethrow(J);
4788 	js_pushboolean(J, b);
4789 }
4790 
ffi_PDFObject_isBoolean(js_State * J)4791 static void ffi_PDFObject_isBoolean(js_State *J)
4792 {
4793 	fz_context *ctx = js_getcontext(J);
4794 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4795 	int b = 0;
4796 	fz_try(ctx)
4797 		b = pdf_is_bool(ctx, obj);
4798 	fz_catch(ctx)
4799 		rethrow(J);
4800 	js_pushboolean(J, b);
4801 }
4802 
ffi_PDFObject_asBoolean(js_State * J)4803 static void ffi_PDFObject_asBoolean(js_State *J)
4804 {
4805 	fz_context *ctx = js_getcontext(J);
4806 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4807 	int b = 0;
4808 	fz_try(ctx)
4809 		b = pdf_to_bool(ctx, obj);
4810 	fz_catch(ctx)
4811 		rethrow(J);
4812 	js_pushboolean(J, b);
4813 }
4814 
ffi_PDFObject_isNumber(js_State * J)4815 static void ffi_PDFObject_isNumber(js_State *J)
4816 {
4817 	fz_context *ctx = js_getcontext(J);
4818 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4819 	int b = 0;
4820 	fz_try(ctx)
4821 		b = pdf_is_number(ctx, obj);
4822 	fz_catch(ctx)
4823 		rethrow(J);
4824 	js_pushboolean(J, b);
4825 }
4826 
ffi_PDFObject_asNumber(js_State * J)4827 static void ffi_PDFObject_asNumber(js_State *J)
4828 {
4829 	fz_context *ctx = js_getcontext(J);
4830 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4831 	float num = 0;
4832 	fz_try(ctx)
4833 		if (pdf_is_int(ctx, obj))
4834 			num = pdf_to_int(ctx, obj);
4835 		else
4836 			num = pdf_to_real(ctx, obj);
4837 	fz_catch(ctx)
4838 		rethrow(J);
4839 	js_pushnumber(J, num);
4840 }
4841 
ffi_PDFObject_isName(js_State * J)4842 static void ffi_PDFObject_isName(js_State *J)
4843 {
4844 	fz_context *ctx = js_getcontext(J);
4845 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4846 	int b = 0;
4847 	fz_try(ctx)
4848 		b = pdf_is_name(ctx, obj);
4849 	fz_catch(ctx)
4850 		rethrow(J);
4851 	js_pushboolean(J, b);
4852 }
4853 
ffi_PDFObject_asName(js_State * J)4854 static void ffi_PDFObject_asName(js_State *J)
4855 {
4856 	fz_context *ctx = js_getcontext(J);
4857 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4858 	const char *name = NULL;
4859 	fz_try(ctx)
4860 		name = pdf_to_name(ctx, obj);
4861 	fz_catch(ctx)
4862 		rethrow(J);
4863 	js_pushstring(J, name);
4864 }
4865 
ffi_PDFObject_isString(js_State * J)4866 static void ffi_PDFObject_isString(js_State *J)
4867 {
4868 	fz_context *ctx = js_getcontext(J);
4869 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4870 	int b = 0;
4871 	fz_try(ctx)
4872 		b = pdf_is_string(ctx, obj);
4873 	fz_catch(ctx)
4874 		rethrow(J);
4875 	js_pushboolean(J, b);
4876 }
4877 
ffi_PDFObject_asString(js_State * J)4878 static void ffi_PDFObject_asString(js_State *J)
4879 {
4880 	fz_context *ctx = js_getcontext(J);
4881 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4882 	const char *string = NULL;
4883 
4884 	fz_try(ctx)
4885 		string = pdf_to_text_string(ctx, obj);
4886 	fz_catch(ctx)
4887 		rethrow(J);
4888 
4889 	js_pushstring(J, string);
4890 }
4891 
ffi_PDFObject_asByteString(js_State * J)4892 static void ffi_PDFObject_asByteString(js_State *J)
4893 {
4894 	fz_context *ctx = js_getcontext(J);
4895 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4896 	const char *buf;
4897 	size_t i, len = 0;
4898 
4899 	fz_try(ctx)
4900 		buf = pdf_to_string(ctx, obj, &len);
4901 	fz_catch(ctx)
4902 		rethrow(J);
4903 
4904 	js_newarray(J);
4905 	for (i = 0; i < len; ++i) {
4906 		js_pushnumber(J, (unsigned char)buf[i]);
4907 		js_setindex(J, -2, (int)i);
4908 	}
4909 }
4910 
ffi_PDFObject_isStream(js_State * J)4911 static void ffi_PDFObject_isStream(js_State *J)
4912 {
4913 	fz_context *ctx = js_getcontext(J);
4914 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4915 	int b = 0;
4916 	fz_try(ctx)
4917 		b = pdf_is_stream(ctx, obj);
4918 	fz_catch(ctx)
4919 		rethrow(J);
4920 	js_pushboolean(J, b);
4921 }
4922 
ffi_PDFObject_readStream(js_State * J)4923 static void ffi_PDFObject_readStream(js_State *J)
4924 {
4925 	fz_context *ctx = js_getcontext(J);
4926 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4927 	fz_buffer *buf = NULL;
4928 	fz_try(ctx)
4929 		buf = pdf_load_stream(ctx, obj);
4930 	fz_catch(ctx)
4931 		rethrow(J);
4932 	ffi_pushbuffer(J, buf);
4933 }
4934 
ffi_PDFObject_readRawStream(js_State * J)4935 static void ffi_PDFObject_readRawStream(js_State *J)
4936 {
4937 	fz_context *ctx = js_getcontext(J);
4938 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4939 	fz_buffer *buf = NULL;
4940 	fz_try(ctx)
4941 		buf = pdf_load_raw_stream(ctx, obj);
4942 	fz_catch(ctx)
4943 		rethrow(J);
4944 	ffi_pushbuffer(J, buf);
4945 }
4946 
ffi_PDFObject_writeObject(js_State * J)4947 static void ffi_PDFObject_writeObject(js_State *J)
4948 {
4949 	fz_context *ctx = js_getcontext(J);
4950 	pdf_obj *ref = js_touserdata(J, 0, "pdf_obj");
4951 	pdf_document *pdf = pdf_get_bound_document(ctx, ref);
4952 	pdf_obj *obj = ffi_toobj(J, pdf, 1);
4953 	fz_try(ctx)
4954 		pdf_update_object(ctx, pdf, pdf_to_num(ctx, ref), obj);
4955 	fz_always(ctx)
4956 		pdf_drop_obj(ctx, obj);
4957 	fz_catch(ctx)
4958 		rethrow(J);
4959 }
4960 
ffi_PDFObject_writeStream(js_State * J)4961 static void ffi_PDFObject_writeStream(js_State *J)
4962 {
4963 	fz_context *ctx = js_getcontext(J);
4964 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4965 	fz_buffer *buf = ffi_tobuffer(J, 1);
4966 	fz_try(ctx)
4967 		pdf_update_stream(ctx, pdf_get_bound_document(ctx, obj), obj, buf, 0);
4968 	fz_always(ctx)
4969 		fz_drop_buffer(ctx, buf);
4970 	fz_catch(ctx)
4971 		rethrow(J);
4972 }
4973 
ffi_PDFObject_writeRawStream(js_State * J)4974 static void ffi_PDFObject_writeRawStream(js_State *J)
4975 {
4976 	fz_context *ctx = js_getcontext(J);
4977 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4978 	fz_buffer *buf = ffi_tobuffer(J, 1);
4979 	fz_try(ctx)
4980 		pdf_update_stream(ctx, pdf_get_bound_document(ctx, obj), obj, buf, 1);
4981 	fz_always(ctx)
4982 		fz_drop_buffer(ctx, buf);
4983 	fz_catch(ctx)
4984 		rethrow(J);
4985 }
4986 
ffi_PDFObject_forEach(js_State * J)4987 static void ffi_PDFObject_forEach(js_State *J)
4988 {
4989 	fz_context *ctx = js_getcontext(J);
4990 	pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
4991 	pdf_obj *val = NULL;
4992 	const char *key = NULL;
4993 	int i, n = 0;
4994 
4995 	fz_try(ctx)
4996 		obj = pdf_resolve_indirect_chain(ctx, obj);
4997 	fz_catch(ctx)
4998 		rethrow(J);
4999 
5000 	if (pdf_is_array(ctx, obj)) {
5001 		fz_try(ctx)
5002 			n = pdf_array_len(ctx, obj);
5003 		fz_catch(ctx)
5004 			rethrow(J);
5005 		for (i = 0; i < n; ++i) {
5006 			fz_try(ctx)
5007 				val = pdf_array_get(ctx, obj, i);
5008 			fz_catch(ctx)
5009 				rethrow(J);
5010 			js_copy(J, 1);
5011 			js_pushnull(J);
5012 			js_pushnumber(J, i);
5013 			ffi_pushobj(J, pdf_keep_obj(ctx, val));
5014 			js_call(J, 2);
5015 			js_pop(J, 1);
5016 		}
5017 		return;
5018 	}
5019 
5020 	if (pdf_is_dict(ctx, obj)) {
5021 		fz_try(ctx)
5022 			n = pdf_dict_len(ctx, obj);
5023 		fz_catch(ctx)
5024 			rethrow(J);
5025 		for (i = 0; i < n; ++i) {
5026 			fz_try(ctx) {
5027 				key = pdf_to_name(ctx, pdf_dict_get_key(ctx, obj, i));
5028 				val = pdf_dict_get_val(ctx, obj, i);
5029 			} fz_catch(ctx)
5030 				rethrow(J);
5031 			js_copy(J, 1);
5032 			js_pushnull(J);
5033 			js_pushstring(J, key);
5034 			ffi_pushobj(J, pdf_keep_obj(ctx, val));
5035 			js_call(J, 2);
5036 			js_pop(J, 1);
5037 		}
5038 		return;
5039 	}
5040 }
5041 
ffi_PDFPage_getWidgets(js_State * J)5042 static void ffi_PDFPage_getWidgets(js_State *J)
5043 {
5044 	fz_context *ctx = js_getcontext(J);
5045 	pdf_page *page = js_touserdata(J, 0, "pdf_page");
5046 	pdf_widget *widget = NULL;
5047 	int i = 0;
5048 
5049 	fz_try(ctx)
5050 		widget = pdf_first_widget(ctx, page);
5051 	fz_catch(ctx)
5052 		rethrow(J);
5053 
5054 	js_newarray(J);
5055 
5056 	while (widget) {
5057 		js_getregistry(J, "pdf_widget");
5058 		js_newuserdata(J, "pdf_widget", pdf_keep_widget(ctx, widget), ffi_gc_pdf_widget);
5059 		js_setindex(J, -2, i++);
5060 
5061 		fz_try(ctx)
5062 			widget = pdf_next_widget(ctx, widget);
5063 		fz_catch(ctx)
5064 			rethrow(J);
5065 	}
5066 }
5067 
ffi_PDFPage_getAnnotations(js_State * J)5068 static void ffi_PDFPage_getAnnotations(js_State *J)
5069 {
5070 	fz_context *ctx = js_getcontext(J);
5071 	pdf_page *page = js_touserdata(J, 0, "pdf_page");
5072 	pdf_annot *annot = NULL;
5073 	int i = 0;
5074 
5075 	fz_try(ctx)
5076 		annot = pdf_first_annot(ctx, page);
5077 	fz_catch(ctx)
5078 		rethrow(J);
5079 
5080 	js_newarray(J);
5081 
5082 	while (annot) {
5083 		js_getregistry(J, "pdf_annot");
5084 		js_newuserdata(J, "pdf_annot", pdf_keep_annot(ctx, annot), ffi_gc_pdf_annot);
5085 		js_setindex(J, -2, i++);
5086 
5087 		fz_try(ctx)
5088 			annot = pdf_next_annot(ctx, annot);
5089 		fz_catch(ctx)
5090 			rethrow(J);
5091 	}
5092 }
5093 
ffi_PDFPage_createAnnotation(js_State * J)5094 static void ffi_PDFPage_createAnnotation(js_State *J)
5095 {
5096 	fz_context *ctx = js_getcontext(J);
5097 	pdf_page *page = js_touserdata(J, 0, "pdf_page");
5098 	const char *name = js_tostring(J, 1);
5099 	pdf_annot *annot = NULL;
5100 	int subtype;
5101 
5102 	fz_try(ctx)
5103 	{
5104 		subtype = pdf_annot_type_from_string(ctx, name);
5105 		annot = pdf_create_annot(ctx, page, subtype);
5106 	}
5107 	fz_catch(ctx)
5108 		rethrow(J);
5109 	js_getregistry(J, "pdf_annot");
5110 	js_newuserdata(J, "pdf_annot", annot, ffi_gc_pdf_annot);
5111 }
5112 
ffi_PDFPage_deleteAnnotation(js_State * J)5113 static void ffi_PDFPage_deleteAnnotation(js_State *J)
5114 {
5115 	fz_context *ctx = js_getcontext(J);
5116 	pdf_page *page = js_touserdata(J, 0, "pdf_page");
5117 	pdf_annot *annot = js_touserdata(J, 1, "pdf_annot");
5118 	fz_try(ctx)
5119 		pdf_delete_annot(ctx, page, annot);
5120 	fz_catch(ctx)
5121 		rethrow(J);
5122 }
5123 
ffi_PDFPage_update(js_State * J)5124 static void ffi_PDFPage_update(js_State *J)
5125 {
5126 	fz_context *ctx = js_getcontext(J);
5127 	pdf_page *page = js_touserdata(J, 0, "pdf_page");
5128 	int changed = 0;
5129 	fz_try(ctx)
5130 		changed = pdf_update_page(ctx, page);
5131 	fz_catch(ctx)
5132 		rethrow(J);
5133 	js_pushboolean(J, changed);
5134 }
5135 
ffi_PDFPage_applyRedactions(js_State * J)5136 static void ffi_PDFPage_applyRedactions(js_State *J)
5137 {
5138 	fz_context *ctx = js_getcontext(J);
5139 	pdf_page *page = js_touserdata(J, 0, "pdf_page");
5140 	pdf_redact_options opts = { 1, PDF_REDACT_IMAGE_PIXELS };
5141 	if (js_isdefined(J, 1)) opts.black_boxes = js_toboolean(J, 1);
5142 	if (js_isdefined(J, 2)) opts.image_method = js_tointeger(J, 2);
5143 	fz_try(ctx)
5144 		pdf_redact_page(ctx, page->doc, page, &opts);
5145 	fz_catch(ctx)
5146 		rethrow(J);
5147 }
5148 
ffi_PDFPage_process(js_State * J)5149 static void ffi_PDFPage_process(js_State *J)
5150 {
5151 	fz_context *ctx = js_getcontext(J);
5152 	pdf_page *page = js_touserdata(J, 0, "pdf_page");
5153 	pdf_processor *proc = new_js_processor(ctx, J);
5154 	fz_try(ctx)
5155 	{
5156 		pdf_obj *resources = pdf_page_resources(ctx, page);
5157 		pdf_obj *contents = pdf_page_contents(ctx, page);
5158 		pdf_process_contents(ctx, proc, page->doc, resources, contents, NULL);
5159 		pdf_close_processor(ctx, proc);
5160 	}
5161 	fz_always(ctx)
5162 		pdf_drop_processor(ctx, proc);
5163 	fz_catch(ctx)
5164 		rethrow(J);
5165 }
5166 
ffi_PDFAnnotation_bound(js_State * J)5167 static void ffi_PDFAnnotation_bound(js_State *J)
5168 {
5169 	fz_context *ctx = js_getcontext(J);
5170 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5171 	fz_rect bounds;
5172 
5173 	fz_try(ctx)
5174 		bounds = pdf_bound_annot(ctx, annot);
5175 	fz_catch(ctx)
5176 		rethrow(J);
5177 
5178 	ffi_pushrect(J, bounds);
5179 }
5180 
ffi_PDFAnnotation_run(js_State * J)5181 static void ffi_PDFAnnotation_run(js_State *J)
5182 {
5183 	fz_context *ctx = js_getcontext(J);
5184 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5185 	fz_device *device = NULL;
5186 	fz_matrix ctm = ffi_tomatrix(J, 2);
5187 
5188 	if (js_isuserdata(J, 1, "fz_device")) {
5189 		device = js_touserdata(J, 1, "fz_device");
5190 		fz_try(ctx)
5191 			pdf_run_annot(ctx, annot, device, ctm, NULL);
5192 		fz_catch(ctx)
5193 			rethrow(J);
5194 	} else {
5195 		device = new_js_device(ctx, J);
5196 		js_copy(J, 1); /* put the js device on the top so the callbacks know where to get it */
5197 		fz_try(ctx) {
5198 			pdf_run_annot(ctx, annot, device, ctm, NULL);
5199 			fz_close_device(ctx, device);
5200 		}
5201 		fz_always(ctx)
5202 			fz_drop_device(ctx, device);
5203 		fz_catch(ctx)
5204 			rethrow(J);
5205 	}
5206 }
5207 
ffi_PDFAnnotation_toDisplayList(js_State * J)5208 static void ffi_PDFAnnotation_toDisplayList(js_State *J)
5209 {
5210 	fz_context *ctx = js_getcontext(J);
5211 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5212 	fz_display_list *list = NULL;
5213 
5214 	fz_try(ctx)
5215 		list = pdf_new_display_list_from_annot(ctx, annot);
5216 	fz_catch(ctx)
5217 		rethrow(J);
5218 
5219 	js_getregistry(J, "fz_display_list");
5220 	js_newuserdata(J, "fz_display_list", list, ffi_gc_fz_display_list);
5221 }
5222 
ffi_PDFAnnotation_toPixmap(js_State * J)5223 static void ffi_PDFAnnotation_toPixmap(js_State *J)
5224 {
5225 	fz_context *ctx = js_getcontext(J);
5226 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5227 	fz_matrix ctm = ffi_tomatrix(J, 1);
5228 	fz_colorspace *colorspace = js_touserdata(J, 2, "fz_colorspace");
5229 	int alpha = js_toboolean(J, 3);
5230 	fz_pixmap *pixmap = NULL;
5231 
5232 	fz_try(ctx)
5233 		pixmap = pdf_new_pixmap_from_annot(ctx, annot, ctm, colorspace, NULL, alpha);
5234 	fz_catch(ctx)
5235 		rethrow(J);
5236 
5237 	js_getregistry(J, "fz_pixmap");
5238 	js_newuserdata(J, "fz_pixmap", pixmap, ffi_gc_fz_pixmap);
5239 }
5240 
ffi_PDFAnnotation_getType(js_State * J)5241 static void ffi_PDFAnnotation_getType(js_State *J)
5242 {
5243 	fz_context *ctx = js_getcontext(J);
5244 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5245 	int type;
5246 	const char *subtype = NULL;
5247 	fz_try(ctx)
5248 	{
5249 		type = pdf_annot_type(ctx, annot);
5250 		subtype = pdf_string_from_annot_type(ctx, type);
5251 	}
5252 	fz_catch(ctx)
5253 		rethrow(J);
5254 	js_pushstring(J, subtype);
5255 }
5256 
ffi_PDFAnnotation_getFlags(js_State * J)5257 static void ffi_PDFAnnotation_getFlags(js_State *J)
5258 {
5259 	fz_context *ctx = js_getcontext(J);
5260 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5261 	int flags = 0;
5262 	fz_try(ctx)
5263 		flags = pdf_annot_flags(ctx, annot);
5264 	fz_catch(ctx)
5265 		rethrow(J);
5266 	js_pushnumber(J, flags);
5267 }
5268 
ffi_PDFAnnotation_setFlags(js_State * J)5269 static void ffi_PDFAnnotation_setFlags(js_State *J)
5270 {
5271 	fz_context *ctx = js_getcontext(J);
5272 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5273 	int flags = js_tonumber(J, 1);
5274 	fz_try(ctx)
5275 		pdf_set_annot_flags(ctx, annot, flags);
5276 	fz_catch(ctx)
5277 		rethrow(J);
5278 }
5279 
ffi_PDFAnnotation_getContents(js_State * J)5280 static void ffi_PDFAnnotation_getContents(js_State *J)
5281 {
5282 	fz_context *ctx = js_getcontext(J);
5283 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5284 	const char *contents = NULL;
5285 
5286 	fz_try(ctx)
5287 		contents = pdf_annot_contents(ctx, annot);
5288 	fz_catch(ctx)
5289 		rethrow(J);
5290 
5291 	js_pushstring(J, contents);
5292 }
5293 
ffi_PDFAnnotation_setContents(js_State * J)5294 static void ffi_PDFAnnotation_setContents(js_State *J)
5295 {
5296 	fz_context *ctx = js_getcontext(J);
5297 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5298 	const char *contents = js_tostring(J, 1);
5299 	fz_try(ctx)
5300 		pdf_set_annot_contents(ctx, annot, contents);
5301 	fz_catch(ctx)
5302 		rethrow(J);
5303 }
5304 
ffi_PDFAnnotation_getRect(js_State * J)5305 static void ffi_PDFAnnotation_getRect(js_State *J)
5306 {
5307 	fz_context *ctx = js_getcontext(J);
5308 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5309 	fz_rect rect;
5310 	fz_try(ctx)
5311 		rect = pdf_annot_rect(ctx, annot);
5312 	fz_catch(ctx)
5313 		rethrow(J);
5314 	ffi_pushrect(J, rect);
5315 }
5316 
ffi_PDFAnnotation_setRect(js_State * J)5317 static void ffi_PDFAnnotation_setRect(js_State *J)
5318 {
5319 	fz_context *ctx = js_getcontext(J);
5320 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5321 	fz_rect rect = ffi_torect(J, 1);
5322 	fz_try(ctx)
5323 		pdf_set_annot_rect(ctx, annot, rect);
5324 	fz_catch(ctx)
5325 		rethrow(J);
5326 }
5327 
ffi_PDFAnnotation_getBorder(js_State * J)5328 static void ffi_PDFAnnotation_getBorder(js_State *J)
5329 {
5330 	fz_context *ctx = js_getcontext(J);
5331 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5332 	float border = 0;
5333 	fz_try(ctx)
5334 		border = pdf_annot_border(ctx, annot);
5335 	fz_catch(ctx)
5336 		rethrow(J);
5337 	js_pushnumber(J, border);
5338 }
5339 
ffi_PDFAnnotation_setBorder(js_State * J)5340 static void ffi_PDFAnnotation_setBorder(js_State *J)
5341 {
5342 	fz_context *ctx = js_getcontext(J);
5343 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5344 	float border = js_tonumber(J, 1);
5345 	fz_try(ctx)
5346 		pdf_set_annot_border(ctx, annot, border);
5347 	fz_catch(ctx)
5348 		rethrow(J);
5349 }
5350 
ffi_PDFAnnotation_getColor(js_State * J)5351 static void ffi_PDFAnnotation_getColor(js_State *J)
5352 {
5353 	fz_context *ctx = js_getcontext(J);
5354 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5355 	int i, n = 0;
5356 	float color[4];
5357 	fz_try(ctx)
5358 		pdf_annot_color(ctx, annot, &n, color);
5359 	fz_catch(ctx)
5360 		rethrow(J);
5361 	js_newarray(J);
5362 	for (i = 0; i < n; ++i) {
5363 		js_pushnumber(J, color[i]);
5364 		js_setindex(J, -2, i);
5365 	}
5366 }
5367 
ffi_PDFAnnotation_setColor(js_State * J)5368 static void ffi_PDFAnnotation_setColor(js_State *J)
5369 {
5370 	fz_context *ctx = js_getcontext(J);
5371 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5372 	int i, n = js_getlength(J, 1);
5373 	float color[4];
5374 	for (i = 0; i < n && i < 4; ++i) {
5375 		js_getindex(J, 1, i);
5376 		color[i] = js_tonumber(J, -1);
5377 		js_pop(J, 1);
5378 	}
5379 	fz_try(ctx)
5380 		pdf_set_annot_color(ctx, annot, n, color);
5381 	fz_catch(ctx)
5382 		rethrow(J);
5383 }
5384 
ffi_PDFAnnotation_getInteriorColor(js_State * J)5385 static void ffi_PDFAnnotation_getInteriorColor(js_State *J)
5386 {
5387 	fz_context *ctx = js_getcontext(J);
5388 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5389 	int i, n = 0;
5390 	float color[4];
5391 	fz_try(ctx)
5392 		pdf_annot_interior_color(ctx, annot, &n, color);
5393 	fz_catch(ctx)
5394 		rethrow(J);
5395 	js_newarray(J);
5396 	for (i = 0; i < n; ++i) {
5397 		js_pushnumber(J, color[i]);
5398 		js_setindex(J, -2, i);
5399 	}
5400 }
5401 
ffi_PDFAnnotation_setInteriorColor(js_State * J)5402 static void ffi_PDFAnnotation_setInteriorColor(js_State *J)
5403 {
5404 	fz_context *ctx = js_getcontext(J);
5405 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5406 	int i, n = js_getlength(J, 1);
5407 	float color[4];
5408 	for (i = 0; i < n && i < 4; ++i) {
5409 		js_getindex(J, 1, i);
5410 		color[i] = js_tonumber(J, -1);
5411 		js_pop(J, 1);
5412 	}
5413 	fz_try(ctx)
5414 		pdf_set_annot_interior_color(ctx, annot, n, color);
5415 	fz_catch(ctx)
5416 		rethrow(J);
5417 }
5418 
ffi_PDFAnnotation_getQuadPoints(js_State * J)5419 static void ffi_PDFAnnotation_getQuadPoints(js_State *J)
5420 {
5421 	fz_context *ctx = js_getcontext(J);
5422 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5423 	fz_quad q;
5424 	int i, n = 0;
5425 
5426 	fz_try(ctx)
5427 		n = pdf_annot_quad_point_count(ctx, annot);
5428 	fz_catch(ctx)
5429 		rethrow(J);
5430 
5431 	js_newarray(J);
5432 	for (i = 0; i < n; ++i) {
5433 		fz_try(ctx)
5434 			q = pdf_annot_quad_point(ctx, annot, i);
5435 		fz_catch(ctx)
5436 			rethrow(J);
5437 		ffi_pushquad(J, q);
5438 		js_setindex(J, -2, i);
5439 	}
5440 }
5441 
ffi_PDFAnnotation_setQuadPoints(js_State * J)5442 static void ffi_PDFAnnotation_setQuadPoints(js_State *J)
5443 {
5444 	fz_context *ctx = js_getcontext(J);
5445 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5446 	fz_quad *qp = NULL;
5447 	int i, n;
5448 
5449 	n = js_getlength(J, 1);
5450 
5451 	fz_try(ctx)
5452 		qp = fz_malloc_array(ctx, n, fz_quad);
5453 	fz_catch(ctx)
5454 		rethrow(J);
5455 
5456 	for (i = 0; i < n; ++i) {
5457 		js_getindex(J, 1, i);
5458 		qp[i] = ffi_toquad(J, -1);
5459 		js_pop(J, 1);
5460 	}
5461 
5462 	fz_try(ctx)
5463 		pdf_set_annot_quad_points(ctx, annot, n, qp);
5464 	fz_always(ctx)
5465 		fz_free(ctx, qp);
5466 	fz_catch(ctx)
5467 		rethrow(J);
5468 }
5469 
ffi_PDFAnnotation_clearQuadPoints(js_State * J)5470 static void ffi_PDFAnnotation_clearQuadPoints(js_State *J)
5471 {
5472 	fz_context *ctx = js_getcontext(J);
5473 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5474 
5475 	fz_try(ctx)
5476 		pdf_clear_annot_quad_points(ctx, annot);
5477 	fz_catch(ctx)
5478 		rethrow(J);
5479 }
5480 
ffi_PDFAnnotation_addQuadPoint(js_State * J)5481 static void ffi_PDFAnnotation_addQuadPoint(js_State *J)
5482 {
5483 	fz_context *ctx = js_getcontext(J);
5484 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5485 	fz_quad q = ffi_toquad(J, 1);
5486 
5487 	fz_try(ctx)
5488 		pdf_add_annot_quad_point(ctx, annot, q);
5489 	fz_catch(ctx)
5490 		rethrow(J);
5491 }
5492 
ffi_PDFAnnotation_getVertices(js_State * J)5493 static void ffi_PDFAnnotation_getVertices(js_State *J)
5494 {
5495 	fz_context *ctx = js_getcontext(J);
5496 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5497 	fz_point p;
5498 	int i, n = 0;
5499 
5500 	fz_try(ctx)
5501 		n = pdf_annot_vertex_count(ctx, annot);
5502 	fz_catch(ctx)
5503 		rethrow(J);
5504 
5505 	js_newarray(J);
5506 	for (i = 0; i < n; ++i) {
5507 		fz_try(ctx)
5508 			p = pdf_annot_vertex(ctx, annot, i);
5509 		fz_catch(ctx)
5510 			rethrow(J);
5511 		ffi_pushpoint(J, p);
5512 		js_setindex(J, -2, i);
5513 	}
5514 }
5515 
ffi_PDFAnnotation_setVertices(js_State * J)5516 static void ffi_PDFAnnotation_setVertices(js_State *J)
5517 {
5518 	fz_context *ctx = js_getcontext(J);
5519 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5520 	fz_point p;
5521 	int i, n;
5522 
5523 	n = js_getlength(J, 1);
5524 
5525 	fz_try(ctx)
5526 		pdf_clear_annot_vertices(ctx, annot);
5527 	fz_catch(ctx)
5528 		rethrow(J);
5529 
5530 	for (i = 0; i < n; ++i) {
5531 		js_getindex(J, 1, i);
5532 		p = ffi_topoint(J, -1);
5533 		js_pop(J, 1);
5534 
5535 		fz_try(ctx)
5536 			pdf_add_annot_vertex(ctx, annot, p);
5537 		fz_catch(ctx)
5538 			rethrow(J);
5539 	}
5540 }
5541 
ffi_PDFAnnotation_clearVertices(js_State * J)5542 static void ffi_PDFAnnotation_clearVertices(js_State *J)
5543 {
5544 	fz_context *ctx = js_getcontext(J);
5545 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5546 
5547 	fz_try(ctx)
5548 		pdf_clear_annot_vertices(ctx, annot);
5549 	fz_catch(ctx)
5550 		rethrow(J);
5551 }
5552 
ffi_PDFAnnotation_addVertex(js_State * J)5553 static void ffi_PDFAnnotation_addVertex(js_State *J)
5554 {
5555 	fz_context *ctx = js_getcontext(J);
5556 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5557 	fz_point p = ffi_topoint(J, 1);
5558 
5559 	fz_try(ctx)
5560 		pdf_add_annot_vertex(ctx, annot, p);
5561 	fz_catch(ctx)
5562 		rethrow(J);
5563 }
5564 
ffi_PDFAnnotation_getInkList(js_State * J)5565 static void ffi_PDFAnnotation_getInkList(js_State *J)
5566 {
5567 	fz_context *ctx = js_getcontext(J);
5568 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5569 	int i, k, m = 0, n = 0;
5570 	fz_point pt;
5571 
5572 	js_newarray(J);
5573 
5574 	fz_try(ctx)
5575 		n = pdf_annot_ink_list_count(ctx, annot);
5576 	fz_catch(ctx)
5577 		rethrow(J);
5578 
5579 	for (i = 0; i < n; ++i) {
5580 		fz_try(ctx)
5581 			m = pdf_annot_ink_list_stroke_count(ctx, annot, i);
5582 		fz_catch(ctx)
5583 			rethrow(J);
5584 
5585 		js_newarray(J);
5586 		for (k = 0; k < m; ++k) {
5587 			fz_try(ctx)
5588 				pt = pdf_annot_ink_list_stroke_vertex(ctx, annot, i, k);
5589 			fz_catch(ctx)
5590 				rethrow(J);
5591 			js_pushnumber(J, pt.x);
5592 			js_setindex(J, -2, k * 2 + 0);
5593 			js_pushnumber(J, pt.y);
5594 			js_setindex(J, -2, k * 2 + 1);
5595 		}
5596 		js_setindex(J, -2, i);
5597 	}
5598 }
5599 
ffi_PDFAnnotation_setInkList(js_State * J)5600 static void ffi_PDFAnnotation_setInkList(js_State *J)
5601 {
5602 	fz_context *ctx = js_getcontext(J);
5603 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5604 	fz_point *points = NULL;
5605 	int *counts = NULL;
5606 	int n, nv, k, i, v;
5607 
5608 	fz_var(counts);
5609 	fz_var(points);
5610 
5611 	n = js_getlength(J, 1);
5612 	nv = 0;
5613 	for (i = 0; i < n; ++i) {
5614 		js_getindex(J, 1, i);
5615 		nv += js_getlength(J, -1) / 2;
5616 		js_pop(J, 1);
5617 	}
5618 
5619 	fz_try(ctx) {
5620 		counts = fz_malloc(ctx, n * sizeof(int));
5621 		points = fz_malloc(ctx, nv * sizeof(fz_point));
5622 	} fz_catch(ctx) {
5623 		fz_free(ctx, counts);
5624 		fz_free(ctx, points);
5625 		rethrow(J);
5626 	}
5627 
5628 	if (js_try(J)) {
5629 		fz_free(ctx, counts);
5630 		fz_free(ctx, points);
5631 		js_throw(J);
5632 	}
5633 	for (i = v = 0; i < n; ++i) {
5634 		js_getindex(J, 1, i);
5635 		counts[i] = js_getlength(J, -1) / 2;
5636 		for (k = 0; k < counts[i]; ++k) {
5637 			js_getindex(J, -1, k*2);
5638 			points[v].x = js_tonumber(J, -1);
5639 			js_pop(J, 1);
5640 			js_getindex(J, -1, k*2+1);
5641 			points[v].y = js_tonumber(J, -1);
5642 			js_pop(J, 1);
5643 			++v;
5644 		}
5645 		js_pop(J, 1);
5646 	}
5647 	js_endtry(J);
5648 
5649 	fz_try(ctx)
5650 		pdf_set_annot_ink_list(ctx, annot, n, counts, points);
5651 	fz_always(ctx) {
5652 		fz_free(ctx, counts);
5653 		fz_free(ctx, points);
5654 	}
5655 	fz_catch(ctx)
5656 		rethrow(J);
5657 }
5658 
ffi_PDFAnnotation_clearInkList(js_State * J)5659 static void ffi_PDFAnnotation_clearInkList(js_State *J)
5660 {
5661 	fz_context *ctx = js_getcontext(J);
5662 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5663 	fz_try(ctx)
5664 		pdf_clear_annot_ink_list(ctx, annot);
5665 	fz_catch(ctx)
5666 		rethrow(J);
5667 }
5668 
ffi_PDFAnnotation_addInkList(js_State * J)5669 static void ffi_PDFAnnotation_addInkList(js_State *J)
5670 {
5671 	fz_context *ctx = js_getcontext(J);
5672 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5673 	int i, n;
5674 	float x, y;
5675 
5676 	n = js_getlength(J, 1);
5677 
5678 	fz_try(ctx)
5679 		pdf_add_annot_ink_list_stroke(ctx, annot);
5680 	fz_catch(ctx)
5681 		rethrow(J);
5682 
5683 	for (i = 0; i < n; i += 2) {
5684 		js_getindex(J, 1, i);
5685 		x = js_tonumber(J, -1);
5686 		js_pop(J, 1);
5687 
5688 		js_getindex(J, 1, i+1);
5689 		y = js_tonumber(J, -1);
5690 		js_pop(J, 1);
5691 
5692 		fz_try(ctx)
5693 			pdf_add_annot_ink_list_stroke_vertex(ctx, annot, fz_make_point(x, y));
5694 		fz_catch(ctx)
5695 			rethrow(J);
5696 	}
5697 }
5698 
ffi_PDFAnnotation_addInkListStroke(js_State * J)5699 static void ffi_PDFAnnotation_addInkListStroke(js_State *J)
5700 {
5701 	fz_context *ctx = js_getcontext(J);
5702 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5703 	fz_try(ctx)
5704 		pdf_add_annot_ink_list_stroke(ctx, annot);
5705 	fz_catch(ctx)
5706 		rethrow(J);
5707 }
5708 
ffi_PDFAnnotation_addInkListStrokeVertex(js_State * J)5709 static void ffi_PDFAnnotation_addInkListStrokeVertex(js_State *J)
5710 {
5711 	fz_context *ctx = js_getcontext(J);
5712 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5713 	float x = js_tonumber(J, 1);
5714 	float y = js_tonumber(J, 2);
5715 	fz_try(ctx)
5716 		pdf_add_annot_ink_list_stroke_vertex(ctx, annot, fz_make_point(x, y));
5717 	fz_catch(ctx)
5718 		rethrow(J);
5719 }
5720 
ffi_PDFAnnotation_getAuthor(js_State * J)5721 static void ffi_PDFAnnotation_getAuthor(js_State *J)
5722 {
5723 	fz_context *ctx = js_getcontext(J);
5724 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5725 	const char *author = NULL;
5726 
5727 	fz_try(ctx)
5728 		author = pdf_annot_author(ctx, annot);
5729 	fz_catch(ctx)
5730 		rethrow(J);
5731 
5732 	js_pushstring(J, author);
5733 }
5734 
ffi_PDFAnnotation_setAuthor(js_State * J)5735 static void ffi_PDFAnnotation_setAuthor(js_State *J)
5736 {
5737 	fz_context *ctx = js_getcontext(J);
5738 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5739 	const char *author = js_tostring(J, 1);
5740 
5741 	fz_try(ctx)
5742 		pdf_set_annot_author(ctx, annot, author);
5743 	fz_catch(ctx)
5744 		rethrow(J);
5745 }
5746 
ffi_PDFAnnotation_getModificationDate(js_State * J)5747 static void ffi_PDFAnnotation_getModificationDate(js_State *J)
5748 {
5749 	fz_context *ctx = js_getcontext(J);
5750 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5751 	double time;
5752 
5753 	fz_try(ctx)
5754 		time = pdf_annot_modification_date(ctx, annot);
5755 	fz_catch(ctx)
5756 		rethrow(J);
5757 
5758 	js_getglobal(J, "Date");
5759 	js_pushnumber(J, time * 1000);
5760 	js_construct(J, 1);
5761 }
5762 
ffi_PDFAnnotation_setModificationDate(js_State * J)5763 static void ffi_PDFAnnotation_setModificationDate(js_State *J)
5764 {
5765 	fz_context *ctx = js_getcontext(J);
5766 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5767 	double time = js_tonumber(J, 1);
5768 
5769 	fz_try(ctx)
5770 		pdf_set_annot_modification_date(ctx, annot, time / 1000);
5771 	fz_catch(ctx)
5772 		rethrow(J);
5773 }
5774 
ffi_PDFAnnotation_getLineEndingStyles(js_State * J)5775 static void ffi_PDFAnnotation_getLineEndingStyles(js_State *J)
5776 {
5777 	fz_context *ctx = js_getcontext(J);
5778 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5779 	enum pdf_line_ending start, end;
5780 
5781 	js_newarray(J);
5782 
5783 	fz_try(ctx)
5784 		pdf_annot_line_ending_styles(ctx, annot, &start, &end);
5785 	fz_catch(ctx)
5786 		rethrow(J);
5787 
5788 	js_newobject(J);
5789 	js_pushliteral(J, string_from_line_ending(start));
5790 	js_setproperty(J, -2, "start");
5791 	js_pushliteral(J, string_from_line_ending(end));
5792 	js_setproperty(J, -2, "end");
5793 }
5794 
ffi_PDFAnnotation_setLineEndingStyles(js_State * J)5795 static void ffi_PDFAnnotation_setLineEndingStyles(js_State *J)
5796 {
5797 	fz_context *ctx = js_getcontext(J);
5798 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5799 	enum pdf_line_ending start = line_ending_from_string(js_tostring(J, 1));
5800 	enum pdf_line_ending end = line_ending_from_string(js_tostring(J, 2));
5801 
5802 	fz_try(ctx)
5803 		pdf_set_annot_line_ending_styles(ctx, annot, start, end);
5804 	fz_catch(ctx)
5805 		rethrow(J);
5806 }
5807 
ffi_PDFAnnotation_updateAppearance(js_State * J)5808 static void ffi_PDFAnnotation_updateAppearance(js_State *J)
5809 {
5810 	fz_context *ctx = js_getcontext(J);
5811 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5812 	fz_try(ctx)
5813 		pdf_update_appearance(ctx, annot);
5814 	fz_catch(ctx)
5815 		rethrow(J);
5816 }
5817 
ffi_PDFAnnotation_update(js_State * J)5818 static void ffi_PDFAnnotation_update(js_State *J)
5819 {
5820 	fz_context *ctx = js_getcontext(J);
5821 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5822 	int changed = 0;
5823 	fz_try(ctx)
5824 		changed = pdf_update_annot(ctx, annot);
5825 	fz_catch(ctx)
5826 		rethrow(J);
5827 	js_pushboolean(J, changed);
5828 }
5829 
ffi_PDFAnnotation_process(js_State * J)5830 static void ffi_PDFAnnotation_process(js_State *J)
5831 {
5832 	fz_context *ctx = js_getcontext(J);
5833 	pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
5834 	pdf_processor *proc = new_js_processor(ctx, J);
5835 	fz_try(ctx)
5836 	{
5837 		pdf_process_annot(ctx, proc, annot->page->doc, annot->page, annot, NULL);
5838 		pdf_close_processor(ctx, proc);
5839 	}
5840 	fz_always(ctx)
5841 		pdf_drop_processor(ctx, proc);
5842 	fz_catch(ctx)
5843 		rethrow(J);
5844 }
5845 
ffi_PDFWidget_getFieldType(js_State * J)5846 static void ffi_PDFWidget_getFieldType(js_State *J)
5847 {
5848 	fz_context *ctx = js_getcontext(J);
5849 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
5850 	int type;
5851 	fz_try(ctx)
5852 		type = pdf_field_type(ctx, widget->obj);
5853 	fz_catch(ctx)
5854 		rethrow(J);
5855 	switch (type)
5856 	{
5857 	default:
5858 	case PDF_WIDGET_TYPE_BUTTON: js_pushstring(J, "button"); break;
5859 	case PDF_WIDGET_TYPE_CHECKBOX: js_pushstring(J, "checkbox"); break;
5860 	case PDF_WIDGET_TYPE_COMBOBOX: js_pushstring(J, "combobox"); break;
5861 	case PDF_WIDGET_TYPE_LISTBOX: js_pushstring(J, "listbox"); break;
5862 	case PDF_WIDGET_TYPE_RADIOBUTTON: js_pushstring(J, "radiobutton"); break;
5863 	case PDF_WIDGET_TYPE_SIGNATURE: js_pushstring(J, "signature"); break;
5864 	case PDF_WIDGET_TYPE_TEXT: js_pushstring(J, "text"); break;
5865 	}
5866 }
5867 
ffi_PDFWidget_getFieldFlags(js_State * J)5868 static void ffi_PDFWidget_getFieldFlags(js_State *J)
5869 {
5870 	fz_context *ctx = js_getcontext(J);
5871 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
5872 	int flags;
5873 	fz_try(ctx)
5874 		flags = pdf_field_flags(ctx, widget->obj);
5875 	fz_catch(ctx)
5876 		rethrow(J);
5877 	js_pushnumber(J, flags);
5878 }
5879 
ffi_PDFWidget_getRect(js_State * J)5880 static void ffi_PDFWidget_getRect(js_State *J)
5881 {
5882 	fz_context *ctx = js_getcontext(J);
5883 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
5884 	fz_rect rect;
5885 	fz_try(ctx)
5886 		rect = pdf_annot_rect(ctx, widget);
5887 	fz_catch(ctx)
5888 		rethrow(J);
5889 	ffi_pushrect(J, rect);
5890 }
5891 
ffi_PDFWidget_setRect(js_State * J)5892 static void ffi_PDFWidget_setRect(js_State *J)
5893 {
5894 	fz_context *ctx = js_getcontext(J);
5895 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
5896 	fz_rect rect = ffi_torect(J, 1);
5897 	fz_try(ctx)
5898 		pdf_set_annot_rect(ctx, widget, rect);
5899 	fz_catch(ctx)
5900 		rethrow(J);
5901 }
5902 
ffi_PDFWidget_getValue(js_State * J)5903 static void ffi_PDFWidget_getValue(js_State *J)
5904 {
5905 	fz_context *ctx = js_getcontext(J);
5906 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
5907 	const char *value;
5908 	fz_try(ctx)
5909 		value = pdf_field_value(ctx, widget->obj);
5910 	fz_catch(ctx)
5911 		rethrow(J);
5912 	js_pushstring(J, value);
5913 }
5914 
ffi_PDFWidget_setTextValue(js_State * J)5915 static void ffi_PDFWidget_setTextValue(js_State *J)
5916 {
5917 	fz_context *ctx = js_getcontext(J);
5918 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
5919 	const char *value = js_tostring(J, 1);
5920 	fz_try(ctx)
5921 		pdf_set_text_field_value(ctx, widget, value);
5922 	fz_catch(ctx)
5923 		rethrow(J);
5924 }
5925 
ffi_PDFWidget_setChoiceValue(js_State * J)5926 static void ffi_PDFWidget_setChoiceValue(js_State *J)
5927 {
5928 	fz_context *ctx = js_getcontext(J);
5929 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
5930 	const char *value = js_tostring(J, 1);
5931 	fz_try(ctx)
5932 		pdf_set_choice_field_value(ctx, widget, value);
5933 	fz_catch(ctx)
5934 		rethrow(J);
5935 }
5936 
ffi_PDFWidget_toggle(js_State * J)5937 static void ffi_PDFWidget_toggle(js_State *J)
5938 {
5939 	fz_context *ctx = js_getcontext(J);
5940 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
5941 	int changed = 0;
5942 	fz_try(ctx)
5943 		changed = pdf_toggle_widget(ctx, widget);
5944 	fz_catch(ctx)
5945 		rethrow(J);
5946 	js_pushboolean(J, changed);
5947 }
5948 
ffi_PDFWidget_getMaxLen(js_State * J)5949 static void ffi_PDFWidget_getMaxLen(js_State *J)
5950 {
5951 	fz_context *ctx = js_getcontext(J);
5952 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
5953 	int maxLen = 0;
5954 	fz_try(ctx)
5955 		maxLen = pdf_text_widget_max_len(ctx, widget);
5956 	fz_catch(ctx)
5957 		rethrow(J);
5958 	js_pushnumber(J, maxLen);
5959 }
5960 
ffi_PDFWidget_getOptions(js_State * J)5961 static void ffi_PDFWidget_getOptions(js_State *J)
5962 {
5963 	fz_context *ctx = js_getcontext(J);
5964 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
5965 	int export = js_toboolean(J, 1);
5966 	const char *opt;
5967 	int i, n;
5968 	fz_try(ctx)
5969 		n = pdf_choice_field_option_count(ctx, widget->obj);
5970 	fz_catch(ctx)
5971 		rethrow(J);
5972 	js_newarray(J);
5973 	for (i = 0; i < n; ++i) {
5974 		fz_try(ctx)
5975 			opt = pdf_choice_field_option(ctx, widget->obj, export, i);
5976 		fz_catch(ctx)
5977 			rethrow(J);
5978 		js_pushstring(J, opt);
5979 	}
5980 	js_endtry(J);
5981 }
5982 
ffi_PDFWidget_update(js_State * J)5983 static void ffi_PDFWidget_update(js_State *J)
5984 {
5985 	fz_context *ctx = js_getcontext(J);
5986 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
5987 	int changed = 0;
5988 	fz_try(ctx)
5989 		changed = pdf_update_widget(ctx, widget);
5990 	fz_catch(ctx)
5991 		rethrow(J);
5992 	js_pushboolean(J, changed);
5993 }
5994 
ffi_PDFWidget_eventEnter(js_State * J)5995 static void ffi_PDFWidget_eventEnter(js_State *J)
5996 {
5997 	fz_context *ctx = js_getcontext(J);
5998 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
5999 	fz_try(ctx)
6000 		pdf_annot_event_enter(ctx, widget);
6001 	fz_catch(ctx)
6002 		rethrow(J);
6003 }
6004 
ffi_PDFWidget_eventExit(js_State * J)6005 static void ffi_PDFWidget_eventExit(js_State *J)
6006 {
6007 	fz_context *ctx = js_getcontext(J);
6008 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
6009 	fz_try(ctx)
6010 		pdf_annot_event_exit(ctx, widget);
6011 	fz_catch(ctx)
6012 		rethrow(J);
6013 }
6014 
ffi_PDFWidget_eventDown(js_State * J)6015 static void ffi_PDFWidget_eventDown(js_State *J)
6016 {
6017 	fz_context *ctx = js_getcontext(J);
6018 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
6019 	fz_try(ctx)
6020 		pdf_annot_event_down(ctx, widget);
6021 	fz_catch(ctx)
6022 		rethrow(J);
6023 }
6024 
ffi_PDFWidget_eventUp(js_State * J)6025 static void ffi_PDFWidget_eventUp(js_State *J)
6026 {
6027 	fz_context *ctx = js_getcontext(J);
6028 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
6029 	fz_try(ctx)
6030 		pdf_annot_event_up(ctx, widget);
6031 	fz_catch(ctx)
6032 		rethrow(J);
6033 }
6034 
ffi_PDFWidget_eventFocus(js_State * J)6035 static void ffi_PDFWidget_eventFocus(js_State *J)
6036 {
6037 	fz_context *ctx = js_getcontext(J);
6038 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
6039 	fz_try(ctx)
6040 		pdf_annot_event_focus(ctx, widget);
6041 	fz_catch(ctx)
6042 		rethrow(J);
6043 }
6044 
ffi_PDFWidget_eventBlur(js_State * J)6045 static void ffi_PDFWidget_eventBlur(js_State *J)
6046 {
6047 	fz_context *ctx = js_getcontext(J);
6048 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
6049 	fz_try(ctx)
6050 		pdf_annot_event_blur(ctx, widget);
6051 	fz_catch(ctx)
6052 		rethrow(J);
6053 }
6054 
ffi_PDFWidget_validateSignature(js_State * J)6055 static void ffi_PDFWidget_validateSignature(js_State *J)
6056 {
6057 	fz_context *ctx = js_getcontext(J);
6058 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
6059 	int val = 0;
6060 	fz_try(ctx)
6061 		val = pdf_validate_signature(ctx, widget);
6062 	fz_catch(ctx)
6063 		rethrow(J);
6064 	js_pushnumber(J, val);
6065 }
6066 
ffi_PDFWidget_isSigned(js_State * J)6067 static void ffi_PDFWidget_isSigned(js_State *J)
6068 {
6069 	fz_context *ctx = js_getcontext(J);
6070 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
6071 	int val = 0;
6072 	fz_try(ctx)
6073 		val = pdf_widget_is_signed(ctx, widget);
6074 	fz_catch(ctx)
6075 		rethrow(J);
6076 	js_pushboolean(J, val);
6077 }
6078 
ffi_PDFWidget_sign(js_State * J)6079 static void ffi_PDFWidget_sign(js_State *J)
6080 {
6081 	fz_context *ctx = js_getcontext(J);
6082 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
6083 	pdf_pkcs7_signer *signer = js_touserdata(J, 1, "pdf_pkcs7_signer");
6084 
6085 	fz_try(ctx)
6086 		pdf_sign_signature(ctx, widget, signer);
6087 	fz_catch(ctx)
6088 		rethrow(J);
6089 }
6090 
ffi_PDFWidget_clearSignature(js_State * J)6091 static void ffi_PDFWidget_clearSignature(js_State *J)
6092 {
6093 	fz_context *ctx = js_getcontext(J);
6094 	pdf_widget *widget = js_touserdata(J, 0, "pdf_widget");
6095 
6096 	fz_try(ctx)
6097 		pdf_clear_signature(ctx, widget);
6098 	fz_catch(ctx)
6099 		rethrow(J);
6100 }
6101 
ffi_new_PDFPKCS7Signer(js_State * J)6102 static void ffi_new_PDFPKCS7Signer(js_State *J)
6103 {
6104 	fz_context *ctx = js_getcontext(J);
6105 	pdf_pkcs7_signer *signer = NULL;
6106 	const char *filename = js_tostring(J, 1);
6107 	const char *password = js_tostring(J, 2);
6108 	fz_try(ctx)
6109 		signer = pkcs7_openssl_read_pfx(ctx, filename, password);
6110 	fz_catch(ctx)
6111 		rethrow(J);
6112 	ffi_pushsigner(J, signer);
6113 }
6114 
6115 #endif /* FZ_ENABLE_PDF */
6116 
murun_main(int argc,char ** argv)6117 int murun_main(int argc, char **argv)
6118 {
6119 	fz_context *ctx;
6120 	js_State *J;
6121 	int i;
6122 
6123 	ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
6124 	fz_register_document_handlers(ctx);
6125 
6126 	J = js_newstate(alloc, ctx, JS_STRICT);
6127 	js_setcontext(J, ctx);
6128 
6129 	/* standard command line javascript functions */
6130 
6131 	js_newcfunction(J, jsB_gc, "gc", 0);
6132 	js_setglobal(J, "gc");
6133 
6134 	js_newcfunction(J, jsB_load, "load", 1);
6135 	js_setglobal(J, "load");
6136 
6137 	js_newcfunction(J, jsB_print, "print", 1);
6138 	js_setglobal(J, "print");
6139 
6140 	js_newcfunction(J, jsB_write, "write", 0);
6141 	js_setglobal(J, "write");
6142 
6143 	js_newcfunction(J, jsB_read, "read", 1);
6144 	js_setglobal(J, "read");
6145 
6146 	js_newcfunction(J, jsB_readline, "readline", 0);
6147 	js_setglobal(J, "readline");
6148 
6149 	js_newcfunction(J, jsB_repr, "repr", 1);
6150 	js_setglobal(J, "repr");
6151 
6152 	js_newcfunction(J, jsB_quit, "quit", 1);
6153 	js_setglobal(J, "quit");
6154 
6155 	js_dostring(J, require_js);
6156 	js_dostring(J, stacktrace_js);
6157 
6158 	/* mupdf module */
6159 
6160 	/* Create superclass for all userdata objects */
6161 	js_dostring(J, "function Userdata() { throw new Error('Userdata is not callable'); }");
6162 	js_getglobal(J, "Userdata");
6163 	js_getproperty(J, -1, "prototype");
6164 	js_setregistry(J, "Userdata");
6165 	js_pop(J, 1);
6166 
6167 	js_getregistry(J, "Userdata");
6168 	js_newobjectx(J);
6169 	{
6170 		jsB_propfun(J, "Buffer.writeByte", ffi_Buffer_writeByte, 1);
6171 		jsB_propfun(J, "Buffer.writeRune", ffi_Buffer_writeRune, 1);
6172 		jsB_propfun(J, "Buffer.writeLine", ffi_Buffer_writeLine, 1);
6173 		jsB_propfun(J, "Buffer.writeBuffer", ffi_Buffer_writeBuffer, 1);
6174 		jsB_propfun(J, "Buffer.write", ffi_Buffer_write, 1);
6175 		jsB_propfun(J, "Buffer.save", ffi_Buffer_save, 1);
6176 	}
6177 	js_setregistry(J, "fz_buffer");
6178 
6179 	js_getregistry(J, "Userdata");
6180 	js_newobjectx(J);
6181 	{
6182 		jsB_propfun(J, "Document.isPDF", ffi_Document_isPDF, 0);
6183 		jsB_propfun(J, "Document.needsPassword", ffi_Document_needsPassword, 0);
6184 		jsB_propfun(J, "Document.authenticatePassword", ffi_Document_authenticatePassword, 1);
6185 		jsB_propfun(J, "Document.hasPermission", ffi_Document_hasPermission, 1);
6186 		jsB_propfun(J, "Document.getMetaData", ffi_Document_getMetaData, 1);
6187 		jsB_propfun(J, "Document.isReflowable", ffi_Document_isReflowable, 0);
6188 		jsB_propfun(J, "Document.layout", ffi_Document_layout, 3);
6189 		jsB_propfun(J, "Document.countPages", ffi_Document_countPages, 0);
6190 		jsB_propfun(J, "Document.loadPage", ffi_Document_loadPage, 1);
6191 		jsB_propfun(J, "Document.loadOutline", ffi_Document_loadOutline, 0);
6192 	}
6193 	js_setregistry(J, "fz_document");
6194 
6195 	js_getregistry(J, "Userdata");
6196 	js_newobjectx(J);
6197 	{
6198 		jsB_propfun(J, "Page.isPDF", ffi_Page_isPDF, 0);
6199 		jsB_propfun(J, "Page.bound", ffi_Page_bound, 0);
6200 		jsB_propfun(J, "Page.run", ffi_Page_run, 3);
6201 		jsB_propfun(J, "Page.toPixmap", ffi_Page_toPixmap, 4);
6202 		jsB_propfun(J, "Page.toDisplayList", ffi_Page_toDisplayList, 1);
6203 		jsB_propfun(J, "Page.toStructuredText", ffi_Page_toStructuredText, 1);
6204 		jsB_propfun(J, "Page.search", ffi_Page_search, 0);
6205 		jsB_propfun(J, "Page.getLinks", ffi_Page_getLinks, 0);
6206 	}
6207 	js_setregistry(J, "fz_page");
6208 
6209 	js_getregistry(J, "Userdata");
6210 	js_newobjectx(J);
6211 	{
6212 		jsB_propfun(J, "Device.close", ffi_Device_close, 0);
6213 
6214 		jsB_propfun(J, "Device.fillPath", ffi_Device_fillPath, 7);
6215 		jsB_propfun(J, "Device.strokePath", ffi_Device_strokePath, 7);
6216 		jsB_propfun(J, "Device.clipPath", ffi_Device_clipPath, 3);
6217 		jsB_propfun(J, "Device.clipStrokePath", ffi_Device_clipStrokePath, 3);
6218 
6219 		jsB_propfun(J, "Device.fillText", ffi_Device_fillText, 6);
6220 		jsB_propfun(J, "Device.strokeText", ffi_Device_strokeText, 7);
6221 		jsB_propfun(J, "Device.clipText", ffi_Device_clipText, 2);
6222 		jsB_propfun(J, "Device.clipStrokeText", ffi_Device_clipStrokeText, 3);
6223 		jsB_propfun(J, "Device.ignoreText", ffi_Device_ignoreText, 2);
6224 
6225 		jsB_propfun(J, "Device.fillShade", ffi_Device_fillShade, 4);
6226 		jsB_propfun(J, "Device.fillImage", ffi_Device_fillImage, 4);
6227 		jsB_propfun(J, "Device.fillImageMask", ffi_Device_fillImageMask, 6);
6228 		jsB_propfun(J, "Device.clipImageMask", ffi_Device_clipImageMask, 2);
6229 
6230 		jsB_propfun(J, "Device.popClip", ffi_Device_popClip, 0);
6231 
6232 		jsB_propfun(J, "Device.beginMask", ffi_Device_beginMask, 6);
6233 		jsB_propfun(J, "Device.endMask", ffi_Device_endMask, 0);
6234 		jsB_propfun(J, "Device.beginGroup", ffi_Device_beginGroup, 5);
6235 		jsB_propfun(J, "Device.endGroup", ffi_Device_endGroup, 0);
6236 		jsB_propfun(J, "Device.beginTile", ffi_Device_beginTile, 6);
6237 		jsB_propfun(J, "Device.endTile", ffi_Device_endTile, 0);
6238 
6239 		jsB_propfun(J, "Device.beginLayer", ffi_Device_beginLayer, 1);
6240 		jsB_propfun(J, "Device.endLayer", ffi_Device_endLayer, 0);
6241 	}
6242 	js_setregistry(J, "fz_device");
6243 
6244 	js_getregistry(J, "Userdata");
6245 	js_newobjectx(J);
6246 	{
6247 		jsB_propfun(J, "ColorSpace.getNumberOfComponents", ffi_ColorSpace_getNumberOfComponents, 0);
6248 		jsB_propfun(J, "ColorSpace.toString", ffi_ColorSpace_toString, 0);
6249 	}
6250 	js_setregistry(J, "fz_colorspace");
6251 	{
6252 		js_getregistry(J, "fz_colorspace");
6253 		js_newuserdata(J, "fz_colorspace", fz_keep_colorspace(ctx, fz_device_gray(ctx)), ffi_gc_fz_colorspace);
6254 		js_setregistry(J, "DeviceGray");
6255 
6256 		js_getregistry(J, "fz_colorspace");
6257 		js_newuserdata(J, "fz_colorspace", fz_keep_colorspace(ctx, fz_device_rgb(ctx)), ffi_gc_fz_colorspace);
6258 		js_setregistry(J, "DeviceRGB");
6259 
6260 		js_getregistry(J, "fz_colorspace");
6261 		js_newuserdata(J, "fz_colorspace", fz_keep_colorspace(ctx, fz_device_bgr(ctx)), ffi_gc_fz_colorspace);
6262 		js_setregistry(J, "DeviceBGR");
6263 
6264 		js_getregistry(J, "fz_colorspace");
6265 		js_newuserdata(J, "fz_colorspace", fz_keep_colorspace(ctx, fz_device_cmyk(ctx)), ffi_gc_fz_colorspace);
6266 		js_setregistry(J, "DeviceCMYK");
6267 	}
6268 
6269 	js_getregistry(J, "Userdata");
6270 	js_newobjectx(J);
6271 	{
6272 		jsB_propfun(J, "Shade.bound", ffi_Shade_bound, 1);
6273 	}
6274 	js_setregistry(J, "fz_shade");
6275 
6276 	js_getregistry(J, "Userdata");
6277 	js_newobjectx(J);
6278 	{
6279 		jsB_propfun(J, "Image.getWidth", ffi_Image_getWidth, 0);
6280 		jsB_propfun(J, "Image.getHeight", ffi_Image_getHeight, 0);
6281 		jsB_propfun(J, "Image.getColorSpace", ffi_Image_getColorSpace, 0);
6282 		jsB_propfun(J, "Image.getXResolution", ffi_Image_getXResolution, 0);
6283 		jsB_propfun(J, "Image.getYResolution", ffi_Image_getYResolution, 0);
6284 		jsB_propfun(J, "Image.getNumberOfComponents", ffi_Image_getNumberOfComponents, 0);
6285 		jsB_propfun(J, "Image.getBitsPerComponent", ffi_Image_getBitsPerComponent, 0);
6286 		jsB_propfun(J, "Image.getInterpolate", ffi_Image_getInterpolate, 0);
6287 		jsB_propfun(J, "Image.getImageMask", ffi_Image_getImageMask, 0);
6288 		jsB_propfun(J, "Image.getMask", ffi_Image_getMask, 0);
6289 		jsB_propfun(J, "Image.toPixmap", ffi_Image_toPixmap, 2);
6290 	}
6291 	js_setregistry(J, "fz_image");
6292 
6293 	js_getregistry(J, "Userdata");
6294 	js_newobjectx(J);
6295 	{
6296 		jsB_propfun(J, "Font.getName", ffi_Font_getName, 0);
6297 		jsB_propfun(J, "Font.encodeCharacter", ffi_Font_encodeCharacter, 1);
6298 		jsB_propfun(J, "Font.advanceGlyph", ffi_Font_advanceGlyph, 2);
6299 	}
6300 	js_setregistry(J, "fz_font");
6301 
6302 	js_getregistry(J, "Userdata");
6303 	js_newobjectx(J);
6304 	{
6305 		jsB_propfun(J, "Text.walk", ffi_Text_walk, 1);
6306 		jsB_propfun(J, "Text.showGlyph", ffi_Text_showGlyph, 5);
6307 		jsB_propfun(J, "Text.showString", ffi_Text_showString, 4);
6308 	}
6309 	js_setregistry(J, "fz_text");
6310 
6311 	js_getregistry(J, "Userdata");
6312 	js_newobjectx(J);
6313 	{
6314 		jsB_propfun(J, "Path.walk", ffi_Path_walk, 1);
6315 		jsB_propfun(J, "Path.moveTo", ffi_Path_moveTo, 2);
6316 		jsB_propfun(J, "Path.lineTo", ffi_Path_lineTo, 2);
6317 		jsB_propfun(J, "Path.curveTo", ffi_Path_curveTo, 6);
6318 		jsB_propfun(J, "Path.curveToV", ffi_Path_curveToV, 4);
6319 		jsB_propfun(J, "Path.curveToY", ffi_Path_curveToY, 4);
6320 		jsB_propfun(J, "Path.closePath", ffi_Path_closePath, 0);
6321 		jsB_propfun(J, "Path.rect", ffi_Path_rect, 4);
6322 		jsB_propfun(J, "Path.bound", ffi_Path_bound, 2);
6323 		jsB_propfun(J, "Path.transform", ffi_Path_transform, 1);
6324 	}
6325 	js_setregistry(J, "fz_path");
6326 
6327 	js_getregistry(J, "Userdata");
6328 	js_newobjectx(J);
6329 	{
6330 		jsB_propfun(J, "DisplayList.run", ffi_DisplayList_run, 2);
6331 		jsB_propfun(J, "DisplayList.toPixmap", ffi_DisplayList_toPixmap, 3);
6332 		jsB_propfun(J, "DisplayList.toStructuredText", ffi_DisplayList_toStructuredText, 1);
6333 		jsB_propfun(J, "DisplayList.search", ffi_DisplayList_search, 1);
6334 	}
6335 	js_setregistry(J, "fz_display_list");
6336 
6337 	js_getregistry(J, "Userdata");
6338 	js_newobjectx(J);
6339 	{
6340 		jsB_propfun(J, "StructuredText.walk", ffi_StructuredText_walk, 1);
6341 		jsB_propfun(J, "StructuredText.search", ffi_StructuredText_search, 1);
6342 		jsB_propfun(J, "StructuredText.highlight", ffi_StructuredText_highlight, 2);
6343 		jsB_propfun(J, "StructuredText.copy", ffi_StructuredText_copy, 2);
6344 	}
6345 	js_setregistry(J, "fz_stext_page");
6346 
6347 	js_getregistry(J, "Userdata");
6348 	js_newobjectx(J);
6349 	{
6350 		jsB_propfun(J, "Pixmap.bound", ffi_Pixmap_bound, 0);
6351 		jsB_propfun(J, "Pixmap.clear", ffi_Pixmap_clear, 1);
6352 
6353 		jsB_propfun(J, "Pixmap.getX", ffi_Pixmap_getX, 0);
6354 		jsB_propfun(J, "Pixmap.getY", ffi_Pixmap_getY, 0);
6355 		jsB_propfun(J, "Pixmap.getWidth", ffi_Pixmap_getWidth, 0);
6356 		jsB_propfun(J, "Pixmap.getHeight", ffi_Pixmap_getHeight, 0);
6357 		jsB_propfun(J, "Pixmap.getNumberOfComponents", ffi_Pixmap_getNumberOfComponents, 0);
6358 		jsB_propfun(J, "Pixmap.getAlpha", ffi_Pixmap_getAlpha, 0);
6359 		jsB_propfun(J, "Pixmap.getStride", ffi_Pixmap_getStride, 0);
6360 		jsB_propfun(J, "Pixmap.getColorSpace", ffi_Pixmap_getColorSpace, 0);
6361 		jsB_propfun(J, "Pixmap.getXResolution", ffi_Pixmap_getXResolution, 0);
6362 		jsB_propfun(J, "Pixmap.getYResolution", ffi_Pixmap_getYResolution, 0);
6363 		jsB_propfun(J, "Pixmap.getSample", ffi_Pixmap_getSample, 3);
6364 		jsB_propfun(J, "Pixmap.warp", ffi_Pixmap_warp, 3);
6365 
6366 		// Pixmap.samples()
6367 		// Pixmap.invert
6368 		// Pixmap.tint
6369 		// Pixmap.gamma
6370 		// Pixmap.scale()
6371 
6372 		jsB_propfun(J, "Pixmap.saveAsPNG", ffi_Pixmap_saveAsPNG, 1);
6373 		// Pixmap.saveAsPNM, PAM, PWG, PCL
6374 
6375 		// Pixmap.halftone() -> Bitmap
6376 		// Pixmap.md5()
6377 	}
6378 	js_setregistry(J, "fz_pixmap");
6379 
6380 	js_getregistry(J, "Userdata");
6381 	js_newobjectx(J);
6382 	{
6383 		jsB_propfun(J, "DocumentWriter.beginPage", ffi_DocumentWriter_beginPage, 1);
6384 		jsB_propfun(J, "DocumentWriter.endPage", ffi_DocumentWriter_endPage, 0);
6385 		jsB_propfun(J, "DocumentWriter.close", ffi_DocumentWriter_close, 0);
6386 	}
6387 	js_setregistry(J, "fz_document_writer");
6388 
6389 #if FZ_ENABLE_PDF
6390 	js_getregistry(J, "fz_document");
6391 	js_newobjectx(J);
6392 	{
6393 		jsB_propfun(J, "PDFDocument.getTrailer", ffi_PDFDocument_getTrailer, 0);
6394 		jsB_propfun(J, "PDFDocument.countObjects", ffi_PDFDocument_countObjects, 0);
6395 		jsB_propfun(J, "PDFDocument.createObject", ffi_PDFDocument_createObject, 0);
6396 		jsB_propfun(J, "PDFDocument.deleteObject", ffi_PDFDocument_deleteObject, 1);
6397 		jsB_propfun(J, "PDFDocument.addObject", ffi_PDFDocument_addObject, 1);
6398 		jsB_propfun(J, "PDFDocument.addStream", ffi_PDFDocument_addStream, 2);
6399 		jsB_propfun(J, "PDFDocument.addRawStream", ffi_PDFDocument_addRawStream, 2);
6400 		jsB_propfun(J, "PDFDocument.addSimpleFont", ffi_PDFDocument_addSimpleFont, 2);
6401 		jsB_propfun(J, "PDFDocument.addCJKFont", ffi_PDFDocument_addCJKFont, 4);
6402 		jsB_propfun(J, "PDFDocument.addFont", ffi_PDFDocument_addFont, 1);
6403 		jsB_propfun(J, "PDFDocument.addImage", ffi_PDFDocument_addImage, 1);
6404 		jsB_propfun(J, "PDFDocument.loadImage", ffi_PDFDocument_loadImage, 1);
6405 		jsB_propfun(J, "PDFDocument.addPage", ffi_PDFDocument_addPage, 4);
6406 		jsB_propfun(J, "PDFDocument.insertPage", ffi_PDFDocument_insertPage, 2);
6407 		jsB_propfun(J, "PDFDocument.deletePage", ffi_PDFDocument_deletePage, 1);
6408 		jsB_propfun(J, "PDFDocument.countPages", ffi_PDFDocument_countPages, 0);
6409 		jsB_propfun(J, "PDFDocument.findPage", ffi_PDFDocument_findPage, 1);
6410 		jsB_propfun(J, "PDFDocument.save", ffi_PDFDocument_save, 2);
6411 
6412 		jsB_propfun(J, "PDFDocument.newNull", ffi_PDFDocument_newNull, 0);
6413 		jsB_propfun(J, "PDFDocument.newBoolean", ffi_PDFDocument_newBoolean, 1);
6414 		jsB_propfun(J, "PDFDocument.newInteger", ffi_PDFDocument_newInteger, 1);
6415 		jsB_propfun(J, "PDFDocument.newReal", ffi_PDFDocument_newReal, 1);
6416 		jsB_propfun(J, "PDFDocument.newString", ffi_PDFDocument_newString, 1);
6417 		jsB_propfun(J, "PDFDocument.newByteString", ffi_PDFDocument_newByteString, 1);
6418 		jsB_propfun(J, "PDFDocument.newName", ffi_PDFDocument_newName, 1);
6419 		jsB_propfun(J, "PDFDocument.newIndirect", ffi_PDFDocument_newIndirect, 2);
6420 		jsB_propfun(J, "PDFDocument.newArray", ffi_PDFDocument_newArray, 1);
6421 		jsB_propfun(J, "PDFDocument.newDictionary", ffi_PDFDocument_newDictionary, 1);
6422 
6423 		jsB_propfun(J, "PDFDocument.newGraftMap", ffi_PDFDocument_newGraftMap, 0);
6424 		jsB_propfun(J, "PDFDocument.graftObject", ffi_PDFDocument_graftObject, 1);
6425 		jsB_propfun(J, "PDFDocument.graftPage", ffi_PDFDocument_graftPage, 3);
6426 
6427 		jsB_propfun(J, "PDFDocument.enableJS", ffi_PDFDocument_enableJS, 0);
6428 		jsB_propfun(J, "PDFDocument.countVersions", ffi_PDFDocument_countVersions, 0);
6429 		jsB_propfun(J, "PDFDocument.countUnsavedVersions", ffi_PDFDocument_countUnsavedVersions, 0);
6430 		jsB_propfun(J, "PDFDocument.validateChangeHistory", ffi_PDFDocument_validateChangeHistory, 0);
6431 		jsB_propfun(J, "PDFDocument.wasPureXFA", ffi_PDFDocument_wasPureXFA, 0);
6432 
6433 		jsB_propfun(J, "PDFDocument.hasUnsavedChanges", ffi_PDFDocument_hasUnsavedChanges, 0);
6434 		jsB_propfun(J, "PDFDocument.wasRepaired", ffi_PDFDocument_wasRepaired, 0);
6435 		jsB_propfun(J, "PDFDocument.canBeSavedIncrementally", ffi_PDFDocument_canBeSavedIncrementally, 0);
6436 	}
6437 	js_setregistry(J, "pdf_document");
6438 
6439 	js_getregistry(J, "fz_page");
6440 	js_newobjectx(J);
6441 	{
6442 		jsB_propfun(J, "PDFPage.getWidgets", ffi_PDFPage_getWidgets, 0);
6443 		jsB_propfun(J, "PDFPage.getAnnotations", ffi_PDFPage_getAnnotations, 0);
6444 		jsB_propfun(J, "PDFPage.createAnnotation", ffi_PDFPage_createAnnotation, 1);
6445 		jsB_propfun(J, "PDFPage.deleteAnnotation", ffi_PDFPage_deleteAnnotation, 1);
6446 		jsB_propfun(J, "PDFPage.update", ffi_PDFPage_update, 0);
6447 		jsB_propfun(J, "PDFPage.applyRedactions", ffi_PDFPage_applyRedactions, 2);
6448 		jsB_propfun(J, "PDFPage.process", ffi_PDFPage_process, 1);
6449 	}
6450 	js_setregistry(J, "pdf_page");
6451 
6452 	js_getregistry(J, "Userdata");
6453 	js_newobjectx(J);
6454 	{
6455 		jsB_propfun(J, "PDFAnnotation.bound", ffi_PDFAnnotation_bound, 0);
6456 		jsB_propfun(J, "PDFAnnotation.run", ffi_PDFAnnotation_run, 2);
6457 		jsB_propfun(J, "PDFAnnotation.toPixmap", ffi_PDFAnnotation_toPixmap, 3);
6458 		jsB_propfun(J, "PDFAnnotation.toDisplayList", ffi_PDFAnnotation_toDisplayList, 0);
6459 
6460 		jsB_propfun(J, "PDFAnnotation.getType", ffi_PDFAnnotation_getType, 0);
6461 		jsB_propfun(J, "PDFAnnotation.getFlags", ffi_PDFAnnotation_getFlags, 0);
6462 		jsB_propfun(J, "PDFAnnotation.setFlags", ffi_PDFAnnotation_setFlags, 1);
6463 		jsB_propfun(J, "PDFAnnotation.getContents", ffi_PDFAnnotation_getContents, 0);
6464 		jsB_propfun(J, "PDFAnnotation.setContents", ffi_PDFAnnotation_setContents, 1);
6465 		jsB_propfun(J, "PDFAnnotation.getRect", ffi_PDFAnnotation_getRect, 0);
6466 		jsB_propfun(J, "PDFAnnotation.setRect", ffi_PDFAnnotation_setRect, 1);
6467 		jsB_propfun(J, "PDFAnnotation.getBorder", ffi_PDFAnnotation_getBorder, 0);
6468 		jsB_propfun(J, "PDFAnnotation.setBorder", ffi_PDFAnnotation_setBorder, 1);
6469 		jsB_propfun(J, "PDFAnnotation.getColor", ffi_PDFAnnotation_getColor, 0);
6470 		jsB_propfun(J, "PDFAnnotation.setColor", ffi_PDFAnnotation_setColor, 1);
6471 		jsB_propfun(J, "PDFAnnotation.getInteriorColor", ffi_PDFAnnotation_getInteriorColor, 0);
6472 		jsB_propfun(J, "PDFAnnotation.setInteriorColor", ffi_PDFAnnotation_setInteriorColor, 1);
6473 		jsB_propfun(J, "PDFAnnotation.getAuthor", ffi_PDFAnnotation_getAuthor, 0);
6474 		jsB_propfun(J, "PDFAnnotation.setAuthor", ffi_PDFAnnotation_setAuthor, 1);
6475 		jsB_propfun(J, "PDFAnnotation.getModificationDate", ffi_PDFAnnotation_getModificationDate, 0);
6476 		jsB_propfun(J, "PDFAnnotation.setModificationDate", ffi_PDFAnnotation_setModificationDate, 0);
6477 		jsB_propfun(J, "PDFAnnotation.getLineEndingStyles", ffi_PDFAnnotation_getLineEndingStyles, 0);
6478 		jsB_propfun(J, "PDFAnnotation.setLineEndingStyles", ffi_PDFAnnotation_setLineEndingStyles, 0);
6479 
6480 		jsB_propfun(J, "PDFAnnotation.getInkList", ffi_PDFAnnotation_getInkList, 0);
6481 		jsB_propfun(J, "PDFAnnotation.setInkList", ffi_PDFAnnotation_setInkList, 1);
6482 		jsB_propfun(J, "PDFAnnotation.clearInkList", ffi_PDFAnnotation_clearInkList, 0);
6483 		jsB_propfun(J, "PDFAnnotation.addInkList", ffi_PDFAnnotation_addInkList, 1);
6484 		jsB_propfun(J, "PDFAnnotation.addInkListStroke", ffi_PDFAnnotation_addInkListStroke, 0);
6485 		jsB_propfun(J, "PDFAnnotation.addInkListStrokeVertex", ffi_PDFAnnotation_addInkListStrokeVertex, 2);
6486 
6487 		jsB_propfun(J, "PDFAnnotation.getQuadPoints", ffi_PDFAnnotation_getQuadPoints, 0);
6488 		jsB_propfun(J, "PDFAnnotation.setQuadPoints", ffi_PDFAnnotation_setQuadPoints, 1);
6489 		jsB_propfun(J, "PDFAnnotation.clearQuadPoints", ffi_PDFAnnotation_clearQuadPoints, 0);
6490 		jsB_propfun(J, "PDFAnnotation.addQuadPoint", ffi_PDFAnnotation_addQuadPoint, 1);
6491 
6492 		jsB_propfun(J, "PDFAnnotation.getVertices", ffi_PDFAnnotation_getVertices, 0);
6493 		jsB_propfun(J, "PDFAnnotation.setVertices", ffi_PDFAnnotation_setVertices, 1);
6494 		jsB_propfun(J, "PDFAnnotation.clearVertices", ffi_PDFAnnotation_clearVertices, 0);
6495 		jsB_propfun(J, "PDFAnnotation.addVertex", ffi_PDFAnnotation_addVertex, 2);
6496 
6497 		jsB_propfun(J, "PDFAnnotation.updateAppearance", ffi_PDFAnnotation_updateAppearance, 0);
6498 		jsB_propfun(J, "PDFAnnotation.update", ffi_PDFAnnotation_update, 0);
6499 
6500 		jsB_propfun(J, "PDFAnnotation.process", ffi_PDFAnnotation_process, 1);
6501 	}
6502 	js_dup(J);
6503 	js_setglobal(J, "PDFAnnot");
6504 	js_setregistry(J, "pdf_annot");
6505 
6506 	js_getregistry(J, "Userdata");
6507 	js_newobjectx(J);
6508 	{
6509 		// jsB_propfun(J, "PDFWidget.bound", ffi_PDFWidget_bound, 0);
6510 		// jsB_propfun(J, "PDFWidget.run", ffi_PDFWidget_run, 2);
6511 		// jsB_propfun(J, "PDFWidget.toPixmap", ffi_PDFWidget_toPixmap, 3);
6512 		// jsB_propfun(J, "PDFWidget.toDisplayList", ffi_PDFWidget_toDisplayList, 0);
6513 
6514 		jsB_propfun(J, "PDFWidget.getFieldType", ffi_PDFWidget_getFieldType, 0);
6515 		jsB_propfun(J, "PDFWidget.getFieldFlags", ffi_PDFWidget_getFieldFlags, 0);
6516 		jsB_propfun(J, "PDFWidget.getRect", ffi_PDFWidget_getRect, 0);
6517 		jsB_propfun(J, "PDFWidget.setRect", ffi_PDFWidget_setRect, 1);
6518 		jsB_propfun(J, "PDFWidget.getValue", ffi_PDFWidget_getValue, 0);
6519 		jsB_propfun(J, "PDFWidget.setTextValue", ffi_PDFWidget_setTextValue, 1);
6520 		jsB_propfun(J, "PDFWidget.setChoiceValue", ffi_PDFWidget_setChoiceValue, 1);
6521 		jsB_propfun(J, "PDFWidget.toggle", ffi_PDFWidget_toggle, 0);
6522 		jsB_propfun(J, "PDFWidget.getMaxLen", ffi_PDFWidget_getMaxLen, 0);
6523 		jsB_propfun(J, "PDFWidget.getOptions", ffi_PDFWidget_getOptions, 1);
6524 
6525 		jsB_propfun(J, "PDFWidget.update", ffi_PDFWidget_update, 0);
6526 
6527 		jsB_propfun(J, "PDFWidget.eventEnter", ffi_PDFWidget_eventEnter, 0);
6528 		jsB_propfun(J, "PDFWidget.eventExit", ffi_PDFWidget_eventExit, 0);
6529 		jsB_propfun(J, "PDFWidget.eventDown", ffi_PDFWidget_eventDown, 0);
6530 		jsB_propfun(J, "PDFWidget.eventUp", ffi_PDFWidget_eventUp, 0);
6531 		jsB_propfun(J, "PDFWidget.eventFocus", ffi_PDFWidget_eventFocus, 0);
6532 		jsB_propfun(J, "PDFWidget.eventBlur", ffi_PDFWidget_eventBlur, 0);
6533 		jsB_propfun(J, "PDFWidget.validateSignature", ffi_PDFWidget_validateSignature, 0);
6534 		jsB_propfun(J, "PDFWidget.isSigned", ffi_PDFWidget_isSigned, 0);
6535 		jsB_propfun(J, "PDFWidget.sign", ffi_PDFWidget_sign, 1);
6536 		jsB_propfun(J, "PDFWidget.clearSignature", ffi_PDFWidget_clearSignature, 0);
6537 	}
6538 	js_dup(J);
6539 	js_setglobal(J, "PDFWidget");
6540 	js_setregistry(J, "pdf_widget");
6541 
6542 	js_getregistry(J, "Userdata");
6543 	js_newobjectx(J);
6544 	{
6545 	}
6546 	js_dup(J);
6547 	js_setglobal(J, "PDFPKCS7Signer");
6548 	js_setregistry(J, "pdf_pkcs7_signer");
6549 
6550 	js_getregistry(J, "Userdata");
6551 	js_newobjectx(J);
6552 	{
6553 		jsB_propfun(J, "PDFObject.get", ffi_PDFObject_get, 1);
6554 		jsB_propfun(J, "PDFObject.put", ffi_PDFObject_put, 2);
6555 		jsB_propfun(J, "PDFObject.push", ffi_PDFObject_push, 1);
6556 		jsB_propfun(J, "PDFObject.delete", ffi_PDFObject_delete, 1);
6557 		jsB_propfun(J, "PDFObject.resolve", ffi_PDFObject_resolve, 0);
6558 		jsB_propfun(J, "PDFObject.toString", ffi_PDFObject_toString, 2);
6559 		jsB_propfun(J, "PDFObject.valueOf", ffi_PDFObject_valueOf, 0);
6560 		jsB_propfun(J, "PDFObject.isArray", ffi_PDFObject_isArray, 0);
6561 		jsB_propfun(J, "PDFObject.isDictionary", ffi_PDFObject_isDictionary, 0);
6562 		jsB_propfun(J, "PDFObject.isIndirect", ffi_PDFObject_isIndirect, 0);
6563 		jsB_propfun(J, "PDFObject.asIndirect", ffi_PDFObject_asIndirect, 0);
6564 		jsB_propfun(J, "PDFObject.isNull", ffi_PDFObject_isNull, 0);
6565 		jsB_propfun(J, "PDFObject.isBoolean", ffi_PDFObject_isBoolean, 0);
6566 		jsB_propfun(J, "PDFObject.asBoolean", ffi_PDFObject_asBoolean, 0);
6567 		jsB_propfun(J, "PDFObject.isNumber", ffi_PDFObject_isNumber, 0);
6568 		jsB_propfun(J, "PDFObject.asNumber", ffi_PDFObject_asNumber, 0);
6569 		jsB_propfun(J, "PDFObject.isName", ffi_PDFObject_isName, 0);
6570 		jsB_propfun(J, "PDFObject.asName", ffi_PDFObject_asName, 0);
6571 		jsB_propfun(J, "PDFObject.isString", ffi_PDFObject_isString, 0);
6572 		jsB_propfun(J, "PDFObject.asString", ffi_PDFObject_asString, 0);
6573 		jsB_propfun(J, "PDFObject.asByteString", ffi_PDFObject_asByteString, 0);
6574 		jsB_propfun(J, "PDFObject.isStream", ffi_PDFObject_isStream, 0);
6575 		jsB_propfun(J, "PDFObject.readStream", ffi_PDFObject_readStream, 0);
6576 		jsB_propfun(J, "PDFObject.readRawStream", ffi_PDFObject_readRawStream, 0);
6577 		jsB_propfun(J, "PDFObject.writeObject", ffi_PDFObject_writeObject, 1);
6578 		jsB_propfun(J, "PDFObject.writeStream", ffi_PDFObject_writeStream, 1);
6579 		jsB_propfun(J, "PDFObject.writeRawStream", ffi_PDFObject_writeRawStream, 1);
6580 		jsB_propfun(J, "PDFObject.forEach", ffi_PDFObject_forEach, 1);
6581 	}
6582 	js_setregistry(J, "pdf_obj");
6583 
6584 	js_getregistry(J, "Userdata");
6585 	js_newobjectx(J);
6586 	{
6587 		jsB_propfun(J, "PDFGraftMap.graftObject", ffi_PDFGraftMap_graftObject, 1);
6588 		jsB_propfun(J, "PDFGraftMap.graftPage", ffi_PDFGraftMap_graftPage, 3);
6589 	}
6590 	js_setregistry(J, "pdf_graft_map");
6591 #endif
6592 
6593 	js_pushglobal(J);
6594 	{
6595 #if FZ_ENABLE_PDF
6596 		jsB_propcon(J, "pdf_document", "PDFDocument", ffi_new_PDFDocument, 1);
6597 #endif
6598 
6599 		jsB_propcon(J, "fz_buffer", "Buffer", ffi_new_Buffer, 1);
6600 		jsB_propcon(J, "fz_document", "Document", ffi_new_Document, 1);
6601 		jsB_propcon(J, "fz_pixmap", "Pixmap", ffi_new_Pixmap, 3);
6602 		jsB_propcon(J, "fz_image", "Image", ffi_new_Image, 2);
6603 		jsB_propcon(J, "fz_font", "Font", ffi_new_Font, 2);
6604 		jsB_propcon(J, "fz_text", "Text", ffi_new_Text, 0);
6605 		jsB_propcon(J, "fz_path", "Path", ffi_new_Path, 0);
6606 		jsB_propcon(J, "fz_display_list", "DisplayList", ffi_new_DisplayList, 1);
6607 		jsB_propcon(J, "fz_device", "DrawDevice", ffi_new_DrawDevice, 2);
6608 		jsB_propcon(J, "fz_device", "DisplayListDevice", ffi_new_DisplayListDevice, 1);
6609 		jsB_propcon(J, "fz_document_writer", "DocumentWriter", ffi_new_DocumentWriter, 3);
6610 		jsB_propcon(J, "pdf_pkcs7_signer", "PDFPKCS7Signer", ffi_new_PDFPKCS7Signer, 2);
6611 
6612 		jsB_propfun(J, "readFile", ffi_readFile, 1);
6613 
6614 		js_getregistry(J, "DeviceGray");
6615 		js_defproperty(J, -2, "DeviceGray", JS_DONTENUM | JS_READONLY | JS_DONTCONF);
6616 
6617 		js_getregistry(J, "DeviceRGB");
6618 		js_defproperty(J, -2, "DeviceRGB", JS_DONTENUM | JS_READONLY | JS_DONTCONF);
6619 
6620 		js_getregistry(J, "DeviceBGR");
6621 		js_defproperty(J, -2, "DeviceBGR", JS_DONTENUM | JS_READONLY | JS_DONTCONF);
6622 
6623 		js_getregistry(J, "DeviceCMYK");
6624 		js_defproperty(J, -2, "DeviceCMYK", JS_DONTENUM | JS_READONLY | JS_DONTCONF);
6625 
6626 		jsB_propfun(J, "setUserCSS", ffi_setUserCSS, 2);
6627 	}
6628 
6629 	/* re-implement matrix math in javascript */
6630 	js_dostring(J, "var Identity = Object.freeze([1,0,0,1,0,0]);");
6631 	js_dostring(J, "function Scale(sx,sy) { return [sx,0,0,sy,0,0]; }");
6632 	js_dostring(J, "function Translate(tx,ty) { return [1,0,0,1,tx,ty]; }");
6633 	js_dostring(J, "function Concat(a,b) { return ["
6634 			"a[0] * b[0] + a[1] * b[2],"
6635 			"a[0] * b[1] + a[1] * b[3],"
6636 			"a[2] * b[0] + a[3] * b[2],"
6637 			"a[2] * b[1] + a[3] * b[3],"
6638 			"a[4] * b[0] + a[5] * b[2] + b[4],"
6639 			"a[4] * b[1] + a[5] * b[3] + b[5]];}");
6640 
6641 	if (argc > 1) {
6642 		js_pushstring(J, argv[1]);
6643 		js_setglobal(J, "scriptPath");
6644 		js_newarray(J);
6645 		for (i = 2; i < argc; ++i) {
6646 			js_pushstring(J, argv[i]);
6647 			js_setindex(J, -2, i - 2);
6648 		}
6649 		js_setglobal(J, "scriptArgs");
6650 		if (js_dofile(J, argv[1]))
6651 		{
6652 			js_freestate(J);
6653 			fz_drop_context(ctx);
6654 			return 1;
6655 		}
6656 	} else {
6657 		char line[256];
6658 		fputs(PS1, stdout);
6659 		while (fgets(line, sizeof line, stdin)) {
6660 			eval_print(J, line);
6661 			fputs(PS1, stdout);
6662 		}
6663 		putchar('\n');
6664 	}
6665 
6666 	js_freestate(J);
6667 	fz_drop_context(ctx);
6668 	return 0;
6669 }
6670 
6671 #endif
6672