summaryrefslogtreecommitdiff
path: root/pdf/pdf_jsimp_v8.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'pdf/pdf_jsimp_v8.cpp')
-rw-r--r--pdf/pdf_jsimp_v8.cpp419
1 files changed, 419 insertions, 0 deletions
diff --git a/pdf/pdf_jsimp_v8.cpp b/pdf/pdf_jsimp_v8.cpp
new file mode 100644
index 00000000..70234d0f
--- /dev/null
+++ b/pdf/pdf_jsimp_v8.cpp
@@ -0,0 +1,419 @@
+/*
+ * 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 "fitz-internal.h"
+#include "mupdf-internal.h"
+#include "pdf_jsimp_cpp.h"
+}
+
+#include <vector>
+#include <set>
+#include <v8.h>
+
+using namespace v8;
+using namespace std;
+
+/* 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
+{
+ void *jsctx;
+ pdf_jsimp_method *meth;
+
+ PDFJSImpMethod(void *jsctx, pdf_jsimp_method *meth) : jsctx(jsctx), 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
+{
+ void *jsctx;
+ pdf_jsimp_getter *get;
+ pdf_jsimp_setter *set;
+
+ PDFJSImpProperty(void *jsctx, pdf_jsimp_getter *get, pdf_jsimp_setter *set) : jsctx(jsctx), get(get), set(set) {}
+};
+
+struct PDFJSImp;
+
+/* Internal representation of the pdf_jsimp_type object */
+struct PDFJSImpType
+{
+ PDFJSImp *imp;
+ Persistent<ObjectTemplate> templ;
+ pdf_jsimp_dtr *dtr;
+ vector<PDFJSImpMethod *> methods;
+ vector<PDFJSImpProperty *> properties;
+
+ PDFJSImpType(PDFJSImp *imp, pdf_jsimp_dtr *dtr): imp(imp), dtr(dtr)
+ {
+ HandleScope scope;
+ templ = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
+ templ->SetInternalFieldCount(1);
+ }
+
+ ~PDFJSImpType()
+ {
+ vector<PDFJSImpMethod *>::iterator mit;
+ for (mit = methods.begin(); mit < methods.end(); mit++)
+ delete *mit;
+
+ vector<PDFJSImpProperty *>::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<Object> pobj;
+ PDFJSImpType *type;
+
+ PDFJSImpGCObj(Handle<Object> obj, PDFJSImpType *type): type(type)
+ {
+ pobj = Persistent<Object>::New(obj);
+ }
+
+ ~PDFJSImpGCObj()
+ {
+ pobj.Dispose();
+ }
+};
+
+/* Internal representation of the pdf_jsimp object */
+struct PDFJSImp
+{
+ fz_context *ctx;
+ void *jsctx;
+ Persistent<Context> context;
+ vector<PDFJSImpType *> types;
+ set<PDFJSImpGCObj *> gclist;
+
+ PDFJSImp(fz_context *ctx, void *jsctx) : ctx(ctx), jsctx(jsctx)
+ {
+ HandleScope scope;
+ context = Persistent<Context>::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<PDFJSImpGCObj *>::iterator oit;
+ for (oit = gclist.begin(); oit != gclist.end(); oit++)
+ {
+ (*oit)->pobj.ClearWeak(); /* So that gcCallback wont get called */
+ PDFJSImpType *vType = (*oit)->type;
+ Local<External> owrap = Local<External>::Cast((*oit)->pobj->GetInternalField(0));
+ vType->dtr(vType->imp->jsctx, owrap->Value());
+ delete *oit;
+ }
+
+ vector<PDFJSImpType *>::iterator it;
+ for (it = types.begin(); it < types.end(); it++)
+ delete *it;
+ }
+};
+
+/* Internal representation of the pdf_jsimp_obj object */
+class PDFJSImpObject
+{
+ Persistent<Value> pobj;
+ String::Utf8Value *utf8;
+
+public:
+ PDFJSImpObject(Handle<Value> obj): utf8(NULL)
+ {
+ pobj = Persistent<Value>::New(obj);
+ }
+
+ PDFJSImpObject(const char *str): utf8(NULL)
+ {
+ pobj = Persistent<Value>::New(String::New(str));
+ }
+
+ ~PDFJSImpObject()
+ {
+ delete utf8;
+ pobj.Dispose();
+ }
+
+ char *toString()
+ {
+ delete utf8;
+ utf8 = new String::Utf8Value(pobj);
+ return **utf8;
+ }
+
+ double toNumber()
+ {
+ return pobj->NumberValue();
+ }
+
+ Handle<Value> toValue()
+ {
+ return pobj;
+ }
+};
+
+extern "C" fz_context *pdf_jsimp_ctx_cpp(pdf_jsimp *imp)
+{
+ return reinterpret_cast<PDFJSImp *>(imp)->ctx;
+}
+
+extern "C" char *pdf_new_jsimp_cpp(fz_context *ctx, void *jsctx, pdf_jsimp **imp)
+{
+ *imp = reinterpret_cast<pdf_jsimp *>(new PDFJSImp(ctx, jsctx));
+
+ return NULL;
+}
+
+extern "C" char *pdf_drop_jsimp_cpp(pdf_jsimp *imp)
+{
+ delete reinterpret_cast<PDFJSImp *>(imp);
+ return NULL;
+}
+
+extern "C" char *pdf_jsimp_new_type_cpp(pdf_jsimp *imp, pdf_jsimp_dtr *dtr, pdf_jsimp_type **type)
+{
+ PDFJSImp *vImp = reinterpret_cast<PDFJSImp *>(imp);
+ PDFJSImpType *vType = new PDFJSImpType(vImp, dtr);
+ vImp->types.push_back(vType);
+ *type = reinterpret_cast<pdf_jsimp_type *>(vType);
+ return NULL;
+}
+
+extern "C" 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<Value> callMethod(const Arguments &args)
+{
+ HandleScope scope;
+ Local<External> mwrap = Local<External>::Cast(args.Data());
+ PDFJSImpMethod *m = (PDFJSImpMethod *)mwrap->Value();
+
+ Local<Object> self = args.Holder();
+ Local<External> owrap;
+ void *nself = NULL;
+ if (self->InternalFieldCount() > 0)
+ {
+ owrap = Local<External>::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<PDFJSImpObject *>(m->meth(m->jsctx, nself, c, reinterpret_cast<pdf_jsimp_obj **>(native_args)));
+ Handle<Value> 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" char *pdf_jsimp_addmethod_cpp(pdf_jsimp *imp, pdf_jsimp_type *type, char *name, pdf_jsimp_method *meth)
+{
+ PDFJSImpType *vType = reinterpret_cast<PDFJSImpType *>(type);
+ HandleScope scope;
+
+ PDFJSImpMethod *pmeth = new PDFJSImpMethod(vType->imp->jsctx, meth);
+ vType->templ->Set(String::New(name), FunctionTemplate::New(callMethod, External::New(pmeth)));
+ vType->methods.push_back(pmeth);
+ return NULL;
+}
+
+static Handle<Value> getProp(Local<String> property, const AccessorInfo &info)
+{
+ HandleScope scope;
+ Local<External> pwrap = Local<External>::Cast(info.Data());
+ PDFJSImpProperty *p = reinterpret_cast<PDFJSImpProperty *>(pwrap->Value());
+
+ Local<Object> self = info.Holder();
+ Local<External> owrap;
+ void *nself = NULL;
+ if (self->InternalFieldCount() > 0)
+ {
+ Local<Value> val = self->GetInternalField(0);
+ if (val->IsExternal())
+ {
+ owrap = Local<External>::Cast(val);
+ nself = owrap->Value();
+ }
+ }
+
+ PDFJSImpObject *obj = reinterpret_cast<PDFJSImpObject *>(p->get(p->jsctx, nself));
+ Handle<Value> val;
+ if (obj)
+ val = obj->toValue();
+ delete obj;
+ return scope.Close(val);
+}
+
+static void setProp(Local<String> property, Local<Value> value, const AccessorInfo &info)
+{
+ HandleScope scope;
+ Local<External> wrap = Local<External>::Cast(info.Data());
+ PDFJSImpProperty *p = reinterpret_cast<PDFJSImpProperty *>(wrap->Value());
+
+ Local<Object> self = info.Holder();
+ Local<External> owrap;
+ void *nself = NULL;
+ if (self->InternalFieldCount() > 0)
+ {
+ owrap = Local<External>::Cast(self->GetInternalField(0));
+ nself = owrap->Value();
+ }
+
+ PDFJSImpObject *obj = new PDFJSImpObject(value);
+
+ p->set(p->jsctx, nself, reinterpret_cast<pdf_jsimp_obj *>(obj));
+ delete obj;
+}
+
+extern "C" char *pdf_jsimp_addproperty_cpp(pdf_jsimp *imp, pdf_jsimp_type *type, char *name, pdf_jsimp_getter *get, pdf_jsimp_setter *set)
+{
+ PDFJSImpType *vType = reinterpret_cast<PDFJSImpType *>(type);
+ HandleScope scope;
+
+ PDFJSImpProperty *prop = new PDFJSImpProperty(vType->imp->jsctx, get, set);
+ vType->templ->SetAccessor(String::New(name), getProp, setProp, External::New(prop));
+ vType->properties.push_back(prop);
+ return NULL;
+}
+
+extern "C" char *pdf_jsimp_set_global_type_cpp(pdf_jsimp *imp, pdf_jsimp_type *type)
+{
+ PDFJSImp *vImp = reinterpret_cast<PDFJSImp *>(imp);
+ PDFJSImpType *vType = reinterpret_cast<PDFJSImpType *>(type);
+ HandleScope scope;
+
+ vImp->context = Persistent<Context>::New(Context::New(NULL, vType->templ));
+ return NULL;
+}
+
+static void gcCallback(Persistent<Value> val, void *parm)
+{
+ PDFJSImpGCObj *gco = reinterpret_cast<PDFJSImpGCObj *>(parm);
+ PDFJSImpType *vType = gco->type;
+ HandleScope scope;
+ Persistent<Object> obj = Persistent<Object>::Cast(val);
+
+ Local<External> owrap = Local<External>::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" char *pdf_jsimp_new_obj_cpp(pdf_jsimp *imp, pdf_jsimp_type *type, void *natobj, pdf_jsimp_obj **robj)
+{
+ PDFJSImpType *vType = reinterpret_cast<PDFJSImpType *>(type);
+ HandleScope scope;
+ Local<Object> 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<pdf_jsimp_obj *>(new PDFJSImpObject(obj));
+ return NULL;
+}
+
+extern "C" char *pdf_jsimp_drop_obj_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj)
+{
+ delete reinterpret_cast<PDFJSImpObject *>(obj);
+ return NULL;
+}
+
+extern "C" char *pdf_jsimp_fromString_cpp(pdf_jsimp *imp, char *str, pdf_jsimp_obj **obj)
+{
+ *obj = reinterpret_cast<pdf_jsimp_obj *>(new PDFJSImpObject(str));
+ return NULL;
+}
+
+extern "C" char *pdf_jsimp_toString_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, char **str)
+{
+ *str = reinterpret_cast<PDFJSImpObject *>(obj)->toString();
+ return NULL;
+}
+
+extern "C" char *pdf_jsimp_toNumber_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, double *num)
+{
+ *num = reinterpret_cast<PDFJSImpObject *>(obj)->toNumber();
+ return NULL;
+}
+
+extern "C" char *pdf_jsimp_array_len_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, int *len)
+{
+ Local<Value> val = reinterpret_cast<PDFJSImpObject *>(obj)->toValue()->ToObject();
+ Local<Array> arr = Local<Array>::Cast(val);
+ *len = arr->Length();
+ return NULL;
+}
+
+extern "C" char *pdf_jsimp_array_item_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, int i, pdf_jsimp_obj **item)
+{
+ Local<Value> val = reinterpret_cast<PDFJSImpObject *>(obj)->toValue()->ToObject();
+ Local<Array> arr = Local<Array>::Cast(val);
+ *item = reinterpret_cast<pdf_jsimp_obj *>(new PDFJSImpObject(arr->Get(Number::New(i))));
+ return NULL;
+}
+
+extern "C" char *pdf_jsimp_execute_cpp(pdf_jsimp *imp, char *code)
+{
+ PDFJSImp *vImp = reinterpret_cast<PDFJSImp *>(imp);
+ HandleScope scope;
+ Context::Scope context_scope(vImp->context);
+ Handle<Script> script = Script::Compile(String::New(code));
+ if (script.IsEmpty())
+ return "compile failed in pdf_jsimp_execute";
+ script->Run();
+ return NULL;
+}
+
+extern "C" char *pdf_jsimp_execute_count_cpp(pdf_jsimp *imp, char *code, int count)
+{
+ PDFJSImp *vImp = reinterpret_cast<PDFJSImp *>(imp);
+ HandleScope scope;
+ Context::Scope context_scope(vImp->context);
+ Handle<Script> script = Script::Compile(String::New(code, count));
+ if (script.IsEmpty())
+ return "compile failed in pdf_jsimp_execute_count";
+ script->Run();
+ return NULL;
+} \ No newline at end of file