Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
7643 views
1
/*
2
This file contains the v8 implementation of the pdf_jsimp API
3
*/
4
5
extern "C" {
6
#include "mupdf/fitz.h"
7
#include "mupdf/pdf.h"
8
#include "pdf-jsimp-cpp.h"
9
}
10
11
#include <vector>
12
#include <set>
13
#include <v8.h>
14
15
using namespace v8;
16
using namespace std;
17
18
struct PDFJSImp;
19
20
/* Object we pass to FunctionTemplate::New, which v8 passes back to us in
21
* callMethod, allowing us to call our client's, passed-in method. */
22
struct PDFJSImpMethod
23
{
24
PDFJSImp *imp;
25
pdf_jsimp_method *meth;
26
27
PDFJSImpMethod(PDFJSImp *imp, pdf_jsimp_method *meth) : imp(imp), meth(meth) {}
28
};
29
30
/* Object we pass to ObjectTemplate::SetAccessor, which v8 passes back to us in
31
* setProp and getProp, allowing us to call our client's, passed-in set/get methods. */
32
struct PDFJSImpProperty
33
{
34
PDFJSImp *imp;
35
pdf_jsimp_getter *get;
36
pdf_jsimp_setter *set;
37
38
PDFJSImpProperty(PDFJSImp *imp, pdf_jsimp_getter *get, pdf_jsimp_setter *set) : imp(imp), get(get), set(set) {}
39
};
40
41
/* Internal representation of the pdf_jsimp_type object */
42
struct PDFJSImpType
43
{
44
PDFJSImp *imp;
45
Persistent<ObjectTemplate> templ;
46
pdf_jsimp_dtr *dtr;
47
vector<PDFJSImpMethod *> methods;
48
vector<PDFJSImpProperty *> properties;
49
50
PDFJSImpType(PDFJSImp *imp, pdf_jsimp_dtr *dtr): imp(imp), dtr(dtr)
51
{
52
HandleScope scope;
53
templ = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
54
templ->SetInternalFieldCount(1);
55
}
56
57
~PDFJSImpType()
58
{
59
vector<PDFJSImpMethod *>::iterator mit;
60
for (mit = methods.begin(); mit < methods.end(); mit++)
61
delete *mit;
62
63
vector<PDFJSImpProperty *>::iterator pit;
64
for (pit = properties.begin(); pit < properties.end(); pit++)
65
delete *pit;
66
67
templ.Dispose();
68
}
69
};
70
71
/* Info via which we destroy the client side part of objects that
72
* v8 garbage collects */
73
struct PDFJSImpGCObj
74
{
75
Persistent<Object> pobj;
76
PDFJSImpType *type;
77
78
PDFJSImpGCObj(Handle<Object> obj, PDFJSImpType *type): type(type)
79
{
80
pobj = Persistent<Object>::New(obj);
81
}
82
83
~PDFJSImpGCObj()
84
{
85
pobj.Dispose();
86
}
87
};
88
89
/* Internal representation of the pdf_jsimp object */
90
struct PDFJSImp
91
{
92
fz_context *ctx;
93
void *jsctx;
94
Persistent<Context> context;
95
vector<PDFJSImpType *> types;
96
set<PDFJSImpGCObj *> gclist;
97
98
PDFJSImp(fz_context *ctx, void *jsctx) : ctx(ctx), jsctx(jsctx)
99
{
100
HandleScope scope;
101
context = Persistent<Context>::New(Context::New());
102
}
103
104
~PDFJSImp()
105
{
106
HandleScope scope;
107
/* Tell v8 our context will not be used again */
108
context.Dispose();
109
110
/* Unlink and destroy all the objects that v8 has yet to gc */
111
set<PDFJSImpGCObj *>::iterator oit;
112
for (oit = gclist.begin(); oit != gclist.end(); oit++)
113
{
114
(*oit)->pobj.ClearWeak(); /* So that gcCallback wont get called */
115
PDFJSImpType *vType = (*oit)->type;
116
Local<External> owrap = Local<External>::Cast((*oit)->pobj->GetInternalField(0));
117
vType->dtr(vType->imp->jsctx, owrap->Value());
118
delete *oit;
119
}
120
121
vector<PDFJSImpType *>::iterator it;
122
for (it = types.begin(); it < types.end(); it++)
123
delete *it;
124
}
125
};
126
127
/* Internal representation of the pdf_jsimp_obj object */
128
class PDFJSImpObject
129
{
130
Persistent<Value> pobj;
131
String::Utf8Value *utf8;
132
133
public:
134
PDFJSImpObject(Handle<Value> obj): utf8(NULL)
135
{
136
pobj = Persistent<Value>::New(obj);
137
}
138
139
PDFJSImpObject(const char *str): utf8(NULL)
140
{
141
pobj = Persistent<Value>::New(String::New(str));
142
}
143
144
PDFJSImpObject(double num): utf8(NULL)
145
{
146
pobj = Persistent<Value>::New(Number::New(num));
147
}
148
149
~PDFJSImpObject()
150
{
151
delete utf8;
152
pobj.Dispose();
153
}
154
155
int type()
156
{
157
if (pobj->IsNull())
158
return JS_TYPE_NULL;
159
else if (pobj->IsString() || pobj->IsStringObject())
160
return JS_TYPE_STRING;
161
else if (pobj->IsNumber() || pobj->IsNumberObject())
162
return JS_TYPE_NUMBER;
163
else if (pobj->IsArray())
164
return JS_TYPE_ARRAY;
165
else if (pobj->IsBoolean() || pobj->IsBooleanObject())
166
return JS_TYPE_BOOLEAN;
167
else
168
return JS_TYPE_UNKNOWN;
169
}
170
171
char *toString()
172
{
173
delete utf8;
174
utf8 = new String::Utf8Value(pobj);
175
return **utf8;
176
}
177
178
double toNumber()
179
{
180
return pobj->NumberValue();
181
}
182
183
Handle<Value> toValue()
184
{
185
return pobj;
186
}
187
};
188
189
extern "C" fz_context *pdf_jsimp_ctx_cpp(pdf_jsimp *imp)
190
{
191
return reinterpret_cast<PDFJSImp *>(imp)->ctx;
192
}
193
194
extern "C" const char *pdf_new_jsimp_cpp(fz_context *ctx, void *jsctx, pdf_jsimp **imp)
195
{
196
Locker lock;
197
*imp = reinterpret_cast<pdf_jsimp *>(new PDFJSImp(ctx, jsctx));
198
199
return NULL;
200
}
201
202
extern "C" const char *pdf_drop_jsimp_cpp(pdf_jsimp *imp)
203
{
204
Locker lock;
205
delete reinterpret_cast<PDFJSImp *>(imp);
206
return NULL;
207
}
208
209
extern "C" const char *pdf_jsimp_new_type_cpp(pdf_jsimp *imp, pdf_jsimp_dtr *dtr, pdf_jsimp_type **type)
210
{
211
Locker lock;
212
PDFJSImp *vImp = reinterpret_cast<PDFJSImp *>(imp);
213
PDFJSImpType *vType = new PDFJSImpType(vImp, dtr);
214
vImp->types.push_back(vType);
215
*type = reinterpret_cast<pdf_jsimp_type *>(vType);
216
return NULL;
217
}
218
219
extern "C" const char *pdf_jsimp_drop_type_cpp(pdf_jsimp *imp, pdf_jsimp_type *type)
220
{
221
/* Types are recorded and destroyed as part of PDFJSImp */
222
return NULL;
223
}
224
225
static Handle<Value> callMethod(const Arguments &args)
226
{
227
HandleScope scope;
228
Local<External> mwrap = Local<External>::Cast(args.Data());
229
PDFJSImpMethod *m = (PDFJSImpMethod *)mwrap->Value();
230
231
Local<Object> self = args.Holder();
232
Local<External> owrap;
233
void *nself = NULL;
234
if (self->InternalFieldCount() > 0)
235
{
236
owrap = Local<External>::Cast(self->GetInternalField(0));
237
nself = owrap->Value();
238
}
239
240
int c = args.Length();
241
PDFJSImpObject **native_args = new PDFJSImpObject*[c];
242
for (int i = 0; i < c; i++)
243
native_args[i] = new PDFJSImpObject(args[i]);
244
245
PDFJSImpObject *obj = reinterpret_cast<PDFJSImpObject *>(pdf_jsimp_call_method(reinterpret_cast<pdf_jsimp *>(m->imp), m->meth, m->imp->jsctx, nself, c, reinterpret_cast<pdf_jsimp_obj **>(native_args)));
246
Handle<Value> val;
247
if (obj)
248
val = obj->toValue();
249
delete obj;
250
251
for (int i = 0; i < c; i++)
252
delete native_args[i];
253
254
delete native_args;
255
256
return scope.Close(val);
257
}
258
259
extern "C" const char *pdf_jsimp_addmethod_cpp(pdf_jsimp *imp, pdf_jsimp_type *type, char *name, pdf_jsimp_method *meth)
260
{
261
Locker lock;
262
PDFJSImpType *vType = reinterpret_cast<PDFJSImpType *>(type);
263
HandleScope scope;
264
265
PDFJSImpMethod *pmeth = new PDFJSImpMethod(vType->imp, meth);
266
vType->templ->Set(String::New(name), FunctionTemplate::New(callMethod, External::New(pmeth)));
267
vType->methods.push_back(pmeth);
268
return NULL;
269
}
270
271
static Handle<Value> getProp(Local<String> property, const AccessorInfo &info)
272
{
273
HandleScope scope;
274
Local<External> pwrap = Local<External>::Cast(info.Data());
275
PDFJSImpProperty *p = reinterpret_cast<PDFJSImpProperty *>(pwrap->Value());
276
277
Local<Object> self = info.Holder();
278
Local<External> owrap;
279
void *nself = NULL;
280
if (self->InternalFieldCount() > 0)
281
{
282
Local<Value> val = self->GetInternalField(0);
283
if (val->IsExternal())
284
{
285
owrap = Local<External>::Cast(val);
286
nself = owrap->Value();
287
}
288
}
289
290
PDFJSImpObject *obj = reinterpret_cast<PDFJSImpObject *>(pdf_jsimp_call_getter(reinterpret_cast<pdf_jsimp *>(p->imp), p->get, p->imp->jsctx, nself));
291
Handle<Value> val;
292
if (obj)
293
val = obj->toValue();
294
delete obj;
295
return scope.Close(val);
296
}
297
298
static void setProp(Local<String> property, Local<Value> value, const AccessorInfo &info)
299
{
300
HandleScope scope;
301
Local<External> wrap = Local<External>::Cast(info.Data());
302
PDFJSImpProperty *p = reinterpret_cast<PDFJSImpProperty *>(wrap->Value());
303
304
Local<Object> self = info.Holder();
305
Local<External> owrap;
306
void *nself = NULL;
307
if (self->InternalFieldCount() > 0)
308
{
309
owrap = Local<External>::Cast(self->GetInternalField(0));
310
nself = owrap->Value();
311
}
312
313
PDFJSImpObject *obj = new PDFJSImpObject(value);
314
315
pdf_jsimp_call_setter(reinterpret_cast<pdf_jsimp *>(p->imp), p->set, p->imp->jsctx, nself, reinterpret_cast<pdf_jsimp_obj *>(obj));
316
delete obj;
317
}
318
319
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)
320
{
321
Locker lock;
322
PDFJSImpType *vType = reinterpret_cast<PDFJSImpType *>(type);
323
HandleScope scope;
324
325
PDFJSImpProperty *prop = new PDFJSImpProperty(vType->imp, get, set);
326
vType->templ->SetAccessor(String::New(name), getProp, setProp, External::New(prop));
327
vType->properties.push_back(prop);
328
return NULL;
329
}
330
331
extern "C" const char *pdf_jsimp_set_global_type_cpp(pdf_jsimp *imp, pdf_jsimp_type *type)
332
{
333
Locker lock;
334
PDFJSImp *vImp = reinterpret_cast<PDFJSImp *>(imp);
335
PDFJSImpType *vType = reinterpret_cast<PDFJSImpType *>(type);
336
HandleScope scope;
337
338
vImp->context = Persistent<Context>::New(Context::New(NULL, vType->templ));
339
return NULL;
340
}
341
342
static void gcCallback(Persistent<Value> val, void *parm)
343
{
344
PDFJSImpGCObj *gco = reinterpret_cast<PDFJSImpGCObj *>(parm);
345
PDFJSImpType *vType = gco->type;
346
HandleScope scope;
347
Persistent<Object> obj = Persistent<Object>::Cast(val);
348
349
Local<External> owrap = Local<External>::Cast(obj->GetInternalField(0));
350
vType->dtr(vType->imp->jsctx, owrap->Value());
351
vType->imp->gclist.erase(gco);
352
delete gco; /* Disposes of the persistent handle */
353
}
354
355
extern "C" const char *pdf_jsimp_new_obj_cpp(pdf_jsimp *imp, pdf_jsimp_type *type, void *natobj, pdf_jsimp_obj **robj)
356
{
357
Locker lock;
358
PDFJSImpType *vType = reinterpret_cast<PDFJSImpType *>(type);
359
HandleScope scope;
360
Local<Object> obj = vType->templ->NewInstance();
361
obj->SetInternalField(0, External::New(natobj));
362
363
/* Arrange for destructor to be called on the client-side object
364
* when the v8 object is garbage collected */
365
if (vType->dtr)
366
{
367
/* Wrap obj in a PDFJSImpGCObj, which takes a persistent handle to
368
* obj, and stores its type with it. The persistent handle tells v8
369
* it cannot just destroy obj leaving the client-side object hanging */
370
PDFJSImpGCObj *gco = new PDFJSImpGCObj(obj, vType);
371
/* Keep the wrapped object in a list, so that we can take back control
372
* of destroying client-side objects when shutting down this context */
373
vType->imp->gclist.insert(gco);
374
/* Tell v8 that it can destroy the persistent handle to obj when it has
375
* no further need for it, but it must inform us via gcCallback */
376
gco->pobj.MakeWeak(gco, gcCallback);
377
}
378
379
*robj = reinterpret_cast<pdf_jsimp_obj *>(new PDFJSImpObject(obj));
380
return NULL;
381
}
382
383
extern "C" const char *pdf_jsimp_drop_obj_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj)
384
{
385
Locker lock;
386
delete reinterpret_cast<PDFJSImpObject *>(obj);
387
return NULL;
388
}
389
390
extern "C" const char *pdf_jsimp_to_type_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, int *type)
391
{
392
Locker lock;
393
*type = reinterpret_cast<PDFJSImpObject *>(obj)->type();
394
return NULL;
395
}
396
397
extern "C" const char *pdf_jsimp_from_string_cpp(pdf_jsimp *imp, char *str, pdf_jsimp_obj **obj)
398
{
399
Locker lock;
400
*obj = reinterpret_cast<pdf_jsimp_obj *>(new PDFJSImpObject(str));
401
return NULL;
402
}
403
404
extern "C" const char *pdf_jsimp_to_string_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, char **str)
405
{
406
Locker lock;
407
*str = reinterpret_cast<PDFJSImpObject *>(obj)->toString();
408
return NULL;
409
}
410
411
extern "C" const char *pdf_jsimp_from_number_cpp(pdf_jsimp *imp, double num, pdf_jsimp_obj **obj)
412
{
413
Locker lock;
414
*obj = reinterpret_cast<pdf_jsimp_obj *>(new PDFJSImpObject(num));
415
return NULL;
416
}
417
418
extern "C" const char *pdf_jsimp_to_number_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, double *num)
419
{
420
Locker lock;
421
*num = reinterpret_cast<PDFJSImpObject *>(obj)->toNumber();
422
return NULL;
423
}
424
425
extern "C" const char *pdf_jsimp_array_len_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, int *len)
426
{
427
Locker lock;
428
Local<Object> jsobj = reinterpret_cast<PDFJSImpObject *>(obj)->toValue()->ToObject();
429
Local<Array> arr = Local<Array>::Cast(jsobj);
430
*len = arr->Length();
431
return NULL;
432
}
433
434
extern "C" const char *pdf_jsimp_array_item_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, int i, pdf_jsimp_obj **item)
435
{
436
Locker lock;
437
Local<Object> jsobj = reinterpret_cast<PDFJSImpObject *>(obj)->toValue()->ToObject();
438
*item = reinterpret_cast<pdf_jsimp_obj *>(new PDFJSImpObject(jsobj->Get(Number::New(i))));
439
return NULL;
440
}
441
442
extern "C" const char *pdf_jsimp_property_cpp(pdf_jsimp *imp, pdf_jsimp_obj *obj, char *prop, pdf_jsimp_obj **pobj)
443
{
444
Locker lock;
445
Local<Object> jsobj = reinterpret_cast<PDFJSImpObject *>(obj)->toValue()->ToObject();
446
*pobj = reinterpret_cast<pdf_jsimp_obj *>(new PDFJSImpObject(jsobj->Get(String::New(prop))));
447
return NULL;
448
}
449
450
extern "C" const char *pdf_jsimp_execute_cpp(pdf_jsimp *imp, char *code)
451
{
452
Locker lock;
453
PDFJSImp *vImp = reinterpret_cast<PDFJSImp *>(imp);
454
HandleScope scope;
455
Context::Scope context_scope(vImp->context);
456
Handle<Script> script = Script::Compile(String::New(code));
457
if (script.IsEmpty())
458
return "compile failed in pdf_jsimp_execute";
459
script->Run();
460
return NULL;
461
}
462
463
extern "C" const char *pdf_jsimp_execute_count_cpp(pdf_jsimp *imp, char *code, int count)
464
{
465
Locker lock;
466
PDFJSImp *vImp = reinterpret_cast<PDFJSImp *>(imp);
467
HandleScope scope;
468
Context::Scope context_scope(vImp->context);
469
Handle<Script> script = Script::Compile(String::New(code, count));
470
if (script.IsEmpty())
471
return "compile failed in pdf_jsimp_execute_count";
472
script->Run();
473
return NULL;
474
}
475
476