1#include "mupdf/fitz.h"
2
3#if FZ_ENABLE_PDF
4#include "mupdf/pdf.h"
5#endif
6
7#if FZ_ENABLE_JS
8
9#include "mujs.h"
10
11#include <string.h>
12#include <stdlib.h>
13#include <stdio.h>
14
15#define PS1 "> "
16
17FZ_NORETURN static void rethrow(js_State *J)
18{
19 js_newerror(J, fz_caught_message(js_getcontext(J)));
20 js_throw(J);
21}
22
23FZ_NORETURN static void rethrow_as_fz(js_State *J)
24{
25 fz_throw(js_getcontext(J), FZ_ERROR_GENERIC, "%s", js_tostring(J, -1));
26}
27
28static void *alloc(void *actx, void *ptr, int n)
29{
30 return fz_realloc_no_throw(actx, ptr, n);
31}
32
33static int eval_print(js_State *J, const char *source)
34{
35 if (js_ploadstring(J, "[string]", source)) {
36 fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
37 js_pop(J, 1);
38 return 1;
39 }
40 js_pushundefined(J);
41 if (js_pcall(J, 0)) {
42 fprintf(stderr, "%s\n", js_trystring(J, -1, "Error"));
43 js_pop(J, 1);
44 return 1;
45 }
46 if (js_isdefined(J, -1)) {
47 printf("%s\n", js_tryrepr(J, -1, "can't convert to string"));
48 }
49 js_pop(J, 1);
50 return 0;
51}
52
53static void jsB_propfun(js_State *J, const char *name, js_CFunction cfun, int n)
54{
55 const char *realname = strchr(name, '.');
56 realname = realname ? realname + 1 : name;
57 js_newcfunction(J, cfun, name, n);
58 js_defproperty(J, -2, realname, JS_DONTENUM);
59}
60
61static void jsB_propcon(js_State *J, const char *tag, const char *name, js_CFunction cfun, int n)
62{
63 const char *realname = strchr(name, '.');
64 realname = realname ? realname + 1 : name;
65 js_getregistry(J, tag);
66 js_newcconstructor(J, cfun, cfun, name, n);
67 js_defproperty(J, -2, realname, JS_DONTENUM);
68}
69
70static void jsB_gc(js_State *J)
71{
72 int report = js_toboolean(J, 1);
73 js_gc(J, report);
74 js_pushundefined(J);
75}
76
77static void jsB_load(js_State *J)
78{
79 const char *filename = js_tostring(J, 1);
80 int rv = js_dofile(J, filename);
81 js_pushboolean(J, !rv);
82}
83
84static void jsB_print(js_State *J)
85{
86 unsigned int i, top = js_gettop(J);
87 for (i = 1; i < top; ++i) {
88 const char *s = js_tostring(J, i);
89 if (i > 1) putchar(' ');
90 fputs(s, stdout);
91 }
92 putchar('\n');
93 js_pushundefined(J);
94}
95
96static void jsB_write(js_State *J)
97{
98 unsigned int i, top = js_gettop(J);
99 for (i = 1; i < top; ++i) {
100 const char *s = js_tostring(J, i);
101 if (i > 1) putchar(' ');
102 fputs(s, stdout);
103 }
104 js_pushundefined(J);
105}
106
107static void jsB_read(js_State *J)
108{
109 fz_context *ctx = js_getcontext(J);
110 const char *filename = js_tostring(J, 1);
111 FILE *f;
112 char *s;
113 long n;
114 size_t t;
115
116 f = fopen(filename, "rb");
117 if (!f) {
118 js_error(J, "cannot open file: '%s'", filename);
119 }
120
121 if (fseek(f, 0, SEEK_END) < 0) {
122 fclose(f);
123 js_error(J, "cannot seek in file: '%s'", filename);
124 }
125
126 n = ftell(f);
127 if (n < 0) {
128 fclose(f);
129 js_error(J, "cannot tell in file: '%s'", filename);
130 }
131
132 if (fseek(f, 0, SEEK_SET) < 0) {
133 fclose(f);
134 js_error(J, "cannot seek in file: '%s'", filename);
135 }
136
137 s = fz_malloc(ctx, n + 1);
138 if (!s) {
139 fclose(f);
140 js_error(J, "cannot allocate storage for file contents: '%s'", filename);
141 }
142
143 t = fread(s, 1, n, f);
144 if (t != n) {
145 fz_free(ctx, s);
146 fclose(f);
147 js_error(J, "cannot read data from file: '%s'", filename);
148 }
149 s[n] = 0;
150
151 js_pushstring(J, s);
152 fz_free(ctx, s);
153 fclose(f);
154}
155
156static void jsB_readline(js_State *J)
157{
158 char line[256];
159 size_t n;
160 if (!fgets(line, sizeof line, stdin))
161 js_error(J, "cannot read line from stdin");
162 n = strlen(line);
163 if (n > 0 && line[n-1] == '\n')
164 line[n-1] = 0;
165 js_pushstring(J, line);
166}
167
168static void jsB_repr(js_State *J)
169{
170 js_repr(J, 1);
171}
172
173static void jsB_quit(js_State *J)
174{
175 exit(js_tonumber(J, 1));
176}
177
178static const char *require_js =
179 "function require(name) {\n"
180 "var cache = require.cache;\n"
181 "if (name in cache) return cache[name];\n"
182 "var exports = {};\n"
183 "cache[name] = exports;\n"
184 "Function('exports', read(name+'.js'))(exports);\n"
185 "return exports;\n"
186 "}\n"
187 "require.cache = Object.create(null);\n"
188;
189
190static const char *stacktrace_js =
191 "Error.prototype.toString = function() {\n"
192 "if (this.stackTrace) return this.name + ': ' + this.message + this.stackTrace;\n"
193 "return this.name + ': ' + this.message;\n"
194 "};\n"
195;
196
197/* destructors */
198
199static void ffi_gc_fz_buffer(js_State *J, void *buf)
200{
201 fz_context *ctx = js_getcontext(J);
202 fz_try(ctx)
203 fz_drop_buffer(ctx, buf);
204 fz_catch(ctx)
205 rethrow(J);
206}
207
208static void ffi_gc_fz_document(js_State *J, void *doc)
209{
210 fz_context *ctx = js_getcontext(J);
211 fz_drop_document(ctx, doc);
212}
213
214static void ffi_gc_fz_page(js_State *J, void *page)
215{
216 fz_context *ctx = js_getcontext(J);
217 fz_drop_page(ctx, page);
218}
219
220static void ffi_gc_fz_colorspace(js_State *J, void *colorspace)
221{
222 fz_context *ctx = js_getcontext(J);
223 fz_drop_colorspace(ctx, colorspace);
224}
225
226static void ffi_gc_fz_pixmap(js_State *J, void *pixmap)
227{
228 fz_context *ctx = js_getcontext(J);
229 fz_drop_pixmap(ctx, pixmap);
230}
231
232static void ffi_gc_fz_path(js_State *J, void *path)
233{
234 fz_context *ctx = js_getcontext(J);
235 fz_drop_path(ctx, path);
236}
237
238static void ffi_gc_fz_text(js_State *J, void *text)
239{
240 fz_context *ctx = js_getcontext(J);
241 fz_drop_text(ctx, text);
242}
243
244static void ffi_gc_fz_font(js_State *J, void *font)
245{
246 fz_context *ctx = js_getcontext(J);
247 fz_drop_font(ctx, font);
248}
249
250static void ffi_gc_fz_shade(js_State *J, void *shade)
251{
252 fz_context *ctx = js_getcontext(J);
253 fz_drop_shade(ctx, shade);
254}
255
256static void ffi_gc_fz_image(js_State *J, void *image)
257{
258 fz_context *ctx = js_getcontext(J);
259 fz_drop_image(ctx, image);
260}
261
262static void ffi_gc_fz_display_list(js_State *J, void *list)
263{
264 fz_context *ctx = js_getcontext(J);
265 fz_drop_display_list(ctx, list);
266}
267
268static void ffi_gc_fz_stext_page(js_State *J, void *text)
269{
270 fz_context *ctx = js_getcontext(J);
271 fz_drop_stext_page(ctx, text);
272}
273
274static void ffi_gc_fz_device(js_State *J, void *device)
275{
276 fz_context *ctx = js_getcontext(J);
277 fz_drop_device(ctx, device);
278}
279
280static void ffi_gc_fz_document_writer(js_State *J, void *wri)
281{
282 fz_context *ctx = js_getcontext(J);
283 fz_drop_document_writer(ctx, wri);
284}
285
286#if FZ_ENABLE_PDF
287
288static void ffi_gc_pdf_annot(js_State *J, void *annot)
289{
290 fz_context *ctx = js_getcontext(J);
291 pdf_drop_annot(ctx, annot);
292}
293
294static void ffi_gc_pdf_document(js_State *J, void *doc)
295{
296 fz_context *ctx = js_getcontext(J);
297 pdf_drop_document(ctx, doc);
298}
299
300static void ffi_gc_pdf_obj(js_State *J, void *obj)
301{
302 fz_context *ctx = js_getcontext(J);
303 pdf_drop_obj(ctx, obj);
304}
305
306static void ffi_gc_pdf_graft_map(js_State *J, void *map)
307{
308 fz_context *ctx = js_getcontext(J);
309 pdf_drop_graft_map(ctx, map);
310}
311
312static fz_document *ffi_todocument(js_State *J, int idx)
313{
314 if (js_isuserdata(J, idx, "pdf_document"))
315 return js_touserdata(J, idx, "pdf_document");
316 return js_touserdata(J, idx, "fz_document");
317}
318
319static void ffi_pushdocument(js_State *J, fz_document *document)
320{
321 fz_context *ctx = js_getcontext(J);
322 pdf_document *pdocument = pdf_document_from_fz_document(ctx, document);
323 if (pdocument) {
324 js_getregistry(J, "pdf_document");
325 js_newuserdata(J, "pdf_document", document, ffi_gc_fz_document);
326 } else {
327 js_getregistry(J, "fz_document");
328 js_newuserdata(J, "fz_document", document, ffi_gc_fz_document);
329 }
330}
331
332static fz_page *ffi_topage(js_State *J, int idx)
333{
334 if (js_isuserdata(J, idx, "pdf_page"))
335 return js_touserdata(J, idx, "pdf_page");
336 return js_touserdata(J, idx, "fz_page");
337}
338
339static void ffi_pushpage(js_State *J, fz_page *page)
340{
341 fz_context *ctx = js_getcontext(J);
342 pdf_page *ppage = pdf_page_from_fz_page(ctx, page);
343 if (ppage) {
344 js_getregistry(J, "pdf_page");
345 js_newuserdata(J, "pdf_page", page, ffi_gc_fz_page);
346 } else {
347 js_getregistry(J, "fz_page");
348 js_newuserdata(J, "fz_page", page, ffi_gc_fz_page);
349 }
350}
351
352#else
353
354static fz_document *ffi_todocument(js_State *J, int idx)
355{
356 return js_touserdata(J, idx, "fz_document");
357}
358
359static void ffi_pushdocument(js_State *J, fz_document *document)
360{
361 js_getregistry(J, "fz_document");
362 js_newuserdata(J, "fz_document", doc, ffi_gc_fz_document);
363}
364
365static fz_page *ffi_topage(js_State *J, int idx)
366{
367 return js_touserdata(J, idx, "fz_page");
368}
369
370static void ffi_pushpage(js_State *J, fz_page *page)
371{
372 js_getregistry(J, "fz_page");
373 js_newuserdata(J, "fz_page", page, ffi_gc_fz_page);
374}
375
376#endif /* FZ_ENABLE_PDF */
377
378/* type conversions */
379
380struct color {
381 fz_colorspace *colorspace;
382 float color[FZ_MAX_COLORS];
383 float alpha;
384};
385
386static fz_matrix ffi_tomatrix(js_State *J, int idx)
387{
388 if (js_iscoercible(J, idx))
389 {
390 fz_matrix matrix;
391 js_getindex(J, idx, 0); matrix.a = js_tonumber(J, -1); js_pop(J, 1);
392 js_getindex(J, idx, 1); matrix.b = js_tonumber(J, -1); js_pop(J, 1);
393 js_getindex(J, idx, 2); matrix.c = js_tonumber(J, -1); js_pop(J, 1);
394 js_getindex(J, idx, 3); matrix.d = js_tonumber(J, -1); js_pop(J, 1);
395 js_getindex(J, idx, 4); matrix.e = js_tonumber(J, -1); js_pop(J, 1);
396 js_getindex(J, idx, 5); matrix.f = js_tonumber(J, -1); js_pop(J, 1);
397 return matrix;
398 }
399 return fz_identity;
400}
401
402static void ffi_pushmatrix(js_State *J, fz_matrix matrix)
403{
404 js_newarray(J);
405 js_pushnumber(J, matrix.a); js_setindex(J, -2, 0);
406 js_pushnumber(J, matrix.b); js_setindex(J, -2, 1);
407 js_pushnumber(J, matrix.c); js_setindex(J, -2, 2);
408 js_pushnumber(J, matrix.d); js_setindex(J, -2, 3);
409 js_pushnumber(J, matrix.e); js_setindex(J, -2, 4);
410 js_pushnumber(J, matrix.f); js_setindex(J, -2, 5);
411}
412
413static fz_point ffi_topoint(js_State *J, int idx)
414{
415 fz_point point;
416 js_getindex(J, idx, 0); point.x = js_tonumber(J, -1); js_pop(J, 1);
417 js_getindex(J, idx, 1); point.y = js_tonumber(J, -1); js_pop(J, 1);
418 return point;
419}
420
421static fz_rect ffi_torect(js_State *J, int idx)
422{
423 fz_rect rect;
424 js_getindex(J, idx, 0); rect.x0 = js_tonumber(J, -1); js_pop(J, 1);
425 js_getindex(J, idx, 1); rect.y0 = js_tonumber(J, -1); js_pop(J, 1);
426 js_getindex(J, idx, 2); rect.x1 = js_tonumber(J, -1); js_pop(J, 1);
427 js_getindex(J, idx, 3); rect.y1 = js_tonumber(J, -1); js_pop(J, 1);
428 return rect;
429}
430
431static void ffi_pushrect(js_State *J, fz_rect rect)
432{
433 js_newarray(J);
434 js_pushnumber(J, rect.x0); js_setindex(J, -2, 0);
435 js_pushnumber(J, rect.y0); js_setindex(J, -2, 1);
436 js_pushnumber(J, rect.x1); js_setindex(J, -2, 2);
437 js_pushnumber(J, rect.y1); js_setindex(J, -2, 3);
438}
439
440static void ffi_pushquad(js_State *J, fz_quad quad)
441{
442 js_newarray(J);
443 js_pushnumber(J, quad.ul.x); js_setindex(J, -2, 0);
444 js_pushnumber(J, quad.ul.y); js_setindex(J, -2, 1);
445 js_pushnumber(J, quad.ur.x); js_setindex(J, -2, 2);
446 js_pushnumber(J, quad.ur.y); js_setindex(J, -2, 3);
447 js_pushnumber(J, quad.ll.x); js_setindex(J, -2, 4);
448 js_pushnumber(J, quad.ll.y); js_setindex(J, -2, 5);
449 js_pushnumber(J, quad.lr.x); js_setindex(J, -2, 6);
450 js_pushnumber(J, quad.lr.y); js_setindex(J, -2, 7);
451}
452
453static fz_irect ffi_toirect(js_State *J, int idx)
454{
455 fz_irect irect;
456 js_getindex(J, idx, 0); irect.x0 = js_tonumber(J, -1); js_pop(J, 1);
457 js_getindex(J, idx, 1); irect.y0 = js_tonumber(J, -1); js_pop(J, 1);
458 js_getindex(J, idx, 2); irect.x1 = js_tonumber(J, -1); js_pop(J, 1);
459 js_getindex(J, idx, 3); irect.y1 = js_tonumber(J, -1); js_pop(J, 1);
460 return irect;
461}
462
463static void ffi_pusharray(js_State *J, const float *v, int n)
464{
465 int i;
466 js_newarray(J);
467 for (i = 0; i < n; ++i) {
468 js_pushnumber(J, v[i]);
469 js_setindex(J, -2, i);
470 }
471}
472
473static void ffi_pushcolorspace(js_State *J, fz_colorspace *colorspace)
474{
475 fz_context *ctx = js_getcontext(J);
476 if (colorspace == fz_device_rgb(ctx))
477 js_getregistry(J, "DeviceRGB");
478 else if (colorspace == fz_device_bgr(ctx))
479 js_getregistry(J, "DeviceBGR");
480 else if (colorspace == fz_device_gray(ctx))
481 js_getregistry(J, "DeviceGray");
482 else if (colorspace == fz_device_cmyk(ctx))
483 js_getregistry(J, "DeviceCMYK");
484 else {
485 js_getregistry(J, "fz_colorspace");
486 js_newuserdata(J, "fz_colorspace", fz_keep_colorspace(ctx, colorspace), ffi_gc_fz_colorspace);
487 }
488}
489
490static void ffi_pushcolor(js_State *J, fz_colorspace *colorspace, const float *color, float alpha)
491{
492 fz_context *ctx = js_getcontext(J);
493 if (colorspace) {
494 ffi_pushcolorspace(J, colorspace);
495 ffi_pusharray(J, color, fz_colorspace_n(ctx, colorspace));
496 } else {
497 js_pushnull(J);
498 js_pushnull(J);
499 }
500 js_pushnumber(J, alpha);
501}
502
503static struct color ffi_tocolor(js_State *J, int idx)
504{
505 struct color c;
506 int n, i;
507 fz_context *ctx = js_getcontext(J);
508 c.colorspace = js_touserdata(J, idx, "fz_colorspace");
509 if (c.colorspace) {
510 n = fz_colorspace_n(ctx, c.colorspace);
511 for (i=0; i < n; ++i) {
512 js_getindex(J, idx + 1, i);
513 c.color[i] = js_tonumber(J, -1);
514 js_pop(J, 1);
515 }
516 }
517 c.alpha = js_tonumber(J, idx + 2);
518 return c;
519}
520
521static fz_color_params ffi_tocolorparams(js_State *J, int idx)
522{
523 /* TODO */
524 return fz_default_color_params;
525}
526
527static void ffi_pushcolorparams(js_State *J, fz_color_params color_params)
528{
529 /* TODO */
530 js_pushnull(J);
531}
532
533static const char *string_from_cap(fz_linecap cap)
534{
535 switch (cap) {
536 default:
537 case FZ_LINECAP_BUTT: return "Butt";
538 case FZ_LINECAP_ROUND: return "Round";
539 case FZ_LINECAP_SQUARE: return "Square";
540 case FZ_LINECAP_TRIANGLE: return "Triangle";
541 }
542}
543
544static const char *string_from_join(fz_linejoin join)
545{
546 switch (join) {
547 default:
548 case FZ_LINEJOIN_MITER: return "Miter";
549 case FZ_LINEJOIN_ROUND: return "Round";
550 case FZ_LINEJOIN_BEVEL: return "Bevel";
551 case FZ_LINEJOIN_MITER_XPS: return "MiterXPS";
552 }
553}
554
555static fz_linecap cap_from_string(const char *str)
556{
557 if (!strcmp(str, "Round")) return FZ_LINECAP_ROUND;
558 if (!strcmp(str, "Square")) return FZ_LINECAP_SQUARE;
559 if (!strcmp(str, "Triangle")) return FZ_LINECAP_TRIANGLE;
560 return FZ_LINECAP_BUTT;
561}
562
563static fz_linejoin join_from_string(const char *str)
564{
565 if (!strcmp(str, "Round")) return FZ_LINEJOIN_ROUND;
566 if (!strcmp(str, "Bevel")) return FZ_LINEJOIN_BEVEL;
567 if (!strcmp(str, "MiterXPS")) return FZ_LINEJOIN_MITER_XPS;
568 return FZ_LINEJOIN_MITER;
569}
570
571static void ffi_pushstroke(js_State *J, const fz_stroke_state *stroke)
572{
573 js_newobject(J);
574 js_pushliteral(J, string_from_cap(stroke->start_cap));
575 js_setproperty(J, -2, "startCap");
576 js_pushliteral(J, string_from_cap(stroke->dash_cap));
577 js_setproperty(J, -2, "dashCap");
578 js_pushliteral(J, string_from_cap(stroke->end_cap));
579 js_setproperty(J, -2, "endCap");
580 js_pushliteral(J, string_from_join(stroke->linejoin));
581 js_setproperty(J, -2, "lineJoin");
582 js_pushnumber(J, stroke->linewidth);
583 js_setproperty(J, -2, "lineWidth");
584 js_pushnumber(J, stroke->miterlimit);
585 js_setproperty(J, -2, "miterLimit");
586 js_pushnumber(J, stroke->dash_phase);
587 js_setproperty(J, -2, "dashPhase");
588 ffi_pusharray(J, stroke->dash_list, stroke->dash_len);
589 js_setproperty(J, -2, "dashes");
590}
591
592static fz_stroke_state ffi_tostroke(js_State *J, int idx)
593{
594 fz_stroke_state stroke = fz_default_stroke_state;
595 if (js_hasproperty(J, idx, "lineCap")) {
596 stroke.start_cap = cap_from_string(js_tostring(J, -1));
597 stroke.dash_cap = stroke.start_cap;
598 stroke.end_cap = stroke.start_cap;
599 }
600 if (js_hasproperty(J, idx, "startCap")) {
601 stroke.start_cap = cap_from_string(js_tostring(J, -1));
602 js_pop(J, 1);
603 }
604 if (js_hasproperty(J, idx, "dashCap")) {
605 stroke.dash_cap = cap_from_string(js_tostring(J, -1));
606 js_pop(J, 1);
607 }
608 if (js_hasproperty(J, idx, "endCap")) {
609 stroke.end_cap = cap_from_string(js_tostring(J, -1));
610 js_pop(J, 1);
611 }
612 if (js_hasproperty(J, idx, "lineJoin")) {
613 stroke.linejoin = join_from_string(js_tostring(J, -1));
614 js_pop(J, 1);
615 }
616 if (js_hasproperty(J, idx, "lineWidth")) {
617 stroke.linewidth = js_tonumber(J, -1);
618 js_pop(J, 1);
619 }
620 if (js_hasproperty(J, idx, "miterLimit")) {
621 stroke.miterlimit = js_tonumber(J, -1);
622 js_pop(J, 1);
623 }
624 if (js_hasproperty(J, idx, "dashPhase")) {
625 stroke.dash_phase = js_tonumber(J, -1);
626 js_pop(J, 1);
627 }
628 if (js_hasproperty(J, idx, "dashes")) {
629 int i, n = js_getlength(J, -1);
630 if (n > nelem(stroke.dash_list))
631 n = nelem(stroke.dash_list);
632 stroke.dash_len = n;
633 for (i = 0; i < n; ++i) {
634 js_getindex(J, -1, i);
635 stroke.dash_list[i] = js_tonumber(J, -1);
636 js_pop(J, 1);
637 }
638 }
639 return stroke;
640}
641
642static void ffi_pushtext(js_State *J, const fz_text *text)
643{
644 fz_context *ctx = js_getcontext(J);
645 js_getregistry(J, "fz_text");
646 js_newuserdata(J, "fz_text", fz_keep_text(ctx, text), ffi_gc_fz_text);
647}
648
649static void ffi_pushpath(js_State *J, const fz_path *path)
650{
651 fz_context *ctx = js_getcontext(J);
652 js_getregistry(J, "fz_path");
653 js_newuserdata(J, "fz_path", fz_keep_path(ctx, path), ffi_gc_fz_path);
654}
655
656static void ffi_pushfont(js_State *J, fz_font *font)
657{
658 fz_context *ctx = js_getcontext(J);
659 js_getregistry(J, "fz_font");
660 js_newuserdata(J, "fz_font", fz_keep_font(ctx, font), ffi_gc_fz_font);
661}
662
663static void ffi_pushshade(js_State *J, fz_shade *shade)
664{
665 fz_context *ctx = js_getcontext(J);
666 js_getregistry(J, "fz_shade");
667 js_newuserdata(J, "fz_shade", fz_keep_shade(ctx, shade), ffi_gc_fz_shade);
668}
669
670static void ffi_pushimage(js_State *J, fz_image *image)
671{
672 fz_context *ctx = js_getcontext(J);
673 js_getregistry(J, "fz_image");
674 js_newuserdata(J, "fz_image", fz_keep_image(ctx, image), ffi_gc_fz_image);
675}
676
677static void ffi_pushimage_own(js_State *J, fz_image *image)
678{
679 js_getregistry(J, "fz_image");
680 js_newuserdata(J, "fz_image", image, ffi_gc_fz_image);
681}
682
683static int is_number(const char *key, int *idx)
684{
685 char *end;
686 *idx = strtol(key, &end, 10);
687 return *end == 0;
688}
689
690static int ffi_buffer_has(js_State *J, void *buf_, const char *key)
691{
692 fz_buffer *buf = buf_;
693 int idx;
694 unsigned char *data;
695 size_t len = fz_buffer_storage(js_getcontext(J), buf, &data);
696 if (is_number(key, &idx)) {
697 if (idx < 0 || (size_t)idx >= len)
698 js_rangeerror(J, "index out of bounds");
699 js_pushnumber(J, data[idx]);
700 return 1;
701 }
702 if (!strcmp(key, "length")) {
703 js_pushnumber(J, len);
704 return 1;
705 }
706 return 0;
707}
708
709static int ffi_buffer_put(js_State *J, void *buf_, const char *key)
710{
711 fz_buffer *buf = buf_;
712 int idx;
713 unsigned char *data;
714 size_t len = fz_buffer_storage(js_getcontext(J), buf, &data);
715 if (is_number(key, &idx)) {
716 if (idx < 0 || (size_t)idx >= len)
717 js_rangeerror(J, "index out of bounds");
718 data[idx] = js_tonumber(J, -1);
719 return 1;
720 }
721 if (!strcmp(key, "length"))
722 js_typeerror(J, "buffer length is read-only");
723 return 0;
724}
725
726static void ffi_pushbuffer(js_State *J, fz_buffer *buf)
727{
728 js_getregistry(J, "fz_buffer");
729 js_newuserdatax(J, "fz_buffer", buf,
730 ffi_buffer_has, ffi_buffer_put, NULL,
731 ffi_gc_fz_buffer);
732}
733
734#if FZ_ENABLE_PDF
735
736static fz_buffer *ffi_tobuffer(js_State *J, int idx)
737{
738 fz_context *ctx = js_getcontext(J);
739 fz_buffer *buf = NULL;
740
741 if (js_isuserdata(J, idx, "fz_buffer"))
742 buf = fz_keep_buffer(ctx, js_touserdata(J, idx, "fz_buffer"));
743 else {
744 const char *str = js_tostring(J, idx);
745 fz_try(ctx)
746 buf = fz_new_buffer_from_copied_data(ctx, (const unsigned char *)str, strlen(str));
747 fz_catch(ctx)
748 rethrow(J);
749 }
750
751 return buf;
752}
753
754#endif /* FZ_ENABLE_PDF */
755
756/* device calling into js from c */
757
758typedef struct js_device_s
759{
760 fz_device super;
761 js_State *J;
762} js_device;
763
764static void
765js_dev_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, fz_matrix ctm,
766 fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
767{
768 js_State *J = ((js_device*)dev)->J;
769 if (js_try(J))
770 rethrow_as_fz(J);
771 if (js_hasproperty(J, -1, "fillPath")) {
772 js_copy(J, -2);
773 ffi_pushpath(J, path);
774 js_pushboolean(J, even_odd);
775 ffi_pushmatrix(J, ctm);
776 ffi_pushcolor(J, colorspace, color, alpha);
777 ffi_pushcolorparams(J, color_params);
778 js_call(J, 7);
779 js_pop(J, 1);
780 }
781 js_endtry(J);
782}
783
784static void
785js_dev_clip_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, fz_matrix ctm,
786 fz_rect scissor)
787{
788 js_State *J = ((js_device*)dev)->J;
789 if (js_try(J))
790 rethrow_as_fz(J);
791 if (js_hasproperty(J, -1, "clipPath")) {
792 js_copy(J, -2);
793 ffi_pushpath(J, path);
794 js_pushboolean(J, even_odd);
795 ffi_pushmatrix(J, ctm);
796 js_call(J, 3);
797 js_pop(J, 1);
798 }
799 js_endtry(J);
800}
801
802static void
803js_dev_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path,
804 const fz_stroke_state *stroke, fz_matrix ctm,
805 fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
806{
807 js_State *J = ((js_device*)dev)->J;
808 if (js_try(J))
809 rethrow_as_fz(J);
810 if (js_hasproperty(J, -1, "strokePath")) {
811 js_copy(J, -2);
812 ffi_pushpath(J, path);
813 ffi_pushstroke(J, stroke);
814 ffi_pushmatrix(J, ctm);
815 ffi_pushcolor(J, colorspace, color, alpha);
816 ffi_pushcolorparams(J, color_params);
817 js_call(J, 7);
818 js_pop(J, 1);
819 }
820 js_endtry(J);
821}
822
823static void
824js_dev_clip_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke,
825 fz_matrix ctm, fz_rect scissor)
826{
827 js_State *J = ((js_device*)dev)->J;
828 if (js_try(J))
829 rethrow_as_fz(J);
830 if (js_hasproperty(J, -1, "clipStrokePath")) {
831 js_copy(J, -2);
832 ffi_pushpath(J, path);
833 ffi_pushstroke(J, stroke);
834 ffi_pushmatrix(J, ctm);
835 js_call(J, 3);
836 js_pop(J, 1);
837 }
838 js_endtry(J);
839}
840
841static void
842js_dev_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm,
843 fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
844{
845 js_State *J = ((js_device*)dev)->J;
846 if (js_try(J))
847 rethrow_as_fz(J);
848 if (js_hasproperty(J, -1, "fillText")) {
849 js_copy(J, -2);
850 ffi_pushtext(J, text);
851 ffi_pushmatrix(J, ctm);
852 ffi_pushcolor(J, colorspace, color, alpha);
853 ffi_pushcolorparams(J, color_params);
854 js_call(J, 6);
855 js_pop(J, 1);
856 }
857 js_endtry(J);
858}
859
860static void
861js_dev_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke,
862 fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
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, "strokeText")) {
868 js_copy(J, -2);
869 ffi_pushtext(J, text);
870 ffi_pushstroke(J, stroke);
871 ffi_pushmatrix(J, ctm);
872 ffi_pushcolor(J, colorspace, color, alpha);
873 ffi_pushcolorparams(J, color_params);
874 js_call(J, 7);
875 js_pop(J, 1);
876 }
877 js_endtry(J);
878}
879
880static void
881js_dev_clip_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm, fz_rect scissor)
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, "clipText")) {
887 js_copy(J, -2);
888 ffi_pushtext(J, text);
889 ffi_pushmatrix(J, ctm);
890 js_call(J, 2);
891 js_pop(J, 1);
892 }
893 js_endtry(J);
894}
895
896static void
897js_dev_clip_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke,
898 fz_matrix ctm, fz_rect scissor)
899{
900 js_State *J = ((js_device*)dev)->J;
901 if (js_try(J))
902 rethrow_as_fz(J);
903 if (js_hasproperty(J, -1, "clipStrokeText")) {
904 js_copy(J, -2);
905 ffi_pushtext(J, text);
906 ffi_pushstroke(J, stroke);
907 ffi_pushmatrix(J, ctm);
908 js_call(J, 3);
909 js_pop(J, 1);
910 }
911 js_endtry(J);
912}
913
914static void
915js_dev_ignore_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm)
916{
917 js_State *J = ((js_device*)dev)->J;
918 if (js_try(J))
919 rethrow_as_fz(J);
920 if (js_hasproperty(J, -1, "ignoreText")) {
921 js_copy(J, -2);
922 ffi_pushtext(J, text);
923 ffi_pushmatrix(J, ctm);
924 js_call(J, 2);
925 js_pop(J, 1);
926 }
927 js_endtry(J);
928}
929
930static void
931js_dev_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha, fz_color_params color_params)
932{
933 js_State *J = ((js_device*)dev)->J;
934 if (js_try(J))
935 rethrow_as_fz(J);
936 if (js_hasproperty(J, -1, "fillShade")) {
937 js_copy(J, -2);
938 ffi_pushshade(J, shade);
939 ffi_pushmatrix(J, ctm);
940 js_pushnumber(J, alpha);
941 ffi_pushcolorparams(J, color_params);
942 js_call(J, 4);
943 js_pop(J, 1);
944 }
945 js_endtry(J);
946}
947
948static void
949js_dev_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, float alpha, fz_color_params color_params)
950{
951 js_State *J = ((js_device*)dev)->J;
952 if (js_try(J))
953 rethrow_as_fz(J);
954 if (js_hasproperty(J, -1, "fillImage")) {
955 js_copy(J, -2);
956 ffi_pushimage(J, image);
957 ffi_pushmatrix(J, ctm);
958 js_pushnumber(J, alpha);
959 ffi_pushcolorparams(J, color_params);
960 js_call(J, 4);
961 js_pop(J, 1);
962 }
963 js_endtry(J);
964}
965
966static void
967js_dev_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm,
968 fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)
969{
970 js_State *J = ((js_device*)dev)->J;
971 if (js_try(J))
972 rethrow_as_fz(J);
973 if (js_hasproperty(J, -1, "fillImageMask")) {
974 js_copy(J, -2);
975 ffi_pushimage(J, image);
976 ffi_pushmatrix(J, ctm);
977 ffi_pushcolor(J, colorspace, color, alpha);
978 ffi_pushcolorparams(J, color_params);
979 js_call(J, 6);
980 js_pop(J, 1);
981 }
982 js_endtry(J);
983}
984
985static void
986js_dev_clip_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, fz_rect scissor)
987{
988 js_State *J = ((js_device*)dev)->J;
989 if (js_try(J))
990 rethrow_as_fz(J);
991 if (js_hasproperty(J, -1, "clipImageMask")) {
992 js_copy(J, -2);
993 ffi_pushimage(J, image);
994 ffi_pushmatrix(J, ctm);
995 js_call(J, 2);
996 js_pop(J, 1);
997 }
998 js_endtry(J);
999}
1000
1001static void
1002js_dev_pop_clip(fz_context *ctx, fz_device *dev)
1003{
1004 js_State *J = ((js_device*)dev)->J;
1005 if (js_try(J))
1006 rethrow_as_fz(J);
1007 if (js_hasproperty(J, -1, "popClip")) {
1008 js_copy(J, -2);
1009 js_call(J, 0);
1010 js_pop(J, 1);
1011 }
1012 js_endtry(J);
1013}
1014
1015static void
1016js_dev_begin_mask(fz_context *ctx, fz_device *dev, fz_rect bbox, int luminosity,
1017 fz_colorspace *colorspace, const float *color, fz_color_params color_params)
1018{
1019 js_State *J = ((js_device*)dev)->J;
1020 if (js_try(J))
1021 rethrow_as_fz(J);
1022 if (js_hasproperty(J, -1, "beginMask")) {
1023 js_copy(J, -2);
1024 ffi_pushrect(J, bbox);
1025 js_pushboolean(J, luminosity);
1026 ffi_pushcolor(J, colorspace, color, 1);
1027 ffi_pushcolorparams(J, color_params);
1028 js_call(J, 6);
1029 js_pop(J, 1);
1030 }
1031 js_endtry(J);
1032}
1033
1034static void
1035js_dev_end_mask(fz_context *ctx, fz_device *dev)
1036{
1037 js_State *J = ((js_device*)dev)->J;
1038 if (js_try(J))
1039 rethrow_as_fz(J);
1040 if (js_hasproperty(J, -1, "endMask")) {
1041 js_copy(J, -2);
1042 js_call(J, 0);
1043 js_pop(J, 1);
1044 }
1045 js_endtry(J);
1046}
1047
1048static void
1049js_dev_begin_group(fz_context *ctx, fz_device *dev, fz_rect bbox,
1050 fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha)
1051{
1052 js_State *J = ((js_device*)dev)->J;
1053 if (js_try(J))
1054 rethrow_as_fz(J);
1055 if (js_hasproperty(J, -1, "beginGroup")) {
1056 js_copy(J, -2);
1057 ffi_pushrect(J, bbox);
1058 js_pushboolean(J, isolated);
1059 js_pushboolean(J, knockout);
1060 js_pushliteral(J, fz_blendmode_name(blendmode));
1061 js_pushnumber(J, alpha);
1062 js_call(J, 5);
1063 js_pop(J, 1);
1064 }
1065 js_endtry(J);
1066}
1067
1068static void
1069js_dev_end_group(fz_context *ctx, fz_device *dev)
1070{
1071 js_State *J = ((js_device*)dev)->J;
1072 if (js_try(J))
1073 rethrow_as_fz(J);
1074 if (js_hasproperty(J, -1, "endGroup")) {
1075 js_copy(J, -2);
1076 js_call(J, 0);
1077 js_pop(J, 1);
1078 }
1079 js_endtry(J);
1080}
1081
1082static int
1083js_dev_begin_tile(fz_context *ctx, fz_device *dev, fz_rect area, fz_rect view,
1084 float xstep, float ystep, fz_matrix ctm, int id)
1085{
1086 js_State *J = ((js_device*)dev)->J;
1087 if (js_try(J))
1088 rethrow_as_fz(J);
1089 if (js_hasproperty(J, -1, "beginTile")) {
1090 int n;
1091 js_copy(J, -2);
1092 ffi_pushrect(J, area);
1093 ffi_pushrect(J, view);
1094 js_pushnumber(J, xstep);
1095 js_pushnumber(J, ystep);
1096 ffi_pushmatrix(J, ctm);
1097 js_pushnumber(J, id);
1098 js_call(J, 6);
1099 n = js_tointeger(J, -1);
1100 js_pop(J, 1);
1101 return n;
1102 }
1103 js_endtry(J);
1104 return 0;
1105}
1106
1107static void
1108js_dev_end_tile(fz_context *ctx, fz_device *dev)
1109{
1110 js_State *J = ((js_device*)dev)->J;
1111 if (js_try(J))
1112 rethrow_as_fz(J);
1113 if (js_hasproperty(J, -1, "endTile")) {
1114 js_copy(J, -2);
1115 js_call(J, 0);
1116 js_pop(J, 1);
1117 }
1118 js_endtry(J);
1119}
1120
1121static void
1122js_dev_begin_layer(fz_context *ctx, fz_device *dev, const char *name)
1123{
1124 js_State *J = ((js_device*)dev)->J;
1125 if (js_try(J))
1126 rethrow_as_fz(J);
1127 if (js_hasproperty(J, -1, "beginLayer")) {
1128 js_copy(J, -2);
1129 js_pushstring(J, name);
1130 js_call(J, 1);
1131 js_pop(J, 1);
1132 }
1133 js_endtry(J);
1134}
1135
1136static void
1137js_dev_end_layer(fz_context *ctx, fz_device *dev)
1138{
1139 js_State *J = ((js_device*)dev)->J;
1140 if (js_try(J))
1141 rethrow_as_fz(J);
1142 if (js_hasproperty(J, -1, "endLayer")) {
1143 js_copy(J, -2);
1144 js_call(J, 0);
1145 js_pop(J, 1);
1146 }
1147 js_endtry(J);
1148}
1149
1150static fz_device *new_js_device(fz_context *ctx, js_State *J)
1151{
1152 js_device *dev = fz_new_derived_device(ctx, js_device);
1153
1154 dev->super.fill_path = js_dev_fill_path;
1155 dev->super.stroke_path = js_dev_stroke_path;
1156 dev->super.clip_path = js_dev_clip_path;
1157 dev->super.clip_stroke_path = js_dev_clip_stroke_path;
1158
1159 dev->super.fill_text = js_dev_fill_text;
1160 dev->super.stroke_text = js_dev_stroke_text;
1161 dev->super.clip_text = js_dev_clip_text;
1162 dev->super.clip_stroke_text = js_dev_clip_stroke_text;
1163 dev->super.ignore_text = js_dev_ignore_text;
1164
1165 dev->super.fill_shade = js_dev_fill_shade;
1166 dev->super.fill_image = js_dev_fill_image;
1167 dev->super.fill_image_mask = js_dev_fill_image_mask;
1168 dev->super.clip_image_mask = js_dev_clip_image_mask;
1169
1170 dev->super.pop_clip = js_dev_pop_clip;
1171
1172 dev->super.begin_mask = js_dev_begin_mask;
1173 dev->super.end_mask = js_dev_end_mask;
1174 dev->super.begin_group = js_dev_begin_group;
1175 dev->super.end_group = js_dev_end_group;
1176
1177 dev->super.begin_tile = js_dev_begin_tile;
1178 dev->super.end_tile = js_dev_end_tile;
1179
1180 dev->super.begin_layer = js_dev_begin_layer;
1181 dev->super.end_layer = js_dev_end_layer;
1182
1183 dev->J = J;
1184 return (fz_device*)dev;
1185}
1186
1187/* device calling into c from js */
1188
1189static void ffi_Device_close(js_State *J)
1190{
1191 fz_context *ctx = js_getcontext(J);
1192 fz_device *dev = js_touserdata(J, 0, "fz_device");
1193 fz_try(ctx)
1194 fz_close_device(ctx, dev);
1195 fz_catch(ctx)
1196 rethrow(J);
1197}
1198
1199static void ffi_Device_fillPath(js_State *J)
1200{
1201 fz_context *ctx = js_getcontext(J);
1202 fz_device *dev = js_touserdata(J, 0, "fz_device");
1203 fz_path *path = js_touserdata(J, 1, "fz_path");
1204 int even_odd = js_toboolean(J, 2);
1205 fz_matrix ctm = ffi_tomatrix(J, 3);
1206 struct color c = ffi_tocolor(J, 4);
1207 fz_color_params color_params = ffi_tocolorparams(J, 7);
1208 fz_try(ctx)
1209 fz_fill_path(ctx, dev, path, even_odd, ctm, c.colorspace, c.color, c.alpha, color_params);
1210 fz_catch(ctx)
1211 rethrow(J);
1212}
1213
1214static void ffi_Device_strokePath(js_State *J)
1215{
1216 fz_context *ctx = js_getcontext(J);
1217 fz_device *dev = js_touserdata(J, 0, "fz_device");
1218 fz_path *path = js_touserdata(J, 1, "fz_path");
1219 fz_stroke_state stroke = ffi_tostroke(J, 2);
1220 fz_matrix ctm = ffi_tomatrix(J, 3);
1221 struct color c = ffi_tocolor(J, 4);
1222 fz_color_params color_params = ffi_tocolorparams(J, 7);
1223 fz_try(ctx)
1224 fz_stroke_path(ctx, dev, path, &stroke, ctm, c.colorspace, c.color, c.alpha, color_params);
1225 fz_catch(ctx)
1226 rethrow(J);
1227}
1228
1229static void ffi_Device_clipPath(js_State *J)
1230{
1231 fz_context *ctx = js_getcontext(J);
1232 fz_device *dev = js_touserdata(J, 0, "fz_device");
1233 fz_path *path = js_touserdata(J, 1, "fz_path");
1234 int even_odd = js_toboolean(J, 2);
1235 fz_matrix ctm = ffi_tomatrix(J, 3);
1236 fz_try(ctx)
1237 fz_clip_path(ctx, dev, path, even_odd, ctm, fz_infinite_rect);
1238 fz_catch(ctx)
1239 rethrow(J);
1240}
1241
1242static void ffi_Device_clipStrokePath(js_State *J)
1243{
1244 fz_context *ctx = js_getcontext(J);
1245 fz_device *dev = js_touserdata(J, 0, "fz_device");
1246 fz_path *path = js_touserdata(J, 1, "fz_path");
1247 fz_stroke_state stroke = ffi_tostroke(J, 2);
1248 fz_matrix ctm = ffi_tomatrix(J, 3);
1249 fz_try(ctx)
1250 fz_clip_stroke_path(ctx, dev, path, &stroke, ctm, fz_infinite_rect);
1251 fz_catch(ctx)
1252 rethrow(J);
1253}
1254
1255static void ffi_Device_fillText(js_State *J)
1256{
1257 fz_context *ctx = js_getcontext(J);
1258 fz_device *dev = js_touserdata(J, 0, "fz_device");
1259 fz_text *text = js_touserdata(J, 1, "fz_text");
1260 fz_matrix ctm = ffi_tomatrix(J, 2);
1261 struct color c = ffi_tocolor(J, 3);
1262 fz_color_params color_params = ffi_tocolorparams(J, 6);
1263 fz_try(ctx)
1264 fz_fill_text(ctx, dev, text, ctm, c.colorspace, c.color, c.alpha, color_params);
1265 fz_catch(ctx)
1266 rethrow(J);
1267}
1268
1269static void ffi_Device_strokeText(js_State *J)
1270{
1271 fz_context *ctx = js_getcontext(J);
1272 fz_device *dev = js_touserdata(J, 0, "fz_device");
1273 fz_text *text = js_touserdata(J, 1, "fz_text");
1274 fz_stroke_state stroke = ffi_tostroke(J, 2);
1275 fz_matrix ctm = ffi_tomatrix(J, 3);
1276 struct color c = ffi_tocolor(J, 4);
1277 fz_color_params color_params = ffi_tocolorparams(J, 7);
1278 fz_try(ctx)
1279 fz_stroke_text(ctx, dev, text, &stroke, ctm, c.colorspace, c.color, c.alpha, color_params);
1280 fz_catch(ctx)
1281 rethrow(J);
1282}
1283
1284static void ffi_Device_clipText(js_State *J)
1285{
1286 fz_context *ctx = js_getcontext(J);
1287 fz_device *dev = js_touserdata(J, 0, "fz_device");
1288 fz_text *text = js_touserdata(J, 1, "fz_text");
1289 fz_matrix ctm = ffi_tomatrix(J, 2);
1290 fz_try(ctx)
1291 fz_clip_text(ctx, dev, text, ctm, fz_infinite_rect);
1292 fz_catch(ctx)
1293 rethrow(J);
1294}
1295
1296static void ffi_Device_clipStrokeText(js_State *J)
1297{
1298 fz_context *ctx = js_getcontext(J);
1299 fz_device *dev = js_touserdata(J, 0, "fz_device");
1300 fz_text *text = js_touserdata(J, 1, "fz_text");
1301 fz_stroke_state stroke = ffi_tostroke(J, 2);
1302 fz_matrix ctm = ffi_tomatrix(J, 3);
1303 fz_try(ctx)
1304 fz_clip_stroke_text(ctx, dev, text, &stroke, ctm, fz_infinite_rect);
1305 fz_catch(ctx)
1306 rethrow(J);
1307}
1308
1309static void ffi_Device_ignoreText(js_State *J)
1310{
1311 fz_context *ctx = js_getcontext(J);
1312 fz_device *dev = js_touserdata(J, 0, "fz_device");
1313 fz_text *text = js_touserdata(J, 1, "fz_text");
1314 fz_matrix ctm = ffi_tomatrix(J, 2);
1315 fz_try(ctx)
1316 fz_ignore_text(ctx, dev, text, ctm);
1317 fz_catch(ctx)
1318 rethrow(J);
1319}
1320
1321static void ffi_Device_fillShade(js_State *J)
1322{
1323 fz_context *ctx = js_getcontext(J);
1324 fz_device *dev = js_touserdata(J, 0, "fz_device");
1325 fz_shade *shade = js_touserdata(J, 1, "fz_shade");
1326 fz_matrix ctm = ffi_tomatrix(J, 2);
1327 float alpha = js_tonumber(J, 3);
1328 fz_color_params color_params = ffi_tocolorparams(J, 4);
1329 fz_try(ctx)
1330 fz_fill_shade(ctx, dev, shade, ctm, alpha, color_params);
1331 fz_catch(ctx)
1332 rethrow(J);
1333}
1334
1335static void ffi_Device_fillImage(js_State *J)
1336{
1337 fz_context *ctx = js_getcontext(J);
1338 fz_device *dev = js_touserdata(J, 0, "fz_device");
1339 fz_image *image = js_touserdata(J, 1, "fz_image");
1340 fz_matrix ctm = ffi_tomatrix(J, 2);
1341 float alpha = js_tonumber(J, 3);
1342 fz_color_params color_params = ffi_tocolorparams(J, 4);
1343 fz_try(ctx)
1344 fz_fill_image(ctx, dev, image, ctm, alpha, color_params);
1345 fz_catch(ctx)
1346 rethrow(J);
1347}
1348
1349static void ffi_Device_fillImageMask(js_State *J)
1350{
1351 fz_context *ctx = js_getcontext(J);
1352 fz_device *dev = js_touserdata(J, 0, "fz_device");
1353 fz_image *image = js_touserdata(J, 1, "fz_image");
1354 fz_matrix ctm = ffi_tomatrix(J, 2);
1355 struct color c = ffi_tocolor(J, 3);
1356 fz_color_params color_params = ffi_tocolorparams(J, 6);
1357 fz_try(ctx)
1358 fz_fill_image_mask(ctx, dev, image, ctm, c.colorspace, c.color, c.alpha, color_params);
1359 fz_catch(ctx)
1360 rethrow(J);
1361}
1362
1363static void ffi_Device_clipImageMask(js_State *J)
1364{
1365 fz_context *ctx = js_getcontext(J);
1366 fz_device *dev = js_touserdata(J, 0, "fz_device");
1367 fz_image *image = js_touserdata(J, 1, "fz_image");
1368 fz_matrix ctm = ffi_tomatrix(J, 2);
1369 fz_try(ctx)
1370 fz_clip_image_mask(ctx, dev, image, ctm, fz_infinite_rect);
1371 fz_catch(ctx)
1372 rethrow(J);
1373}
1374
1375static void ffi_Device_popClip(js_State *J)
1376{
1377 fz_context *ctx = js_getcontext(J);
1378 fz_device *dev = js_touserdata(J, 0, "fz_device");
1379 fz_try(ctx)
1380 fz_pop_clip(ctx, dev);
1381 fz_catch(ctx)
1382 rethrow(J);
1383}
1384
1385static void ffi_Device_beginMask(js_State *J)
1386{
1387 fz_context *ctx = js_getcontext(J);
1388 fz_device *dev = js_touserdata(J, 0, "fz_device");
1389 fz_rect area = ffi_torect(J, 1);
1390 int luminosity = js_toboolean(J, 2);
1391 struct color c = ffi_tocolor(J, 3);
1392 fz_color_params color_params = ffi_tocolorparams(J, 6);
1393 fz_try(ctx)
1394 fz_begin_mask(ctx, dev, area, luminosity, c.colorspace, c.color, color_params);
1395 fz_catch(ctx)
1396 rethrow(J);
1397}
1398
1399static void ffi_Device_endMask(js_State *J)
1400{
1401 fz_context *ctx = js_getcontext(J);
1402 fz_device *dev = js_touserdata(J, 0, "fz_device");
1403 fz_try(ctx)
1404 fz_end_mask(ctx, dev);
1405 fz_catch(ctx)
1406 rethrow(J);
1407}
1408
1409static void ffi_Device_beginGroup(js_State *J)
1410{
1411 fz_context *ctx = js_getcontext(J);
1412 fz_device *dev = js_touserdata(J, 0, "fz_device");
1413 fz_rect area = ffi_torect(J, 1);
1414 int isolated = js_toboolean(J, 2);
1415 int knockout = js_toboolean(J, 3);
1416 int blendmode = fz_lookup_blendmode(js_tostring(J, 4));
1417 float alpha = js_tonumber(J, 5);
1418 fz_try(ctx)
1419 fz_begin_group(ctx, dev, area, NULL, isolated, knockout, blendmode, alpha);
1420 fz_catch(ctx)
1421 rethrow(J);
1422}
1423
1424static void ffi_Device_endGroup(js_State *J)
1425{
1426 fz_context *ctx = js_getcontext(J);
1427 fz_device *dev = js_touserdata(J, 0, "fz_device");
1428 fz_try(ctx)
1429 fz_end_group(ctx, dev);
1430 fz_catch(ctx)
1431 rethrow(J);
1432}
1433
1434static void ffi_Device_beginTile(js_State *J)
1435{
1436 fz_context *ctx = js_getcontext(J);
1437 fz_device *dev = js_touserdata(J, 0, "fz_device");
1438 fz_rect area = ffi_torect(J, 1);
1439 fz_rect view = ffi_torect(J, 2);
1440 float xstep = js_tonumber(J, 3);
1441 float ystep = js_tonumber(J, 4);
1442 fz_matrix ctm = ffi_tomatrix(J, 5);
1443 int id = js_tonumber(J, 6);
1444 int n = 0;
1445 fz_try(ctx)
1446 n = fz_begin_tile_id(ctx, dev, area, view, xstep, ystep, ctm, id);
1447 fz_catch(ctx)
1448 rethrow(J);
1449 js_pushnumber(J, n);
1450}
1451
1452static void ffi_Device_endTile(js_State *J)
1453{
1454 fz_context *ctx = js_getcontext(J);
1455 fz_device *dev = js_touserdata(J, 0, "fz_device");
1456 fz_try(ctx)
1457 fz_end_tile(ctx, dev);
1458 fz_catch(ctx)
1459 rethrow(J);
1460}
1461
1462static void ffi_Device_beginLayer(js_State *J)
1463{
1464 fz_context *ctx = js_getcontext(J);
1465 fz_device *dev = js_touserdata(J, 0, "fz_device");
1466 const char *name = js_tostring(J, 1);
1467 fz_try(ctx)
1468 fz_begin_layer(ctx, dev, name);
1469 fz_catch(ctx)
1470 rethrow(J);
1471}
1472
1473static void ffi_Device_endLayer(js_State *J)
1474{
1475 fz_context *ctx = js_getcontext(J);
1476 fz_device *dev = js_touserdata(J, 0, "fz_device");
1477 fz_try(ctx)
1478 fz_end_layer(ctx, dev);
1479 fz_catch(ctx)
1480 rethrow(J);
1481}
1482
1483/* mupdf module */
1484
1485static void ffi_readFile(js_State *J)
1486{
1487 fz_context *ctx = js_getcontext(J);
1488 const char *filename = js_tostring(J, 1);
1489 fz_buffer *buf = NULL;
1490 fz_try(ctx)
1491 buf = fz_read_file(ctx, filename);
1492 fz_catch(ctx)
1493 rethrow(J);
1494 ffi_pushbuffer(J, buf);
1495}
1496
1497static void ffi_setUserCSS(js_State *J)
1498{
1499 fz_context *ctx = js_getcontext(J);
1500 const char *user_css = js_tostring(J, 1);
1501 int use_doc_css = js_iscoercible(J, 2) ? js_toboolean(J, 2) : 1;
1502 fz_try(ctx) {
1503 fz_set_user_css(ctx, user_css);
1504 fz_set_use_document_css(ctx, use_doc_css);
1505 } fz_catch(ctx)
1506 rethrow(J);
1507}
1508
1509static void ffi_new_Buffer(js_State *J)
1510{
1511 fz_context *ctx = js_getcontext(J);
1512 int n = js_isdefined(J, 1) ? js_tonumber(J, 1) : 0;
1513 fz_buffer *buf = NULL;
1514 fz_try(ctx)
1515 buf = fz_new_buffer(ctx, n);
1516 fz_catch(ctx)
1517 rethrow(J);
1518 ffi_pushbuffer(J, buf);
1519}
1520
1521static void ffi_Buffer_writeByte(js_State *J)
1522{
1523 fz_context *ctx = js_getcontext(J);
1524 fz_buffer *buf = js_touserdata(J, 0, "fz_buffer");
1525 unsigned char val = js_tonumber(J, 1);
1526 fz_try(ctx)
1527 fz_append_byte(ctx, buf, val);
1528 fz_catch(ctx)
1529 rethrow(J);
1530}
1531
1532static void ffi_Buffer_writeRune(js_State *J)
1533{
1534 fz_context *ctx = js_getcontext(J);
1535 fz_buffer *buf = js_touserdata(J, 0, "fz_buffer");
1536 int val = js_tonumber(J, 1);
1537 fz_try(ctx)
1538 fz_append_rune(ctx, buf, val);
1539 fz_catch(ctx)
1540 rethrow(J);
1541}
1542
1543static void ffi_Buffer_write(js_State *J)
1544{
1545 fz_context *ctx = js_getcontext(J);
1546 fz_buffer *buf = js_touserdata(J, 0, "fz_buffer");
1547 int i, n = js_gettop(J);
1548
1549 for (i = 1; i < n; ++i) {
1550 const char *s = js_tostring(J, i);
1551 fz_try(ctx) {
1552 if (i > 1)
1553 fz_append_byte(ctx, buf, ' ');
1554 fz_append_string(ctx, buf, s);
1555 } fz_catch(ctx)
1556 rethrow(J);
1557 }
1558}
1559
1560static void ffi_Buffer_writeLine(js_State *J)
1561{
1562 fz_context *ctx = js_getcontext(J);
1563 fz_buffer *buf = js_touserdata(J, 0, "fz_buffer");
1564 ffi_Buffer_write(J);
1565 fz_try(ctx)
1566 fz_append_byte(ctx, buf, '\n');
1567 fz_catch(ctx)
1568 rethrow(J);
1569}
1570
1571static void ffi_Buffer_writeBuffer(js_State *J)
1572{
1573 fz_context *ctx = js_getcontext(J);
1574 fz_buffer *buf = js_touserdata(J, 0, "fz_buffer");
1575 fz_buffer *cat = js_touserdata(J, 1, "fz_buffer");
1576 fz_try(ctx)
1577 fz_append_buffer(ctx, buf, cat);
1578 fz_catch(ctx)
1579 rethrow(J);
1580}
1581
1582static void ffi_Buffer_save(js_State *J)
1583{
1584 fz_context *ctx = js_getcontext(J);
1585 fz_buffer *buf = js_touserdata(J, 0, "fz_buffer");
1586 const char *filename = js_tostring(J, 1);
1587 fz_try(ctx)
1588 fz_save_buffer(ctx, buf, filename);
1589 fz_catch(ctx)
1590 rethrow(J);
1591}
1592
1593static void ffi_new_Document(js_State *J)
1594{
1595 fz_context *ctx = js_getcontext(J);
1596 const char *filename = js_tostring(J, 1);
1597 fz_document *doc = NULL;
1598
1599 fz_try(ctx)
1600 doc = fz_open_document(ctx, filename);
1601 fz_catch(ctx)
1602 rethrow(J);
1603
1604 ffi_pushdocument(J, doc);
1605}
1606
1607static void ffi_Document_isPDF(js_State *J)
1608{
1609 js_pushboolean(J, js_isuserdata(J, 0, "pdf_document"));
1610}
1611
1612static void ffi_Document_countPages(js_State *J)
1613{
1614 fz_context *ctx = js_getcontext(J);
1615 fz_document *doc = ffi_todocument(J, 0);
1616 int count = 0;
1617
1618 fz_try(ctx)
1619 count = fz_count_pages(ctx, doc);
1620 fz_catch(ctx)
1621 rethrow(J);
1622
1623 js_pushnumber(J, count);
1624}
1625
1626static void ffi_Document_loadPage(js_State *J)
1627{
1628 fz_context *ctx = js_getcontext(J);
1629 fz_document *doc = ffi_todocument(J, 0);
1630 int number = js_tointeger(J, 1);
1631 fz_page *page = NULL;
1632
1633 fz_try(ctx)
1634 page = fz_load_page(ctx, doc, number);
1635 fz_catch(ctx)
1636 rethrow(J);
1637
1638 ffi_pushpage(J, page);
1639}
1640
1641static void ffi_Document_needsPassword(js_State *J)
1642{
1643 fz_context *ctx = js_getcontext(J);
1644 fz_document *doc = ffi_todocument(J, 0);
1645 int b = 0;
1646
1647 fz_try(ctx)
1648 b = fz_needs_password(ctx, doc);
1649 fz_catch(ctx)
1650 rethrow(J);
1651
1652 js_pushboolean(J, b);
1653}
1654
1655static void ffi_Document_authenticatePassword(js_State *J)
1656{
1657 fz_context *ctx = js_getcontext(J);
1658 fz_document *doc = ffi_todocument(J, 0);
1659 const char *password = js_tostring(J, 1);
1660 int b = 0;
1661
1662 fz_try(ctx)
1663 b = fz_authenticate_password(ctx, doc, password);
1664 fz_catch(ctx)
1665 rethrow(J);
1666
1667 js_pushboolean(J, b);
1668}
1669
1670static void ffi_Document_getMetaData(js_State *J)
1671{
1672 fz_context *ctx = js_getcontext(J);
1673 fz_document *doc = ffi_todocument(J, 0);
1674 const char *key = js_tostring(J, 1);
1675 char info[256];
1676 int found;
1677
1678 fz_try(ctx)
1679 found = fz_lookup_metadata(ctx, doc, key, info, sizeof info);
1680 fz_catch(ctx)
1681 rethrow(J);
1682
1683 if (found)
1684 js_pushstring(J, info);
1685 else
1686 js_pushundefined(J);
1687}
1688
1689static void ffi_Document_isReflowable(js_State *J)
1690{
1691 fz_context *ctx = js_getcontext(J);
1692 fz_document *doc = ffi_todocument(J, 0);
1693 int is_reflowable = 0;
1694
1695 fz_try(ctx)
1696 is_reflowable = fz_is_document_reflowable(ctx, doc);
1697 fz_catch(ctx)
1698 rethrow(J);
1699
1700 js_pushboolean(J, is_reflowable);
1701}
1702
1703static void ffi_Document_layout(js_State *J)
1704{
1705 fz_context *ctx = js_getcontext(J);
1706 fz_document *doc = ffi_todocument(J, 0);
1707 float w = js_tonumber(J, 1);
1708 float h = js_tonumber(J, 2);
1709 float em = js_tonumber(J, 3);
1710
1711 fz_try(ctx)
1712 fz_layout_document(ctx, doc, w, h, em);
1713 fz_catch(ctx)
1714 rethrow(J);
1715}
1716
1717static void to_outline(js_State *J, fz_outline *outline)
1718{
1719 int i = 0;
1720 js_newarray(J);
1721 while (outline) {
1722 js_newobject(J);
1723
1724 if (outline->title)
1725 js_pushstring(J, outline->title);
1726 else
1727 js_pushundefined(J);
1728 js_setproperty(J, -2, "title");
1729
1730 if (outline->uri)
1731 js_pushstring(J, outline->uri);
1732 else
1733 js_pushundefined(J);
1734 js_setproperty(J, -2, "uri");
1735
1736 if (outline->page >= 0)
1737 js_pushnumber(J, outline->page);
1738 else
1739 js_pushundefined(J);
1740 js_setproperty(J, -2, "page");
1741
1742 if (outline->down) {
1743 to_outline(J, outline->down);
1744 js_setproperty(J, -2, "down");
1745 }
1746
1747 js_setindex(J, -2, i++);
1748 outline = outline->next;
1749 }
1750}
1751
1752static void ffi_Document_loadOutline(js_State *J)
1753{
1754 fz_context *ctx = js_getcontext(J);
1755 fz_document *doc = ffi_todocument(J, 0);
1756 fz_outline *outline = NULL;
1757
1758 fz_try(ctx)
1759 outline = fz_load_outline(ctx, doc);
1760 fz_catch(ctx)
1761 rethrow(J);
1762
1763 to_outline(J, outline);
1764
1765 fz_drop_outline(ctx, outline);
1766}
1767
1768static void ffi_Page_isPDF(js_State *J)
1769{
1770 js_pushboolean(J, js_isuserdata(J, 0, "pdf_page"));
1771}
1772
1773static void ffi_Page_bound(js_State *J)
1774{
1775 fz_context *ctx = js_getcontext(J);
1776 fz_page *page = ffi_topage(J, 0);
1777 fz_rect bounds;
1778
1779 fz_try(ctx)
1780 bounds = fz_bound_page(ctx, page);
1781 fz_catch(ctx)
1782 rethrow(J);
1783
1784 ffi_pushrect(J, bounds);
1785}
1786
1787static void ffi_Page_run(js_State *J)
1788{
1789 fz_context *ctx = js_getcontext(J);
1790 fz_page *page = ffi_topage(J, 0);
1791 fz_device *device = NULL;
1792 fz_matrix ctm = ffi_tomatrix(J, 2);
1793 int no_annots = js_isdefined(J, 3) ? js_toboolean(J, 3) : 0;
1794
1795 if (js_isuserdata(J, 1, "fz_device")) {
1796 device = js_touserdata(J, 1, "fz_device");
1797 fz_try(ctx)
1798 if (no_annots)
1799 fz_run_page_contents(ctx, page, device, ctm, NULL);
1800 else
1801 fz_run_page(ctx, page, device, ctm, NULL);
1802 fz_catch(ctx)
1803 rethrow(J);
1804 } else {
1805 device = new_js_device(ctx, J);
1806 js_copy(J, 1); /* put the js device on the top so the callbacks know where to get it */
1807 fz_try(ctx) {
1808 if (no_annots)
1809 fz_run_page_contents(ctx, page, device, ctm, NULL);
1810 else
1811 fz_run_page(ctx, page, device, ctm, NULL);
1812 fz_close_device(ctx, device);
1813 }
1814 fz_always(ctx)
1815 fz_drop_device(ctx, device);
1816 fz_catch(ctx)
1817 rethrow(J);
1818 }
1819}
1820
1821static void ffi_Page_toDisplayList(js_State *J)
1822{
1823 fz_context *ctx = js_getcontext(J);
1824 fz_page *page = ffi_topage(J, 0);
1825 int no_annots = js_isdefined(J, 1) ? js_toboolean(J, 1) : 0;
1826 fz_display_list *list = NULL;
1827
1828 fz_try(ctx)
1829 if (no_annots)
1830 list = fz_new_display_list_from_page_contents(ctx, page);
1831 else
1832 list = fz_new_display_list_from_page(ctx, page);
1833 fz_catch(ctx)
1834 rethrow(J);
1835
1836 js_getregistry(J, "fz_display_list");
1837 js_newuserdata(J, "fz_display_list", list, ffi_gc_fz_display_list);
1838}
1839
1840static void ffi_Page_toPixmap(js_State *J)
1841{
1842 fz_context *ctx = js_getcontext(J);
1843 fz_page *page = ffi_topage(J, 0);
1844 fz_matrix ctm = ffi_tomatrix(J, 1);
1845 fz_colorspace *colorspace = js_touserdata(J, 2, "fz_colorspace");
1846 int alpha = js_toboolean(J, 3);
1847 int no_annots = js_isdefined(J, 4) ? js_toboolean(J, 4) : 0;
1848 fz_pixmap *pixmap = NULL;
1849
1850 fz_try(ctx)
1851 if (no_annots)
1852 pixmap = fz_new_pixmap_from_page_contents(ctx, page, ctm, colorspace, alpha);
1853 else
1854 pixmap = fz_new_pixmap_from_page(ctx, page, ctm, colorspace, alpha);
1855 fz_catch(ctx)
1856 rethrow(J);
1857
1858 js_getregistry(J, "fz_pixmap");
1859 js_newuserdata(J, "fz_pixmap", pixmap, ffi_gc_fz_pixmap);
1860}
1861
1862static void ffi_Page_toStructuredText(js_State *J)
1863{
1864 fz_context *ctx = js_getcontext(J);
1865 fz_page *page = ffi_topage(J, 0);
1866 const char *options = js_iscoercible(J, 1) ? js_tostring(J, 1) : NULL;
1867 fz_stext_options so;
1868 fz_stext_page *text = NULL;
1869
1870 fz_try(ctx) {
1871 fz_parse_stext_options(ctx, &so, options);
1872 text = fz_new_stext_page_from_page(ctx, page, &so);
1873 }
1874 fz_catch(ctx)
1875 rethrow(J);
1876
1877 js_getregistry(J, "fz_stext_page");
1878 js_newuserdata(J, "fz_stext_page", text, ffi_gc_fz_stext_page);
1879}
1880
1881static void ffi_Page_search(js_State *J)
1882{
1883 fz_context *ctx = js_getcontext(J);
1884 fz_page *page = ffi_topage(J, 0);
1885 const char *needle = js_tostring(J, 1);
1886 fz_quad hits[256];
1887 int i, n = 0;
1888
1889 fz_try(ctx)
1890 n = fz_search_page(ctx, page, needle, hits, nelem(hits));
1891 fz_catch(ctx)
1892 rethrow(J);
1893
1894 js_newarray(J);
1895 for (i = 0; i < n; ++i) {
1896 ffi_pushquad(J, hits[i]);
1897 js_setindex(J, -2, i);
1898 }
1899}
1900
1901static void ffi_Page_getLinks(js_State *J)
1902{
1903 fz_context *ctx = js_getcontext(J);
1904 fz_page *page = ffi_topage(J, 0);
1905 fz_link *link, *links = NULL;
1906 int i = 0;
1907
1908 js_newarray(J);
1909
1910 fz_try(ctx)
1911 links = fz_load_links(ctx, page);
1912 fz_catch(ctx)
1913 rethrow(J);
1914
1915 js_newarray(J);
1916 for (link = links; link; link = link->next) {
1917 js_newobject(J);
1918
1919 ffi_pushrect(J, link->rect);
1920 js_setproperty(J, -2, "bounds");
1921
1922 js_pushstring(J, link->uri);
1923 js_setproperty(J, -2, "uri");
1924
1925 js_setindex(J, -2, i++);
1926 }
1927
1928 fz_drop_link(ctx, links);
1929}
1930
1931static void ffi_ColorSpace_getNumberOfComponents(js_State *J)
1932{
1933 fz_colorspace *colorspace = js_touserdata(J, 0, "fz_colorspace");
1934 fz_context *ctx = js_getcontext(J);
1935 js_pushnumber(J, fz_colorspace_n(ctx, colorspace));
1936}
1937
1938static void ffi_ColorSpace_toString(js_State *J)
1939{
1940 fz_colorspace *colorspace = js_touserdata(J, 0, "fz_colorspace");
1941 fz_context *ctx = js_getcontext(J);
1942 js_pushstring(J, fz_colorspace_name(ctx, colorspace));
1943}
1944
1945static void ffi_new_Pixmap(js_State *J)
1946{
1947 fz_context *ctx = js_getcontext(J);
1948 fz_colorspace *colorspace = js_touserdata(J, 1, "fz_colorspace");
1949 fz_irect bounds = ffi_toirect(J, 2);
1950 int alpha = js_toboolean(J, 3);
1951 fz_pixmap *pixmap = NULL;
1952
1953 fz_try(ctx)
1954 pixmap = fz_new_pixmap_with_bbox(ctx, colorspace, bounds, 0, alpha);
1955 fz_catch(ctx)
1956 rethrow(J);
1957
1958 js_getregistry(J, "fz_pixmap");
1959 js_newuserdata(J, "fz_pixmap", pixmap, ffi_gc_fz_pixmap);
1960}
1961
1962static void ffi_Pixmap_saveAsPNG(js_State *J)
1963{
1964 fz_context *ctx = js_getcontext(J);
1965 fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
1966 const char *filename = js_tostring(J, 1);
1967
1968 fz_try(ctx)
1969 fz_save_pixmap_as_png(ctx, pixmap, filename);
1970 fz_catch(ctx)
1971 rethrow(J);
1972}
1973
1974static void ffi_Pixmap_bound(js_State *J)
1975{
1976 fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
1977 fz_rect bounds;
1978
1979 // fz_irect and fz_pixmap_bbox instead
1980 bounds.x0 = pixmap->x;
1981 bounds.y0 = pixmap->y;
1982 bounds.x1 = pixmap->x + pixmap->w;
1983 bounds.y1 = pixmap->y + pixmap->h;
1984
1985 ffi_pushrect(J, bounds);
1986}
1987
1988static void ffi_Pixmap_clear(js_State *J)
1989{
1990 fz_context *ctx = js_getcontext(J);
1991 fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
1992 if (js_isdefined(J, 1)) {
1993 int value = js_tonumber(J, 1);
1994 fz_try(ctx)
1995 fz_clear_pixmap_with_value(ctx, pixmap, value);
1996 fz_catch(ctx)
1997 rethrow(J);
1998 } else {
1999 fz_try(ctx)
2000 fz_clear_pixmap(ctx, pixmap);
2001 fz_catch(ctx)
2002 rethrow(J);
2003 }
2004}
2005
2006static void ffi_Pixmap_getX(js_State *J)
2007{
2008 fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2009 js_pushnumber(J, pixmap->x);
2010}
2011
2012static void ffi_Pixmap_getY(js_State *J)
2013{
2014 fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2015 js_pushnumber(J, pixmap->y);
2016}
2017
2018static void ffi_Pixmap_getWidth(js_State *J)
2019{
2020 fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2021 js_pushnumber(J, pixmap->w);
2022}
2023
2024static void ffi_Pixmap_getHeight(js_State *J)
2025{
2026 fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2027 js_pushnumber(J, pixmap->h);
2028}
2029
2030static void ffi_Pixmap_getNumberOfComponents(js_State *J)
2031{
2032 fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2033 js_pushnumber(J, pixmap->n);
2034}
2035
2036static void ffi_Pixmap_getAlpha(js_State *J)
2037{
2038 fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2039 js_pushnumber(J, pixmap->alpha);
2040}
2041
2042static void ffi_Pixmap_getStride(js_State *J)
2043{
2044 fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2045 js_pushnumber(J, pixmap->stride);
2046}
2047
2048static void ffi_Pixmap_getSample(js_State *J)
2049{
2050 fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2051 int x = js_tointeger(J, 1);
2052 int y = js_tointeger(J, 2);
2053 int k = js_tointeger(J, 3);
2054 if (x < 0 || x >= pixmap->w) js_rangeerror(J, "X out of range");
2055 if (y < 0 || y >= pixmap->h) js_rangeerror(J, "Y out of range");
2056 if (k < 0 || k >= pixmap->n) js_rangeerror(J, "N out of range");
2057 js_pushnumber(J, pixmap->samples[(x + y * pixmap->w) * pixmap->n + k]);
2058}
2059
2060static void ffi_Pixmap_getXResolution(js_State *J)
2061{
2062 fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2063 js_pushnumber(J, pixmap->xres);
2064}
2065
2066static void ffi_Pixmap_getYResolution(js_State *J)
2067{
2068 fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2069 js_pushnumber(J, pixmap->yres);
2070}
2071
2072static void ffi_Pixmap_getColorSpace(js_State *J)
2073{
2074 fz_pixmap *pixmap = js_touserdata(J, 0, "fz_pixmap");
2075 ffi_pushcolorspace(J, pixmap->colorspace);
2076}
2077
2078static void ffi_new_Image(js_State *J)
2079{
2080 fz_context *ctx = js_getcontext(J);
2081 fz_image *image = NULL;
2082
2083 if (js_isuserdata(J, 1, "fz_pixmap")) {
2084 fz_pixmap *pixmap = js_touserdata(J, 1, "fz_pixmap");
2085 fz_try(ctx)
2086 image = fz_new_image_from_pixmap(ctx, pixmap, NULL);
2087 fz_catch(ctx)
2088 rethrow(J);
2089 } else {
2090 const char *name = js_tostring(J, 1);
2091 fz_try(ctx)
2092 image = fz_new_image_from_file(ctx, name);
2093 fz_catch(ctx)
2094 rethrow(J);
2095 }
2096
2097 ffi_pushimage_own(J, image);
2098}
2099
2100static void ffi_Image_getWidth(js_State *J)
2101{
2102 fz_image *image = js_touserdata(J, 0, "fz_image");
2103 js_pushnumber(J, image->w);
2104}
2105
2106static void ffi_Image_getHeight(js_State *J)
2107{
2108 fz_image *image = js_touserdata(J, 0, "fz_image");
2109 js_pushnumber(J, image->h);
2110}
2111
2112static void ffi_Image_getXResolution(js_State *J)
2113{
2114 fz_image *image = js_touserdata(J, 0, "fz_image");
2115 js_pushnumber(J, image->xres);
2116}
2117
2118static void ffi_Image_getYResolution(js_State *J)
2119{
2120 fz_image *image = js_touserdata(J, 0, "fz_image");
2121 js_pushnumber(J, image->yres);
2122}
2123
2124static void ffi_Image_getNumberOfComponents(js_State *J)
2125{
2126 fz_image *image = js_touserdata(J, 0, "fz_image");
2127 js_pushnumber(J, image->n);
2128}
2129
2130static void ffi_Image_getBitsPerComponent(js_State *J)
2131{
2132 fz_image *image = js_touserdata(J, 0, "fz_image");
2133 js_pushnumber(J, image->bpc);
2134}
2135
2136static void ffi_Image_getInterpolate(js_State *J)
2137{
2138 fz_image *image = js_touserdata(J, 0, "fz_image");
2139 js_pushboolean(J, image->interpolate);
2140}
2141
2142static void ffi_Image_getImageMask(js_State *J)
2143{
2144 fz_image *image = js_touserdata(J, 0, "fz_image");
2145 js_pushboolean(J, image->imagemask);
2146}
2147
2148static void ffi_Image_getMask(js_State *J)
2149{
2150 fz_image *image = js_touserdata(J, 0, "fz_image");
2151 if (image->mask)
2152 ffi_pushimage(J, image->mask);
2153 else
2154 js_pushnull(J);
2155}
2156
2157static void ffi_Image_getColorSpace(js_State *J)
2158{
2159 fz_image *image = js_touserdata(J, 0, "fz_image");
2160 ffi_pushcolorspace(J, image->colorspace);
2161}
2162
2163static void ffi_Image_toPixmap(js_State *J)
2164{
2165 fz_context *ctx = js_getcontext(J);
2166 fz_image *image = js_touserdata(J, 0, "fz_image");
2167 fz_matrix matrix_, *matrix = NULL;
2168 fz_pixmap *pixmap = NULL;
2169
2170 if (js_isnumber(J, 1) && js_isnumber(J, 2)) {
2171 matrix_ = fz_scale(js_tonumber(J, 1), js_tonumber(J, 2));
2172 matrix = &matrix_;
2173 }
2174
2175 fz_try(ctx)
2176 pixmap = fz_get_pixmap_from_image(ctx, image, NULL, matrix, NULL, NULL);
2177 fz_catch(ctx)
2178 rethrow(J);
2179
2180 js_getregistry(J, "fz_pixmap");
2181 js_newuserdata(J, "fz_pixmap", pixmap, ffi_gc_fz_pixmap);
2182}
2183
2184static void ffi_Shade_bound(js_State *J)
2185{
2186 fz_context *ctx = js_getcontext(J);
2187 fz_shade *shade = js_touserdata(J, 0, "fz_shade");
2188 fz_matrix ctm = ffi_tomatrix(J, 1);
2189 fz_rect bounds;
2190
2191 fz_try(ctx)
2192 bounds = fz_bound_shade(ctx, shade, ctm);
2193 fz_catch(ctx)
2194 rethrow(J);
2195
2196 ffi_pushrect(J, bounds);
2197}
2198
2199static void ffi_new_Font(js_State *J)
2200{
2201 fz_context *ctx = js_getcontext(J);
2202 const char *name = js_tostring(J, 1);
2203 int index = js_isnumber(J, 2) ? js_tonumber(J, 2) : 0;
2204 const unsigned char *data;
2205 int size;
2206 fz_font *font = NULL;
2207
2208 fz_try(ctx) {
2209 data = fz_lookup_base14_font(ctx, name, &size);
2210 if (!data)
2211 data = fz_lookup_cjk_font_by_language(ctx, name, &size, &index);
2212 if (data)
2213 font = fz_new_font_from_memory(ctx, name, data, size, index, 0);
2214 else
2215 font = fz_new_font_from_file(ctx, name, name, index, 0);
2216 }
2217 fz_catch(ctx)
2218 rethrow(J);
2219
2220 js_getregistry(J, "fz_font");
2221 js_newuserdata(J, "fz_font", font, ffi_gc_fz_font);
2222}
2223
2224static void ffi_Font_getName(js_State *J)
2225{
2226 fz_context *ctx = js_getcontext(J);
2227 fz_font *font = js_touserdata(J, 0, "fz_font");
2228 js_pushstring(J, fz_font_name(ctx, font));
2229}
2230
2231static void ffi_Font_encodeCharacter(js_State *J)
2232{
2233 fz_context *ctx = js_getcontext(J);
2234 fz_font *font = js_touserdata(J, 0, "fz_font");
2235 int unicode = js_tonumber(J, 1);
2236 int glyph = 0;
2237 fz_try(ctx)
2238 glyph = fz_encode_character(ctx, font, unicode);
2239 fz_catch(ctx)
2240 rethrow(J);
2241 js_pushnumber(J, glyph);
2242}
2243
2244static void ffi_Font_advanceGlyph(js_State *J)
2245{
2246 fz_context *ctx = js_getcontext(J);
2247 fz_font *font = js_touserdata(J, 0, "fz_font");
2248 int glyph = js_tonumber(J, 1);
2249 int wmode = js_isdefined(J, 2) ? js_toboolean(J, 2) : 0;
2250
2251 float advance = 0;
2252 fz_try(ctx)
2253 advance = fz_advance_glyph(ctx, font, glyph, wmode);
2254 fz_catch(ctx)
2255 rethrow(J);
2256 js_pushnumber(J, advance);
2257}
2258
2259static void ffi_new_Text(js_State *J)
2260{
2261 fz_context *ctx = js_getcontext(J);
2262 fz_text *text = NULL;
2263
2264 fz_try(ctx)
2265 text = fz_new_text(ctx);
2266 fz_catch(ctx)
2267 rethrow(J);
2268
2269 js_getregistry(J, "fz_text");
2270 js_newuserdata(J, "fz_text", text, ffi_gc_fz_text);
2271}
2272
2273static void ffi_Text_walk(js_State *J)
2274{
2275 fz_text *text = js_touserdata(J, 0, "fz_text");
2276 fz_text_span *span;
2277 fz_matrix trm;
2278 int i;
2279
2280 js_getproperty(J, 1, "showGlyph");
2281 for (span = text->head; span; span = span->next) {
2282 ffi_pushfont(J, span->font);
2283 trm = span->trm;
2284 for (i = 0; i < span->len; ++i) {
2285 trm.e = span->items[i].x;
2286 trm.f = span->items[i].y;
2287 js_copy(J, -2); /* showGlyph function */
2288 js_copy(J, 1); /* object for this binding */
2289 js_copy(J, -3); /* font */
2290 ffi_pushmatrix(J, trm);
2291 js_pushnumber(J, span->items[i].gid);
2292 js_pushnumber(J, span->items[i].ucs);
2293 js_pushnumber(J, span->wmode);
2294 js_pushnumber(J, span->bidi_level);
2295 js_call(J, 6);
2296 js_pop(J, 1);
2297 }
2298 js_pop(J, 1); /* pop font object */
2299 }
2300 js_pop(J, 1); /* pop showGlyph function */
2301}
2302
2303static void ffi_Text_showGlyph(js_State *J)
2304{
2305 fz_context *ctx = js_getcontext(J);
2306 fz_text *text = js_touserdata(J, 0, "fz_text");
2307 fz_font *font = js_touserdata(J, 1, "fz_font");
2308 fz_matrix trm = ffi_tomatrix(J, 2);
2309 int glyph = js_tointeger(J, 3);
2310 int unicode = js_tointeger(J, 4);
2311 int wmode = js_isdefined(J, 5) ? js_toboolean(J, 5) : 0;
2312
2313 fz_try(ctx)
2314 fz_show_glyph(ctx, text, font, trm, glyph, unicode, wmode, 0, FZ_BIDI_NEUTRAL, FZ_LANG_UNSET);
2315 fz_catch(ctx)
2316 rethrow(J);
2317}
2318
2319static void ffi_Text_showString(js_State *J)
2320{
2321 fz_context *ctx = js_getcontext(J);
2322 fz_text *text = js_touserdata(J, 0, "fz_text");
2323 fz_font *font = js_touserdata(J, 1, "fz_font");
2324 fz_matrix trm = ffi_tomatrix(J, 2);
2325 const char *s = js_tostring(J, 3);
2326 int wmode = js_isdefined(J, 4) ? js_toboolean(J, 4) : 0;
2327
2328 fz_try(ctx)
2329 trm = fz_show_string(ctx, text, font, trm, s, wmode, 0, FZ_BIDI_NEUTRAL, FZ_LANG_UNSET);
2330 fz_catch(ctx)
2331 rethrow(J);
2332
2333 /* update matrix with new pen position */
2334 js_pushnumber(J, trm.e);
2335 js_setindex(J, 2, 4);
2336 js_pushnumber(J, trm.f);
2337 js_setindex(J, 2, 5);
2338}
2339
2340static void ffi_new_Path(js_State *J)
2341{
2342 fz_context *ctx = js_getcontext(J);
2343 fz_path *path = NULL;
2344
2345 fz_try(ctx)
2346 path = fz_new_path(ctx);
2347 fz_catch(ctx)
2348 rethrow(J);
2349
2350 js_getregistry(J, "fz_path");
2351 js_newuserdata(J, "fz_path", path, ffi_gc_fz_path);
2352}
2353
2354static void ffi_Path_walk_moveTo(fz_context *ctx, void *arg, float x, float y)
2355{
2356 js_State *J = arg;
2357 if (js_try(J))
2358 rethrow_as_fz(J);
2359 if (js_hasproperty(J, 1, "moveTo")) {
2360 js_copy(J, 1);
2361 js_pushnumber(J, x);
2362 js_pushnumber(J, y);
2363 js_call(J, 2);
2364 js_pop(J, 1);
2365 }
2366 js_endtry(J);
2367}
2368
2369static void ffi_Path_walk_lineTo(fz_context *ctx, void *arg, float x, float y)
2370{
2371 js_State *J = arg;
2372 if (js_try(J))
2373 rethrow_as_fz(J);
2374 if (js_hasproperty(J, 1, "lineTo")) {
2375 js_copy(J, 1);
2376 js_pushnumber(J, x);
2377 js_pushnumber(J, y);
2378 js_call(J, 2);
2379 js_pop(J, 1);
2380 }
2381 js_endtry(J);
2382}
2383
2384static void ffi_Path_walk_curveTo(fz_context *ctx, void *arg,
2385 float x1, float y1, float x2, float y2, float x3, float y3)
2386{
2387 js_State *J = arg;
2388 if (js_try(J))
2389 rethrow_as_fz(J);
2390 if (js_hasproperty(J, 1, "curveTo")) {
2391 js_copy(J, 1);
2392 js_pushnumber(J, x1);
2393 js_pushnumber(J, y1);
2394 js_pushnumber(J, x2);
2395 js_pushnumber(J, y2);
2396 js_pushnumber(J, x3);
2397 js_pushnumber(J, y3);
2398 js_call(J, 6);
2399 js_pop(J, 1);
2400 }
2401 js_endtry(J);
2402}
2403
2404static void ffi_Path_walk_closePath(fz_context *ctx, void *arg)
2405{
2406 js_State *J = arg;
2407 if (js_try(J))
2408 rethrow_as_fz(J);
2409 if (js_hasproperty(J, 1, "closePath")) {
2410 js_copy(J, 1);
2411 js_call(J, 0);
2412 js_pop(J, 1);
2413 }
2414 js_endtry(J);
2415}
2416
2417static void ffi_Path_walk(js_State *J)
2418{
2419 fz_context *ctx = js_getcontext(J);
2420 fz_path *path = js_touserdata(J, 0, "fz_path");
2421 fz_path_walker walker = {
2422 ffi_Path_walk_moveTo,
2423 ffi_Path_walk_lineTo,
2424 ffi_Path_walk_curveTo,
2425 ffi_Path_walk_closePath,
2426 };
2427
2428 fz_try(ctx)
2429 fz_walk_path(ctx, path, &walker, J);
2430 fz_catch(ctx)
2431 rethrow(J);
2432}
2433
2434static void ffi_Path_moveTo(js_State *J)
2435{
2436 fz_context *ctx = js_getcontext(J);
2437 fz_path *path = js_touserdata(J, 0, "fz_path");
2438 float x = js_tonumber(J, 1);
2439 float y = js_tonumber(J, 2);
2440
2441 fz_try(ctx)
2442 fz_moveto(ctx, path, x, y);
2443 fz_catch(ctx)
2444 rethrow(J);
2445}
2446
2447static void ffi_Path_lineTo(js_State *J)
2448{
2449 fz_context *ctx = js_getcontext(J);
2450 fz_path *path = js_touserdata(J, 0, "fz_path");
2451 float x = js_tonumber(J, 1);
2452 float y = js_tonumber(J, 2);
2453
2454 fz_try(ctx)
2455 fz_lineto(ctx, path, x, y);
2456 fz_catch(ctx)
2457 rethrow(J);
2458}
2459
2460static void ffi_Path_curveTo(js_State *J)
2461{
2462 fz_context *ctx = js_getcontext(J);
2463 fz_path *path = js_touserdata(J, 0, "fz_path");
2464 float x1 = js_tonumber(J, 1);
2465 float y1 = js_tonumber(J, 2);
2466 float x2 = js_tonumber(J, 3);
2467 float y2 = js_tonumber(J, 4);
2468 float x3 = js_tonumber(J, 5);
2469 float y3 = js_tonumber(J, 6);
2470
2471 fz_try(ctx)
2472 fz_curveto(ctx, path, x1, y1, x2, y2, x3, y3);
2473 fz_catch(ctx)
2474 rethrow(J);
2475}
2476
2477static void ffi_Path_curveToV(js_State *J)
2478{
2479 fz_context *ctx = js_getcontext(J);
2480 fz_path *path = js_touserdata(J, 0, "fz_path");
2481 float cx = js_tonumber(J, 1);
2482 float cy = js_tonumber(J, 2);
2483 float ex = js_tonumber(J, 3);
2484 float ey = js_tonumber(J, 4);
2485
2486 fz_try(ctx)
2487 fz_curvetov(ctx, path, cx, cy, ex, ey);
2488 fz_catch(ctx)
2489 rethrow(J);
2490}
2491
2492static void ffi_Path_curveToY(js_State *J)
2493{
2494 fz_context *ctx = js_getcontext(J);
2495 fz_path *path = js_touserdata(J, 0, "fz_path");
2496 float cx = js_tonumber(J, 1);
2497 float cy = js_tonumber(J, 2);
2498 float ex = js_tonumber(J, 3);
2499 float ey = js_tonumber(J, 4);
2500
2501 fz_try(ctx)
2502 fz_curvetoy(ctx, path, cx, cy, ex, ey);
2503 fz_catch(ctx)
2504 rethrow(J);
2505}
2506
2507static void ffi_Path_closePath(js_State *J)
2508{
2509 fz_context *ctx = js_getcontext(J);
2510 fz_path *path = js_touserdata(J, 0, "fz_path");
2511
2512 fz_try(ctx)
2513 fz_closepath(ctx, path);
2514 fz_catch(ctx)
2515 rethrow(J);
2516}
2517
2518static void ffi_Path_rect(js_State *J)
2519{
2520 fz_context *ctx = js_getcontext(J);
2521 fz_path *path = js_touserdata(J, 0, "fz_path");
2522 float x1 = js_tonumber(J, 1);
2523 float y1 = js_tonumber(J, 2);
2524 float x2 = js_tonumber(J, 3);
2525 float y2 = js_tonumber(J, 4);
2526
2527 fz_try(ctx)
2528 fz_rectto(ctx, path, x1, y1, x2, y2);
2529 fz_catch(ctx)
2530 rethrow(J);
2531}
2532
2533static void ffi_Path_bound(js_State *J)
2534{
2535 fz_context *ctx = js_getcontext(J);
2536 fz_path *path = js_touserdata(J, 0, "fz_path");
2537 fz_stroke_state stroke = ffi_tostroke(J, 1);
2538 fz_matrix ctm = ffi_tomatrix(J, 2);
2539 fz_rect bounds;
2540
2541 fz_try(ctx)
2542 bounds = fz_bound_path(ctx, path, &stroke, ctm);
2543 fz_catch(ctx)
2544 rethrow(J);
2545
2546 ffi_pushrect(J, bounds);
2547}
2548
2549static void ffi_Path_transform(js_State *J)
2550{
2551 fz_context *ctx = js_getcontext(J);
2552 fz_path *path = js_touserdata(J, 0, "fz_path");
2553 fz_matrix ctm = ffi_tomatrix(J, 1);
2554
2555 fz_try(ctx)
2556 fz_transform_path(ctx, path, ctm);
2557 fz_catch(ctx)
2558 rethrow(J);
2559}
2560
2561static void ffi_new_DisplayList(js_State *J)
2562{
2563 fz_context *ctx = js_getcontext(J);
2564 fz_rect mediabox = js_iscoercible(J, 1) ? ffi_torect(J, 1) : fz_empty_rect;
2565 fz_display_list *list = NULL;
2566
2567 fz_try(ctx)
2568 list = fz_new_display_list(ctx, mediabox);
2569 fz_catch(ctx)
2570 rethrow(J);
2571
2572 js_getregistry(J, "fz_display_list");
2573 js_newuserdata(J, "fz_display_list", list, ffi_gc_fz_display_list);
2574}
2575
2576static void ffi_DisplayList_run(js_State *J)
2577{
2578 fz_context *ctx = js_getcontext(J);
2579 fz_display_list *list = js_touserdata(J, 0, "fz_display_list");
2580 fz_device *device = NULL;
2581 fz_matrix ctm = ffi_tomatrix(J, 2);
2582
2583 if (js_isuserdata(J, 1, "fz_device")) {
2584 device = js_touserdata(J, 1, "fz_device");
2585 fz_try(ctx)
2586 fz_run_display_list(ctx, list, device, ctm, fz_infinite_rect, NULL);
2587 fz_catch(ctx)
2588 rethrow(J);
2589 } else {
2590 device = new_js_device(ctx, J);
2591 js_copy(J, 1);
2592 fz_try(ctx) {
2593 fz_run_display_list(ctx, list, device, ctm, fz_infinite_rect, NULL);
2594 fz_close_device(ctx, device);
2595 }
2596 fz_always(ctx)
2597 fz_drop_device(ctx, device);
2598 fz_catch(ctx)
2599 rethrow(J);
2600 }
2601}
2602
2603static void ffi_DisplayList_toPixmap(js_State *J)
2604{
2605 fz_context *ctx = js_getcontext(J);
2606 fz_display_list *list = js_touserdata(J, 0, "fz_display_list");
2607 fz_matrix ctm = ffi_tomatrix(J, 1);
2608 fz_colorspace *colorspace = js_touserdata(J, 2, "fz_colorspace");
2609 int alpha = js_isdefined(J, 3) ? js_toboolean(J, 3) : 0;
2610 fz_pixmap *pixmap = NULL;
2611
2612 fz_try(ctx)
2613 pixmap = fz_new_pixmap_from_display_list(ctx, list, ctm, colorspace, alpha);
2614 fz_catch(ctx)
2615 rethrow(J);
2616
2617 js_getregistry(J, "fz_pixmap");
2618 js_newuserdata(J, "fz_pixmap", pixmap, ffi_gc_fz_pixmap);
2619}
2620
2621static void ffi_DisplayList_toStructuredText(js_State *J)
2622{
2623 fz_context *ctx = js_getcontext(J);
2624 fz_display_list *list = js_touserdata(J, 0, "fz_display_list");
2625 const char *options = js_iscoercible(J, 1) ? js_tostring(J, 1) : NULL;
2626 fz_stext_options so;
2627 fz_stext_page *text = NULL;
2628
2629 fz_try(ctx) {
2630 fz_parse_stext_options(ctx, &so, options);
2631 text = fz_new_stext_page_from_display_list(ctx, list, &so);
2632 }
2633 fz_catch(ctx)
2634 rethrow(J);
2635
2636 js_getregistry(J, "fz_stext_page");
2637 js_newuserdata(J, "fz_stext_page", text, ffi_gc_fz_stext_page);
2638}
2639
2640static void ffi_DisplayList_search(js_State *J)
2641{
2642 fz_context *ctx = js_getcontext(J);
2643 fz_display_list *list = js_touserdata(J, 0, "fz_display_list");
2644 const char *needle = js_tostring(J, 1);
2645 fz_quad hits[256];
2646 int i, n = 0;
2647
2648 fz_try(ctx)
2649 n = fz_search_display_list(ctx, list, needle, hits, nelem(hits));
2650 fz_catch(ctx)
2651 rethrow(J);
2652
2653 js_newarray(J);
2654 for (i = 0; i < n; ++i) {
2655 ffi_pushquad(J, hits[i]);
2656 js_setindex(J, -2, i);
2657 }
2658}
2659
2660static void ffi_StructuredText_search(js_State *J)
2661{
2662 fz_context *ctx = js_getcontext(J);
2663 fz_stext_page *text = js_touserdata(J, 0, "fz_stext_page");
2664 const char *needle = js_tostring(J, 1);
2665 fz_quad hits[256];
2666 int i, n = 0;
2667
2668 fz_try(ctx)
2669 n = fz_search_stext_page(ctx, text, needle, hits, nelem(hits));
2670 fz_catch(ctx)
2671 rethrow(J);
2672
2673 js_newarray(J);
2674 for (i = 0; i < n; ++i) {
2675 ffi_pushquad(J, hits[i]);
2676 js_setindex(J, -2, i);
2677 }
2678}
2679
2680static void ffi_StructuredText_highlight(js_State *J)
2681{
2682 fz_context *ctx = js_getcontext(J);
2683 fz_stext_page *text = js_touserdata(J, 0, "fz_stext_page");
2684 fz_point a = ffi_topoint(J, 1);
2685 fz_point b = ffi_topoint(J, 2);
2686 fz_quad hits[256];
2687 int i, n = 0;
2688
2689 fz_try(ctx)
2690 n = fz_highlight_selection(ctx, text, a, b, hits, nelem(hits));
2691 fz_catch(ctx)
2692 rethrow(J);
2693
2694 js_newarray(J);
2695 for (i = 0; i < n; ++i) {
2696 ffi_pushquad(J, hits[i]);
2697 js_setindex(J, -2, i);
2698 }
2699}
2700
2701static void ffi_StructuredText_copy(js_State *J)
2702{
2703 fz_context *ctx = js_getcontext(J);
2704 fz_stext_page *text = js_touserdata(J, 0, "fz_stext_page");
2705 fz_point a = ffi_topoint(J, 1);
2706 fz_point b = ffi_topoint(J, 2);
2707 char *s = NULL;
2708
2709 fz_try(ctx)
2710 s = fz_copy_selection(ctx, text, a, b, 0);
2711 fz_catch(ctx)
2712 rethrow(J);
2713
2714 js_pushstring(J, s);
2715
2716 fz_try(ctx)
2717 fz_free(ctx, s);
2718 fz_catch(ctx)
2719 rethrow(J);
2720}
2721
2722static void ffi_new_DisplayListDevice(js_State *J)
2723{
2724 fz_context *ctx = js_getcontext(J);
2725 fz_display_list *list = js_touserdata(J, 0, "fz_display_list");
2726 fz_device *device = NULL;
2727
2728 fz_try(ctx)
2729 device = fz_new_list_device(ctx, list);
2730 fz_catch(ctx)
2731 rethrow(J);
2732
2733 js_getregistry(J, "fz_device");
2734 js_newuserdata(J, "fz_device", device, ffi_gc_fz_device);
2735}
2736
2737static void ffi_new_DrawDevice(js_State *J)
2738{
2739 fz_context *ctx = js_getcontext(J);
2740 fz_matrix transform = ffi_tomatrix(J, 1);
2741 fz_pixmap *pixmap = js_touserdata(J, 2, "fz_pixmap");
2742 fz_device *device = NULL;
2743
2744 fz_try(ctx)
2745 device = fz_new_draw_device(ctx, transform, pixmap);
2746 fz_catch(ctx)
2747 rethrow(J);
2748
2749 js_getregistry(J, "fz_device");
2750 js_newuserdata(J, "fz_device", device, ffi_gc_fz_device);
2751}
2752
2753static void ffi_new_DocumentWriter(js_State *J)
2754{
2755 fz_context *ctx = js_getcontext(J);
2756 const char *filename = js_tostring(J, 1);
2757 const char *format = js_iscoercible(J, 2) ? js_tostring(J, 2) : NULL;
2758 const char *options = js_iscoercible(J, 3) ? js_tostring(J, 3) : NULL;
2759 fz_document_writer *wri = NULL;
2760
2761 fz_try(ctx)
2762 wri = fz_new_document_writer(ctx, filename, format, options);
2763 fz_catch(ctx)
2764 rethrow(J);
2765
2766 js_getregistry(J, "fz_document_writer");
2767 js_newuserdata(J, "fz_document_writer", wri, ffi_gc_fz_document_writer);
2768}
2769
2770static void ffi_DocumentWriter_beginPage(js_State *J)
2771{
2772 fz_context *ctx = js_getcontext(J);
2773 fz_document_writer *wri = js_touserdata(J, 0, "fz_document_writer");
2774 fz_rect mediabox = ffi_torect(J, 1);
2775 fz_device *device = NULL;
2776
2777 fz_try(ctx)
2778 device = fz_begin_page(ctx, wri, mediabox);
2779 fz_catch(ctx)
2780 rethrow(J);
2781
2782 js_getregistry(J, "fz_device");
2783 js_newuserdata(J, "fz_device", fz_keep_device(ctx, device), ffi_gc_fz_device);
2784}
2785
2786static void ffi_DocumentWriter_endPage(js_State *J)
2787{
2788 fz_context *ctx = js_getcontext(J);
2789 fz_document_writer *wri = js_touserdata(J, 0, "fz_document_writer");
2790 fz_try(ctx)
2791 fz_end_page(ctx, wri);
2792 fz_catch(ctx)
2793 rethrow(J);
2794}
2795
2796static void ffi_DocumentWriter_close(js_State *J)
2797{
2798 fz_context *ctx = js_getcontext(J);
2799 fz_document_writer *wri = js_touserdata(J, 0, "fz_document_writer");
2800 fz_try(ctx)
2801 fz_close_document_writer(ctx, wri);
2802 fz_catch(ctx)
2803 rethrow(J);
2804}
2805
2806/* PDF specifics */
2807
2808#if FZ_ENABLE_PDF
2809
2810static pdf_obj *ffi_toobj(js_State *J, pdf_document *pdf, int idx)
2811{
2812 fz_context *ctx = js_getcontext(J);
2813 pdf_obj *obj = NULL;
2814
2815 /* make sure index is absolute */
2816 if (idx < 0)
2817 idx += js_gettop(J);
2818
2819 if (js_isuserdata(J, idx, "pdf_obj"))
2820 return pdf_keep_obj(ctx, js_touserdata(J, idx, "pdf_obj"));
2821
2822 if (js_isnumber(J, idx)) {
2823 float f = js_tonumber(J, idx);
2824 fz_try(ctx)
2825 if (f == (int)f)
2826 obj = pdf_new_int(ctx, f);
2827 else
2828 obj = pdf_new_real(ctx, f);
2829 fz_catch(ctx)
2830 rethrow(J);
2831 return obj;
2832 }
2833
2834 if (js_isstring(J, idx)) {
2835 const char *s = js_tostring(J, idx);
2836 fz_try(ctx)
2837 if (s[0] == '(' && s[1] != 0)
2838 obj = pdf_new_string(ctx, s+1, strlen(s)-2);
2839 else
2840 obj = pdf_new_name(ctx, s);
2841 fz_catch(ctx)
2842 rethrow(J);
2843 return obj;
2844 }
2845
2846 if (js_isboolean(J, idx)) {
2847 return js_toboolean(J, idx) ? PDF_TRUE : PDF_FALSE;
2848 }
2849
2850 if (js_isnull(J, idx)) {
2851 return PDF_NULL;
2852 }
2853
2854 if (js_isarray(J, idx)) {
2855 int i, n = js_getlength(J, idx);
2856 pdf_obj *val;
2857 fz_try(ctx)
2858 obj = pdf_new_array(ctx, pdf, n);
2859 fz_catch(ctx)
2860 rethrow(J);
2861 if (js_try(J)) {
2862 pdf_drop_obj(ctx, obj);
2863 js_throw(J);
2864 }
2865 for (i = 0; i < n; ++i) {
2866 js_getindex(J, idx, i);
2867 val = ffi_toobj(J, pdf, -1);
2868 fz_try(ctx)
2869 pdf_array_push_drop(ctx, obj, val);
2870 fz_catch(ctx)
2871 rethrow(J);
2872 js_pop(J, 1);
2873 }
2874 js_endtry(J);
2875 return obj;
2876 }
2877
2878 if (js_isobject(J, idx)) {
2879 const char *key;
2880 pdf_obj *val;
2881 fz_try(ctx)
2882 obj = pdf_new_dict(ctx, pdf, 0);
2883 fz_catch(ctx)
2884 rethrow(J);
2885 if (js_try(J)) {
2886 pdf_drop_obj(ctx, obj);
2887 js_throw(J);
2888 }
2889 js_pushiterator(J, idx, 1);
2890 while ((key = js_nextiterator(J, -1))) {
2891 js_getproperty(J, idx, key);
2892 val = ffi_toobj(J, pdf, -1);
2893 fz_try(ctx)
2894 pdf_dict_puts_drop(ctx, obj, key, val);
2895 fz_catch(ctx)
2896 rethrow(J);
2897 js_pop(J, 1);
2898 }
2899 js_pop(J, 1);
2900 js_endtry(J);
2901 return obj;
2902 }
2903
2904 js_error(J, "cannot convert JS type to PDF");
2905}
2906
2907static void ffi_pushobj(js_State *J, pdf_obj *obj);
2908
2909static int ffi_pdf_obj_has(js_State *J, void *obj, const char *key)
2910{
2911 fz_context *ctx = js_getcontext(J);
2912 pdf_obj *val = NULL;
2913 int idx, len = 0;
2914
2915 if (!strcmp(key, "length")) {
2916 fz_try(ctx)
2917 len = pdf_array_len(ctx, obj);
2918 fz_catch(ctx)
2919 rethrow(J);
2920 js_pushnumber(J, len);
2921 return 1;
2922 }
2923
2924 if (is_number(key, &idx)) {
2925 fz_try(ctx)
2926 val = pdf_array_get(ctx, obj, idx);
2927 fz_catch(ctx)
2928 rethrow(J);
2929 } else {
2930 fz_try(ctx)
2931 val = pdf_dict_gets(ctx, obj, key);
2932 fz_catch(ctx)
2933 rethrow(J);
2934 }
2935 if (val) {
2936 ffi_pushobj(J, pdf_keep_obj(ctx, val));
2937 return 1;
2938 }
2939 return 0;
2940}
2941
2942static int ffi_pdf_obj_put(js_State *J, void *obj, const char *key)
2943{
2944 fz_context *ctx = js_getcontext(J);
2945 pdf_document *pdf = NULL;
2946 pdf_obj *val;
2947 int idx;
2948
2949 fz_try(ctx)
2950 pdf = pdf_get_bound_document(ctx, obj);
2951 fz_catch(ctx)
2952 rethrow(J);
2953
2954 val = ffi_toobj(J, pdf, -1);
2955
2956 if (is_number(key, &idx)) {
2957 fz_try(ctx)
2958 pdf_array_put(ctx, obj, idx, val);
2959 fz_always(ctx)
2960 pdf_drop_obj(ctx, val);
2961 fz_catch(ctx)
2962 rethrow(J);
2963 } else {
2964 fz_try(ctx)
2965 pdf_dict_puts(ctx, obj, key, val);
2966 fz_always(ctx)
2967 pdf_drop_obj(ctx, val);
2968 fz_catch(ctx)
2969 rethrow(J);
2970 }
2971 return 1;
2972}
2973
2974static int ffi_pdf_obj_delete(js_State *J, void *obj, const char *key)
2975{
2976 fz_context *ctx = js_getcontext(J);
2977 int idx;
2978
2979 if (is_number(key, &idx)) {
2980 fz_try(ctx)
2981 pdf_array_delete(ctx, obj, idx);
2982 fz_catch(ctx)
2983 rethrow(J);
2984 } else {
2985 fz_try(ctx)
2986 pdf_dict_dels(ctx, obj, key);
2987 fz_catch(ctx)
2988 rethrow(J);
2989 }
2990 return 1;
2991}
2992
2993static void ffi_pushobj(js_State *J, pdf_obj *obj)
2994{
2995 if (obj) {
2996 js_getregistry(J, "pdf_obj");
2997 js_newuserdatax(J, "pdf_obj", obj,
2998 ffi_pdf_obj_has, ffi_pdf_obj_put, ffi_pdf_obj_delete,
2999 ffi_gc_pdf_obj);
3000 } else {
3001 js_pushnull(J);
3002 }
3003}
3004
3005static void ffi_new_PDFDocument(js_State *J)
3006{
3007 fz_context *ctx = js_getcontext(J);
3008 const char *filename = js_iscoercible(J, 1) ? js_tostring(J, 1) : NULL;
3009 pdf_document *pdf = NULL;
3010
3011 fz_try(ctx)
3012 if (filename)
3013 pdf = pdf_open_document(ctx, filename);
3014 else
3015 pdf = pdf_create_document(ctx);
3016 fz_catch(ctx)
3017 rethrow(J);
3018
3019 js_getregistry(J, "pdf_document");
3020 js_newuserdata(J, "pdf_document", pdf, ffi_gc_pdf_document);
3021}
3022
3023static void ffi_PDFDocument_getTrailer(js_State *J)
3024{
3025 fz_context *ctx = js_getcontext(J);
3026 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3027 pdf_obj *trailer = NULL;
3028
3029 fz_try(ctx)
3030 trailer = pdf_trailer(ctx, pdf);
3031 fz_catch(ctx)
3032 rethrow(J);
3033
3034 ffi_pushobj(J, pdf_keep_obj(ctx, trailer));
3035}
3036
3037static void ffi_PDFDocument_countObjects(js_State *J)
3038{
3039 fz_context *ctx = js_getcontext(J);
3040 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3041 int count = 0;
3042
3043 fz_try(ctx)
3044 count = pdf_xref_len(ctx, pdf);
3045 fz_catch(ctx)
3046 rethrow(J);
3047
3048 js_pushnumber(J, count);
3049}
3050
3051static void ffi_PDFDocument_createObject(js_State *J)
3052{
3053 fz_context *ctx = js_getcontext(J);
3054 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3055 pdf_obj *ind = NULL;
3056
3057 fz_try(ctx)
3058 ind = pdf_new_indirect(ctx, pdf, pdf_create_object(ctx, pdf), 0);
3059 fz_catch(ctx)
3060 rethrow(J);
3061
3062 ffi_pushobj(J, ind);
3063}
3064
3065static void ffi_PDFDocument_deleteObject(js_State *J)
3066{
3067 fz_context *ctx = js_getcontext(J);
3068 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3069 pdf_obj *ind = js_isuserdata(J, 1, "pdf_obj") ? js_touserdata(J, 1, "pdf_obj") : NULL;
3070 int num = ind ? pdf_to_num(ctx, ind) : js_tonumber(J, 1);
3071
3072 fz_try(ctx)
3073 pdf_delete_object(ctx, pdf, num);
3074 fz_catch(ctx)
3075 rethrow(J);
3076}
3077
3078static void ffi_PDFDocument_addObject(js_State *J)
3079{
3080 fz_context *ctx = js_getcontext(J);
3081 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3082 pdf_obj *obj = ffi_toobj(J, pdf, 1);
3083 pdf_obj *ind = NULL;
3084
3085 fz_try(ctx)
3086 ind = pdf_add_object_drop(ctx, pdf, obj);
3087 fz_catch(ctx)
3088 rethrow(J);
3089
3090 ffi_pushobj(J, ind);
3091}
3092
3093static void ffi_PDFDocument_addStream_imp(js_State *J, int compressed)
3094{
3095 fz_context *ctx = js_getcontext(J);
3096 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3097 fz_buffer *buf = ffi_tobuffer(J, 1); /* FIXME: leak if ffi_toobj throws */
3098 pdf_obj *obj = js_iscoercible(J, 2) ? ffi_toobj(J, pdf, 2) : NULL;
3099 pdf_obj *ind = NULL;
3100
3101 fz_try(ctx)
3102 ind = pdf_add_stream(ctx, pdf, buf, obj, compressed);
3103 fz_always(ctx) {
3104 fz_drop_buffer(ctx, buf);
3105 pdf_drop_obj(ctx, obj);
3106 } fz_catch(ctx)
3107 rethrow(J);
3108
3109 ffi_pushobj(J, ind);
3110}
3111
3112static void ffi_PDFDocument_addStream(js_State *J)
3113{
3114 ffi_PDFDocument_addStream_imp(J, 0);
3115}
3116
3117static void ffi_PDFDocument_addRawStream(js_State *J)
3118{
3119 ffi_PDFDocument_addStream_imp(J, 1);
3120}
3121
3122static void ffi_PDFDocument_addImage(js_State *J)
3123{
3124 fz_context *ctx = js_getcontext(J);
3125 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3126 fz_image *image = js_touserdata(J, 1, "fz_image");
3127 pdf_obj *ind = NULL;
3128
3129 fz_try(ctx)
3130 ind = pdf_add_image(ctx, pdf, image);
3131 fz_catch(ctx)
3132 rethrow(J);
3133
3134 ffi_pushobj(J, ind);
3135}
3136
3137static void ffi_PDFDocument_loadImage(js_State *J)
3138{
3139 fz_context *ctx = js_getcontext(J);
3140 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3141 pdf_obj *obj = ffi_toobj(J, pdf, 1);
3142 fz_image *img = NULL;
3143
3144 fz_try(ctx)
3145 img = pdf_load_image(ctx, pdf, obj);
3146 fz_catch(ctx)
3147 rethrow(J);
3148
3149 ffi_pushimage_own(J, img);
3150}
3151
3152static void ffi_PDFDocument_addSimpleFont(js_State *J)
3153{
3154 fz_context *ctx = js_getcontext(J);
3155 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3156 fz_font *font = js_touserdata(J, 1, "fz_font");
3157 const char *encname = js_tostring(J, 2);
3158 pdf_obj *ind = NULL;
3159 int enc = PDF_SIMPLE_ENCODING_LATIN;
3160
3161 if (!strcmp(encname, "Latin") || !strcmp(encname, "Latn"))
3162 enc = PDF_SIMPLE_ENCODING_LATIN;
3163 else if (!strcmp(encname, "Greek") || !strcmp(encname, "Grek"))
3164 enc = PDF_SIMPLE_ENCODING_GREEK;
3165 else if (!strcmp(encname, "Cyrillic") || !strcmp(encname, "Cyrl"))
3166 enc = PDF_SIMPLE_ENCODING_CYRILLIC;
3167
3168 fz_try(ctx)
3169 ind = pdf_add_simple_font(ctx, pdf, font, enc);
3170 fz_catch(ctx)
3171 rethrow(J);
3172
3173 ffi_pushobj(J, ind);
3174}
3175
3176static void ffi_PDFDocument_addCJKFont(js_State *J)
3177{
3178 fz_context *ctx = js_getcontext(J);
3179 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3180 fz_font *font = js_touserdata(J, 1, "fz_font");
3181 const char *lang = js_tostring(J, 2);
3182 const char *wm = js_tostring(J, 3);
3183 const char *ss = js_tostring(J, 4);
3184 int ordering;
3185 int wmode = 0;
3186 int serif = 1;
3187 pdf_obj *ind = NULL;
3188
3189 ordering = fz_lookup_cjk_ordering_by_language(lang);
3190
3191 if (!strcmp(wm, "V"))
3192 wmode = 1;
3193 if (!strcmp(ss, "sans") || !strcmp(ss, "sans-serif"))
3194 serif = 0;
3195
3196 fz_try(ctx)
3197 ind = pdf_add_cjk_font(ctx, pdf, font, ordering, wmode, serif);
3198 fz_catch(ctx)
3199 rethrow(J);
3200
3201 ffi_pushobj(J, ind);
3202}
3203
3204static void ffi_PDFDocument_addFont(js_State *J)
3205{
3206 fz_context *ctx = js_getcontext(J);
3207 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3208 fz_font *font = js_touserdata(J, 1, "fz_font");
3209 pdf_obj *ind = NULL;
3210
3211 fz_try(ctx)
3212 ind = pdf_add_cid_font(ctx, pdf, font);
3213 fz_catch(ctx)
3214 rethrow(J);
3215
3216 ffi_pushobj(J, ind);
3217}
3218
3219static void ffi_PDFDocument_addPage(js_State *J)
3220{
3221 fz_context *ctx = js_getcontext(J);
3222 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3223 fz_rect mediabox = ffi_torect(J, 1);
3224 int rotate = js_tonumber(J, 2);
3225 pdf_obj *resources = ffi_toobj(J, pdf, 3); /* FIXME: leak if ffi_tobuffer throws */
3226 fz_buffer *contents = ffi_tobuffer(J, 4);
3227 pdf_obj *ind = NULL;
3228
3229 fz_try(ctx)
3230 ind = pdf_add_page(ctx, pdf, mediabox, rotate, resources, contents);
3231 fz_always(ctx) {
3232 fz_drop_buffer(ctx, contents);
3233 pdf_drop_obj(ctx, resources);
3234 } fz_catch(ctx)
3235 rethrow(J);
3236
3237 ffi_pushobj(J, ind);
3238}
3239
3240static void ffi_PDFDocument_insertPage(js_State *J)
3241{
3242 fz_context *ctx = js_getcontext(J);
3243 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3244 int at = js_tonumber(J, 1);
3245 pdf_obj *obj = ffi_toobj(J, pdf, 2);
3246
3247 fz_try(ctx)
3248 pdf_insert_page(ctx, pdf, at, obj);
3249 fz_always(ctx)
3250 pdf_drop_obj(ctx, obj);
3251 fz_catch(ctx)
3252 rethrow(J);
3253}
3254
3255static void ffi_PDFDocument_deletePage(js_State *J)
3256{
3257 fz_context *ctx = js_getcontext(J);
3258 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3259 int at = js_tonumber(J, 1);
3260
3261 fz_try(ctx)
3262 pdf_delete_page(ctx, pdf, at);
3263 fz_catch(ctx)
3264 rethrow(J);
3265}
3266
3267static void ffi_PDFDocument_countPages(js_State *J)
3268{
3269 fz_context *ctx = js_getcontext(J);
3270 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3271 int count = 0;
3272
3273 fz_try(ctx)
3274 count = pdf_count_pages(ctx, pdf);
3275 fz_catch(ctx)
3276 rethrow(J);
3277
3278 js_pushnumber(J, count);
3279}
3280
3281static void ffi_PDFDocument_findPage(js_State *J)
3282{
3283 fz_context *ctx = js_getcontext(J);
3284 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3285 int at = js_tonumber(J, 1);
3286 pdf_obj *obj = NULL;
3287
3288 fz_try(ctx)
3289 obj = pdf_lookup_page_obj(ctx, pdf, at);
3290 fz_catch(ctx)
3291 rethrow(J);
3292
3293 ffi_pushobj(J, pdf_keep_obj(ctx, obj));
3294}
3295
3296static void ffi_PDFDocument_save(js_State *J)
3297{
3298 fz_context *ctx = js_getcontext(J);
3299 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3300 const char *filename = js_tostring(J, 1);
3301 const char *options = js_iscoercible(J, 2) ? js_tostring(J, 2) : NULL;
3302 pdf_write_options pwo;
3303
3304 fz_try(ctx) {
3305 pdf_parse_write_options(ctx, &pwo, options);
3306 pdf_save_document(ctx, pdf, filename, &pwo);
3307 } fz_catch(ctx)
3308 rethrow(J);
3309}
3310
3311static void ffi_PDFDocument_newNull(js_State *J)
3312{
3313 ffi_pushobj(J, PDF_NULL);
3314}
3315
3316static void ffi_PDFDocument_newBoolean(js_State *J)
3317{
3318 int val = js_toboolean(J, 1);
3319 ffi_pushobj(J, val ? PDF_TRUE : PDF_FALSE);
3320}
3321
3322static void ffi_PDFDocument_newInteger(js_State *J)
3323{
3324 fz_context *ctx = js_getcontext(J);
3325 int val = js_tointeger(J, 1);
3326 pdf_obj *obj = NULL;
3327 fz_try(ctx)
3328 obj = pdf_new_int(ctx, val);
3329 fz_catch(ctx)
3330 rethrow(J);
3331 ffi_pushobj(J, obj);
3332}
3333
3334static void ffi_PDFDocument_newReal(js_State *J)
3335{
3336 fz_context *ctx = js_getcontext(J);
3337 float val = js_tonumber(J, 1);
3338 pdf_obj *obj = NULL;
3339 fz_try(ctx)
3340 obj = pdf_new_real(ctx, val);
3341 fz_catch(ctx)
3342 rethrow(J);
3343 ffi_pushobj(J, obj);
3344}
3345
3346static void ffi_PDFDocument_newString(js_State *J)
3347{
3348 fz_context *ctx = js_getcontext(J);
3349 const char *val = js_tostring(J, 1);
3350 pdf_obj *obj = NULL;
3351
3352 fz_try(ctx)
3353 obj = pdf_new_text_string(ctx, val);
3354 fz_catch(ctx)
3355 rethrow(J);
3356 ffi_pushobj(J, obj);
3357}
3358
3359static void ffi_PDFDocument_newByteString(js_State *J)
3360{
3361 fz_context *ctx = js_getcontext(J);
3362 int n, i;
3363 char *buf;
3364 pdf_obj *obj = NULL;
3365
3366 n = js_getlength(J, 1);
3367
3368 fz_try(ctx)
3369 buf = fz_malloc(ctx, n);
3370 fz_catch(ctx)
3371 rethrow(J);
3372
3373 if (js_try(J)) {
3374 fz_free(ctx, buf);
3375 js_throw(J);
3376 }
3377
3378 for (i = 0; i < n; ++i) {
3379 js_getindex(J, 1, i);
3380 buf[i] = js_tonumber(J, -1);
3381 js_pop(J, 1);
3382 }
3383
3384 js_endtry(J);
3385
3386 fz_try(ctx)
3387 obj = pdf_new_string(ctx, buf, n);
3388 fz_always(ctx)
3389 fz_free(ctx, buf);
3390 fz_catch(ctx)
3391 rethrow(J);
3392 ffi_pushobj(J, obj);
3393}
3394
3395static void ffi_PDFDocument_newName(js_State *J)
3396{
3397 fz_context *ctx = js_getcontext(J);
3398 const char *val = js_tostring(J, 1);
3399 pdf_obj *obj = NULL;
3400 fz_try(ctx)
3401 obj = pdf_new_name(ctx, val);
3402 fz_catch(ctx)
3403 rethrow(J);
3404 ffi_pushobj(J, obj);
3405}
3406
3407static void ffi_PDFDocument_newIndirect(js_State *J)
3408{
3409 fz_context *ctx = js_getcontext(J);
3410 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3411 int num = js_tointeger(J, 1);
3412 int gen = js_tointeger(J, 2);
3413 pdf_obj *obj = NULL;
3414 fz_try(ctx)
3415 obj = pdf_new_indirect(ctx, pdf, num, gen);
3416 fz_catch(ctx)
3417 rethrow(J);
3418 ffi_pushobj(J, obj);
3419}
3420
3421static void ffi_PDFDocument_newArray(js_State *J)
3422{
3423 fz_context *ctx = js_getcontext(J);
3424 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3425 pdf_obj *obj = NULL;
3426 fz_try(ctx)
3427 obj = pdf_new_array(ctx, pdf, 0);
3428 fz_catch(ctx)
3429 rethrow(J);
3430 ffi_pushobj(J, obj);
3431}
3432
3433static void ffi_PDFDocument_newDictionary(js_State *J)
3434{
3435 fz_context *ctx = js_getcontext(J);
3436 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3437 pdf_obj *obj = NULL;
3438 fz_try(ctx)
3439 obj = pdf_new_dict(ctx, pdf, 0);
3440 fz_catch(ctx)
3441 rethrow(J);
3442 ffi_pushobj(J, obj);
3443}
3444
3445static void ffi_PDFDocument_newGraftMap(js_State *J)
3446{
3447 fz_context *ctx = js_getcontext(J);
3448 pdf_document *pdf = js_touserdata(J, 0, "pdf_document");
3449 pdf_graft_map *map = NULL;
3450 fz_try(ctx)
3451 map = pdf_new_graft_map(ctx, pdf);
3452 fz_catch(ctx)
3453 rethrow(J);
3454 js_getregistry(J, "pdf_graft_map");
3455 js_newuserdata(J, "pdf_graft_map", map, ffi_gc_pdf_graft_map);
3456}
3457
3458static void ffi_PDFDocument_graftObject(js_State *J)
3459{
3460 fz_context *ctx = js_getcontext(J);
3461 pdf_document *dst = js_touserdata(J, 0, "pdf_document");
3462 pdf_obj *obj = js_touserdata(J, 1, "pdf_obj");
3463 fz_try(ctx)
3464 obj = pdf_graft_object(ctx, dst, obj);
3465 fz_catch(ctx)
3466 rethrow(J);
3467 ffi_pushobj(J, obj);
3468}
3469
3470static void ffi_PDFGraftMap_graftObject(js_State *J)
3471{
3472 fz_context *ctx = js_getcontext(J);
3473 pdf_graft_map *map = js_touserdata(J, 0, "pdf_graft_map");
3474 pdf_obj *obj = js_touserdata(J, 1, "pdf_obj");
3475 fz_try(ctx)
3476 obj = pdf_graft_mapped_object(ctx, map, obj);
3477 fz_catch(ctx)
3478 rethrow(J);
3479 ffi_pushobj(J, obj);
3480}
3481
3482static void ffi_PDFObject_get(js_State *J)
3483{
3484 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3485 const char *key = js_tostring(J, 1);
3486 if (!ffi_pdf_obj_has(J, obj, key))
3487 js_pushundefined(J);
3488}
3489
3490static void ffi_PDFObject_put(js_State *J)
3491{
3492 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3493 const char *key = js_tostring(J, 1);
3494 js_copy(J, 2);
3495 ffi_pdf_obj_put(J, obj, key);
3496}
3497
3498static void ffi_PDFObject_delete(js_State *J)
3499{
3500 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3501 const char *key = js_tostring(J, 1);
3502 ffi_pdf_obj_delete(J, obj, key);
3503}
3504
3505static void ffi_PDFObject_push(js_State *J)
3506{
3507 fz_context *ctx = js_getcontext(J);
3508 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3509 pdf_document *pdf = pdf_get_bound_document(ctx, obj);
3510 pdf_obj *item = ffi_toobj(J, pdf, 1);
3511 fz_try(ctx)
3512 pdf_array_push(ctx, obj, item);
3513 fz_always(ctx)
3514 pdf_drop_obj(ctx, item);
3515 fz_catch(ctx)
3516 rethrow(J);
3517}
3518
3519static void ffi_PDFObject_resolve(js_State *J)
3520{
3521 fz_context *ctx = js_getcontext(J);
3522 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3523 pdf_obj *ind = NULL;
3524 fz_try(ctx)
3525 ind = pdf_resolve_indirect(ctx, obj);
3526 fz_catch(ctx)
3527 rethrow(J);
3528 ffi_pushobj(J, pdf_keep_obj(ctx, ind));
3529}
3530
3531static void ffi_PDFObject_toString(js_State *J)
3532{
3533 fz_context *ctx = js_getcontext(J);
3534 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3535 int tight = js_isdefined(J, 1) ? js_toboolean(J, 1) : 1;
3536 int ascii = js_isdefined(J, 2) ? js_toboolean(J, 2) : 0;
3537 char *s = NULL;
3538 int n;
3539
3540 fz_try(ctx)
3541 s = pdf_sprint_obj(ctx, NULL, 0, &n, obj, tight, ascii);
3542 fz_catch(ctx)
3543 rethrow(J);
3544
3545 if (js_try(J)) {
3546 fz_free(ctx, s);
3547 js_throw(J);
3548 }
3549 js_pushstring(J, s);
3550 js_endtry(J);
3551 fz_free(ctx, s);
3552}
3553
3554static void ffi_PDFObject_valueOf(js_State *J)
3555{
3556 fz_context *ctx = js_getcontext(J);
3557 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3558 if (pdf_is_indirect(ctx, obj))
3559 js_pushstring(J, "R");
3560 else if (pdf_is_null(ctx, obj))
3561 js_pushnull(J);
3562 else if (pdf_is_bool(ctx, obj))
3563 js_pushboolean(J, pdf_to_bool(ctx, obj));
3564 else if (pdf_is_int(ctx, obj))
3565 js_pushnumber(J, pdf_to_int(ctx, obj));
3566 else if (pdf_is_real(ctx, obj))
3567 js_pushnumber(J, pdf_to_real(ctx, obj));
3568 else if (pdf_is_string(ctx, obj))
3569 js_pushlstring(J, pdf_to_str_buf(ctx, obj), pdf_to_str_len(ctx, obj));
3570 else if (pdf_is_name(ctx, obj))
3571 js_pushstring(J, pdf_to_name(ctx, obj));
3572 else
3573 js_copy(J, 0);
3574}
3575
3576static void ffi_PDFObject_isArray(js_State *J)
3577{
3578 fz_context *ctx = js_getcontext(J);
3579 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3580 int b = 0;
3581 fz_try(ctx)
3582 b = pdf_is_array(ctx, obj);
3583 fz_catch(ctx)
3584 rethrow(J);
3585 js_pushboolean(J, b);
3586}
3587
3588static void ffi_PDFObject_isDictionary(js_State *J)
3589{
3590 fz_context *ctx = js_getcontext(J);
3591 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3592 int b = 0;
3593 fz_try(ctx)
3594 b = pdf_is_dict(ctx, obj);
3595 fz_catch(ctx)
3596 rethrow(J);
3597 js_pushboolean(J, b);
3598}
3599
3600static void ffi_PDFObject_isIndirect(js_State *J)
3601{
3602 fz_context *ctx = js_getcontext(J);
3603 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3604 int b = 0;
3605 fz_try(ctx)
3606 b = pdf_is_indirect(ctx, obj);
3607 fz_catch(ctx)
3608 rethrow(J);
3609 js_pushboolean(J, b);
3610}
3611
3612static void ffi_PDFObject_asIndirect(js_State *J)
3613{
3614 fz_context *ctx = js_getcontext(J);
3615 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3616 int num = 0;
3617 fz_try(ctx)
3618 num = pdf_to_num(ctx, obj);
3619 fz_catch(ctx)
3620 rethrow(J);
3621 js_pushnumber(J, num);
3622}
3623
3624static void ffi_PDFObject_isNull(js_State *J)
3625{
3626 fz_context *ctx = js_getcontext(J);
3627 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3628 int b = 0;
3629 fz_try(ctx)
3630 b = pdf_is_null(ctx, obj);
3631 fz_catch(ctx)
3632 rethrow(J);
3633 js_pushboolean(J, b);
3634}
3635
3636static void ffi_PDFObject_isBoolean(js_State *J)
3637{
3638 fz_context *ctx = js_getcontext(J);
3639 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3640 int b = 0;
3641 fz_try(ctx)
3642 b = pdf_is_bool(ctx, obj);
3643 fz_catch(ctx)
3644 rethrow(J);
3645 js_pushboolean(J, b);
3646}
3647
3648static void ffi_PDFObject_asBoolean(js_State *J)
3649{
3650 fz_context *ctx = js_getcontext(J);
3651 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3652 int b = 0;
3653 fz_try(ctx)
3654 b = pdf_to_bool(ctx, obj);
3655 fz_catch(ctx)
3656 rethrow(J);
3657 js_pushboolean(J, b);
3658}
3659
3660static void ffi_PDFObject_isNumber(js_State *J)
3661{
3662 fz_context *ctx = js_getcontext(J);
3663 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3664 int b = 0;
3665 fz_try(ctx)
3666 b = pdf_is_number(ctx, obj);
3667 fz_catch(ctx)
3668 rethrow(J);
3669 js_pushboolean(J, b);
3670}
3671
3672static void ffi_PDFObject_asNumber(js_State *J)
3673{
3674 fz_context *ctx = js_getcontext(J);
3675 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3676 float num = 0;
3677 fz_try(ctx)
3678 if (pdf_is_int(ctx, obj))
3679 num = pdf_to_int(ctx, obj);
3680 else
3681 num = pdf_to_real(ctx, obj);
3682 fz_catch(ctx)
3683 rethrow(J);
3684 js_pushnumber(J, num);
3685}
3686
3687static void ffi_PDFObject_isName(js_State *J)
3688{
3689 fz_context *ctx = js_getcontext(J);
3690 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3691 int b = 0;
3692 fz_try(ctx)
3693 b = pdf_is_name(ctx, obj);
3694 fz_catch(ctx)
3695 rethrow(J);
3696 js_pushboolean(J, b);
3697}
3698
3699static void ffi_PDFObject_asName(js_State *J)
3700{
3701 fz_context *ctx = js_getcontext(J);
3702 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3703 const char *name = NULL;
3704 fz_try(ctx)
3705 name = pdf_to_name(ctx, obj);
3706 fz_catch(ctx)
3707 rethrow(J);
3708 js_pushstring(J, name);
3709}
3710
3711static void ffi_PDFObject_isString(js_State *J)
3712{
3713 fz_context *ctx = js_getcontext(J);
3714 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3715 int b = 0;
3716 fz_try(ctx)
3717 b = pdf_is_string(ctx, obj);
3718 fz_catch(ctx)
3719 rethrow(J);
3720 js_pushboolean(J, b);
3721}
3722
3723static void ffi_PDFObject_asString(js_State *J)
3724{
3725 fz_context *ctx = js_getcontext(J);
3726 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3727 const char *string = NULL;
3728
3729 fz_try(ctx)
3730 string = pdf_to_text_string(ctx, obj);
3731 fz_catch(ctx)
3732 rethrow(J);
3733
3734 js_pushstring(J, string);
3735}
3736
3737static void ffi_PDFObject_asByteString(js_State *J)
3738{
3739 fz_context *ctx = js_getcontext(J);
3740 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3741 const char *buf;
3742 size_t i, len = 0;
3743
3744 fz_try(ctx)
3745 buf = pdf_to_string(ctx, obj, &len);
3746 fz_catch(ctx)
3747 rethrow(J);
3748
3749 js_newarray(J);
3750 for (i = 0; i < len; ++i) {
3751 js_pushnumber(J, (unsigned char)buf[i]);
3752 js_setindex(J, -2, i);
3753 }
3754}
3755
3756static void ffi_PDFObject_isStream(js_State *J)
3757{
3758 fz_context *ctx = js_getcontext(J);
3759 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3760 int b = 0;
3761 fz_try(ctx)
3762 b = pdf_is_stream(ctx, obj);
3763 fz_catch(ctx)
3764 rethrow(J);
3765 js_pushboolean(J, b);
3766}
3767
3768static void ffi_PDFObject_readStream(js_State *J)
3769{
3770 fz_context *ctx = js_getcontext(J);
3771 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3772 fz_buffer *buf = NULL;
3773 fz_try(ctx)
3774 buf = pdf_load_stream(ctx, obj);
3775 fz_catch(ctx)
3776 rethrow(J);
3777 ffi_pushbuffer(J, buf);
3778}
3779
3780static void ffi_PDFObject_readRawStream(js_State *J)
3781{
3782 fz_context *ctx = js_getcontext(J);
3783 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3784 fz_buffer *buf = NULL;
3785 fz_try(ctx)
3786 buf = pdf_load_raw_stream(ctx, obj);
3787 fz_catch(ctx)
3788 rethrow(J);
3789 ffi_pushbuffer(J, buf);
3790}
3791
3792static void ffi_PDFObject_writeObject(js_State *J)
3793{
3794 fz_context *ctx = js_getcontext(J);
3795 pdf_obj *ref = js_touserdata(J, 0, "pdf_obj");
3796 pdf_document *pdf = pdf_get_bound_document(ctx, ref);
3797 pdf_obj *obj = ffi_toobj(J, pdf, 1);
3798 fz_try(ctx)
3799 pdf_update_object(ctx, pdf, pdf_to_num(ctx, ref), obj);
3800 fz_always(ctx)
3801 pdf_drop_obj(ctx, obj);
3802 fz_catch(ctx)
3803 rethrow(J);
3804}
3805
3806static void ffi_PDFObject_writeStream(js_State *J)
3807{
3808 fz_context *ctx = js_getcontext(J);
3809 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3810 fz_buffer *buf = ffi_tobuffer(J, 1);
3811 fz_try(ctx)
3812 pdf_update_stream(ctx, pdf_get_bound_document(ctx, obj), obj, buf, 0);
3813 fz_always(ctx)
3814 fz_drop_buffer(ctx, buf);
3815 fz_catch(ctx)
3816 rethrow(J);
3817}
3818
3819static void ffi_PDFObject_writeRawStream(js_State *J)
3820{
3821 fz_context *ctx = js_getcontext(J);
3822 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3823 fz_buffer *buf = ffi_tobuffer(J, 1);
3824 fz_try(ctx)
3825 pdf_update_stream(ctx, pdf_get_bound_document(ctx, obj), obj, buf, 1);
3826 fz_always(ctx)
3827 fz_drop_buffer(ctx, buf);
3828 fz_catch(ctx)
3829 rethrow(J);
3830}
3831
3832static void ffi_PDFObject_forEach(js_State *J)
3833{
3834 fz_context *ctx = js_getcontext(J);
3835 pdf_obj *obj = js_touserdata(J, 0, "pdf_obj");
3836 pdf_obj *val = NULL;
3837 const char *key = NULL;
3838 int i, n = 0;
3839
3840 fz_try(ctx)
3841 obj = pdf_resolve_indirect_chain(ctx, obj);
3842 fz_catch(ctx)
3843 rethrow(J);
3844
3845 if (pdf_is_array(ctx, obj)) {
3846 fz_try(ctx)
3847 n = pdf_array_len(ctx, obj);
3848 fz_catch(ctx)
3849 rethrow(J);
3850 for (i = 0; i < n; ++i) {
3851 fz_try(ctx)
3852 val = pdf_array_get(ctx, obj, i);
3853 fz_catch(ctx)
3854 rethrow(J);
3855 js_copy(J, 1);
3856 js_pushnull(J);
3857 js_pushnumber(J, i);
3858 ffi_pushobj(J, pdf_keep_obj(ctx, val));
3859 js_call(J, 2);
3860 js_pop(J, 1);
3861 }
3862 return;
3863 }
3864
3865 if (pdf_is_dict(ctx, obj)) {
3866 fz_try(ctx)
3867 n = pdf_dict_len(ctx, obj);
3868 fz_catch(ctx)
3869 rethrow(J);
3870 for (i = 0; i < n; ++i) {
3871 fz_try(ctx) {
3872 key = pdf_to_name(ctx, pdf_dict_get_key(ctx, obj, i));
3873 val = pdf_dict_get_val(ctx, obj, i);
3874 } fz_catch(ctx)
3875 rethrow(J);
3876 js_copy(J, 1);
3877 js_pushnull(J);
3878 js_pushstring(J, key);
3879 ffi_pushobj(J, pdf_keep_obj(ctx, val));
3880 js_call(J, 2);
3881 js_pop(J, 1);
3882 }
3883 return;
3884 }
3885}
3886
3887static void ffi_PDFPage_getAnnotations(js_State *J)
3888{
3889 fz_context *ctx = js_getcontext(J);
3890 pdf_page *page = js_touserdata(J, 0, "pdf_page");
3891 pdf_annot *annot = NULL;
3892 int i = 0;
3893
3894 js_newarray(J);
3895
3896 fz_try(ctx)
3897 annot = pdf_first_annot(ctx, page);
3898 fz_catch(ctx)
3899 rethrow(J);
3900
3901 while (annot) {
3902 js_newuserdata(J, "pdf_annot", pdf_keep_annot(ctx, annot), ffi_gc_pdf_annot);
3903 js_setindex(J, -2, i++);
3904
3905 fz_try(ctx)
3906 annot = pdf_next_annot(ctx, annot);
3907 fz_catch(ctx)
3908 rethrow(J);
3909 }
3910}
3911
3912static void ffi_PDFPage_createAnnotation(js_State *J)
3913{
3914 fz_context *ctx = js_getcontext(J);
3915 pdf_page *page = js_touserdata(J, 0, "pdf_page");
3916 const char *name = js_tostring(J, 1);
3917 pdf_annot *annot = NULL;
3918 int subtype;
3919
3920 fz_try(ctx)
3921 {
3922 subtype = pdf_annot_type_from_string(ctx, name);
3923 annot = pdf_create_annot(ctx, page, subtype);
3924 }
3925 fz_catch(ctx)
3926 rethrow(J);
3927 js_newuserdata(J, "pdf_annot", annot, ffi_gc_pdf_annot);
3928}
3929
3930static void ffi_PDFPage_deleteAnnotation(js_State *J)
3931{
3932 fz_context *ctx = js_getcontext(J);
3933 pdf_page *page = js_touserdata(J, 0, "pdf_page");
3934 pdf_annot *annot = js_touserdata(J, 1, "pdf_annot");
3935 fz_try(ctx)
3936 pdf_delete_annot(ctx, page, annot);
3937 fz_catch(ctx)
3938 rethrow(J);
3939}
3940
3941static void ffi_PDFPage_update(js_State *J)
3942{
3943 fz_context *ctx = js_getcontext(J);
3944 pdf_page *page = js_touserdata(J, 0, "pdf_page");
3945 int changed = 0;
3946 fz_try(ctx)
3947 changed = pdf_update_page(ctx, page);
3948 fz_catch(ctx)
3949 rethrow(J);
3950 js_pushboolean(J, changed);
3951}
3952
3953static void ffi_PDFAnnotation_bound(js_State *J)
3954{
3955 fz_context *ctx = js_getcontext(J);
3956 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
3957 fz_rect bounds;
3958
3959 fz_try(ctx)
3960 bounds = pdf_bound_annot(ctx, annot);
3961 fz_catch(ctx)
3962 rethrow(J);
3963
3964 ffi_pushrect(J, bounds);
3965}
3966
3967static void ffi_PDFAnnotation_run(js_State *J)
3968{
3969 fz_context *ctx = js_getcontext(J);
3970 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
3971 fz_device *device = NULL;
3972 fz_matrix ctm = ffi_tomatrix(J, 2);
3973
3974 if (js_isuserdata(J, 1, "fz_device")) {
3975 device = js_touserdata(J, 1, "fz_device");
3976 fz_try(ctx)
3977 pdf_run_annot(ctx, annot, device, ctm, NULL);
3978 fz_catch(ctx)
3979 rethrow(J);
3980 } else {
3981 device = new_js_device(ctx, J);
3982 js_copy(J, 1); /* put the js device on the top so the callbacks know where to get it */
3983 fz_try(ctx) {
3984 pdf_run_annot(ctx, annot, device, ctm, NULL);
3985 fz_close_device(ctx, device);
3986 }
3987 fz_always(ctx)
3988 fz_drop_device(ctx, device);
3989 fz_catch(ctx)
3990 rethrow(J);
3991 }
3992}
3993
3994static void ffi_PDFAnnotation_toDisplayList(js_State *J)
3995{
3996 fz_context *ctx = js_getcontext(J);
3997 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
3998 fz_display_list *list = NULL;
3999
4000 fz_try(ctx)
4001 list = pdf_new_display_list_from_annot(ctx, annot);
4002 fz_catch(ctx)
4003 rethrow(J);
4004
4005 js_getregistry(J, "fz_display_list");
4006 js_newuserdata(J, "fz_display_list", list, ffi_gc_fz_display_list);
4007}
4008
4009static void ffi_PDFAnnotation_toPixmap(js_State *J)
4010{
4011 fz_context *ctx = js_getcontext(J);
4012 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4013 fz_matrix ctm = ffi_tomatrix(J, 1);
4014 fz_colorspace *colorspace = js_touserdata(J, 2, "fz_colorspace");
4015 int alpha = js_toboolean(J, 3);
4016 fz_pixmap *pixmap = NULL;
4017
4018 fz_try(ctx)
4019 pixmap = pdf_new_pixmap_from_annot(ctx, annot, ctm, colorspace, NULL, alpha);
4020 fz_catch(ctx)
4021 rethrow(J);
4022
4023 js_getregistry(J, "fz_pixmap");
4024 js_newuserdata(J, "fz_pixmap", pixmap, ffi_gc_fz_pixmap);
4025}
4026
4027static void ffi_PDFAnnotation_getType(js_State *J)
4028{
4029 fz_context *ctx = js_getcontext(J);
4030 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4031 int type;
4032 const char *subtype = NULL;
4033 fz_try(ctx)
4034 {
4035 type = pdf_annot_type(ctx, annot);
4036 subtype = pdf_string_from_annot_type(ctx, type);
4037 }
4038 fz_catch(ctx)
4039 rethrow(J);
4040 js_pushstring(J, subtype);
4041}
4042
4043static void ffi_PDFAnnotation_getFlags(js_State *J)
4044{
4045 fz_context *ctx = js_getcontext(J);
4046 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4047 int flags = 0;
4048 fz_try(ctx)
4049 flags = pdf_annot_flags(ctx, annot);
4050 fz_catch(ctx)
4051 rethrow(J);
4052 js_pushnumber(J, flags);
4053}
4054
4055static void ffi_PDFAnnotation_setFlags(js_State *J)
4056{
4057 fz_context *ctx = js_getcontext(J);
4058 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4059 int flags = js_tonumber(J, 1);
4060 fz_try(ctx)
4061 pdf_set_annot_flags(ctx, annot, flags);
4062 fz_catch(ctx)
4063 rethrow(J);
4064}
4065
4066static void ffi_PDFAnnotation_getContents(js_State *J)
4067{
4068 fz_context *ctx = js_getcontext(J);
4069 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4070 const char *contents = NULL;
4071
4072 fz_try(ctx)
4073 contents = pdf_annot_contents(ctx, annot);
4074 fz_catch(ctx)
4075 rethrow(J);
4076
4077 js_pushstring(J, contents);
4078}
4079
4080static void ffi_PDFAnnotation_setContents(js_State *J)
4081{
4082 fz_context *ctx = js_getcontext(J);
4083 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4084 const char *contents = js_tostring(J, 1);
4085 fz_try(ctx)
4086 pdf_set_annot_contents(ctx, annot, contents);
4087 fz_catch(ctx)
4088 rethrow(J);
4089}
4090
4091static void ffi_PDFAnnotation_getRect(js_State *J)
4092{
4093 fz_context *ctx = js_getcontext(J);
4094 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4095 fz_rect rect;
4096 fz_try(ctx)
4097 rect = pdf_annot_rect(ctx, annot);
4098 fz_catch(ctx)
4099 rethrow(J);
4100 ffi_pushrect(J, rect);
4101}
4102
4103static void ffi_PDFAnnotation_setRect(js_State *J)
4104{
4105 fz_context *ctx = js_getcontext(J);
4106 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4107 fz_rect rect = ffi_torect(J, 1);
4108 fz_try(ctx)
4109 pdf_set_annot_rect(ctx, annot, rect);
4110 fz_catch(ctx)
4111 rethrow(J);
4112}
4113
4114static void ffi_PDFAnnotation_getBorder(js_State *J)
4115{
4116 fz_context *ctx = js_getcontext(J);
4117 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4118 float border = 0;
4119 fz_try(ctx)
4120 border = pdf_annot_border(ctx, annot);
4121 fz_catch(ctx)
4122 rethrow(J);
4123 js_pushnumber(J, border);
4124}
4125
4126static void ffi_PDFAnnotation_setBorder(js_State *J)
4127{
4128 fz_context *ctx = js_getcontext(J);
4129 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4130 float border = js_tonumber(J, 1);
4131 fz_try(ctx)
4132 pdf_set_annot_border(ctx, annot, border);
4133 fz_catch(ctx)
4134 rethrow(J);
4135}
4136
4137static void ffi_PDFAnnotation_getColor(js_State *J)
4138{
4139 fz_context *ctx = js_getcontext(J);
4140 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4141 int i, n = 0;
4142 float color[4];
4143 fz_try(ctx)
4144 pdf_annot_color(ctx, annot, &n, color);
4145 fz_catch(ctx)
4146 rethrow(J);
4147 js_newarray(J);
4148 for (i = 0; i < n; ++i) {
4149 js_pushnumber(J, color[i]);
4150 js_setindex(J, -2, i);
4151 }
4152}
4153
4154static void ffi_PDFAnnotation_setColor(js_State *J)
4155{
4156 fz_context *ctx = js_getcontext(J);
4157 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4158 int i, n = js_getlength(J, 1);
4159 float color[4];
4160 for (i = 0; i < n && i < 4; ++i) {
4161 js_getindex(J, 1, i);
4162 color[i] = js_tonumber(J, -1);
4163 js_pop(J, 1);
4164 }
4165 fz_try(ctx)
4166 pdf_set_annot_color(ctx, annot, n, color);
4167 fz_catch(ctx)
4168 rethrow(J);
4169}
4170
4171static void ffi_PDFAnnotation_getInteriorColor(js_State *J)
4172{
4173 fz_context *ctx = js_getcontext(J);
4174 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4175 int i, n = 0;
4176 float color[4];
4177 fz_try(ctx)
4178 pdf_annot_interior_color(ctx, annot, &n, color);
4179 fz_catch(ctx)
4180 rethrow(J);
4181 js_newarray(J);
4182 for (i = 0; i < n; ++i) {
4183 js_pushnumber(J, color[i]);
4184 js_setindex(J, -2, i);
4185 }
4186}
4187
4188static void ffi_PDFAnnotation_setInteriorColor(js_State *J)
4189{
4190 fz_context *ctx = js_getcontext(J);
4191 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4192 int i, n = js_getlength(J, 1);
4193 float color[4];
4194 for (i = 0; i < n && i < 4; ++i) {
4195 js_getindex(J, 1, i);
4196 color[i] = js_tonumber(J, -1);
4197 js_pop(J, 1);
4198 }
4199 fz_try(ctx)
4200 pdf_set_annot_interior_color(ctx, annot, n, color);
4201 fz_catch(ctx)
4202 rethrow(J);
4203}
4204
4205static void ffi_PDFAnnotation_getQuadPoints(js_State *J)
4206{
4207 fz_context *ctx = js_getcontext(J);
4208 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4209 float qp[8] = { 0 };
4210 int i, k, n = 0;
4211
4212 fz_try(ctx)
4213 n = pdf_annot_quad_point_count(ctx, annot);
4214 fz_catch(ctx)
4215 rethrow(J);
4216
4217 js_newarray(J);
4218 for (i = 0; i < n; ++i) {
4219 fz_try(ctx)
4220 pdf_annot_quad_point(ctx, annot, i, qp);
4221 fz_catch(ctx)
4222 rethrow(J);
4223 js_newarray(J);
4224 for (k = 0; k < 8; ++k) {
4225 js_pushnumber(J, qp[k]);
4226 js_setindex(J, -2, k);
4227 }
4228 js_setindex(J, -2, i);
4229 }
4230}
4231
4232static void ffi_PDFAnnotation_setQuadPoints(js_State *J)
4233{
4234 fz_context *ctx = js_getcontext(J);
4235 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4236 float *qp = NULL;
4237 int k, i, n;
4238
4239 n = js_getlength(J, 1);
4240
4241 fz_try(ctx)
4242 qp = fz_malloc(ctx, n * 8 * sizeof *qp);
4243 fz_catch(ctx)
4244 rethrow(J);
4245
4246 for (i = 0; i < n; ++i) {
4247 js_getindex(J, 1, i);
4248 for (k = 0; k < 8; ++k) {
4249 js_getindex(J, -1, k);
4250 qp[i * 8 + k] = js_tonumber(J, -1);
4251 js_pop(J, 1);
4252 }
4253 js_pop(J, 1);
4254 }
4255
4256 fz_try(ctx)
4257 pdf_set_annot_quad_points(ctx, annot, n, qp);
4258 fz_always(ctx)
4259 fz_free(ctx, qp);
4260 fz_catch(ctx)
4261 rethrow(J);
4262}
4263
4264static void ffi_PDFAnnotation_getInkList(js_State *J)
4265{
4266 fz_context *ctx = js_getcontext(J);
4267 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4268 int i, k, m = 0, n = 0;
4269 fz_point pt;
4270
4271 js_newarray(J);
4272
4273 fz_try(ctx)
4274 n = pdf_annot_ink_list_count(ctx, annot);
4275 fz_catch(ctx)
4276 rethrow(J);
4277
4278 for (i = 0; i < n; ++i) {
4279 fz_try(ctx)
4280 m = pdf_annot_ink_list_stroke_count(ctx, annot, i);
4281 fz_catch(ctx)
4282 rethrow(J);
4283
4284 js_newarray(J);
4285 for (k = 0; k < m; ++k) {
4286 fz_try(ctx)
4287 pt = pdf_annot_ink_list_stroke_vertex(ctx, annot, i, k);
4288 fz_catch(ctx)
4289 rethrow(J);
4290 js_pushnumber(J, pt.x);
4291 js_setindex(J, -2, k * 2 + 0);
4292 js_pushnumber(J, pt.y);
4293 js_setindex(J, -2, k * 2 + 1);
4294 }
4295 js_setindex(J, -2, i);
4296 }
4297}
4298
4299static void ffi_PDFAnnotation_setInkList(js_State *J)
4300{
4301 fz_context *ctx = js_getcontext(J);
4302 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4303 fz_point *points = NULL;
4304 int *counts = NULL;
4305 int n, nv, k, i, v;
4306
4307 fz_var(counts);
4308 fz_var(points);
4309
4310 n = js_getlength(J, 1);
4311 nv = 0;
4312 for (i = 0; i < n; ++i) {
4313 js_getindex(J, 1, i);
4314 nv += js_getlength(J, -1) / 2;
4315 js_pop(J, 1);
4316 }
4317
4318 fz_try(ctx) {
4319 counts = fz_malloc(ctx, n * sizeof(int));
4320 points = fz_malloc(ctx, nv * sizeof(fz_point));
4321 } fz_catch(ctx) {
4322 fz_free(ctx, counts);
4323 fz_free(ctx, points);
4324 rethrow(J);
4325 }
4326
4327 if (js_try(J)) {
4328 fz_free(ctx, counts);
4329 fz_free(ctx, points);
4330 js_throw(J);
4331 }
4332 for (i = v = 0; i < n; ++i) {
4333 js_getindex(J, 1, i);
4334 counts[i] = js_getlength(J, -1) / 2;
4335 for (k = 0; k < counts[i]; ++k) {
4336 js_getindex(J, -1, k*2);
4337 points[v].x = js_tonumber(J, -1);
4338 js_pop(J, 1);
4339 js_getindex(J, -1, k*2+1);
4340 points[v].y = js_tonumber(J, -1);
4341 js_pop(J, 1);
4342 ++v;
4343 }
4344 js_pop(J, 1);
4345 }
4346 js_endtry(J);
4347
4348 fz_try(ctx)
4349 pdf_set_annot_ink_list(ctx, annot, n, counts, points);
4350 fz_always(ctx) {
4351 fz_free(ctx, counts);
4352 fz_free(ctx, points);
4353 }
4354 fz_catch(ctx)
4355 rethrow(J);
4356}
4357
4358static void ffi_PDFAnnotation_getAuthor(js_State *J)
4359{
4360 fz_context *ctx = js_getcontext(J);
4361 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4362 const char *author = NULL;
4363
4364 fz_try(ctx)
4365 author = pdf_annot_author(ctx, annot);
4366 fz_catch(ctx)
4367 rethrow(J);
4368
4369 js_pushstring(J, author);
4370}
4371
4372static void ffi_PDFAnnotation_setAuthor(js_State *J)
4373{
4374 fz_context *ctx = js_getcontext(J);
4375 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4376 const char *author = js_tostring(J, 1);
4377
4378 fz_try(ctx)
4379 pdf_set_annot_author(ctx, annot, author);
4380 fz_catch(ctx)
4381 rethrow(J);
4382}
4383
4384static void ffi_PDFAnnotation_getModificationDate(js_State *J)
4385{
4386 fz_context *ctx = js_getcontext(J);
4387 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4388 double time;
4389
4390 fz_try(ctx)
4391 time = pdf_annot_modification_date(ctx, annot);
4392 fz_catch(ctx)
4393 rethrow(J);
4394
4395 js_getglobal(J, "Date");
4396 js_pushnumber(J, time * 1000);
4397 js_construct(J, 1);
4398}
4399
4400static void ffi_PDFAnnotation_setModificationDate(js_State *J)
4401{
4402 fz_context *ctx = js_getcontext(J);
4403 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4404 double time = js_tonumber(J, 1);
4405
4406 fz_try(ctx)
4407 pdf_set_annot_modification_date(ctx, annot, time / 1000);
4408 fz_catch(ctx)
4409 rethrow(J);
4410}
4411
4412static void ffi_PDFAnnotation_updateAppearance(js_State *J)
4413{
4414 fz_context *ctx = js_getcontext(J);
4415 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4416 fz_try(ctx)
4417 pdf_update_appearance(ctx, annot);
4418 fz_catch(ctx)
4419 rethrow(J);
4420}
4421
4422static void ffi_PDFAnnotation_update(js_State *J)
4423{
4424 fz_context *ctx = js_getcontext(J);
4425 pdf_annot *annot = js_touserdata(J, 0, "pdf_annot");
4426 int changed = 0;
4427 fz_try(ctx)
4428 changed = pdf_update_annot(ctx, annot);
4429 fz_catch(ctx)
4430 rethrow(J);
4431 js_pushboolean(J, changed);
4432}
4433
4434#endif /* FZ_ENABLE_PDF */
4435
4436int murun_main(int argc, char **argv)
4437{
4438 fz_context *ctx;
4439 js_State *J;
4440 int i;
4441
4442 ctx = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED);
4443 fz_register_document_handlers(ctx);
4444
4445 J = js_newstate(alloc, ctx, JS_STRICT);
4446 js_setcontext(J, ctx);
4447
4448 /* standard command line javascript functions */
4449
4450 js_newcfunction(J, jsB_gc, "gc", 0);
4451 js_setglobal(J, "gc");
4452
4453 js_newcfunction(J, jsB_load, "load", 1);
4454 js_setglobal(J, "load");
4455
4456 js_newcfunction(J, jsB_print, "print", 1);
4457 js_setglobal(J, "print");
4458
4459 js_newcfunction(J, jsB_write, "write", 0);
4460 js_setglobal(J, "write");
4461
4462 js_newcfunction(J, jsB_read, "read", 1);
4463 js_setglobal(J, "read");
4464
4465 js_newcfunction(J, jsB_readline, "readline", 0);
4466 js_setglobal(J, "readline");
4467
4468 js_newcfunction(J, jsB_repr, "repr", 1);
4469 js_setglobal(J, "repr");
4470
4471 js_newcfunction(J, jsB_quit, "quit", 1);
4472 js_setglobal(J, "quit");
4473
4474 js_dostring(J, require_js);
4475 js_dostring(J, stacktrace_js);
4476
4477 /* mupdf module */
4478
4479 /* Create superclass for all userdata objects */
4480 js_dostring(J, "function Userdata() { throw new Error('Userdata is not callable'); }");
4481 js_getglobal(J, "Userdata");
4482 js_getproperty(J, -1, "prototype");
4483 js_setregistry(J, "Userdata");
4484 js_pop(J, 1);
4485
4486 js_getregistry(J, "Userdata");
4487 js_newobjectx(J);
4488 {
4489 jsB_propfun(J, "Buffer.writeByte", ffi_Buffer_writeByte, 1);
4490 jsB_propfun(J, "Buffer.writeRune", ffi_Buffer_writeRune, 1);
4491 jsB_propfun(J, "Buffer.writeLine", ffi_Buffer_writeLine, 1);
4492 jsB_propfun(J, "Buffer.writeBuffer", ffi_Buffer_writeBuffer, 1);
4493 jsB_propfun(J, "Buffer.write", ffi_Buffer_write, 1);
4494 jsB_propfun(J, "Buffer.save", ffi_Buffer_save, 1);
4495 }
4496 js_setregistry(J, "fz_buffer");
4497
4498 js_getregistry(J, "Userdata");
4499 js_newobjectx(J);
4500 {
4501 jsB_propfun(J, "Document.isPDF", ffi_Document_isPDF, 0);
4502 jsB_propfun(J, "Document.needsPassword", ffi_Document_needsPassword, 0);
4503 jsB_propfun(J, "Document.authenticatePassword", ffi_Document_authenticatePassword, 1);
4504 //jsB_propfun(J, "Document.hasPermission", ffi_Document_hasPermission, 1);
4505 jsB_propfun(J, "Document.getMetaData", ffi_Document_getMetaData, 1);
4506 jsB_propfun(J, "Document.isReflowable", ffi_Document_isReflowable, 0);
4507 jsB_propfun(J, "Document.layout", ffi_Document_layout, 3);
4508 jsB_propfun(J, "Document.countPages", ffi_Document_countPages, 0);
4509 jsB_propfun(J, "Document.loadPage", ffi_Document_loadPage, 1);
4510 jsB_propfun(J, "Document.loadOutline", ffi_Document_loadOutline, 0);
4511 }
4512 js_setregistry(J, "fz_document");
4513
4514 js_getregistry(J, "Userdata");
4515 js_newobjectx(J);
4516 {
4517 jsB_propfun(J, "Page.isPDF", ffi_Page_isPDF, 0);
4518 jsB_propfun(J, "Page.bound", ffi_Page_bound, 0);
4519 jsB_propfun(J, "Page.run", ffi_Page_run, 3);
4520 jsB_propfun(J, "Page.toPixmap", ffi_Page_toPixmap, 4);
4521 jsB_propfun(J, "Page.toDisplayList", ffi_Page_toDisplayList, 1);
4522 jsB_propfun(J, "Page.toStructuredText", ffi_Page_toStructuredText, 1);
4523 jsB_propfun(J, "Page.search", ffi_Page_search, 0);
4524 jsB_propfun(J, "Page.getLinks", ffi_Page_getLinks, 0);
4525 }
4526 js_setregistry(J, "fz_page");
4527
4528 js_getregistry(J, "Userdata");
4529 js_newobjectx(J);
4530 {
4531 jsB_propfun(J, "Device.close", ffi_Device_close, 0);
4532
4533 jsB_propfun(J, "Device.fillPath", ffi_Device_fillPath, 7);
4534 jsB_propfun(J, "Device.strokePath", ffi_Device_strokePath, 7);
4535 jsB_propfun(J, "Device.clipPath", ffi_Device_clipPath, 3);
4536 jsB_propfun(J, "Device.clipStrokePath", ffi_Device_clipStrokePath, 3);
4537
4538 jsB_propfun(J, "Device.fillText", ffi_Device_fillText, 6);
4539 jsB_propfun(J, "Device.strokeText", ffi_Device_strokeText, 7);
4540 jsB_propfun(J, "Device.clipText", ffi_Device_clipText, 2);
4541 jsB_propfun(J, "Device.clipStrokeText", ffi_Device_clipStrokeText, 3);
4542 jsB_propfun(J, "Device.ignoreText", ffi_Device_ignoreText, 2);
4543
4544 jsB_propfun(J, "Device.fillShade", ffi_Device_fillShade, 4);
4545 jsB_propfun(J, "Device.fillImage", ffi_Device_fillImage, 4);
4546 jsB_propfun(J, "Device.fillImageMask", ffi_Device_fillImageMask, 6);
4547 jsB_propfun(J, "Device.clipImageMask", ffi_Device_clipImageMask, 2);
4548
4549 jsB_propfun(J, "Device.popClip", ffi_Device_popClip, 0);
4550
4551 jsB_propfun(J, "Device.beginMask", ffi_Device_beginMask, 6);
4552 jsB_propfun(J, "Device.endMask", ffi_Device_endMask, 0);
4553 jsB_propfun(J, "Device.beginGroup", ffi_Device_beginGroup, 5);
4554 jsB_propfun(J, "Device.endGroup", ffi_Device_endGroup, 0);
4555 jsB_propfun(J, "Device.beginTile", ffi_Device_beginTile, 6);
4556 jsB_propfun(J, "Device.endTile", ffi_Device_endTile, 0);
4557
4558 jsB_propfun(J, "Device.beginLayer", ffi_Device_beginLayer, 1);
4559 jsB_propfun(J, "Device.endLayer", ffi_Device_endLayer, 0);
4560 }
4561 js_setregistry(J, "fz_device");
4562
4563 js_getregistry(J, "Userdata");
4564 js_newobjectx(J);
4565 {
4566 jsB_propfun(J, "ColorSpace.getNumberOfComponents", ffi_ColorSpace_getNumberOfComponents, 0);
4567 jsB_propfun(J, "ColorSpace.toString", ffi_ColorSpace_toString, 0);
4568 }
4569 js_setregistry(J, "fz_colorspace");
4570 {
4571 js_getregistry(J, "fz_colorspace");
4572 js_newuserdata(J, "fz_colorspace", fz_keep_colorspace(ctx, fz_device_gray(ctx)), ffi_gc_fz_colorspace);
4573 js_setregistry(J, "DeviceGray");
4574
4575 js_getregistry(J, "fz_colorspace");
4576 js_newuserdata(J, "fz_colorspace", fz_keep_colorspace(ctx, fz_device_rgb(ctx)), ffi_gc_fz_colorspace);
4577 js_setregistry(J, "DeviceRGB");
4578
4579 js_getregistry(J, "fz_colorspace");
4580 js_newuserdata(J, "fz_colorspace", fz_keep_colorspace(ctx, fz_device_bgr(ctx)), ffi_gc_fz_colorspace);
4581 js_setregistry(J, "DeviceBGR");
4582
4583 js_getregistry(J, "fz_colorspace");
4584 js_newuserdata(J, "fz_colorspace", fz_keep_colorspace(ctx, fz_device_cmyk(ctx)), ffi_gc_fz_colorspace);
4585 js_setregistry(J, "DeviceCMYK");
4586 }
4587
4588 js_getregistry(J, "Userdata");
4589 js_newobjectx(J);
4590 {
4591 jsB_propfun(J, "Shade.bound", ffi_Shade_bound, 1);
4592 }
4593 js_setregistry(J, "fz_shade");
4594
4595 js_getregistry(J, "Userdata");
4596 js_newobjectx(J);
4597 {
4598 jsB_propfun(J, "Image.getWidth", ffi_Image_getWidth, 0);
4599 jsB_propfun(J, "Image.getHeight", ffi_Image_getHeight, 0);
4600 jsB_propfun(J, "Image.getColorSpace", ffi_Image_getColorSpace, 0);
4601 jsB_propfun(J, "Image.getXResolution", ffi_Image_getXResolution, 0);
4602 jsB_propfun(J, "Image.getYResolution", ffi_Image_getYResolution, 0);
4603 jsB_propfun(J, "Image.getNumberOfComponents", ffi_Image_getNumberOfComponents, 0);
4604 jsB_propfun(J, "Image.getBitsPerComponent", ffi_Image_getBitsPerComponent, 0);
4605 jsB_propfun(J, "Image.getInterpolate", ffi_Image_getInterpolate, 0);
4606 jsB_propfun(J, "Image.getImageMask", ffi_Image_getImageMask, 0);
4607 jsB_propfun(J, "Image.getMask", ffi_Image_getMask, 0);
4608 jsB_propfun(J, "Image.toPixmap", ffi_Image_toPixmap, 2);
4609 }
4610 js_setregistry(J, "fz_image");
4611
4612 js_getregistry(J, "Userdata");
4613 js_newobjectx(J);
4614 {
4615 jsB_propfun(J, "Font.getName", ffi_Font_getName, 0);
4616 jsB_propfun(J, "Font.encodeCharacter", ffi_Font_encodeCharacter, 1);
4617 jsB_propfun(J, "Font.advanceGlyph", ffi_Font_advanceGlyph, 2);
4618 }
4619 js_setregistry(J, "fz_font");
4620
4621 js_getregistry(J, "Userdata");
4622 js_newobjectx(J);
4623 {
4624 jsB_propfun(J, "Text.walk", ffi_Text_walk, 1);
4625 jsB_propfun(J, "Text.showGlyph", ffi_Text_showGlyph, 5);
4626 jsB_propfun(J, "Text.showString", ffi_Text_showString, 4);
4627 }
4628 js_setregistry(J, "fz_text");
4629
4630 js_getregistry(J, "Userdata");
4631 js_newobjectx(J);
4632 {
4633 jsB_propfun(J, "Path.walk", ffi_Path_walk, 1);
4634 jsB_propfun(J, "Path.moveTo", ffi_Path_moveTo, 2);
4635 jsB_propfun(J, "Path.lineTo", ffi_Path_lineTo, 2);
4636 jsB_propfun(J, "Path.curveTo", ffi_Path_curveTo, 6);
4637 jsB_propfun(J, "Path.curveToV", ffi_Path_curveToV, 4);
4638 jsB_propfun(J, "Path.curveToY", ffi_Path_curveToY, 4);
4639 jsB_propfun(J, "Path.closePath", ffi_Path_closePath, 0);
4640 jsB_propfun(J, "Path.rect", ffi_Path_rect, 4);
4641 jsB_propfun(J, "Path.bound", ffi_Path_bound, 2);
4642 jsB_propfun(J, "Path.transform", ffi_Path_transform, 1);
4643 }
4644 js_setregistry(J, "fz_path");
4645
4646 js_getregistry(J, "Userdata");
4647 js_newobjectx(J);
4648 {
4649 jsB_propfun(J, "DisplayList.run", ffi_DisplayList_run, 2);
4650 jsB_propfun(J, "DisplayList.toPixmap", ffi_DisplayList_toPixmap, 3);
4651 jsB_propfun(J, "DisplayList.toStructuredText", ffi_DisplayList_toStructuredText, 1);
4652 jsB_propfun(J, "DisplayList.search", ffi_DisplayList_search, 1);
4653 }
4654 js_setregistry(J, "fz_display_list");
4655
4656 js_getregistry(J, "Userdata");
4657 js_newobjectx(J);
4658 {
4659 jsB_propfun(J, "StructuredText.search", ffi_StructuredText_search, 1);
4660 jsB_propfun(J, "StructuredText.highlight", ffi_StructuredText_highlight, 2);
4661 jsB_propfun(J, "StructuredText.copy", ffi_StructuredText_copy, 2);
4662 }
4663 js_setregistry(J, "fz_stext_page");
4664
4665 js_getregistry(J, "Userdata");
4666 js_newobjectx(J);
4667 {
4668 jsB_propfun(J, "Pixmap.bound", ffi_Pixmap_bound, 0);
4669 jsB_propfun(J, "Pixmap.clear", ffi_Pixmap_clear, 1);
4670
4671 jsB_propfun(J, "Pixmap.getX", ffi_Pixmap_getX, 0);
4672 jsB_propfun(J, "Pixmap.getY", ffi_Pixmap_getY, 0);
4673 jsB_propfun(J, "Pixmap.getWidth", ffi_Pixmap_getWidth, 0);
4674 jsB_propfun(J, "Pixmap.getHeight", ffi_Pixmap_getHeight, 0);
4675 jsB_propfun(J, "Pixmap.getNumberOfComponents", ffi_Pixmap_getNumberOfComponents, 0);
4676 jsB_propfun(J, "Pixmap.getAlpha", ffi_Pixmap_getAlpha, 0);
4677 jsB_propfun(J, "Pixmap.getStride", ffi_Pixmap_getStride, 0);
4678 jsB_propfun(J, "Pixmap.getColorSpace", ffi_Pixmap_getColorSpace, 0);
4679 jsB_propfun(J, "Pixmap.getXResolution", ffi_Pixmap_getXResolution, 0);
4680 jsB_propfun(J, "Pixmap.getYResolution", ffi_Pixmap_getYResolution, 0);
4681 jsB_propfun(J, "Pixmap.getSample", ffi_Pixmap_getSample, 3);
4682
4683 // Pixmap.samples()
4684 // Pixmap.invert
4685 // Pixmap.tint
4686 // Pixmap.gamma
4687 // Pixmap.scale()
4688
4689 jsB_propfun(J, "Pixmap.saveAsPNG", ffi_Pixmap_saveAsPNG, 1);
4690 // Pixmap.saveAsPNM, PAM, PWG, PCL
4691
4692 // Pixmap.halftone() -> Bitmap
4693 // Pixmap.md5()
4694 }
4695 js_setregistry(J, "fz_pixmap");
4696
4697 js_getregistry(J, "Userdata");
4698 js_newobjectx(J);
4699 {
4700 jsB_propfun(J, "DocumentWriter.beginPage", ffi_DocumentWriter_beginPage, 1);
4701 jsB_propfun(J, "DocumentWriter.endPage", ffi_DocumentWriter_endPage, 0);
4702 jsB_propfun(J, "DocumentWriter.close", ffi_DocumentWriter_close, 0);
4703 }
4704 js_setregistry(J, "fz_document_writer");
4705
4706#if FZ_ENABLE_PDF
4707 js_getregistry(J, "fz_document");
4708 js_newobjectx(J);
4709 {
4710 jsB_propfun(J, "PDFDocument.getTrailer", ffi_PDFDocument_getTrailer, 0);
4711 jsB_propfun(J, "PDFDocument.countObjects", ffi_PDFDocument_countObjects, 0);
4712 jsB_propfun(J, "PDFDocument.createObject", ffi_PDFDocument_createObject, 0);
4713 jsB_propfun(J, "PDFDocument.deleteObject", ffi_PDFDocument_deleteObject, 1);
4714 jsB_propfun(J, "PDFDocument.addObject", ffi_PDFDocument_addObject, 1);
4715 jsB_propfun(J, "PDFDocument.addStream", ffi_PDFDocument_addStream, 2);
4716 jsB_propfun(J, "PDFDocument.addRawStream", ffi_PDFDocument_addRawStream, 2);
4717 jsB_propfun(J, "PDFDocument.addSimpleFont", ffi_PDFDocument_addSimpleFont, 2);
4718 jsB_propfun(J, "PDFDocument.addCJKFont", ffi_PDFDocument_addCJKFont, 4);
4719 jsB_propfun(J, "PDFDocument.addFont", ffi_PDFDocument_addFont, 1);
4720 jsB_propfun(J, "PDFDocument.addImage", ffi_PDFDocument_addImage, 1);
4721 jsB_propfun(J, "PDFDocument.loadImage", ffi_PDFDocument_loadImage, 1);
4722 jsB_propfun(J, "PDFDocument.addPage", ffi_PDFDocument_addPage, 4);
4723 jsB_propfun(J, "PDFDocument.insertPage", ffi_PDFDocument_insertPage, 2);
4724 jsB_propfun(J, "PDFDocument.deletePage", ffi_PDFDocument_deletePage, 1);
4725 jsB_propfun(J, "PDFDocument.countPages", ffi_PDFDocument_countPages, 0);
4726 jsB_propfun(J, "PDFDocument.findPage", ffi_PDFDocument_findPage, 1);
4727 jsB_propfun(J, "PDFDocument.save", ffi_PDFDocument_save, 2);
4728
4729 jsB_propfun(J, "PDFDocument.newNull", ffi_PDFDocument_newNull, 0);
4730 jsB_propfun(J, "PDFDocument.newBoolean", ffi_PDFDocument_newBoolean, 1);
4731 jsB_propfun(J, "PDFDocument.newInteger", ffi_PDFDocument_newInteger, 1);
4732 jsB_propfun(J, "PDFDocument.newReal", ffi_PDFDocument_newReal, 1);
4733 jsB_propfun(J, "PDFDocument.newString", ffi_PDFDocument_newString, 1);
4734 jsB_propfun(J, "PDFDocument.newByteString", ffi_PDFDocument_newByteString, 1);
4735 jsB_propfun(J, "PDFDocument.newName", ffi_PDFDocument_newName, 1);
4736 jsB_propfun(J, "PDFDocument.newIndirect", ffi_PDFDocument_newIndirect, 2);
4737 jsB_propfun(J, "PDFDocument.newArray", ffi_PDFDocument_newArray, 1);
4738 jsB_propfun(J, "PDFDocument.newDictionary", ffi_PDFDocument_newDictionary, 1);
4739
4740 jsB_propfun(J, "PDFDocument.newGraftMap", ffi_PDFDocument_newGraftMap, 0);
4741 jsB_propfun(J, "PDFDocument.graftObject", ffi_PDFDocument_graftObject, 1);
4742 }
4743 js_setregistry(J, "pdf_document");
4744
4745 js_getregistry(J, "fz_page");
4746 js_newobjectx(J);
4747 {
4748 jsB_propfun(J, "PDFPage.getAnnotations", ffi_PDFPage_getAnnotations, 0);
4749 jsB_propfun(J, "PDFPage.createAnnotation", ffi_PDFPage_createAnnotation, 1);
4750 jsB_propfun(J, "PDFPage.deleteAnnotation", ffi_PDFPage_deleteAnnotation, 1);
4751 jsB_propfun(J, "PDFPage.update", ffi_PDFPage_update, 0);
4752 }
4753 js_setregistry(J, "pdf_page");
4754
4755 js_getregistry(J, "Userdata");
4756 js_newobjectx(J);
4757 {
4758 jsB_propfun(J, "PDFAnnotation.bound", ffi_PDFAnnotation_bound, 0);
4759 jsB_propfun(J, "PDFAnnotation.run", ffi_PDFAnnotation_run, 2);
4760 jsB_propfun(J, "PDFAnnotation.toPixmap", ffi_PDFAnnotation_toPixmap, 3);
4761 jsB_propfun(J, "PDFAnnotation.toDisplayList", ffi_PDFAnnotation_toDisplayList, 0);
4762 jsB_propfun(J, "PDFAnnotation.getType", ffi_PDFAnnotation_getType, 0);
4763 jsB_propfun(J, "PDFAnnotation.getFlags", ffi_PDFAnnotation_getFlags, 0);
4764 jsB_propfun(J, "PDFAnnotation.setFlags", ffi_PDFAnnotation_setFlags, 1);
4765 jsB_propfun(J, "PDFAnnotation.getContents", ffi_PDFAnnotation_getContents, 0);
4766 jsB_propfun(J, "PDFAnnotation.setContents", ffi_PDFAnnotation_setContents, 1);
4767 jsB_propfun(J, "PDFAnnotation.getRect", ffi_PDFAnnotation_getRect, 0);
4768 jsB_propfun(J, "PDFAnnotation.setRect", ffi_PDFAnnotation_setRect, 1);
4769 jsB_propfun(J, "PDFAnnotation.getBorder", ffi_PDFAnnotation_getBorder, 0);
4770 jsB_propfun(J, "PDFAnnotation.setBorder", ffi_PDFAnnotation_setBorder, 1);
4771 jsB_propfun(J, "PDFAnnotation.getColor", ffi_PDFAnnotation_getColor, 0);
4772 jsB_propfun(J, "PDFAnnotation.setColor", ffi_PDFAnnotation_setColor, 1);
4773 jsB_propfun(J, "PDFAnnotation.getInteriorColor", ffi_PDFAnnotation_getInteriorColor, 0);
4774 jsB_propfun(J, "PDFAnnotation.setInteriorColor", ffi_PDFAnnotation_setInteriorColor, 1);
4775 jsB_propfun(J, "PDFAnnotation.getQuadPoints", ffi_PDFAnnotation_getQuadPoints, 0);
4776 jsB_propfun(J, "PDFAnnotation.setQuadPoints", ffi_PDFAnnotation_setQuadPoints, 1);
4777 jsB_propfun(J, "PDFAnnotation.getInkList", ffi_PDFAnnotation_getInkList, 0);
4778 jsB_propfun(J, "PDFAnnotation.setInkList", ffi_PDFAnnotation_setInkList, 1);
4779 jsB_propfun(J, "PDFAnnotation.getAuthor", ffi_PDFAnnotation_getAuthor, 0);
4780 jsB_propfun(J, "PDFAnnotation.setAuthor", ffi_PDFAnnotation_setAuthor, 1);
4781 jsB_propfun(J, "PDFAnnotation.getModificationDate", ffi_PDFAnnotation_getModificationDate, 0);
4782 jsB_propfun(J, "PDFAnnotation.setModificationDate", ffi_PDFAnnotation_setModificationDate, 0);
4783 jsB_propfun(J, "PDFAnnotation.updateAppearance", ffi_PDFAnnotation_updateAppearance, 0);
4784 jsB_propfun(J, "PDFAnnotation.update", ffi_PDFAnnotation_update, 0);
4785 }
4786 js_setregistry(J, "pdf_annot");
4787
4788 js_getregistry(J, "Userdata");
4789 js_newobjectx(J);
4790 {
4791 jsB_propfun(J, "PDFObject.get", ffi_PDFObject_get, 1);
4792 jsB_propfun(J, "PDFObject.put", ffi_PDFObject_put, 2);
4793 jsB_propfun(J, "PDFObject.push", ffi_PDFObject_push, 1);
4794 jsB_propfun(J, "PDFObject.delete", ffi_PDFObject_delete, 1);
4795 jsB_propfun(J, "PDFObject.resolve", ffi_PDFObject_resolve, 0);
4796 jsB_propfun(J, "PDFObject.toString", ffi_PDFObject_toString, 2);
4797 jsB_propfun(J, "PDFObject.valueOf", ffi_PDFObject_valueOf, 0);
4798 jsB_propfun(J, "PDFObject.isArray", ffi_PDFObject_isArray, 0);
4799 jsB_propfun(J, "PDFObject.isDictionary", ffi_PDFObject_isDictionary, 0);
4800 jsB_propfun(J, "PDFObject.isIndirect", ffi_PDFObject_isIndirect, 0);
4801 jsB_propfun(J, "PDFObject.asIndirect", ffi_PDFObject_asIndirect, 0);
4802 jsB_propfun(J, "PDFObject.isNull", ffi_PDFObject_isNull, 0);
4803 jsB_propfun(J, "PDFObject.isBoolean", ffi_PDFObject_isBoolean, 0);
4804 jsB_propfun(J, "PDFObject.asBoolean", ffi_PDFObject_asBoolean, 0);
4805 jsB_propfun(J, "PDFObject.isNumber", ffi_PDFObject_isNumber, 0);
4806 jsB_propfun(J, "PDFObject.asNumber", ffi_PDFObject_asNumber, 0);
4807 jsB_propfun(J, "PDFObject.isName", ffi_PDFObject_isName, 0);
4808 jsB_propfun(J, "PDFObject.asName", ffi_PDFObject_asName, 0);
4809 jsB_propfun(J, "PDFObject.isString", ffi_PDFObject_isString, 0);
4810 jsB_propfun(J, "PDFObject.asString", ffi_PDFObject_asString, 0);
4811 jsB_propfun(J, "PDFObject.asByteString", ffi_PDFObject_asByteString, 0);
4812 jsB_propfun(J, "PDFObject.isStream", ffi_PDFObject_isStream, 0);
4813 jsB_propfun(J, "PDFObject.readStream", ffi_PDFObject_readStream, 0);
4814 jsB_propfun(J, "PDFObject.readRawStream", ffi_PDFObject_readRawStream, 0);
4815 jsB_propfun(J, "PDFObject.writeObject", ffi_PDFObject_writeObject, 1);
4816 jsB_propfun(J, "PDFObject.writeStream", ffi_PDFObject_writeStream, 1);
4817 jsB_propfun(J, "PDFObject.writeRawStream", ffi_PDFObject_writeRawStream, 1);
4818 jsB_propfun(J, "PDFObject.forEach", ffi_PDFObject_forEach, 1);
4819 }
4820 js_setregistry(J, "pdf_obj");
4821
4822 js_getregistry(J, "Userdata");
4823 js_newobjectx(J);
4824 {
4825 jsB_propfun(J, "PDFGraftMap.graftObject", ffi_PDFGraftMap_graftObject, 1);
4826 }
4827 js_setregistry(J, "pdf_graft_map");
4828#endif
4829
4830 js_pushglobal(J);
4831 {
4832#if FZ_ENABLE_PDF
4833 jsB_propcon(J, "pdf_document", "PDFDocument", ffi_new_PDFDocument, 1);
4834#endif
4835
4836 jsB_propcon(J, "fz_buffer", "Buffer", ffi_new_Buffer, 1);
4837 jsB_propcon(J, "fz_document", "Document", ffi_new_Document, 1);
4838 jsB_propcon(J, "fz_pixmap", "Pixmap", ffi_new_Pixmap, 3);
4839 jsB_propcon(J, "fz_image", "Image", ffi_new_Image, 1);
4840 jsB_propcon(J, "fz_font", "Font", ffi_new_Font, 2);
4841 jsB_propcon(J, "fz_text", "Text", ffi_new_Text, 0);
4842 jsB_propcon(J, "fz_path", "Path", ffi_new_Path, 0);
4843 jsB_propcon(J, "fz_display_list", "DisplayList", ffi_new_DisplayList, 1);
4844 jsB_propcon(J, "fz_device", "DrawDevice", ffi_new_DrawDevice, 2);
4845 jsB_propcon(J, "fz_device", "DisplayListDevice", ffi_new_DisplayListDevice, 1);
4846 jsB_propcon(J, "fz_document_writer", "DocumentWriter", ffi_new_DocumentWriter, 3);
4847
4848 jsB_propfun(J, "readFile", ffi_readFile, 1);
4849
4850 js_getregistry(J, "DeviceGray");
4851 js_defproperty(J, -2, "DeviceGray", JS_DONTENUM | JS_READONLY | JS_DONTCONF);
4852
4853 js_getregistry(J, "DeviceRGB");
4854 js_defproperty(J, -2, "DeviceRGB", JS_DONTENUM | JS_READONLY | JS_DONTCONF);
4855
4856 js_getregistry(J, "DeviceBGR");
4857 js_defproperty(J, -2, "DeviceBGR", JS_DONTENUM | JS_READONLY | JS_DONTCONF);
4858
4859 js_getregistry(J, "DeviceCMYK");
4860 js_defproperty(J, -2, "DeviceCMYK", JS_DONTENUM | JS_READONLY | JS_DONTCONF);
4861
4862 jsB_propfun(J, "setUserCSS", ffi_setUserCSS, 2);
4863 }
4864
4865 /* re-implement matrix math in javascript */
4866 js_dostring(J, "var Identity = Object.freeze([1,0,0,1,0,0]);");
4867 js_dostring(J, "function Scale(sx,sy) { return [sx,0,0,sy,0,0]; }");
4868 js_dostring(J, "function Translate(tx,ty) { return [1,0,0,1,tx,ty]; }");
4869 js_dostring(J, "function Concat(a,b) { return ["
4870 "a[0] * b[0] + a[1] * b[2],"
4871 "a[0] * b[1] + a[1] * b[3],"
4872 "a[2] * b[0] + a[3] * b[2],"
4873 "a[2] * b[1] + a[3] * b[3],"
4874 "a[4] * b[0] + a[5] * b[2] + b[4],"
4875 "a[4] * b[1] + a[5] * b[3] + b[5]];}");
4876
4877 if (argc > 1) {
4878 js_pushstring(J, argv[1]);
4879 js_setglobal(J, "scriptPath");
4880 js_newarray(J);
4881 for (i = 2; i < argc; ++i) {
4882 js_pushstring(J, argv[i]);
4883 js_setindex(J, -2, i - 2);
4884 }
4885 js_setglobal(J, "scriptArgs");
4886 if (js_dofile(J, argv[1]))
4887 {
4888 js_freestate(J);
4889 fz_drop_context(ctx);
4890 return 1;
4891 }
4892 } else {
4893 char line[256];
4894 fputs(PS1, stdout);
4895 while (fgets(line, sizeof line, stdin)) {
4896 eval_print(J, line);
4897 fputs(PS1, stdout);
4898 }
4899 putchar('\n');
4900 }
4901
4902 js_freestate(J);
4903 fz_drop_context(ctx);
4904 return 0;
4905}
4906
4907#endif
4908