diff options
-rw-r--r-- | ios/MuPDF.xcodeproj/project.pbxproj | 4 | ||||
-rw-r--r-- | ios/loading.png | bin | 0 -> 3258 bytes | |||
-rw-r--r-- | ios/main.m | 319 |
3 files changed, 136 insertions, 187 deletions
diff --git a/ios/MuPDF.xcodeproj/project.pbxproj b/ios/MuPDF.xcodeproj/project.pbxproj index a70ca95e..6c8be45e 100644 --- a/ios/MuPDF.xcodeproj/project.pbxproj +++ b/ios/MuPDF.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 96476B4614599D9400EA67C0 /* loading.png in Resources */ = {isa = PBXBuildFile; fileRef = 96476B4514599D9400EA67C0 /* loading.png */; }; 968F2E9C14539C880085264E /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 968F2E9B14539C880085264E /* UIKit.framework */; }; 968F2E9E14539C880085264E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 968F2E9D14539C880085264E /* Foundation.framework */; }; 968F2EA014539C880085264E /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 968F2E9F14539C880085264E /* CoreGraphics.framework */; }; @@ -22,6 +23,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 96476B4514599D9400EA67C0 /* loading.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = loading.png; sourceTree = "<group>"; }; 968F2E8E14539BEB0085264E /* build_libs.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = build_libs.sh; sourceTree = "<group>"; }; 968F2E8F14539BEB0085264E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 968F2E9014539BEB0085264E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; }; @@ -64,6 +66,7 @@ 968F2E9214539BF10085264E /* Sources */ = { isa = PBXGroup; children = ( + 96476B4514599D9400EA67C0 /* loading.png */, 968F2E8E14539BEB0085264E /* build_libs.sh */, 968F2E8F14539BEB0085264E /* Info.plist */, 968F2E9014539BEB0085264E /* main.m */, @@ -165,6 +168,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 96476B4614599D9400EA67C0 /* loading.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/ios/loading.png b/ios/loading.png Binary files differnew file mode 100644 index 00000000..42b54e70 --- /dev/null +++ b/ios/loading.png @@ -8,8 +8,11 @@ #include "pdf/mupdf.h" #include "xps/muxps.h" +#define GAP 0 + static dispatch_queue_t queue; static fz_glyph_cache *glyphcache = NULL; +static UIImage *loadingImage = nil; @interface MuLibraryController : UITableViewController { @@ -18,40 +21,35 @@ static fz_glyph_cache *glyphcache = NULL; - (void) reload; @end +@interface MuOutlineController : UITableViewController +{ + id target; + NSMutableArray *titles; + NSMutableArray *pages; +} +- (id) initWithTarget: (id)aTarget titles: (NSMutableArray*)aTitles pages: (NSMutableArray*)aPages; +@end + @interface MuDocumentController : UIViewController <UIScrollViewDelegate> { pdf_xref *xref; - struct { - NSMutableArray *titles; - NSMutableArray *pages; - } outline; + MuOutlineController *outline; UIScrollView *canvas; UIImageView **pageviews; - char *cancel; int width; // current screen size int height; int current; // currently visible page } - (id) initWithFile: (NSString*)filename; -- (void) layoutVisiblePages; - (void) loadPage: (int)number; +- (void) reloadPage: (int)number; - (void) unloadPage: (int)number; -- (void) resizePage: (int)number; +- (void) layoutPage: (int)number; - (void) gotoPage: (int)number animated: (BOOL)animated; - (void) didSingleTap: (UITapGestureRecognizer*)sender; -- (void) toggleNavigationBar; - (void) showOutline: (id)sender; @end -@interface MuOutlineController : UITableViewController -{ - MuDocumentController *target; - NSMutableArray *titles; - NSMutableArray *pages; -} -- (id) initWithTarget: (MuDocumentController*)aTarget titles: (NSMutableArray*)aTitles pages: (NSMutableArray*)aPages; -@end - @interface MuAppDelegate : NSObject <UIApplicationDelegate, UINavigationControllerDelegate> { UIWindow *window; @@ -124,20 +122,20 @@ static void releasePixmap(void *info, const void *data, size_t size) fz_drop_pixmap(info); } -static UIImage *imageWithPixmap(fz_pixmap *pix) +static UIImage *newImageWithPixmap(fz_pixmap *pix) { CGDataProviderRef cgdata = CGDataProviderCreateWithData(pix, pix->samples, pix->w * 4 * pix->h, releasePixmap); CGImageRef cgimage = CGImageCreate(pix->w, pix->h, 8, 32, 4 * pix->w, CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrderDefault, cgdata, NULL, NO, kCGRenderingIntentDefault); - UIImage *image = [UIImage imageWithCGImage: cgimage]; + UIImage *image = [[UIImage alloc] initWithCGImage: cgimage]; CGDataProviderRelease(cgdata); CGImageRelease(cgimage); return image; } -static UIImageView *new_page_view(pdf_xref *xref, int number, float width, float height) +static UIImage *renderPage(pdf_xref *xref, int number, float width, float height) { fz_bbox bbox; fz_matrix ctm; @@ -150,7 +148,7 @@ static UIImageView *new_page_view(pdf_xref *xref, int number, float width, float error = pdf_load_page(&page, xref, number); if (error) { showAlert(@"Cannot load page"); - return [[UIImageView alloc] initWithImage: [UIImage imageNamed: @"mupdf_icon.png"]]; + return nil; } hscale = width / page->mediabox.x1 - page->mediabox.x0; @@ -173,7 +171,7 @@ static UIImageView *new_page_view(pdf_xref *xref, int number, float width, float pdf_age_store(xref->store, 3); fz_flush_warnings(); - return [[UIImageView alloc] initWithImage: imageWithPixmap(pix)]; + return newImageWithPixmap(pix); } #pragma mark - @@ -182,7 +180,7 @@ static UIImageView *new_page_view(pdf_xref *xref, int number, float width, float - (void) reload { - [self setTitle: @"Library"]; + [self setTitle: @"MuPDF"]; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *docdir = [paths objectAtIndex: 0]; @@ -249,7 +247,7 @@ static UIImageView *new_page_view(pdf_xref *xref, int number, float width, float @implementation MuOutlineController -- (id) initWithTarget: (MuDocumentController*)aTarget titles: (NSMutableArray*)aTitles pages: (NSMutableArray*)aPages +- (id) initWithTarget: (id)aTarget titles: (NSMutableArray*)aTitles pages: (NSMutableArray*)aPages { self = [super initWithStyle: UITableViewStylePlain]; if (self) { @@ -343,16 +341,10 @@ printf("open xref '%s'\n", filename); return nil; } - outline.titles = [[NSMutableArray alloc] init]; - outline.pages = [[NSMutableArray alloc] init]; - loadOutline(outline.titles, outline.pages, xref); - pageviews = calloc(pdf_count_pages(xref), sizeof *pageviews); - cancel = malloc(pdf_count_pages(xref)); canvas = [[UIScrollView alloc] initWithFrame: CGRectMake(0,0,10,10)]; -// [canvas setPagingEnabled: YES]; - [canvas setBackgroundColor: [UIColor grayColor]]; + [canvas setPagingEnabled: YES]; [canvas setShowsHorizontalScrollIndicator: NO]; [canvas setShowsVerticalScrollIndicator: NO]; [canvas setDelegate: self]; @@ -362,45 +354,53 @@ printf("open xref '%s'\n", filename); [self setTitle: nsfilename]; - if ([outline.titles count]) { + NSMutableArray *titles = [[NSMutableArray alloc] init]; + NSMutableArray *pages = [[NSMutableArray alloc] init]; + loadOutline(titles, pages, xref); + if ([titles count]) { + outline = [[MuOutlineController alloc] initWithTarget: self titles: titles pages: pages]; + [[outline tableView] setSeparatorStyle: UITableViewCellSeparatorStyleNone]; [[self navigationItem] setRightBarButtonItem: [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemBookmarks target:self action:@selector(showOutline:)]]; } + [titles release]; + [pages release]; return self; } -- (void) loadPage: (int)number +- (void) dealloc { - if (number < 0 || number >= pdf_count_pages(xref)) - return; - - cancel[number] = NO; + for (int i = 0; i < pdf_count_pages(xref); i++) + if (pageviews[i]) + [pageviews[i] release]; + pdf_xref *self_xref = xref; // don't use self after dealloc has finished dispatch_async(queue, ^{ - if (!cancel[number] && !pageviews[number]) { - printf("load %d: in worker thread\n", number); - - UIImageView *page = new_page_view(xref, number, width, height); - - pageviews[number] = page; // weak reference + printf("dealloced, close xref\n"); + if (self_xref) + pdf_free_xref(self_xref); + }); - dispatch_async(dispatch_get_main_queue(), ^{ - printf(" load %d: adding view in main thread\n", number); + free(pageviews); + [outline release]; + [canvas release]; + [super dealloc]; +} - CGRect frame = [page frame]; - frame.origin.x = number * width; - frame.origin.x += (width - frame.size.width) / 2; - frame.origin.y += (height - frame.size.height) / 2; - [page setFrame: frame]; +- (void) loadPage: (int)number +{ + if (number < 0 || number >= pdf_count_pages(xref)) + return; - [canvas addSubview: page]; - [page release]; - }); - } - }); + if (!pageviews[number]) { + pageviews[number] = [[UIImageView alloc] initWithImage: loadingImage]; + [pageviews[number] setCenter: CGPointMake(number * width + width / 2, height / 2)]; + [canvas addSubview: pageviews[number]]; + [self reloadPage: number]; + } } - (void) unloadPage: (int)number @@ -408,39 +408,65 @@ printf("open xref '%s'\n", filename); if (number < 0 || number >= pdf_count_pages(xref)) return; - cancel[number] = YES; + if (pageviews[number]) { + [pageviews[number] removeFromSuperview]; + [pageviews[number] release]; + pageviews[number] = nil; + } +} + +- (void) reloadPage: (int)number +{ + if (number < 0 || number >= pdf_count_pages(xref)) + return; dispatch_async(queue, ^{ if (pageviews[number]) { - printf("unload %d: in worker thread\n", number); - UIView *page = pageviews[number]; - pageviews[number] = nil; + printf("load %d: rendering page in worker thread\n", number); + UIImage *image = renderPage(xref, number, width - GAP, height); dispatch_async(dispatch_get_main_queue(), ^{ - printf(" unload %d: removing view in main thread\n", number); - [page removeFromSuperview]; + printf("load %d: replacing image in main thread\n", number); + if (pageviews[number]) { + [pageviews[number] setImage: image]; + [self layoutPage: number]; + } + [image release]; }); } }); } -- (void) dealloc +- (void) layoutPage: (int)number { - pdf_xref *self_xref = xref; // don't use self after dealloc has finished - dispatch_async(queue, ^{ - printf("close xref\n"); - if (self_xref) - pdf_free_xref(self_xref); - }); - - [outline.titles release]; - [outline.pages release]; - [canvas release]; - [super dealloc]; + if (pageviews[number]) { + UIImageView *page = pageviews[number]; + UIImage *image = [page image]; + if (image != loadingImage) { + CGRect frame = [page frame]; + CGSize pagesize = [image size]; + float scale = MIN((width - GAP) / pagesize.width, height / pagesize.height); + if (fabs(scale - 1) > 0.1) { + [self reloadPage: number]; + frame.size.width = pagesize.width * scale; + frame.size.height = pagesize.height * scale; + frame.origin.x = number * width; + frame.origin.y = 0; + frame.origin.x += (width - frame.size.width) / 2; + frame.origin.y += (height - frame.size.height) / 2; + [page setFrame: frame]; + } else { + [page sizeToFit]; + [page setCenter: CGPointMake(number * width + width/2, height/2)]; + } + } else { + [page sizeToFit]; + [page setCenter: CGPointMake(number * width + width/2, height/2)]; + } + } } - (void) viewWillAppear: (BOOL)animated { -puts("viewWillAppear"); CGSize size = [canvas frame].size; width = size.width; height = size.height; @@ -450,80 +476,37 @@ puts("viewWillAppear"); [canvas setContentOffset: CGPointMake(current * width, 0)]; } -- (void) viewDidDisappear: (BOOL)animated +- (void) scrollViewWillBeginDragging: (UIScrollView *)scrollView { -puts("viewDidDisappear"); - [super viewDidDisappear: animated]; - for (int i = 0; i < pdf_count_pages(xref); i++) - [self unloadPage: i]; -} - -- (void) resizePage: (int)number -{ - if (pageviews[number]) { - CGRect frame = [pageviews[number] frame]; - CGSize pagesize = [[pageviews[number] image] size]; - float scale = MIN(width / pagesize.width, height / pagesize.height); - frame.size.width = pagesize.width * scale; - frame.size.height = pagesize.height * scale; - frame.origin.x = number * width; - frame.origin.y = 0; - frame.origin.x += (width - frame.size.width) / 2; - frame.origin.y += (height - frame.size.height) / 2; - [pageviews[number] setFrame: frame]; + if (![[self navigationController] isNavigationBarHidden]) { + [[self navigationController] setNavigationBarHidden: YES animated: YES]; + [canvas setContentInset: UIEdgeInsetsZero]; } } -- (void) reconfigure -{ - CGSize size = [canvas frame].size; - int max_width = MAX(width, size.width); - - if (size.width == width && size.height == height) - return; - - width = size.width; - height = size.height; - -printf("reconfigure current=%d width=%d\n", current, width); - - for (int i = 0; i < pdf_count_pages(xref); i++) - [self resizePage: i]; - - [canvas setContentInset: UIEdgeInsetsZero]; - [canvas setContentSize: CGSizeMake(pdf_count_pages(xref) * max_width, height)]; - [canvas setContentOffset: CGPointMake(current * width, 0)]; -} - -- (void) layoutVisiblePages +- (void) scrollViewDidScroll: (UIScrollView*)scrollview { - int i, number; - - if (width == 0) return; // not visible yet + if (width == 0) + return; // not visible yet float x = [canvas contentOffset].x + width * 0.5f; + int number = x / width; - number = x / width; - -#if 1 - for (i = 0; i < pdf_count_pages(xref); i++) - if (0) // i != number) +#if 0 + for (int i = 0; i < pdf_count_pages(xref); i++) + if (i != number) [self unloadPage: i]; [self loadPage: number]; #else - for (i = 0; i < pdf_count_pages(xref); i++) + for (int i = 0; i < pdf_count_pages(xref); i++) if (i < number - 1 || i > number + 1) [self unloadPage: i]; - [self loadPage: number]; [self loadPage: number + 1]; [self loadPage: number - 1]; #endif - if (current != number) { - printf("changed page to %d\n", number); - current = number; - } + current = number; } - (void) gotoPage: (int)number animated: (BOOL)animated @@ -536,35 +519,23 @@ printf("reconfigure current=%d width=%d\n", current, width); [canvas setContentOffset: CGPointMake(current * width, 0) animated: animated]; } -- (void) scrollViewDidScroll: (UIScrollView*)scrollview -{ - [self layoutVisiblePages]; -} - - (BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)o { return YES; } -- (void) willRotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration -{ -puts("willRotateToInterfaceOrientation"); -} - - (void) willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration { -puts("willAnimateRotationToInterfaceOrientation"); - CGSize size = [canvas frame].size; int max_width = MAX(width, size.width); width = size.width; height = size.height; -printf("reconfigure current=%d width=%d\n", current, width); - + [self layoutPage: current]; // make sure current page is first in queue for (int i = 0; i < pdf_count_pages(xref); i++) - [self resizePage: i]; + if (i != current) + [self layoutPage: i]; // use max_width so we don't clamp the content offset too early during animation [canvas setContentInset: UIEdgeInsetsZero]; @@ -574,7 +545,6 @@ printf("reconfigure current=%d width=%d\n", current, width); - (void) didRotateFromInterfaceOrientation: (UIInterfaceOrientation)o { -puts("didRotateFromInterfaceOrientation"); [canvas setContentInset: UIEdgeInsetsZero]; [canvas setContentSize: CGSizeMake(pdf_count_pages(xref) * width, height)]; [canvas setContentOffset: CGPointMake(current * width, 0)]; @@ -588,26 +558,23 @@ puts("didRotateFromInterfaceOrientation"); float x1 = width - x0; p.x -= ofs.x; p.y -= ofs.y; - if (p.x < x0) [self gotoPage: current - 1 animated: YES]; - else if (p.x > x1) [self gotoPage: current + 1 animated: YES]; - else [self toggleNavigationBar]; -} - -- (void) toggleNavigationBar -{ - UINavigationController *navigator = [self navigationController]; - if ([navigator isNavigationBarHidden]) - [navigator setNavigationBarHidden: NO animated: NO]; - else - [navigator setNavigationBarHidden: YES animated: NO]; - [canvas setContentInset: UIEdgeInsetsZero]; + if (p.x < x0) + [self gotoPage: current - 1 animated: YES]; + else if (p.x > x1) + [self gotoPage: current + 1 animated: YES]; + else { + UINavigationController *navigator = [self navigationController]; + if ([navigator isNavigationBarHidden]) + [navigator setNavigationBarHidden: NO animated: YES]; + else + [navigator setNavigationBarHidden: YES animated: YES]; + [canvas setContentInset: UIEdgeInsetsZero]; + } } - (void) showOutline: (id)sender { - MuOutlineController *ctl = [[MuOutlineController alloc] initWithTarget: self titles: outline.titles pages: outline.pages]; - [[self navigationController] pushViewController: ctl animated: YES]; - [ctl release]; + [[self navigationController] pushViewController: outline animated: YES]; } @end @@ -622,6 +589,8 @@ puts("didRotateFromInterfaceOrientation"); glyphcache = fz_new_glyph_cache(); + loadingImage = [[UIImage imageNamed: @"loading.png"] retain]; + library = [[MuLibraryController alloc] initWithStyle: UITableViewStylePlain]; navigator = [[UINavigationController alloc] initWithRootViewController: library]; @@ -629,6 +598,7 @@ puts("didRotateFromInterfaceOrientation"); [navigator setDelegate: self]; window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]]; + [window setBackgroundColor: [UIColor scrollViewTexturedBackgroundColor]]; [window addSubview: [navigator view]]; [window makeKeyAndVisible]; @@ -637,52 +607,27 @@ puts("didRotateFromInterfaceOrientation"); - (void)applicationDidEnterBackground:(UIApplication *)application { - /* - Use this method to release shared resources, save user data, invalidate timers, - and store enough application state information to restore your application to - its current state in case it is terminated later. - If your application supports background execution, - called instead of applicationWillTerminate: when the user quits. - */ printf("applicationDidEnterBackground!\n"); } - (void)applicationWillEnterForeground:(UIApplication *)application { - /* - Called as part of transition from the background to the - inactive state: here you can undo many of the changes made - on entering the background. - */ printf("applicationWillEnterForeground!\n"); } - (void)applicationDidBecomeActive:(UIApplication *)application { - /* - Restart any tasks that were paused (or not yet started) while - the application was inactive. If the application was previously - in the background, optionally refresh the user interface. - */ printf("applicationDidBecomeActive!\n"); [library reload]; } - (void)applicationWillTerminate:(UIApplication *)application { - /* - Called when the application is about to terminate. - See also applicationDidEnterBackground:. - */ printf("applicationWillTerminate!\n"); } - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { - /* - Free up as much memory as possible by purging cached data objects that can - be recreated (or reloaded from disk) later. - */ printf("applicationDidReceiveMemoryWarning\n"); } |