summaryrefslogtreecommitdiff
path: root/apps/macosx/macpdf.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/macosx/macpdf.c')
-rw-r--r--apps/macosx/macpdf.c613
1 files changed, 613 insertions, 0 deletions
diff --git a/apps/macosx/macpdf.c b/apps/macosx/macpdf.c
new file mode 100644
index 00000000..5e48a4ea
--- /dev/null
+++ b/apps/macosx/macpdf.c
@@ -0,0 +1,613 @@
+#include <Carbon/Carbon.h>
+
+#include <fitz.h>
+#include <mupdf.h>
+
+#define kViewClassID CFSTR("com.artofcode.mupdf.View")
+#define kViewPrivate 'MU_v'
+
+typedef struct viewctx
+{
+ WindowRef window;
+ HIViewRef view;
+ char *doctitle;
+
+ float zoom;
+ int rotate;
+ int pageno;
+
+ pdf_page *page;
+ fz_obj *pageobj;
+
+ pdf_xref *xref;
+ pdf_pagetree *pages;
+ pdf_outline *outline;
+ fz_renderer *rast;
+ fz_pixmap *image;
+} viewctx;
+
+static OSStatus
+view_construct(EventRef inEvent)
+{
+ OSStatus err;
+ viewctx *ctx;
+
+ ctx = (viewctx *)malloc(sizeof(viewctx));
+ require_action(ctx != NULL, CantMalloc, err = memFullErr);
+ err = GetEventParameter(inEvent, kEventParamHIObjectInstance,
+ typeHIObjectRef, NULL, sizeof(HIObjectRef), NULL,
+ (HIObjectRef *)&ctx->view);
+ require_noerr(err, ParameterMissing);
+ err = SetEventParameter(inEvent, kEventParamHIObjectInstance,
+ typeVoidPtr, sizeof(viewctx *), &ctx);
+
+ ParameterMissing:
+ if (err != noErr)
+ free(ctx);
+
+ CantMalloc:
+ return err;
+}
+
+static OSStatus
+view_destruct(EventRef inEvent, viewctx *inData)
+{
+ free(inData);
+ return noErr;
+}
+
+static OSStatus
+view_initialize(EventHandlerCallRef inCallRef, EventRef inEvent,
+ viewctx *ctx)
+{
+ OSStatus err;
+ HIRect bounds;
+
+ err = CallNextEventHandler(inCallRef, inEvent);
+ require_noerr(err, TroubleInSuperClass);
+
+ ctx->zoom = 1.0;
+ ctx->rotate = 0;
+ ctx->pageno = 1;
+ ctx->window = nil;
+
+ ParameterMissing:
+ TroubleInSuperClass:
+ return err;
+}
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846 /* pi */
+#endif
+
+static void
+cgcontext_set_rgba(CGContextRef ctx, unsigned int rgba)
+{
+ const double norm = 1.0 / 255;
+ CGContextSetRGBFillColor(ctx,
+ ((rgba >> 24) & 0xff) * norm,
+ ((rgba >> 16) & 0xff) * norm,
+ ((rgba >> 8) & 0xff) * norm,
+ (rgba & 0xff) * norm);
+}
+
+static void
+draw_dot(CGContextRef ctx, double x, double y, double r,
+ unsigned int rgba)
+{
+ cgcontext_set_rgba(ctx, rgba);
+ CGMutablePathRef path = CGPathCreateMutable();
+ CGPathAddArc(path, NULL, x, y, r, 0, 2 * M_PI, false);
+ CGContextAddPath(ctx, path);
+ CGPathRelease(path);
+ CGContextFillPath(ctx);
+}
+
+static void
+draw_raw_rect(CGContextRef ctx, double x0, double y0, double x1, double y1,
+ unsigned int rgba)
+{
+ HIRect rect;
+
+ cgcontext_set_rgba(ctx, rgba);
+ rect.origin.x = x0;
+ rect.origin.y = y0;
+ rect.size.width = x1 - x0;
+ rect.size.height = y1 - y0;
+ CGContextFillRect(ctx, rect);
+}
+
+static void
+draw_rect(CGContextRef ctx, double x, double y, double r,
+ unsigned int rgba)
+{
+ draw_raw_rect(ctx, x - r, y - r, x + r, y + r, rgba);
+}
+
+static OSStatus
+view_draw(EventRef inEvent, viewctx *ctx)
+{
+ OSStatus err;
+ CGContextRef gc;
+ CGDataProviderRef provider;
+ CGImageRef image;
+ CGColorSpaceRef colorspace;
+ CGRect rect;
+
+ err = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef,
+ NULL, sizeof(CGContextRef), NULL, &gc);
+ require_noerr(err, cleanup);
+
+ colorspace = CGColorSpaceCreateDeviceRGB();
+ provider = CGDataProviderCreateWithData(NULL, ctx->image->samples,
+ ctx->image->w * ctx->image->h * 4,
+ NULL);
+ image = CGImageCreate(ctx->image->w, ctx->image->h,
+ 8, 32, ctx->image->w * 4,
+ colorspace, kCGImageAlphaNoneSkipFirst, provider,
+ NULL, 0, kCGRenderingIntentDefault);
+
+ rect.origin.x = 0;
+ rect.origin.y = 0;
+ rect.size.width = ctx->image->w;
+ rect.size.height = ctx->image->h;
+ HIViewDrawCGImage(gc, &rect, image);
+
+ CGColorSpaceRelease(colorspace);
+ CGDataProviderRelease(provider);
+
+ cleanup:
+ return err;
+}
+
+static OSStatus
+view_get_data(EventRef inEvent, viewctx *inData)
+{
+ OSStatus err;
+ OSType tag;
+ Ptr ptr;
+ Size outSize;
+
+ /* Probably could use a bit more error checking here, for type
+ and size match. Also, just returning a viewctx seems a
+ little hacky. */
+ err = GetEventParameter(inEvent, kEventParamControlDataTag, typeEnumeration,
+ NULL, sizeof(OSType), NULL, &tag);
+ require_noerr(err, ParameterMissing);
+
+ err = GetEventParameter(inEvent, kEventParamControlDataBuffer, typePtr,
+ NULL, sizeof(Ptr), NULL, &ptr);
+
+ if (tag == kViewPrivate) {
+ *((viewctx **)ptr) = inData;
+ outSize = sizeof(viewctx *);
+ } else
+ err = errDataNotSupported;
+
+ if (err == noErr)
+ err = SetEventParameter(inEvent, kEventParamControlDataBufferSize, typeLongInteger,
+ sizeof(Size), &outSize);
+
+ ParameterMissing:
+ return err;
+}
+
+static OSStatus
+view_set_data(EventRef inEvent, viewctx *inData)
+{
+ OSStatus err;
+ Ptr ptr;
+ OSType tag;
+
+ err = GetEventParameter(inEvent, kEventParamControlDataTag, typeEnumeration,
+ NULL, sizeof(OSType), NULL, &tag);
+ require_noerr(err, ParameterMissing);
+
+ err = GetEventParameter(inEvent, kEventParamControlDataBuffer, typePtr,
+ NULL, sizeof(Ptr), NULL, &ptr);
+ require_noerr(err, ParameterMissing);
+
+ if (tag == 'Plat') {
+ //inData->p = *(plate **)ptr;
+ } else
+ err = errDataNotSupported;
+
+ ParameterMissing:
+ return err;
+}
+
+static OSStatus
+view_hittest(EventRef inEvent, viewctx *inData)
+{
+ OSStatus err;
+ HIPoint where;
+ HIRect bounds;
+ ControlPartCode part;
+
+ err = GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint,
+ NULL, sizeof(HIPoint), NULL, &where);
+ require_noerr(err, ParameterMissing);
+
+ err = HIViewGetBounds(inData->view, &bounds);
+ require_noerr(err, ParameterMissing);
+
+ if (CGRectContainsPoint(bounds, where))
+ part = 1;
+ else
+ part = kControlNoPart;
+ err = SetEventParameter(inEvent, kEventParamControlPart,
+ typeControlPartCode, sizeof(ControlPartCode),
+ &part);
+ printf("hittest %g, %g!\n", where.x, where.y);
+
+ ParameterMissing:
+ return err;
+}
+
+static void
+view_queue_draw(viewctx *pe)
+{
+ HIViewSetNeedsDisplay(pe->view, true);
+}
+
+
+static int
+view_motion(viewctx *pe, double x, double y)
+{
+ //if (pe->p->motmode == MOTION_MODE_MOVE)
+ //plate_motion_move(pe->p, x, y);
+ //else if (pe->p->motmode == MOTION_MODE_SELECT)
+ //plate_motion_select(pe->p, x, y);
+ view_queue_draw(pe);
+ return 1;
+}
+
+static int
+view_button_release(viewctx *pe)
+{
+ int need_redraw;
+
+ //need_redraw = (pe->p->motmode == MOTION_MODE_SELECT);
+
+ //plate_unpress(pe->p);
+
+ if (need_redraw)
+ view_queue_draw(pe);
+ return 1;
+}
+
+pascal OSStatus
+view_handler(EventHandlerCallRef inCallRef,
+ EventRef inEvent,
+ void* inUserData )
+{
+ OSStatus err = eventNotHandledErr;
+ UInt32 eventClass = GetEventClass(inEvent);
+ UInt32 eventKind = GetEventKind(inEvent);
+ viewctx *data = (viewctx *)inUserData;
+
+ switch (eventClass) {
+ case kEventClassHIObject:
+ switch (eventKind) {
+ case kEventHIObjectConstruct:
+ err = view_construct(inEvent);
+ break;
+ case kEventHIObjectInitialize:
+ err = view_initialize(inCallRef, inEvent, data);
+ break;
+ case kEventHIObjectDestruct:
+ err = view_destruct(inEvent, data);
+ break;
+ }
+ break;
+ case kEventClassControl:
+ switch (eventKind) {
+ case kEventControlInitialize:
+ err = noErr;
+ break;
+ case kEventControlDraw:
+ err = view_draw(inEvent, data);
+ break;
+ case kEventControlGetData:
+ err = view_get_data(inEvent, data);
+ break;
+ case kEventControlSetData:
+ err = view_set_data(inEvent, data);
+ break;
+ case kEventControlHitTest:
+ err = view_hittest(inEvent, data);
+ break;
+ /*...*/
+ }
+ break;
+ }
+ return err;
+}
+
+OSStatus
+view_register(void)
+{
+ OSStatus err = noErr;
+ static HIObjectClassRef view_ClassRef = NULL;
+
+ if (view_ClassRef == NULL) {
+ EventTypeSpec eventList[] = {
+ { kEventClassHIObject, kEventHIObjectConstruct },
+ { kEventClassHIObject, kEventHIObjectInitialize },
+ { kEventClassHIObject, kEventHIObjectDestruct },
+
+ { kEventClassControl, kEventControlActivate },
+ { kEventClassControl, kEventControlDeactivate },
+ { kEventClassControl, kEventControlDraw },
+ { kEventClassControl, kEventControlHiliteChanged },
+ { kEventClassControl, kEventControlHitTest },
+ { kEventClassControl, kEventControlInitialize },
+ { kEventClassControl, kEventControlGetData },
+ { kEventClassControl, kEventControlSetData },
+ };
+ err = HIObjectRegisterSubclass(kViewClassID,
+ kHIViewClassID,
+ NULL,
+ view_handler,
+ GetEventTypeCount(eventList),
+ eventList,
+ NULL,
+ &view_ClassRef);
+ }
+ return err;
+}
+
+OSStatus view_create(
+ WindowRef inWindow,
+ const HIRect* inBounds,
+ HIViewRef* outView)
+{
+ OSStatus err;
+ EventRef event;
+
+ err = view_register();
+ require_noerr(err, CantRegister);
+
+ err = CreateEvent(NULL, kEventClassHIObject, kEventHIObjectInitialize,
+ GetCurrentEventTime(), 0, &event);
+ require_noerr(err, CantCreateEvent);
+
+ if (inBounds != NULL) {
+ err = SetEventParameter(event, 'Boun', typeHIRect, sizeof(HIRect),
+ inBounds);
+ require_noerr(err, CantSetParameter);
+ }
+
+ err = HIObjectCreate(kViewClassID, event, (HIObjectRef*)outView);
+ require_noerr(err, CantCreate);
+
+ if (inWindow != NULL) {
+ HIViewRef root;
+ err = GetRootControl(inWindow, &root);
+ require_noerr(err, CantGetRootView);
+ err = HIViewAddSubview(root, *outView);
+ }
+ CantCreate:
+ CantGetRootView:
+ CantSetParameter:
+ CantCreateEvent:
+ ReleaseEvent(event);
+ CantRegister:
+ return err;
+}
+
+OSStatus
+view_openpdf(HIViewRef view, char *filename)
+{
+ OSStatus err;
+ viewctx *ctx;
+
+ err = GetControlData(view, 1, kViewPrivate, 4, &ctx, NULL);
+ require_noerr(err, CantGetPrivate);
+
+ fz_error *error;
+ fz_obj *obj;
+ pdf_xref *xref;
+
+ error = pdf_newxref(&xref);
+ if (error)
+ fz_abort(error);
+ ctx->xref = xref;
+
+ error = pdf_loadxref(xref, filename);
+ if (error)
+ {
+ fz_warn(error->msg);
+ printf("trying to repair...\n");
+ error = pdf_repairxref(xref, filename);
+ if (error)
+ fz_abort(error);
+ }
+
+ error = pdf_decryptxref(xref);
+ if (error)
+ fz_abort(error);
+
+#if 0
+ if (xref->crypt)
+ {
+ error = pdf_setpassword(xref->crypt, password);
+ if (error) fz_abort(error);
+ }
+#endif
+
+ obj = fz_dictgets(xref->trailer, "Root");
+ if (!obj)
+ fz_abort(fz_throw("syntaxerror: missing Root object"));
+ error = pdf_loadindirect(&xref->root, xref, obj);
+ if (error) fz_abort(error);
+
+ obj = fz_dictgets(xref->trailer, "Info");
+ if (obj)
+ {
+ error = pdf_loadindirect(&xref->info, xref, obj);
+ if (error) fz_abort(error);
+ }
+
+ error = pdf_loadnametrees(xref);
+ if (error) fz_abort(error);
+
+ error = pdf_loadoutline(&ctx->outline, xref);
+ if (error) fz_abort(error);
+
+ ctx->doctitle = filename;
+ if (xref->info)
+ {
+ obj = fz_dictgets(xref->info, "Title");
+ if (obj)
+ {
+ error = pdf_toutf8(&ctx->doctitle, obj);
+ if (error) fz_abort(error);
+ }
+ }
+
+ error = pdf_loadpagetree(&ctx->pages, xref);
+ if (error) fz_abort(error);
+
+ //count = pdf_getpagecount(ctx->pages);
+
+ error = fz_newrenderer(&ctx->rast, pdf_devicergb, 0, 1024 * 512);
+ if (error) fz_abort(error);
+
+ ctx->image = nil;
+ printf("hit bottom\n");
+
+
+ CantGetPrivate:
+ return err;
+}
+
+OSStatus view_showpage(HIViewRef view)
+{
+ OSStatus err;
+ viewctx *ctx;
+
+ err = GetControlData(view, 1, kViewPrivate, 4, &ctx, NULL);
+ require_noerr(err, CantGetPrivate);
+
+ fz_error *error;
+ fz_matrix ctm;
+ fz_rect bbox;
+ fz_obj *obj;
+ char s[256];
+
+ assert(ctx->pageno > 0 && ctx->pageno <= pdf_getpagecount(ctx->pages));
+
+ //XDefineCursor(xdpy, xwin, xcwait);
+
+ if (ctx->image)
+ fz_droppixmap(ctx->image);
+ ctx->image = nil;
+
+ obj = pdf_getpageobject(ctx->pages, ctx->pageno - 1);
+ if (obj == ctx->pageobj)
+ goto Lskipload;
+ ctx->pageobj = obj;
+
+ if (ctx->page)
+ pdf_droppage(ctx->page);
+
+ error = pdf_loadpage(&ctx->page, ctx->xref, ctx->pageobj);
+ if (error)
+ fz_abort(error);
+
+Lskipload:
+
+ ctm = fz_identity();
+ ctm = fz_concat(ctm, fz_translate(0, -ctx->page->mediabox.max.y));
+ ctm = fz_concat(ctm, fz_scale(ctx->zoom, -ctx->zoom));
+ ctm = fz_concat(ctm, fz_rotate(ctx->rotate + ctx->page->rotate));
+
+ bbox = fz_transformaabb(ctm, ctx->page->mediabox);
+
+ error = fz_rendertree(&ctx->image, ctx->rast, ctx->page->tree, ctm, fz_roundrect(bbox), 1);
+ if (error)
+ fz_abort(error);
+
+ //XDefineCursor(xdpy, xwin, xcarrow);
+
+ {
+ char buf[512];
+ int count = pdf_getpagecount(ctx->pages);
+ sprintf(buf, "%s - %d/%d", ctx->doctitle, ctx->pageno, count);
+ //xtitle(buf);
+ }
+
+ //xresize();
+ //xblit();
+ CantGetPrivate:
+ return err;
+}
+
+static void
+init_window(viewctx *ctx)
+{
+ WindowRef window = ctx->window;
+ HIViewRef viewPane;
+ static const HIViewID viewPaneID = { 'Poof', 666 };
+ OSStatus err;
+
+ err = HIViewFindByID(HIViewGetRoot(window), viewPaneID, &viewPane);
+ printf("err from findbyid: %d\n", err);
+}
+
+int
+openpdf(WindowRef window, const char *filename)
+{
+ HIViewRef viewPane;
+ static const HIViewID viewPaneID = { 'Poof', 666 };
+ OSStatus err;
+
+ err = HIViewFindByID(HIViewGetRoot(window), viewPaneID, &viewPane);
+ require_noerr(err, cleanup);
+
+ err = view_openpdf(viewPane, filename);
+ require_noerr(err, cleanup);
+
+ err = view_showpage(viewPane);
+
+ cleanup:
+ return err;
+}
+
+int main(int argc, char *argv[])
+{
+ IBNibRef nibRef;
+ OSStatus err;
+ WindowRef window;
+
+ fz_cpudetect();
+ fz_accelerate();
+
+ err = view_register();
+ require_noerr(err, CantRegisterView);
+
+ err = CreateNibReference(CFSTR("main"), &nibRef);
+ printf("err = %d\n", err);
+ require_noerr(err, CantGetNibRef);
+
+ err = SetMenuBarFromNib(nibRef, CFSTR("MenuBar"));
+ require_noerr(err, CantSetMenuBar);
+
+ err = CreateWindowFromNib(nibRef, CFSTR("MainWindow"), &window);
+ require_noerr(err, CantCreateWindow);
+
+ openpdf(window, "/Users/tor/src/pdf/tiger.pdf");
+
+ DisposeNibReference(nibRef);
+
+ ShowWindow(window);
+ RunApplicationEventLoop();
+
+ CantGetNibRef:
+ CantSetMenuBar:
+ CantCreateWindow:
+ CantRegisterView:
+
+ return err;
+}