summaryrefslogtreecommitdiff
path: root/pdf
diff options
context:
space:
mode:
authorPaul Gardiner <paul@glidos.net>2012-05-14 13:48:39 +0100
committerPaul Gardiner <paul@glidos.net>2012-05-15 13:20:28 +0100
commit0d8050285b4684ffcfe5472e85e5fce195e83988 (patch)
tree302ce07ea32f94cee922e54a8f8bdecb0600fb52 /pdf
parent407e39962d537d7c9cc38110cf37c0b93f329d0e (diff)
downloadmupdf-0d8050285b4684ffcfe5472e85e5fce195e83988.tar.xz
JavaScript: arrange for v8 gc to destroy native-side objects
Diffstat (limited to 'pdf')
-rw-r--r--pdf/pdf_js.c2
-rw-r--r--pdf/pdf_jsimp_v8.cpp185
2 files changed, 142 insertions, 45 deletions
diff --git a/pdf/pdf_js.c b/pdf/pdf_js.c
index 49771421..6af7c672 100644
--- a/pdf/pdf_js.c
+++ b/pdf/pdf_js.c
@@ -8,7 +8,6 @@ struct pdf_js_s
pdf_jsimp *imp;
pdf_jsimp_type *doctype;
pdf_jsimp_type *fieldtype;
- pdf_jsimp_obj *jsdoc;
};
static pdf_jsimp_obj *field_getValue(void *jsctx, void *obj)
@@ -137,7 +136,6 @@ void pdf_drop_js(pdf_js *js)
if (js)
{
fz_context *ctx = js->doc->ctx;
- pdf_jsimp_drop_obj(js->imp, js->jsdoc);
pdf_jsimp_drop_type(js->imp, js->fieldtype);
pdf_jsimp_drop_type(js->imp, js->doctype);
pdf_drop_jsimp(js->imp);
diff --git a/pdf/pdf_jsimp_v8.cpp b/pdf/pdf_jsimp_v8.cpp
index 158fe63c..837a4919 100644
--- a/pdf/pdf_jsimp_v8.cpp
+++ b/pdf/pdf_jsimp_v8.cpp
@@ -9,35 +9,44 @@ extern "C" {
#include "mupdf-internal.h"
}
+#include <vector>
+#include <set>
#include <v8.h>
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
{
- fz_context *ctx;
- void *jsctx;
- Persistent<Context> context;
+ void *jsctx;
+ pdf_jsimp_method *meth;
- PDFJSImp(fz_context *ctx, void *jsctx) : ctx(ctx), jsctx(jsctx)
- {
- HandleScope scope;
- context = Persistent<Context>::New(Context::New());
- }
+ PDFJSImpMethod(void *jsctx, pdf_jsimp_method *meth) : jsctx(jsctx), meth(meth) {}
+};
- ~PDFJSImp()
- {
- context.Dispose();
- }
+/* 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) {}
};
-/* We need only a couple of specific methods for calc.pdf */
+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)
{
@@ -48,43 +57,89 @@ struct PDFJSImpType
~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();
}
};
-struct PDFJSImpMethod
+/* Info via which we destroy the client side part of objects that
+ * v8 garbage collects */
+struct PDFJSImpGCObj
{
- void *jsctx;
- pdf_jsimp_method *meth;
+ Persistent<Object> pobj;
+ PDFJSImpType *type;
- PDFJSImpMethod(void *jsctx, pdf_jsimp_method *meth) : jsctx(jsctx), meth(meth) {}
+ PDFJSImpGCObj(Handle<Object> obj, PDFJSImpType *type): type(type)
+ {
+ pobj = Persistent<Object>::New(obj);
+ }
+
+ ~PDFJSImpGCObj()
+ {
+ pobj.Dispose();
+ }
};
-struct PDFJSImpProperty
+/* Internal representation of the pdf_jsimp object */
+struct PDFJSImp
{
- void *jsctx;
- pdf_jsimp_getter *get;
- pdf_jsimp_setter *set;
+ fz_context *ctx;
+ void *jsctx;
+ Persistent<Context> context;
+ vector<PDFJSImpType *> types;
+ set<PDFJSImpGCObj *> gclist;
- PDFJSImpProperty(void *jsctx, pdf_jsimp_getter *get, pdf_jsimp_setter *set) : jsctx(jsctx), get(get), set(set) {}
+ 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)
+ PDFJSImpObject(Handle<Value> obj): utf8(NULL)
{
pobj = Persistent<Value>::New(obj);
- utf8 = NULL;
}
- PDFJSImpObject(const char *str)
+ PDFJSImpObject(const char *str): utf8(NULL)
{
pobj = Persistent<Value>::New(String::New(str));
- utf8 = NULL;
}
~PDFJSImpObject()
@@ -119,31 +174,34 @@ extern "C" void pdf_drop_jsimp(pdf_jsimp *imp)
extern "C" pdf_jsimp_type *pdf_jsimp_new_type(pdf_jsimp *imp, pdf_jsimp_dtr *dtr)
{
- return reinterpret_cast<pdf_jsimp_type *>(new PDFJSImpType((PDFJSImp *)imp, dtr));
+ PDFJSImp *vImp = reinterpret_cast<PDFJSImp *>(imp);
+ PDFJSImpType *vType = new PDFJSImpType(vImp, dtr);
+ vImp->types.push_back(vType);
+ return reinterpret_cast<pdf_jsimp_type *>(vType);
}
extern "C" void pdf_jsimp_drop_type(pdf_jsimp *imp, pdf_jsimp_type *type)
{
- delete reinterpret_cast<PDFJSImpType *>(type);
+ /* Types are recorded and destroyed as part of PDFJSImp */
}
static Handle<Value> callMethod(const Arguments &args)
{
HandleScope scope;
- Local<Object> self = args.Holder();
- Local<External> owrap;
- void *nself = NULL;
Local<External> mwrap = Local<External>::Cast(args.Data());
PDFJSImpMethod *m = (PDFJSImpMethod *)mwrap->Value();
- int c = args.Length();
- PDFJSImpObject **native_args = new PDFJSImpObject*[c];
+ 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]);
@@ -164,18 +222,27 @@ extern "C" void pdf_jsimp_addmethod(pdf_jsimp *imp, pdf_jsimp_type *type, char *
PDFJSImpType *vType = reinterpret_cast<PDFJSImpType *>(type);
HandleScope scope;
- vType->templ->Set(String::New(name), FunctionTemplate::New(callMethod, External::New(new PDFJSImpMethod(vType->imp->jsctx, meth))));
+ 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);
}
static Handle<Value> getProp(Local<String> property, const AccessorInfo &info)
{
HandleScope scope;
- Local<Object> self = info.Holder();
- Local<External> owrap = Local<External>::Cast(self->GetInternalField(0));
Local<External> pwrap = Local<External>::Cast(info.Data());
PDFJSImpProperty *p = reinterpret_cast<PDFJSImpProperty *>(pwrap->Value());
- PDFJSImpObject *obj = reinterpret_cast<PDFJSImpObject *>(p->get(p->jsctx, owrap->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 = reinterpret_cast<PDFJSImpObject *>(p->get(p->jsctx, nself));
Handle<Value> val = obj->toValue();
delete obj;
return scope.Close(val);
@@ -184,13 +251,21 @@ static Handle<Value> getProp(Local<String> property, const AccessorInfo &info)
static void setProp(Local<String> property, Local<Value> value, const AccessorInfo &info)
{
HandleScope scope;
- Local<Object> self = info.Holder();
- Local<External> owrap = Local<External>::Cast(self->GetInternalField(0));
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, owrap->Value(), reinterpret_cast<pdf_jsimp_obj *>(obj));
+ p->set(p->jsctx, nself, reinterpret_cast<pdf_jsimp_obj *>(obj));
delete obj;
}
@@ -199,7 +274,9 @@ extern "C" void pdf_jsimp_addproperty(pdf_jsimp *imp, pdf_jsimp_type *type, char
PDFJSImpType *vType = reinterpret_cast<PDFJSImpType *>(type);
HandleScope scope;
- vType->templ->SetAccessor(String::New(name), getProp, setProp, External::New(new PDFJSImpProperty(vType->imp->jsctx, get, set)));
+ 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);
}
extern "C" void pdf_jsimp_set_global_type(pdf_jsimp *imp, pdf_jsimp_type *type)
@@ -211,6 +288,19 @@ extern "C" void pdf_jsimp_set_global_type(pdf_jsimp *imp, pdf_jsimp_type *type)
vImp->context = Persistent<Context>::New(Context::New(NULL, vType->templ));
}
+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" pdf_jsimp_obj *pdf_jsimp_new_obj(pdf_jsimp *imp, pdf_jsimp_type *type, void *natobj)
{
PDFJSImpType *vType = reinterpret_cast<PDFJSImpType *>(type);
@@ -218,6 +308,15 @@ extern "C" pdf_jsimp_obj *pdf_jsimp_new_obj(pdf_jsimp *imp, pdf_jsimp_type *type
Local<Object> obj = vType->templ->NewInstance();
obj->SetInternalField(0, External::New(natobj));
+ /* Arrange for destructor to be called on the client sire object
+ * when the v8 object is garbage collected */
+ if (vType->dtr)
+ {
+ PDFJSImpGCObj *gco = new PDFJSImpGCObj(obj, vType);
+ vType->imp->gclist.insert(gco);
+ gco->pobj.MakeWeak(gco, gcCallback);
+ }
+
return reinterpret_cast<pdf_jsimp_obj *>(new PDFJSImpObject(obj));
}