diff options
author | Tor Andersson <tor.andersson@artifex.com> | 2011-10-27 02:41:02 +0200 |
---|---|---|
committer | Tor Andersson <tor.andersson@artifex.com> | 2011-11-01 23:46:57 +0100 |
commit | fb5118956f8618bb3cbc79e85e121da0e8a7564e (patch) | |
tree | 34c4ee31f8edba3d120fa3d8be73aa3db2bd4bd8 | |
parent | d2bed7099b64a6792adefc9bf0bef7da3e2cbd0e (diff) | |
download | mupdf-fb5118956f8618bb3cbc79e85e121da0e8a7564e.tar.xz |
Render pages in a background thread.
-rw-r--r-- | ios/main.m | 368 |
1 files changed, 238 insertions, 130 deletions
@@ -19,14 +19,22 @@ @interface MuDocumentController : UIViewController <UIScrollViewDelegate> { pdf_xref *xref; + struct { + NSMutableArray *titles; + NSMutableArray *pages; + } outline; UIScrollView *canvas; UIView **pageviews; + UIView **loadviews; + UIView *rotateview; + char *cancel; int width; // current screen size int height; int current; // currently visible page } - (id) initWithFile: (NSString*)filename; - (void) reconfigure; +- (void) layoutVisiblePages; - (void) loadPage: (int)number; - (void) unloadPage: (int)number; - (void) gotoPage: (int)number animated: (BOOL)animated; @@ -37,12 +45,11 @@ @interface MuOutlineController : UITableViewController { - MuDocumentController *document; + MuDocumentController *target; NSMutableArray *titles; NSMutableArray *pages; } -- (id) initWithStyle: (UITableViewStyle)style xref: (pdf_xref*)xref outline: (pdf_outline*)outline; -- (void) gotoPage: (int)number; +- (id) initWithTarget: (MuDocumentController*)aTarget titles: (NSMutableArray*)aTitles pages: (NSMutableArray*)aPages; @end @interface MuAppDelegate : NSObject <UIApplicationDelegate, UINavigationControllerDelegate> @@ -53,19 +60,12 @@ } @end +static dispatch_queue_t queue; static fz_glyph_cache *glyphcache = NULL; - static MuAppDelegate *app = nil; #pragma mark - -static int get_page_number(pdf_xref *xref, pdf_link *link) -{ - if (link->kind == PDF_LINK_GOTO) - return pdf_find_page_number(xref, fz_array_get(link->dest, 0)); - return 0; -} - static void showAlert(NSString *msg) { char msgbuf[160 * 30]; @@ -90,6 +90,39 @@ static void showAlert(NSString *msg) [alert release]; } +static int pageNumberFromLink(pdf_xref *xref, pdf_link *link) +{ + if (link->kind == PDF_LINK_GOTO) + return pdf_find_page_number(xref, fz_array_get(link->dest, 0)); + return -1; +} + +static void loadOutlineImp(NSMutableArray *titles, NSMutableArray *pages, pdf_xref *xref, pdf_outline *outline, int level) +{ + char buf[512]; + memset(buf, 0, sizeof buf); + memset(buf, ' ', level * 4); + while (outline) + { + int number = pageNumberFromLink(xref, outline->link); + if (number >= 0) { + [titles addObject: [NSString stringWithFormat: @"%s%s", buf, outline->title]]; + [pages addObject: [NSNumber numberWithInt: number]]; + } + loadOutlineImp(titles, pages, xref, outline->child, level + 1); + outline = outline->next; + } +} + +static void loadOutline(NSMutableArray *titles, NSMutableArray *pages, pdf_xref *xref) +{ + pdf_outline *outline = pdf_load_outline(xref); + if (outline) { + loadOutlineImp(titles, pages, xref, outline, 0); + pdf_free_outline(outline); + } +} + static void releasePixmap(void *info, const void *data, size_t size) { fz_drop_pixmap(info); @@ -119,8 +152,7 @@ static UIImageView *new_page_view(pdf_xref *xref, int number, float width, float float scale, hscale, vscale; error = pdf_load_page(&page, xref, number); - if (error) - { + if (error) { showAlert(@"Cannot load page"); return [[UIImageView alloc] initWithImage: [UIImage imageNamed: @"mupdf_icon.png"]]; } @@ -226,38 +258,22 @@ static UIImageView *new_page_view(pdf_xref *xref, int number, float width, float @implementation MuOutlineController -static void loadOutline(NSMutableArray *titles, NSMutableArray *pages, pdf_xref *xref, pdf_outline *outline, int level) +- (id) initWithTarget: (MuDocumentController*)aTarget titles: (NSMutableArray*)aTitles pages: (NSMutableArray*)aPages { - char buf[512]; - memset(buf, 0, sizeof buf); - memset(buf, ' ', level * 4); - while (outline) - { - [titles addObject: [NSString stringWithFormat: @"%s%s", buf, outline->title]]; - [pages addObject: [NSNumber numberWithInt: get_page_number(xref, outline->link)]]; - printf("-- %s\n", outline->title); - loadOutline(titles, pages, xref, outline->child, level + 1); - outline = outline->next; - } -} - -- (id) initWithStyle: (UITableViewStyle)style document: (MuDocumentController*)document xref: (pdf_xref*)xref outline: (pdf_outline*)outline; -{ - self = [super initWithStyle: style]; + self = [super initWithStyle: UITableViewStylePlain]; if (self) { [self setTitle: @"Table of Contents"]; - self->document = [document retain]; - titles = [[NSMutableArray alloc] init]; - pages = [[NSMutableArray alloc] init]; - loadOutline(titles, pages, xref, outline, 0); + target = [aTarget retain]; + titles = [aTitles retain]; + pages = [aPages retain]; } return self; } - (void) dealloc { - [document release]; + [target release]; [titles release]; [pages release]; [super dealloc]; @@ -294,13 +310,8 @@ static void loadOutline(NSMutableArray *titles, NSMutableArray *pages, pdf_xref - (void) tableView: (UITableView*)tableView didSelectRowAtIndexPath: (NSIndexPath*)indexPath { NSNumber *page = [pages objectAtIndex: [indexPath row]]; - [self gotoPage: [page intValue]]; -} - -- (void) gotoPage: (int)number -{ + [target gotoPage: [page intValue] animated: NO]; [[self navigationController] popViewControllerAnimated: YES]; - [document gotoPage: number animated: NO]; } @end @@ -319,11 +330,14 @@ static void loadOutline(NSMutableArray *titles, NSMutableArray *pages, pdf_xref if (!self) return nil; + // make sure we're not doing any background processing + dispatch_sync(queue, ^{}); + strcpy(filename, [NSHomeDirectory() UTF8String]); strcat(filename, "/Documents/"); strcat(filename, [nsfilename UTF8String]); - NSLog(@"filename = '%s'\n", filename); +printf("open xref '%s'\n", filename); error = pdf_open_xref(&xref, filename, password); if (error) @@ -341,7 +355,13 @@ static void loadOutline(NSMutableArray *titles, NSMutableArray *pages, pdf_xref 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); + loadviews = calloc(pdf_count_pages(xref), sizeof *loadviews); + cancel = malloc(pdf_count_pages(xref)); canvas = [[UIScrollView alloc] initWithFrame: CGRectMake(0,0,10,10)]; [canvas setPagingEnabled: YES]; @@ -355,12 +375,13 @@ static void loadOutline(NSMutableArray *titles, NSMutableArray *pages, pdf_xref [self setTitle: nsfilename]; -// [self setToolbarItems: [NSArray arrayWithObjects: pager, nil]]; - - [[self navigationItem] setRightBarButtonItem: - [[UIBarButtonItem alloc] - initWithBarButtonSystemItem: UIBarButtonSystemItemBookmarks - target:self action:@selector(showOutline:)]]; + if ([outline.titles count]) + { + [[self navigationItem] setRightBarButtonItem: + [[UIBarButtonItem alloc] + initWithBarButtonSystemItem: UIBarButtonSystemItemBookmarks + target:self action:@selector(showOutline:)]]; + } [self setToolbarItems: [NSArray arrayWithObjects: @@ -372,27 +393,98 @@ static void loadOutline(NSMutableArray *titles, NSMutableArray *pages, pdf_xref return self; } -- (void) dealloc +- (void) loadPage: (int)number { - if (xref) - { - for (int i = 0; i < pdf_count_pages(xref); i++) - [self unloadPage: i]; - pdf_free_xref(xref); - xref = NULL; + UILabel *loading; + + if (number < 0 || number >= pdf_count_pages(xref)) + return; + + cancel[number] = NO; + + if (!loadviews[number] && !pageviews[number]) { + loading = [[UILabel alloc] initWithFrame: CGRectMake(number * width + width/3, height/3, width/3, height/3)]; + [loading setText: [NSString stringWithFormat: @"Loading page %d of %d", number + 1, pdf_count_pages(xref)]]; + [loading setTextAlignment: UITextAlignmentCenter]; + [canvas addSubview: loading]; + loadviews[number] = loading; +printf("loadviews[current] added original %p\n", loadviews[number]); + [loading release]; } - [canvas release]; - [super dealloc]; + + dispatch_async(queue, ^{ + if (cancel[number]) { + dispatch_async(dispatch_get_main_queue(), ^{ + if (loadviews[number]) { + printf(" load %d: canceled\n", number); + [loadviews[number] removeFromSuperview]; + loadviews[number] = nil; + } + }); + } else if (!pageviews[number]) { + printf("load %d: in worker thread\n", number); + + UIImageView *page = new_page_view(xref, number, width, height); + + 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]; + + pageviews[number] = page; // weak reference + + dispatch_async(dispatch_get_main_queue(), ^{ + printf(" load %d: adding view in main thread\n", number); +printf("loadviews[current] removed %p\n", loadviews[number]); + [loadviews[number] removeFromSuperview]; + loadviews[number] = nil; + [canvas addSubview: page]; + [page release]; + + if (rotateview) { + [rotateview removeFromSuperview]; + [rotateview release]; + rotateview = nil; + } + }); + } + }); } -- (BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)o +- (void) unloadPage: (int)number { - return YES; + if (number < 0 || number >= pdf_count_pages(xref)) + return; + + cancel[number] = YES; + + dispatch_async(queue, ^{ + if (pageviews[number]) { + printf("unload %d: in worker thread\n", number); + UIView *page = pageviews[number]; + pageviews[number] = nil; + dispatch_async(dispatch_get_main_queue(), ^{ + printf(" unload %d: removing view in main thread\n", number); + [page removeFromSuperview]; + }); + } + }); } -- (void) didRotateFromInterfaceOrientation: (UIInterfaceOrientation)o +- (void) dealloc { - [self reconfigure]; + 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]; } - (void) viewWillAppear: (BOOL)animated @@ -402,21 +494,23 @@ static void loadOutline(NSMutableArray *titles, NSMutableArray *pages, pdf_xref [self reconfigure]; } +- (void) viewDidDisappear: (BOOL)animated +{ + [super viewDidDisappear: animated]; + for (int i = 0; i < pdf_count_pages(xref); i++) + [self unloadPage: i]; +} + - (void) reconfigure { CGSize size = [canvas frame].size; -printf("reconfig w=%g h=%g\n", size.width, size.height); - if (size.width == width && size.height == height) return; width = size.width; height = size.height; - // facing pages mode in landscape - // if (size.width > size.height) size.width *= 0.5; - for (int i = 0; i < pdf_count_pages(xref); i++) [self unloadPage: i]; @@ -424,41 +518,42 @@ printf("reconfig w=%g h=%g\n", size.width, size.height); [canvas setContentSize: CGSizeMake(pdf_count_pages(xref) * width, height)]; [canvas setContentOffset: CGPointMake(current * width, 0) animated: NO]; - [self scrollViewDidScroll: canvas]; + if (rotateview) { + CGRect frame = [rotateview frame]; + frame.origin.x = current * width; + frame.origin.y = 0; + frame.origin.x += (width - frame.size.width) / 2; + frame.origin.y += (height - frame.size.height) / 2; + [rotateview setFrame: frame]; + } + + [self layoutVisiblePages]; } -- (void) loadPage: (int)number +- (void) layoutVisiblePages { - if (number < 0 || number >= pdf_count_pages(xref)) - return; - if (!pageviews[number]) - { -printf("load page %d\n", number); - UIImageView *page = new_page_view(xref, number, width, height); + int i; - 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]; + if (width == 0) return; // not visible yet - [canvas addSubview: page]; + float x = [canvas contentOffset].x + width * 0.5f; - pageviews[number] = page; - } -} + current = x / width; -- (void) unloadPage: (int)number -{ - if (number < 0 || number >= pdf_count_pages(xref)) - return; - if (pageviews[number]) - { -printf("unload %d\n", number); - [pageviews[number] removeFromSuperview]; - [pageviews[number] release]; - pageviews[number] = nil; - } +#if 0 + for (i = 0; i < pdf_count_pages(xref); i++) + if (i != current) + [self unloadPage: i]; + [self loadPage: current]; +#else + for (i = 0; i < pdf_count_pages(xref); i++) + if (i < current - 1 || i > current + 1) + [self unloadPage: i]; + + [self loadPage: current]; + [self loadPage: current + 1]; + [self loadPage: current - 1]; +#endif } - (void) gotoPage: (int)number animated: (BOOL)animated @@ -473,42 +568,49 @@ printf("unload %d\n", number); - (void) scrollViewDidScroll: (UIScrollView*)scrollview { - int i; - - if (width == 0) return; // not visible yet - - float x = [canvas contentOffset].x + width * 0.5f; + [self layoutVisiblePages]; +} - current = x / width; +- (BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)o +{ + return YES; +} - for (i = 0; i < pdf_count_pages(xref); i++) - if (i < current - 1 || i > current + 2) - [self unloadPage: i]; +- (void) willRotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration +{ +puts("willRotateToInterfaceOrientation"); + if (pageviews[current]) { + rotateview = [[UIImageView alloc] initWithImage: [(UIImageView*)pageviews[current] image]]; + [rotateview setFrame: [pageviews[current] frame]]; + [canvas addSubview: rotateview]; + } - [self loadPage: current]; - [self loadPage: current - 1]; - [self loadPage: current + 1]; + for (int i = 0; i < pdf_count_pages(xref); i++) + [self unloadPage: i]; + dispatch_sync(queue, ^{}); } - (void) willAnimateRotationToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration { - CGSize size = [canvas frame].size; - UIView *page = pageviews[current]; - CGRect frame = [page frame]; - float scale = MIN(size.width / frame.size.width, size.height / frame.size.height); - int i; - - for (i = 0; i < pdf_count_pages(xref); i++) - if (i != current) - [self unloadPage: i]; +puts("willAnimateRotationToInterfaceOrientation"); + if (rotateview) { + CGSize size = [canvas frame].size; + CGRect frame = [rotateview frame]; + float scale = MIN(size.width / frame.size.width, size.height / frame.size.height); + frame.size.width *= scale; + frame.size.height *= scale; + frame.origin.x = current * width; + frame.origin.y = 0; + frame.origin.x += (size.width - frame.size.width) / 2; + frame.origin.y += (size.height - frame.size.height) / 2; + [rotateview setFrame: frame]; + } +} - frame.size.width *= scale; - frame.size.height *= scale; - frame.origin.x = current * width; - frame.origin.y = 0; - frame.origin.x += (size.width - frame.size.width) / 2; - frame.origin.y += (size.height - frame.size.height) / 2; - [page setFrame: frame]; +- (void) didRotateFromInterfaceOrientation: (UIInterfaceOrientation)o +{ +puts("didRotateFromInterfaceOrientation"); + [self reconfigure]; } - (void) didSingleTap: (UITapGestureRecognizer*)sender @@ -539,11 +641,9 @@ printf("unload %d\n", number); - (void) showOutline: (id)sender { - pdf_outline *outline = pdf_load_outline(xref); - MuOutlineController *ctl = [[MuOutlineController alloc] initWithStyle: UITableViewStylePlain document: self xref: xref outline: outline]; + MuOutlineController *ctl = [[MuOutlineController alloc] initWithTarget: self titles: outline.titles pages: outline.pages]; [[self navigationController] pushViewController: ctl animated: YES]; [ctl release]; -// pdf_free_outline(outline); } @end @@ -556,6 +656,12 @@ printf("unload %d\n", number); { app = self; + NSThread *foo = [[NSThread alloc] init]; + [foo start]; + [foo release]; + + queue = dispatch_queue_create("com.artifex.mupdf.queue", NULL); + glyphcache = fz_new_glyph_cache(); library = [[MuLibraryController alloc] initWithStyle: UITableViewStylePlain]; @@ -564,7 +670,7 @@ printf("unload %d\n", number); [[navigator navigationBar] setTranslucent: YES]; [[navigator toolbar] setTranslucent: YES]; [navigator setToolbarHidden: NO animated: NO]; - [navigator setDelegate: app]; + [navigator setDelegate: self]; window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]]; [window addSubview: [navigator view]]; @@ -582,7 +688,7 @@ printf("unload %d\n", number); If your application supports background execution, called instead of applicationWillTerminate: when the user quits. */ -printf("applicationDidEnterBackground!\n"); + printf("applicationDidEnterBackground!\n"); } - (void)applicationWillEnterForeground:(UIApplication *)application @@ -592,7 +698,7 @@ printf("applicationDidEnterBackground!\n"); inactive state: here you can undo many of the changes made on entering the background. */ -printf("applicationWillEnterForeground!\n"); + printf("applicationWillEnterForeground!\n"); } - (void)applicationDidBecomeActive:(UIApplication *)application @@ -602,7 +708,7 @@ printf("applicationWillEnterForeground!\n"); the application was inactive. If the application was previously in the background, optionally refresh the user interface. */ -printf("applicationDidBecomeActive!\n"); + printf("applicationDidBecomeActive!\n"); [library reload]; } @@ -620,10 +726,12 @@ printf("applicationDidBecomeActive!\n"); Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later. */ +printf("RUNNING OUT OF MEMORY SOON!!!111eleven\n"); } - (void) dealloc { + dispatch_release(queue); [library release]; [navigator release]; [window release]; @@ -636,7 +744,7 @@ printf("applicationDidBecomeActive!\n"); int main(int argc, char *argv[]) { - NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; int retVal = UIApplicationMain(argc, argv, nil, @"MuAppDelegate"); [pool release]; return retVal; |