From 0a927854a10e1e6b9770a81e2e1d9f3093631757 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Wed, 19 Jun 2013 15:29:44 +0200 Subject: Rearrange source files. --- source/pdf/js/pdf-js-none.c | 36 ++ source/pdf/js/pdf-js.c | 919 +++++++++++++++++++++++++++++++++++++++++ source/pdf/js/pdf-jsimp-cpp.c | 225 ++++++++++ source/pdf/js/pdf-jsimp-cpp.h | 29 ++ source/pdf/js/pdf-jsimp-v8.cpp | 476 +++++++++++++++++++++ source/pdf/js/pdf-util.js | 875 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 2560 insertions(+) create mode 100644 source/pdf/js/pdf-js-none.c create mode 100644 source/pdf/js/pdf-js.c create mode 100644 source/pdf/js/pdf-jsimp-cpp.c create mode 100644 source/pdf/js/pdf-jsimp-cpp.h create mode 100644 source/pdf/js/pdf-jsimp-v8.cpp create mode 100644 source/pdf/js/pdf-util.js (limited to 'source/pdf/js') diff --git a/source/pdf/js/pdf-js-none.c b/source/pdf/js/pdf-js-none.c new file mode 100644 index 00000000..00cc5b54 --- /dev/null +++ b/source/pdf/js/pdf-js-none.c @@ -0,0 +1,36 @@ +#include "mupdf/pdf.h" + +pdf_js *pdf_new_js(pdf_document *doc) +{ + return NULL; +} + +void pdf_js_load_document_level(pdf_js *js) +{ +} + +void pdf_drop_js(pdf_js *js) +{ +} + +void pdf_js_setup_event(pdf_js *js, pdf_js_event *e) +{ +} + +pdf_js_event *pdf_js_get_event(pdf_js *js) +{ + return NULL; +} + +void pdf_js_execute(pdf_js *js, char *code) +{ +} + +void pdf_js_execute_count(pdf_js *js, char *code, int count) +{ +} + +int pdf_js_supported(void) +{ + return 0; +} diff --git a/source/pdf/js/pdf-js.c b/source/pdf/js/pdf-js.c new file mode 100644 index 00000000..4a2313f1 --- /dev/null +++ b/source/pdf/js/pdf-js.c @@ -0,0 +1,919 @@ +#include "mupdf/pdf.h" + +struct pdf_js_s +{ + pdf_document *doc; + pdf_obj *form; + pdf_js_event event; + pdf_jsimp *imp; + pdf_jsimp_type *doctype; + pdf_jsimp_type *eventtype; + pdf_jsimp_type *fieldtype; + pdf_jsimp_type *apptype; +}; + +static pdf_jsimp_obj *app_alert(void *jsctx, void *obj, int argc, pdf_jsimp_obj *args[]) +{ + pdf_js *js = (pdf_js *)jsctx; + fz_context *ctx = js->doc->ctx; + pdf_jsimp_obj *cMsg_obj = NULL; + pdf_jsimp_obj *nIcon_obj = NULL; + pdf_jsimp_obj *nType_obj = NULL; + pdf_jsimp_obj *cTitle_obj = NULL; + pdf_jsimp_obj *nButton_obj = NULL; + pdf_alert_event event; + int arg_is_obj = 0; + + if (argc < 1 || argc > 6) + return NULL; + + event.message = ""; + event.icon_type = PDF_ALERT_ICON_ERROR; + event.button_group_type = PDF_ALERT_BUTTON_GROUP_OK; + event.title = "MuPDF"; + event.check_box_message = NULL; + event.button_pressed = 0; + + fz_var(cMsg_obj); + fz_var(nIcon_obj); + fz_var(nType_obj); + fz_var(cTitle_obj); + fz_try(ctx) + { + arg_is_obj = (argc == 1 && pdf_jsimp_to_type(js->imp, args[0]) != JS_TYPE_STRING); + if (arg_is_obj) + { + cMsg_obj = pdf_jsimp_property(js->imp, args[0], "cMsg"); + nIcon_obj = pdf_jsimp_property(js->imp, args[0], "nIcon"); + nType_obj = pdf_jsimp_property(js->imp, args[0], "nType"); + cTitle_obj = pdf_jsimp_property(js->imp, args[0], "cTitle"); + } + else + { + switch (argc) + { + case 6: + case 5: + case 4: + cTitle_obj = args[3]; + case 3: + nType_obj = args[2]; + case 2: + nIcon_obj = args[1]; + case 1: + cMsg_obj = args[0]; + } + } + + if (cMsg_obj) + event.message = pdf_jsimp_to_string(js->imp, cMsg_obj); + + if (nIcon_obj) + event.icon_type = (int)pdf_jsimp_to_number(js->imp, nIcon_obj); + + if (nType_obj) + event.button_group_type = (int)pdf_jsimp_to_number(js->imp, nType_obj); + + if (cTitle_obj) + event.title = pdf_jsimp_to_string(js->imp, cTitle_obj); + + pdf_event_issue_alert(js->doc, &event); + nButton_obj = pdf_jsimp_from_number(js->imp, (double)event.button_pressed); + } + fz_always(ctx) + { + if (arg_is_obj) + { + pdf_jsimp_drop_obj(js->imp, cMsg_obj); + pdf_jsimp_drop_obj(js->imp, nIcon_obj); + pdf_jsimp_drop_obj(js->imp, nType_obj); + pdf_jsimp_drop_obj(js->imp, cTitle_obj); + } + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } + + return nButton_obj; +} + +static pdf_jsimp_obj *app_execDialog(void *jsctx, void *obj, int argc, pdf_jsimp_obj *args[]) +{ + pdf_js *js = (pdf_js *)jsctx; + + pdf_event_issue_exec_dialog(js->doc); + + return NULL; +} + +static pdf_jsimp_obj *app_execMenuItem(void *jsctx, void *obj, int argc, pdf_jsimp_obj *args[]) +{ + pdf_js *js = (pdf_js *)jsctx; + + if (argc == 1) + pdf_event_issue_exec_menu_item(js->doc, pdf_jsimp_to_string(js->imp, args[0])); + + return NULL; +} + +static pdf_jsimp_obj *app_launchURL(void *jsctx, void *obj, int argc, pdf_jsimp_obj *args[]) +{ + pdf_js *js = (pdf_js *)jsctx; + char *cUrl; + int bNewFrame = 0; + + switch (argc) + { + default: + return NULL; + case 2: + bNewFrame = (int)pdf_jsimp_to_number(js->imp, args[1]); + case 1: + cUrl = pdf_jsimp_to_string(js->imp, args[0]); + } + + pdf_event_issue_launch_url(js->doc, cUrl, bNewFrame); + + return NULL; +} + +static pdf_obj *load_color(fz_context *ctx, pdf_jsimp *imp, pdf_jsimp_obj *val) +{ + pdf_obj *col = NULL; + pdf_obj *comp = NULL; + pdf_jsimp_obj *jscomp = NULL; + int i; + int n; + + n = pdf_jsimp_array_len(imp, val); + + /* The only legitimate color expressed as an array of length 1 + * is [T], meaning transparent. Return a NULL object to represent + * transparent */ + if (n <= 1) + return NULL; + + col = pdf_new_array(ctx, n-1); + + fz_var(comp); + fz_var(jscomp); + fz_try(ctx) + { + for (i = 0; i < n-1; i++) + { + jscomp = pdf_jsimp_array_item(imp, val, i+1); + comp = pdf_new_real(ctx, pdf_jsimp_to_number(imp, jscomp)); + pdf_array_push(col, comp); + pdf_jsimp_drop_obj(imp, jscomp); + jscomp = NULL; + pdf_drop_obj(comp); + comp = NULL; + } + } + fz_catch(ctx) + { + pdf_jsimp_drop_obj(imp, jscomp); + pdf_drop_obj(comp); + pdf_drop_obj(col); + fz_rethrow(ctx); + } + + return col; +} + +static pdf_jsimp_obj *field_buttonSetCaption(void *jsctx, void *obj, int argc, pdf_jsimp_obj *args[]) +{ + pdf_js *js = (pdf_js *)jsctx; + pdf_obj *field = (pdf_obj *)obj; + char *name; + + if (argc != 1) + return NULL; + + name = pdf_jsimp_to_string(js->imp, args[0]); + pdf_field_set_button_caption(js->doc, field, name); + + return NULL; +} + +static pdf_jsimp_obj *field_getName(void *jsctx, void *obj) +{ + pdf_js *js = (pdf_js *)jsctx; + fz_context *ctx = js->doc->ctx; + pdf_obj *field = (pdf_obj *)obj; + char *name; + pdf_jsimp_obj *oname = NULL; + + if (field == NULL) + return NULL; + + name = pdf_field_name(js->doc, field); + fz_try(ctx) + { + oname = pdf_jsimp_from_string(js->imp, name); + } + fz_always(ctx) + { + fz_free(ctx, name); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } + + return oname; +} + +static void field_setName(void *jsctx, void *obj, pdf_jsimp_obj *val) +{ + pdf_js *js = (pdf_js *)jsctx; + fz_warn(js->doc->ctx, "Unexpected call to field_setName"); +} + +static pdf_jsimp_obj *field_getDisplay(void *jsctx, void *obj) +{ + pdf_js *js = (pdf_js *)jsctx; + pdf_obj *field = (pdf_obj *)obj; + + return field ? pdf_jsimp_from_number(js->imp, (double)pdf_field_display(js->doc, field)) : NULL; +} + +static void field_setDisplay(void *jsctx, void *obj, pdf_jsimp_obj *val) +{ + pdf_js *js = (pdf_js *)jsctx; + fz_context *ctx = js->doc->ctx; + pdf_obj *field = (pdf_obj *)obj; + + if (field) + pdf_field_set_display(js->doc, field, (int)pdf_jsimp_to_number(js->imp, val)); +} + +static pdf_jsimp_obj *field_getFillColor(void *jsctx, void *obj) +{ + return NULL; +} + +static void field_setFillColor(void *jsctx, void *obj, pdf_jsimp_obj *val) +{ + pdf_js *js = (pdf_js *)jsctx; + fz_context *ctx = js->doc->ctx; + pdf_obj *field = (pdf_obj *)obj; + pdf_obj *col; + + if (!field) + return; + + col = load_color(js->doc->ctx, js->imp, val); + fz_try(ctx) + { + pdf_field_set_fill_color(js->doc, field, col); + } + fz_always(ctx) + { + pdf_drop_obj(col); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } +} + +static pdf_jsimp_obj *field_getTextColor(void *jsctx, void *obj) +{ + return NULL; +} + +static void field_setTextColor(void *jsctx, void *obj, pdf_jsimp_obj *val) +{ + pdf_js *js = (pdf_js *)jsctx; + fz_context *ctx = js->doc->ctx; + pdf_obj *field = (pdf_obj *)obj; + pdf_obj *col; + + if (!field) + return; + + col = load_color(js->doc->ctx, js->imp, val); + fz_try(ctx) + { + pdf_field_set_text_color(js->doc, field, col); + } + fz_always(ctx) + { + pdf_drop_obj(col); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } +} + +static pdf_jsimp_obj *field_getBorderStyle(void *jsctx, void *obj) +{ + pdf_js *js = (pdf_js *)jsctx; + pdf_obj *field = (pdf_obj *)obj; + + return field ? pdf_jsimp_from_string(js->imp, pdf_field_border_style(js->doc, field)) : NULL; +} + +static void field_setBorderStyle(void *jsctx, void *obj, pdf_jsimp_obj *val) +{ + pdf_js *js = (pdf_js *)jsctx; + pdf_obj *field = (pdf_obj *)obj; + + if (field) + pdf_field_set_border_style(js->doc, field, pdf_jsimp_to_string(js->imp, val)); +} + +static pdf_jsimp_obj *field_getValue(void *jsctx, void *obj) +{ + pdf_js *js = (pdf_js *)jsctx; + pdf_obj *field = (pdf_obj *)obj; + char *fval; + + if (!field) + return NULL; + + fval = pdf_field_value(js->doc, field); + return pdf_jsimp_from_string(js->imp, fval?fval:""); +} + +static void field_setValue(void *jsctx, void *obj, pdf_jsimp_obj *val) +{ + pdf_js *js = (pdf_js *)jsctx; + pdf_obj *field = (pdf_obj *)obj; + + if (field) + (void)pdf_field_set_value(js->doc, field, pdf_jsimp_to_string(js->imp, val)); +} + +static pdf_jsimp_obj *event_getTarget(void *jsctx, void *obj) +{ + pdf_js *js = (pdf_js *)jsctx; + + return pdf_jsimp_new_obj(js->imp, js->fieldtype, js->event.target); +} + +static void event_setTarget(void *jsctx, void *obj, pdf_jsimp_obj *val) +{ + pdf_js *js = (pdf_js *)jsctx; + fz_warn(js->doc->ctx, "Unexpected call to event_setTarget"); +} + +static pdf_jsimp_obj *event_getValue(void *jsctx, void *obj) +{ + pdf_js *js = (pdf_js *)jsctx; + char *v = js->event.value; + + return pdf_jsimp_from_string(js->imp, v?v:""); +} + +static void event_setValue(void *jsctx, void *obj, pdf_jsimp_obj *val) +{ + pdf_js *js = (pdf_js *)jsctx; + fz_context *ctx = js->doc->ctx; + fz_free(ctx, js->event.value); + js->event.value = NULL; + js->event.value = fz_strdup(ctx, pdf_jsimp_to_string(js->imp, val)); +} + +static pdf_jsimp_obj *event_getWillCommit(void *jsctx, void *obj) +{ + pdf_js *js = (pdf_js *)jsctx; + + return pdf_jsimp_from_number(js->imp, 1.0); +} + +static void event_setWillCommit(void *jsctx, void *obj, pdf_jsimp_obj *val) +{ + pdf_js *js = (pdf_js *)jsctx; + fz_warn(js->doc->ctx, "Unexpected call to event_setWillCommit"); +} + +static pdf_jsimp_obj *event_getRC(void *jsctx, void *obj) +{ + pdf_js *js = (pdf_js *)jsctx; + + return pdf_jsimp_from_number(js->imp, (double)js->event.rc); +} + +static void event_setRC(void *jsctx, void *obj, pdf_jsimp_obj *val) +{ + pdf_js *js = (pdf_js *)jsctx; + + js->event.rc = (int)pdf_jsimp_to_number(js->imp, val); +} + +static pdf_jsimp_obj *doc_getEvent(void *jsctx, void *obj) +{ + pdf_js *js = (pdf_js *)jsctx; + + return pdf_jsimp_new_obj(js->imp, js->eventtype, &js->event); +} + +static void doc_setEvent(void *jsctx, void *obj, pdf_jsimp_obj *val) +{ + pdf_js *js = (pdf_js *)jsctx; + fz_warn(js->doc->ctx, "Unexpected call to doc_setEvent"); +} + +static pdf_jsimp_obj *doc_getApp(void *jsctx, void *obj) +{ + pdf_js *js = (pdf_js *)jsctx; + + return pdf_jsimp_new_obj(js->imp, js->apptype, NULL); +} + +static void doc_setApp(void *jsctx, void *obj, pdf_jsimp_obj *val) +{ + pdf_js *js = (pdf_js *)jsctx; + fz_warn(js->doc->ctx, "Unexpected call to doc_setApp"); +} + +static char *utf8_to_pdf(fz_context *ctx, char *utf8) +{ + char *pdf = fz_malloc(ctx, strlen(utf8)+1); + int i = 0; + unsigned char c; + + while ((c = *utf8) != 0) + { + if ((c & 0x80) == 0 && pdf_doc_encoding[c] == c) + { + pdf[i++] = c; + utf8++ ; + } + else + { + int rune; + int j; + + utf8 += fz_chartorune(&rune, utf8); + + for (j = 0; j < sizeof(pdf_doc_encoding) && pdf_doc_encoding[j] != rune; j++) + ; + + if (j < sizeof(pdf_doc_encoding)) + pdf[i++] = j; + } + } + + pdf[i] = 0; + + return pdf; +} + +static pdf_jsimp_obj *doc_getField(void *jsctx, void *obj, int argc, pdf_jsimp_obj *args[]) +{ + pdf_js *js = (pdf_js *)jsctx; + fz_context *ctx = js->doc->ctx; + pdf_obj *dict = NULL; + char *utf8; + char *name = NULL; + + if (argc != 1) + return NULL; + + fz_var(dict); + fz_var(name); + fz_try(ctx) + { + utf8 = pdf_jsimp_to_string(js->imp, args[0]); + + if (utf8) + { + name = utf8_to_pdf(ctx, utf8); + dict = pdf_lookup_field(js->form, name); + } + } + fz_always(ctx) + { + fz_free(ctx, name); + } + fz_catch(ctx) + { + /* FIXME: TryLater ? */ + fz_warn(ctx, "doc_getField failed: %s", fz_caught_message(ctx)); + dict = NULL; + } + + return dict ? pdf_jsimp_new_obj(js->imp, js->fieldtype, dict) : NULL; +} + +static void reset_field(pdf_js *js, pdf_jsimp_obj *item) +{ + fz_context *ctx = js->doc->ctx; + char *name = NULL; + char *utf8 = pdf_jsimp_to_string(js->imp, item); + + if (utf8) + { + pdf_obj *field; + + fz_var(name); + fz_try(ctx) + { + name = utf8_to_pdf(ctx, utf8); + field = pdf_lookup_field(js->form, name); + if (field) + pdf_field_reset(js->doc, field); + } + fz_always(ctx) + { + fz_free(ctx, name); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } + } +} + +static pdf_jsimp_obj *doc_resetForm(void *jsctx, void *obj, int argc, pdf_jsimp_obj *args[]) +{ + pdf_js *js = (pdf_js *)jsctx; + fz_context *ctx = js->doc->ctx; + pdf_jsimp_obj *arr = NULL; + pdf_jsimp_obj *elem = NULL; + + switch (argc) + { + case 0: + break; + case 1: + switch (pdf_jsimp_to_type(js->imp, args[0])) + { + case JS_TYPE_NULL: + break; + case JS_TYPE_ARRAY: + arr = args[0]; + break; + case JS_TYPE_STRING: + elem = args[0]; + break; + default: + return NULL; + } + break; + default: + return NULL; + } + + fz_try(ctx) + { + if(arr) + { + /* An array of fields has been passed in. Call + * pdf_reset_field on each */ + int i, n = pdf_jsimp_array_len(js->imp, arr); + + for (i = 0; i < n; i++) + { + pdf_jsimp_obj *item = pdf_jsimp_array_item(js->imp, arr, i); + + if (item) + reset_field(js, item); + + } + } + else if (elem) + { + reset_field(js, elem); + } + else + { + /* No argument or null passed in means reset all. */ + int i, n = pdf_array_len(js->form); + + for (i = 0; i < n; i++) + pdf_field_reset(js->doc, pdf_array_get(js->form, i)); + } + } + fz_catch(ctx) + { + fz_warn(ctx, "doc_resetForm failed: %s", fz_caught_message(ctx)); + } + + return NULL; +} + +static pdf_jsimp_obj *doc_print(void *jsctx, void *obj, int argc, pdf_jsimp_obj *args[]) +{ + pdf_js *js = (pdf_js *)jsctx; + + pdf_event_issue_print(js->doc); + + return NULL; +} + +static pdf_jsimp_obj *doc_mailDoc(void *jsctx, void *obj, int argc, pdf_jsimp_obj *args[]) +{ + pdf_js *js = (pdf_js *)jsctx; + fz_context *ctx = js->doc->ctx; + pdf_jsimp_obj *bUI_obj = NULL; + pdf_jsimp_obj *cTo_obj = NULL; + pdf_jsimp_obj *cCc_obj = NULL; + pdf_jsimp_obj *cBcc_obj = NULL; + pdf_jsimp_obj *cSubject_obj = NULL; + pdf_jsimp_obj *cMessage_obj = NULL; + pdf_mail_doc_event event; + int arg_is_obj = 0; + + if (argc < 1 || argc > 6) + return NULL; + + event.ask_user = 1; + event.to = ""; + event.cc = ""; + event.bcc = ""; + event.subject = ""; + event.message = ""; + + fz_var(bUI_obj); + fz_var(cTo_obj); + fz_var(cCc_obj); + fz_var(cBcc_obj); + fz_var(cSubject_obj); + fz_var(cMessage_obj); + fz_try(ctx) + { + arg_is_obj = (argc == 1 && pdf_jsimp_to_type(js->imp, args[0]) != JS_TYPE_BOOLEAN); + if (arg_is_obj) + { + bUI_obj = pdf_jsimp_property(js->imp, args[0], "bUI"); + cTo_obj = pdf_jsimp_property(js->imp, args[0], "cTo"); + cCc_obj = pdf_jsimp_property(js->imp, args[0], "cCc"); + cBcc_obj = pdf_jsimp_property(js->imp, args[0], "cBcc"); + cSubject_obj = pdf_jsimp_property(js->imp, args[0], "cSubject"); + cMessage_obj = pdf_jsimp_property(js->imp, args[0], "cMessage"); + } + else + { + switch (argc) + { + case 6: + cMessage_obj = args[5]; + case 5: + cSubject_obj = args[4]; + case 4: + cBcc_obj = args[3]; + case 3: + cCc_obj = args[2]; + case 2: + cTo_obj = args[1]; + case 1: + bUI_obj = args[0]; + } + } + + if (bUI_obj) + event.ask_user = (int)pdf_jsimp_to_number(js->imp, bUI_obj); + + if (cTo_obj) + event.to = pdf_jsimp_to_string(js->imp, cTo_obj); + + if (cCc_obj) + event.cc = pdf_jsimp_to_string(js->imp, cCc_obj); + + if (cBcc_obj) + event.bcc = pdf_jsimp_to_string(js->imp, cBcc_obj); + + if (cSubject_obj) + event.subject = pdf_jsimp_to_string(js->imp, cSubject_obj); + + if (cMessage_obj) + event.message = pdf_jsimp_to_string(js->imp, cMessage_obj); + + pdf_event_issue_mail_doc(js->doc, &event); + } + fz_always(ctx) + { + if (arg_is_obj) + { + pdf_jsimp_drop_obj(js->imp, bUI_obj); + pdf_jsimp_drop_obj(js->imp, cTo_obj); + pdf_jsimp_drop_obj(js->imp, cCc_obj); + pdf_jsimp_drop_obj(js->imp, cBcc_obj); + pdf_jsimp_drop_obj(js->imp, cSubject_obj); + pdf_jsimp_drop_obj(js->imp, cMessage_obj); + } + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } + + return NULL; +} + +static void declare_dom(pdf_js *js) +{ + pdf_jsimp *imp = js->imp; + + /* Create the document type */ + js->doctype = pdf_jsimp_new_type(imp, NULL); + pdf_jsimp_addmethod(imp, js->doctype, "getField", doc_getField); + pdf_jsimp_addmethod(imp, js->doctype, "resetForm", doc_resetForm); + pdf_jsimp_addmethod(imp, js->doctype, "print", doc_print); + pdf_jsimp_addmethod(imp, js->doctype, "mailDoc", doc_mailDoc); + pdf_jsimp_addproperty(imp, js->doctype, "event", doc_getEvent, doc_setEvent); + pdf_jsimp_addproperty(imp, js->doctype, "app", doc_getApp, doc_setApp); + + /* Create the event type */ + js->eventtype = pdf_jsimp_new_type(imp, NULL); + pdf_jsimp_addproperty(imp, js->eventtype, "target", event_getTarget, event_setTarget); + pdf_jsimp_addproperty(imp, js->eventtype, "value", event_getValue, event_setValue); + pdf_jsimp_addproperty(imp, js->eventtype, "willCommit", event_getWillCommit, event_setWillCommit); + pdf_jsimp_addproperty(imp, js->eventtype, "rc", event_getRC, event_setRC); + + /* Create the field type */ + js->fieldtype = pdf_jsimp_new_type(imp, NULL); + pdf_jsimp_addproperty(imp, js->fieldtype, "value", field_getValue, field_setValue); + pdf_jsimp_addproperty(imp, js->fieldtype, "borderStyle", field_getBorderStyle, field_setBorderStyle); + pdf_jsimp_addproperty(imp, js->fieldtype, "textColor", field_getTextColor, field_setTextColor); + pdf_jsimp_addproperty(imp, js->fieldtype, "fillColor", field_getFillColor, field_setFillColor); + pdf_jsimp_addproperty(imp, js->fieldtype, "display", field_getDisplay, field_setDisplay); + pdf_jsimp_addproperty(imp, js->fieldtype, "name", field_getName, field_setName); + pdf_jsimp_addmethod(imp, js->fieldtype, "buttonSetCaption", field_buttonSetCaption); + + /* Create the app type */ + js->apptype = pdf_jsimp_new_type(imp, NULL); + pdf_jsimp_addmethod(imp, js->apptype, "alert", app_alert); + pdf_jsimp_addmethod(imp, js->apptype, "execDialog", app_execDialog); + pdf_jsimp_addmethod(imp, js->apptype, "execMenuItem", app_execMenuItem); + pdf_jsimp_addmethod(imp, js->apptype, "launchURL", app_launchURL); + + /* Create the document object and tell the engine to use */ + pdf_jsimp_set_global_type(js->imp, js->doctype); +} + +static void preload_helpers(pdf_js *js) +{ + /* When testing on the cluster, redefine the Date object + * to use a fixed date */ +#ifdef CLUSTER + pdf_jsimp_execute(js->imp, +"var MuPDFOldDate = Date\n" +"Date = function() { return new MuPDFOldDate(1979,5,15); }\n" + ); +#endif + + pdf_jsimp_execute(js->imp, +#include "gen_js_util.h" + ); +} + +pdf_js *pdf_new_js(pdf_document *doc) +{ + fz_context *ctx = doc->ctx; + pdf_js *js = NULL; + + fz_var(js); + fz_try(ctx) + { + pdf_obj *root, *acroform; + + js = fz_malloc_struct(ctx, pdf_js); + js->doc = doc; + + /* Find the form array */ + root = pdf_dict_gets(pdf_trailer(doc), "Root"); + acroform = pdf_dict_gets(root, "AcroForm"); + js->form = pdf_dict_gets(acroform, "Fields"); + + /* Initialise the javascript engine, passing the main context + * for use in memory allocation and exception handling. Also + * pass our js context, for it to pass back to us. */ + js->imp = pdf_new_jsimp(ctx, js); + declare_dom(js); + + preload_helpers(js); + } + fz_catch(ctx) + { + pdf_drop_js(js); + js = NULL; + } + + return js; +} + +void pdf_js_load_document_level(pdf_js *js) +{ + pdf_document *doc = js->doc; + fz_context *ctx = doc->ctx; + pdf_obj *javascript = NULL; + char *codebuf = NULL; + + fz_var(javascript); + fz_var(codebuf); + fz_try(ctx) + { + int len, i; + + javascript = pdf_load_name_tree(doc, "JavaScript"); + len = pdf_dict_len(javascript); + + for (i = 0; i < len; i++) + { + pdf_obj *fragment = pdf_dict_get_val(javascript, i); + pdf_obj *code = pdf_dict_gets(fragment, "JS"); + + fz_var(codebuf); + fz_try(ctx) + { + codebuf = pdf_to_utf8(doc, code); + pdf_jsimp_execute(js->imp, codebuf); + } + fz_always(ctx) + { + fz_free(ctx, codebuf); + codebuf = NULL; + } + fz_catch(ctx) + { + /* FIXME: TryLater ? */ + fz_warn(ctx, "Warning: %s", fz_caught_message(ctx)); + } + } + } + fz_always(ctx) + { + pdf_drop_obj(javascript); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } +} + +void pdf_drop_js(pdf_js *js) +{ + if (js) + { + fz_context *ctx = js->doc->ctx; + fz_free(ctx, js->event.value); + pdf_jsimp_drop_type(js->imp, js->apptype); + pdf_jsimp_drop_type(js->imp, js->fieldtype); + pdf_jsimp_drop_type(js->imp, js->doctype); + pdf_drop_jsimp(js->imp); + fz_free(ctx, js); + } +} + +void pdf_js_setup_event(pdf_js *js, pdf_js_event *e) +{ + if (js) + { + fz_context *ctx = js->doc->ctx; + char *ev = e->value ? e->value : ""; + char *v = fz_strdup(ctx, ev); + + fz_free(ctx, js->event.value); + js->event.value = v; + + js->event.target = e->target; + js->event.rc = 1; + } +} + +pdf_js_event *pdf_js_get_event(pdf_js *js) +{ + return js ? &js->event : NULL; +} + +void pdf_js_execute(pdf_js *js, char *code) +{ + if (js) + { + fz_context *ctx = js->doc->ctx; + fz_try(ctx) + { + pdf_jsimp_execute(js->imp, code); + } + fz_catch(ctx) + { + } + } +} + +void pdf_js_execute_count(pdf_js *js, char *code, int count) +{ + if (js) + { + fz_context *ctx = js->doc->ctx; + fz_try(ctx) + { + pdf_jsimp_execute_count(js->imp, code, count); + } + fz_catch(ctx) + { + } + } +} + +int pdf_js_supported(void) +{ + return 1; +} diff --git a/source/pdf/js/pdf-jsimp-cpp.c b/source/pdf/js/pdf-jsimp-cpp.c new file mode 100644 index 00000000..7e8031a6 --- /dev/null +++ b/source/pdf/js/pdf-jsimp-cpp.c @@ -0,0 +1,225 @@ +/* This file contains wrapper functions for pdf_jsimp functions implemented + * in C++, from which calls to fz_throw aren't safe. The C++ versions + * return errors explicitly, and these wrappers then throw them. */ + +#include "mupdf/pdf.h" +#include "pdf-jsimp-cpp.h" + +pdf_jsimp *pdf_new_jsimp(fz_context *ctx, void *jsctx) +{ + pdf_jsimp *jsi = NULL; + const char *err = pdf_new_jsimp_cpp(ctx, jsctx, &jsi); + if (err != NULL) + fz_throw(ctx, FZ_ERROR_GENERIC, "%s", err); + + return jsi; +} + +void pdf_drop_jsimp(pdf_jsimp *imp) +{ + if (imp) + { + fz_context *ctx = pdf_jsimp_ctx_cpp(imp); + const char *err = pdf_drop_jsimp_cpp(imp); + if (err != NULL) + fz_warn(ctx, "%s", err); + } +} + +pdf_jsimp_type *pdf_jsimp_new_type(pdf_jsimp *imp, pdf_jsimp_dtr *dtr) +{ + pdf_jsimp_type *type = NULL; + const char *err = pdf_jsimp_new_type_cpp(imp, dtr, &type); + if (err != NULL) + fz_throw(pdf_jsimp_ctx_cpp(imp), FZ_ERROR_GENERIC, "%s", err); + + return type; +} + +void pdf_jsimp_drop_type(pdf_jsimp *imp, pdf_jsimp_type *type) +{ + const char *err = pdf_jsimp_drop_type_cpp(imp, type); + if (err != NULL) + fz_warn(pdf_jsimp_ctx_cpp(imp), "%s", err); +} + +void pdf_jsimp_addmethod(pdf_jsimp *imp, pdf_jsimp_type *type, char *name, pdf_jsimp_method *meth) +{ + const char *err = pdf_jsimp_addmethod_cpp(imp, type, name, meth); + if (err != NULL) + fz_throw(pdf_jsimp_ctx_cpp(imp), FZ_ERROR_GENERIC, "%s", err); +} + +void pdf_jsimp_addproperty(pdf_jsimp *imp, pdf_jsimp_type *type, char *name, pdf_jsimp_getter *get, pdf_jsimp_setter *set) +{ + const char *err = pdf_jsimp_addproperty_cpp(imp, type, name, get, set); + if (err != NULL) + fz_throw(pdf_jsimp_ctx_cpp(imp), FZ_ERROR_GENERIC, "%s", err); +} + +void pdf_jsimp_set_global_type(pdf_jsimp *imp, pdf_jsimp_type *type) +{ + const char *err = pdf_jsimp_set_global_type_cpp(imp, type); + if (err != NULL) + fz_throw(pdf_jsimp_ctx_cpp(imp), FZ_ERROR_GENERIC, "%s", err); +} + +pdf_jsimp_obj *pdf_jsimp_new_obj(pdf_jsimp *imp, pdf_jsimp_type *type, void *natobj) +{ + pdf_jsimp_obj *obj = NULL; + const char *err = pdf_jsimp_new_obj_cpp(imp, type, natobj, &obj); + if (err != NULL) + fz_throw(pdf_jsimp_ctx_cpp(imp), FZ_ERROR_GENERIC, "%s", err); + + return obj; +} + +void pdf_jsimp_drop_obj(pdf_jsimp *imp, pdf_jsimp_obj *obj) +{ + const char *err = pdf_jsimp_drop_obj_cpp(imp, obj); + if (err != NULL) + fz_warn(pdf_jsimp_ctx_cpp(imp), "%s", err); +} + +int pdf_jsimp_to_type(pdf_jsimp *imp, pdf_jsimp_obj *obj) +{ + int type = 0; + const char *err = pdf_jsimp_to_type_cpp(imp, obj, &type); + if (err != NULL) + fz_throw(pdf_jsimp_ctx_cpp(imp), FZ_ERROR_GENERIC, "%s", err); + + return type; +} + +pdf_jsimp_obj *pdf_jsimp_from_string(pdf_jsimp *imp, char *str) +{ + pdf_jsimp_obj *obj = NULL; + const char *err = pdf_jsimp_from_string_cpp(imp, str, &obj); + if (err != NULL) + fz_throw(pdf_jsimp_ctx_cpp(imp), FZ_ERROR_GENERIC, "%s", err); + + return obj; +} + +char *pdf_jsimp_to_string(pdf_jsimp *imp, pdf_jsimp_obj *obj) +{ + char *str = NULL; + const char *err = pdf_jsimp_to_string_cpp(imp, obj, &str); + if (err != NULL) + fz_throw(pdf_jsimp_ctx_cpp(imp), FZ_ERROR_GENERIC, "%s", err); + + return str; +} + +pdf_jsimp_obj *pdf_jsimp_from_number(pdf_jsimp *imp, double num) +{ + pdf_jsimp_obj *obj = NULL; + const char *err = pdf_jsimp_from_number_cpp(imp, num, &obj); + if (err != NULL) + fz_throw(pdf_jsimp_ctx_cpp(imp), FZ_ERROR_GENERIC, "%s", err); + + return obj; +} + +double pdf_jsimp_to_number(pdf_jsimp *imp, pdf_jsimp_obj *obj) +{ + double num; + const char *err = pdf_jsimp_to_number_cpp(imp, obj, &num); + if (err != NULL) + fz_throw(pdf_jsimp_ctx_cpp(imp), FZ_ERROR_GENERIC, "%s", err); + + return num; +} + +int pdf_jsimp_array_len(pdf_jsimp *imp, pdf_jsimp_obj *obj) +{ + int len = 0; + const char *err = pdf_jsimp_array_len_cpp(imp, obj, &len); + if (err != NULL) + fz_throw(pdf_jsimp_ctx_cpp(imp), FZ_ERROR_GENERIC, "%s", err); + + return len; +} + +pdf_jsimp_obj *pdf_jsimp_array_item(pdf_jsimp *imp, pdf_jsimp_obj *obj, int i) +{ + pdf_jsimp_obj *item = NULL; + const char *err = pdf_jsimp_array_item_cpp(imp, obj, i, &item); + if (err != NULL) + fz_throw(pdf_jsimp_ctx_cpp(imp), FZ_ERROR_GENERIC, "%s", err); + + return item; +} + +pdf_jsimp_obj *pdf_jsimp_property(pdf_jsimp *imp, pdf_jsimp_obj *obj, char *prop) +{ + pdf_jsimp_obj *pobj = NULL; + const char *err = pdf_jsimp_property_cpp(imp, obj, prop, &pobj); + if (err != NULL) + fz_throw(pdf_jsimp_ctx_cpp(imp), FZ_ERROR_GENERIC, "%s", err); + + return pobj; +} + +void pdf_jsimp_execute(pdf_jsimp *imp, char *code) +{ + const char *err = pdf_jsimp_execute_cpp(imp, code); + if (err != NULL) + fz_throw(pdf_jsimp_ctx_cpp(imp), FZ_ERROR_GENERIC, "%s", err); +} + +void pdf_jsimp_execute_count(pdf_jsimp *imp, char *code, int count) +{ + const char *err = pdf_jsimp_execute_count_cpp(imp, code, count); + if (err != NULL) + fz_throw(pdf_jsimp_ctx_cpp(imp), FZ_ERROR_GENERIC, "%s", err); +} +pdf_jsimp_obj *pdf_jsimp_call_method(pdf_jsimp *imp, pdf_jsimp_method *meth, void *jsctx, void *obj, int argc, pdf_jsimp_obj *args[]) +{ + fz_context *ctx = pdf_jsimp_ctx_cpp(imp); + pdf_jsimp_obj *res; + + fz_try(ctx) + { + res = meth(jsctx, obj, argc, args); + } + fz_catch(ctx) + { + res = NULL; + fz_warn(ctx, "%s", fz_caught_message(ctx)); + } + + return res; +} + +pdf_jsimp_obj *pdf_jsimp_call_getter(pdf_jsimp *imp, pdf_jsimp_getter *get, void *jsctx, void *obj) +{ + fz_context *ctx = pdf_jsimp_ctx_cpp(imp); + pdf_jsimp_obj *res; + + fz_try(ctx) + { + res = get(jsctx, obj); + } + fz_catch(ctx) + { + res = NULL; + fz_warn(ctx, "%s", fz_caught_message(ctx)); + } + + return res; +} + +void pdf_jsimp_call_setter(pdf_jsimp *imp, pdf_jsimp_setter *set, void *jsctx, void *obj, pdf_jsimp_obj *val) +{ + fz_context *ctx = pdf_jsimp_ctx_cpp(imp); + + fz_try(ctx) + { + set(jsctx, obj, val); + } + fz_catch(ctx) + { + fz_warn(ctx, "%s", fz_caught_message(ctx)); + } +} diff --git a/source/pdf/js/pdf-jsimp-cpp.h b/source/pdf/js/pdf-jsimp-cpp.h new file mode 100644 index 00000000..83af1d23 --- /dev/null +++ b/source/pdf/js/pdf-jsimp-cpp.h @@ -0,0 +1,29 @@ +/* C++ version of the pdf_jsimp api. C++ cannot safely call fz_throw, + * so C++ implementations return explicit errors in char * form. */ + +fz_context *pdf_jsimp_ctx_cpp(pdf_jsimp *imp); +const char *pdf_new_jsimp_cpp(fz_context *ctx, void *jsctx, pdf_jsimp **imp); +const char *pdf_drop_jsimp_cpp(pdf_jsimp *imp); +const char *pdf_jsimp_new_type_cpp(pdf_jsimp *imp, pdf_jsimp_dtr *dtr, pdf_jsimp_type **type); +const char *pdf_jsimp_drop_type_cpp(pdf_jsimp *imp, pdf_jsimp_type *type); +const char *pdf_jsimp_addmethod_cpp(pdf_jsimp *imp, pdf_jsimp_type *type, char *name, pdf_jsimp_method *meth); +const char *pdf_jsimp_addproperty_cpp(pdf_jsimp *imp, pdf_jsimp_type *type, char *name, pdf_jsimp_getter *get, pdf_jsimp_setter *set); +const char *pdf_jsimp_set_global_type_cpp(pdf_jsimp *imp, pdf_jsimp_type *type); +const char *pdf_jsimp_new_obj_cpp(pdf_jsimp *imp, pdf_jsimp_type *type, void *natobj, pdf_jsimp_obj **obj); +const char *pdf_jsimp_drop_obj_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj); +const char *pdf_jsimp_to_type_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, int *type); +const char *pdf_jsimp_from_string_cpp(pdf_jsimp *imp, char *str, pdf_jsimp_obj **obj); +const char *pdf_jsimp_to_string_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, char **str); +const char *pdf_jsimp_from_number_cpp(pdf_jsimp *imp, double num, pdf_jsimp_obj **obj); +const char *pdf_jsimp_to_number_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, double *num); +const char *pdf_jsimp_array_len_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, int *len); +const char *pdf_jsimp_array_item_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, int i, pdf_jsimp_obj **item); +const char *pdf_jsimp_property_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, char *prop, pdf_jsimp_obj **pobj); +const char *pdf_jsimp_execute_cpp(pdf_jsimp *imp, char *code); +const char *pdf_jsimp_execute_count_cpp(pdf_jsimp *imp, char *code, int count); + +/* Also when calling back into mupdf, all exceptions must be caught. The functions bellow + * wrap these calls */ +pdf_jsimp_obj *pdf_jsimp_call_method(pdf_jsimp *imp, pdf_jsimp_method *meth, void *jsctx, void *obj, int argc, pdf_jsimp_obj *args[]); +pdf_jsimp_obj *pdf_jsimp_call_getter(pdf_jsimp *imp, pdf_jsimp_getter *get, void *jsctx, void *obj); +void pdf_jsimp_call_setter(pdf_jsimp *imp, pdf_jsimp_setter *set, void *jsctx, void *obj, pdf_jsimp_obj *val); diff --git a/source/pdf/js/pdf-jsimp-v8.cpp b/source/pdf/js/pdf-jsimp-v8.cpp new file mode 100644 index 00000000..f3894b6b --- /dev/null +++ b/source/pdf/js/pdf-jsimp-v8.cpp @@ -0,0 +1,476 @@ +/* + * This is a dummy JavaScript engine. It cheats by recognising the specific + * strings in calc.pdf, and hence will work only for that file. It is for + * testing only. + */ + +extern "C" { +#include "mupdf/fitz.h" +#include "mupdf/pdf.h" +#include "pdf-jsimp-cpp.h" +} + +#include +#include +#include + +using namespace v8; +using namespace std; + +struct PDFJSImp; + +/* Object we pass to FunctionTemplate::New, which v8 passes back to us in + * callMethod, allowing us to call our client's, passed-in method. */ +struct PDFJSImpMethod +{ + PDFJSImp *imp; + pdf_jsimp_method *meth; + + PDFJSImpMethod(PDFJSImp *imp, pdf_jsimp_method *meth) : imp(imp), meth(meth) {} +}; + +/* Object we pass to ObjectTemplate::SetAccessor, which v8 passes back to us in + * setProp and getProp, allowing us to call our client's, passed-in set/get methods. */ +struct PDFJSImpProperty +{ + PDFJSImp *imp; + pdf_jsimp_getter *get; + pdf_jsimp_setter *set; + + PDFJSImpProperty(PDFJSImp *imp, pdf_jsimp_getter *get, pdf_jsimp_setter *set) : imp(imp), get(get), set(set) {} +}; + +/* Internal representation of the pdf_jsimp_type object */ +struct PDFJSImpType +{ + PDFJSImp *imp; + Persistent templ; + pdf_jsimp_dtr *dtr; + vector methods; + vector properties; + + PDFJSImpType(PDFJSImp *imp, pdf_jsimp_dtr *dtr): imp(imp), dtr(dtr) + { + HandleScope scope; + templ = Persistent::New(ObjectTemplate::New()); + templ->SetInternalFieldCount(1); + } + + ~PDFJSImpType() + { + vector::iterator mit; + for (mit = methods.begin(); mit < methods.end(); mit++) + delete *mit; + + vector::iterator pit; + for (pit = properties.begin(); pit < properties.end(); pit++) + delete *pit; + + templ.Dispose(); + } +}; + +/* Info via which we destroy the client side part of objects that + * v8 garbage collects */ +struct PDFJSImpGCObj +{ + Persistent pobj; + PDFJSImpType *type; + + PDFJSImpGCObj(Handle obj, PDFJSImpType *type): type(type) + { + pobj = Persistent::New(obj); + } + + ~PDFJSImpGCObj() + { + pobj.Dispose(); + } +}; + +/* Internal representation of the pdf_jsimp object */ +struct PDFJSImp +{ + fz_context *ctx; + void *jsctx; + Persistent context; + vector types; + set gclist; + + PDFJSImp(fz_context *ctx, void *jsctx) : ctx(ctx), jsctx(jsctx) + { + HandleScope scope; + context = Persistent::New(Context::New()); + } + + ~PDFJSImp() + { + HandleScope scope; + /* Tell v8 our context will not be used again */ + context.Dispose(); + + /* Unlink and destroy all the objects that v8 has yet to gc */ + set::iterator oit; + for (oit = gclist.begin(); oit != gclist.end(); oit++) + { + (*oit)->pobj.ClearWeak(); /* So that gcCallback wont get called */ + PDFJSImpType *vType = (*oit)->type; + Local owrap = Local::Cast((*oit)->pobj->GetInternalField(0)); + vType->dtr(vType->imp->jsctx, owrap->Value()); + delete *oit; + } + + vector::iterator it; + for (it = types.begin(); it < types.end(); it++) + delete *it; + } +}; + +/* Internal representation of the pdf_jsimp_obj object */ +class PDFJSImpObject +{ + Persistent pobj; + String::Utf8Value *utf8; + +public: + PDFJSImpObject(Handle obj): utf8(NULL) + { + pobj = Persistent::New(obj); + } + + PDFJSImpObject(const char *str): utf8(NULL) + { + pobj = Persistent::New(String::New(str)); + } + + PDFJSImpObject(double num): utf8(NULL) + { + pobj = Persistent::New(Number::New(num)); + } + + ~PDFJSImpObject() + { + delete utf8; + pobj.Dispose(); + } + + int type() + { + if (pobj->IsNull()) + return JS_TYPE_NULL; + else if (pobj->IsString() || pobj->IsStringObject()) + return JS_TYPE_STRING; + else if (pobj->IsNumber() || pobj->IsNumberObject()) + return JS_TYPE_NUMBER; + else if (pobj->IsArray()) + return JS_TYPE_ARRAY; + else if (pobj->IsBoolean() || pobj->IsBooleanObject()) + return JS_TYPE_BOOLEAN; + else + return JS_TYPE_UNKNOWN; + } + + char *toString() + { + delete utf8; + utf8 = new String::Utf8Value(pobj); + return **utf8; + } + + double toNumber() + { + return pobj->NumberValue(); + } + + Handle toValue() + { + return pobj; + } +}; + +extern "C" fz_context *pdf_jsimp_ctx_cpp(pdf_jsimp *imp) +{ + return reinterpret_cast(imp)->ctx; +} + +extern "C" const char *pdf_new_jsimp_cpp(fz_context *ctx, void *jsctx, pdf_jsimp **imp) +{ + Locker lock; + *imp = reinterpret_cast(new PDFJSImp(ctx, jsctx)); + + return NULL; +} + +extern "C" const char *pdf_drop_jsimp_cpp(pdf_jsimp *imp) +{ + Locker lock; + delete reinterpret_cast(imp); + return NULL; +} + +extern "C" const char *pdf_jsimp_new_type_cpp(pdf_jsimp *imp, pdf_jsimp_dtr *dtr, pdf_jsimp_type **type) +{ + Locker lock; + PDFJSImp *vImp = reinterpret_cast(imp); + PDFJSImpType *vType = new PDFJSImpType(vImp, dtr); + vImp->types.push_back(vType); + *type = reinterpret_cast(vType); + return NULL; +} + +extern "C" const char *pdf_jsimp_drop_type_cpp(pdf_jsimp *imp, pdf_jsimp_type *type) +{ + /* Types are recorded and destroyed as part of PDFJSImp */ + return NULL; +} + +static Handle callMethod(const Arguments &args) +{ + HandleScope scope; + Local mwrap = Local::Cast(args.Data()); + PDFJSImpMethod *m = (PDFJSImpMethod *)mwrap->Value(); + + Local self = args.Holder(); + Local owrap; + void *nself = NULL; + if (self->InternalFieldCount() > 0) + { + owrap = Local::Cast(self->GetInternalField(0)); + nself = owrap->Value(); + } + + int c = args.Length(); + PDFJSImpObject **native_args = new PDFJSImpObject*[c]; + for (int i = 0; i < c; i++) + native_args[i] = new PDFJSImpObject(args[i]); + + PDFJSImpObject *obj = reinterpret_cast(pdf_jsimp_call_method(reinterpret_cast(m->imp), m->meth, m->imp->jsctx, nself, c, reinterpret_cast(native_args))); + Handle val; + if (obj) + val = obj->toValue(); + delete obj; + + for (int i = 0; i < c; i++) + delete native_args[i]; + + delete native_args; + + return scope.Close(val); +} + +extern "C" const char *pdf_jsimp_addmethod_cpp(pdf_jsimp *imp, pdf_jsimp_type *type, char *name, pdf_jsimp_method *meth) +{ + Locker lock; + PDFJSImpType *vType = reinterpret_cast(type); + HandleScope scope; + + PDFJSImpMethod *pmeth = new PDFJSImpMethod(vType->imp, meth); + vType->templ->Set(String::New(name), FunctionTemplate::New(callMethod, External::New(pmeth))); + vType->methods.push_back(pmeth); + return NULL; +} + +static Handle getProp(Local property, const AccessorInfo &info) +{ + HandleScope scope; + Local pwrap = Local::Cast(info.Data()); + PDFJSImpProperty *p = reinterpret_cast(pwrap->Value()); + + Local self = info.Holder(); + Local owrap; + void *nself = NULL; + if (self->InternalFieldCount() > 0) + { + Local val = self->GetInternalField(0); + if (val->IsExternal()) + { + owrap = Local::Cast(val); + nself = owrap->Value(); + } + } + + PDFJSImpObject *obj = reinterpret_cast(pdf_jsimp_call_getter(reinterpret_cast(p->imp), p->get, p->imp->jsctx, nself)); + Handle val; + if (obj) + val = obj->toValue(); + delete obj; + return scope.Close(val); +} + +static void setProp(Local property, Local value, const AccessorInfo &info) +{ + HandleScope scope; + Local wrap = Local::Cast(info.Data()); + PDFJSImpProperty *p = reinterpret_cast(wrap->Value()); + + Local self = info.Holder(); + Local owrap; + void *nself = NULL; + if (self->InternalFieldCount() > 0) + { + owrap = Local::Cast(self->GetInternalField(0)); + nself = owrap->Value(); + } + + PDFJSImpObject *obj = new PDFJSImpObject(value); + + pdf_jsimp_call_setter(reinterpret_cast(p->imp), p->set, p->imp->jsctx, nself, reinterpret_cast(obj)); + delete obj; +} + +extern "C" const char *pdf_jsimp_addproperty_cpp(pdf_jsimp *imp, pdf_jsimp_type *type, char *name, pdf_jsimp_getter *get, pdf_jsimp_setter *set) +{ + Locker lock; + PDFJSImpType *vType = reinterpret_cast(type); + HandleScope scope; + + PDFJSImpProperty *prop = new PDFJSImpProperty(vType->imp, get, set); + vType->templ->SetAccessor(String::New(name), getProp, setProp, External::New(prop)); + vType->properties.push_back(prop); + return NULL; +} + +extern "C" const char *pdf_jsimp_set_global_type_cpp(pdf_jsimp *imp, pdf_jsimp_type *type) +{ + Locker lock; + PDFJSImp *vImp = reinterpret_cast(imp); + PDFJSImpType *vType = reinterpret_cast(type); + HandleScope scope; + + vImp->context = Persistent::New(Context::New(NULL, vType->templ)); + return NULL; +} + +static void gcCallback(Persistent val, void *parm) +{ + PDFJSImpGCObj *gco = reinterpret_cast(parm); + PDFJSImpType *vType = gco->type; + HandleScope scope; + Persistent obj = Persistent::Cast(val); + + Local owrap = Local::Cast(obj->GetInternalField(0)); + vType->dtr(vType->imp->jsctx, owrap->Value()); + vType->imp->gclist.erase(gco); + delete gco; /* Disposes of the persistent handle */ +} + +extern "C" const char *pdf_jsimp_new_obj_cpp(pdf_jsimp *imp, pdf_jsimp_type *type, void *natobj, pdf_jsimp_obj **robj) +{ + Locker lock; + PDFJSImpType *vType = reinterpret_cast(type); + HandleScope scope; + Local obj = vType->templ->NewInstance(); + obj->SetInternalField(0, External::New(natobj)); + + /* Arrange for destructor to be called on the client-side object + * when the v8 object is garbage collected */ + if (vType->dtr) + { + /* Wrap obj in a PDFJSImpGCObj, which takes a persistent handle to + * obj, and stores its type with it. The persistent handle tells v8 + * it cannot just destroy obj leaving the client-side object hanging */ + PDFJSImpGCObj *gco = new PDFJSImpGCObj(obj, vType); + /* Keep the wrapped object in a list, so that we can take back control + * of destroying client-side objects when shutting down this context */ + vType->imp->gclist.insert(gco); + /* Tell v8 that it can destroy the persistent handle to obj when it has + * no further need for it, but it must inform us via gcCallback */ + gco->pobj.MakeWeak(gco, gcCallback); + } + + *robj = reinterpret_cast(new PDFJSImpObject(obj)); + return NULL; +} + +extern "C" const char *pdf_jsimp_drop_obj_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj) +{ + Locker lock; + delete reinterpret_cast(obj); + return NULL; +} + +extern "C" const char *pdf_jsimp_to_type_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, int *type) +{ + Locker lock; + *type = reinterpret_cast(obj)->type(); + return NULL; +} + +extern "C" const char *pdf_jsimp_from_string_cpp(pdf_jsimp *imp, char *str, pdf_jsimp_obj **obj) +{ + Locker lock; + *obj = reinterpret_cast(new PDFJSImpObject(str)); + return NULL; +} + +extern "C" const char *pdf_jsimp_to_string_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, char **str) +{ + Locker lock; + *str = reinterpret_cast(obj)->toString(); + return NULL; +} + +extern "C" const char *pdf_jsimp_from_number_cpp(pdf_jsimp *imp, double num, pdf_jsimp_obj **obj) +{ + Locker lock; + *obj = reinterpret_cast(new PDFJSImpObject(num)); + return NULL; +} + +extern "C" const char *pdf_jsimp_to_number_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, double *num) +{ + Locker lock; + *num = reinterpret_cast(obj)->toNumber(); + return NULL; +} + +extern "C" const char *pdf_jsimp_array_len_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, int *len) +{ + Locker lock; + Local jsobj = reinterpret_cast(obj)->toValue()->ToObject(); + Local arr = Local::Cast(jsobj); + *len = arr->Length(); + return NULL; +} + +extern "C" const char *pdf_jsimp_array_item_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, int i, pdf_jsimp_obj **item) +{ + Locker lock; + Local jsobj = reinterpret_cast(obj)->toValue()->ToObject(); + *item = reinterpret_cast(new PDFJSImpObject(jsobj->Get(Number::New(i)))); + return NULL; +} + +extern "C" const char *pdf_jsimp_property_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, char *prop, pdf_jsimp_obj **pobj) +{ + Locker lock; + Local jsobj = reinterpret_cast(obj)->toValue()->ToObject(); + *pobj = reinterpret_cast(new PDFJSImpObject(jsobj->Get(String::New(prop)))); + return NULL; +} + +extern "C" const char *pdf_jsimp_execute_cpp(pdf_jsimp *imp, char *code) +{ + Locker lock; + PDFJSImp *vImp = reinterpret_cast(imp); + HandleScope scope; + Context::Scope context_scope(vImp->context); + Handle