diff options
Diffstat (limited to 'macpdf/view.c')
-rw-r--r-- | macpdf/view.c | 525 |
1 files changed, 525 insertions, 0 deletions
diff --git a/macpdf/view.c b/macpdf/view.c new file mode 100644 index 00000000..b44718aa --- /dev/null +++ b/macpdf/view.c @@ -0,0 +1,525 @@ +/* This module implements a Carbon HIView object for a pattern plate + editor. */ + +#include "carbonpdf.h" + +#define kViewClassID CFSTR("com.artofcode.mupdf.View") +#define kViewPrivate 'MU_v' + +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; +} |