summaryrefslogtreecommitdiff
path: root/ios
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2011-10-27 02:41:02 +0200
committerTor Andersson <tor.andersson@artifex.com>2011-11-01 23:46:57 +0100
commitfb5118956f8618bb3cbc79e85e121da0e8a7564e (patch)
tree34c4ee31f8edba3d120fa3d8be73aa3db2bd4bd8 /ios
parentd2bed7099b64a6792adefc9bf0bef7da3e2cbd0e (diff)
downloadmupdf-fb5118956f8618bb3cbc79e85e121da0e8a7564e.tar.xz
Render pages in a background thread.
Diffstat (limited to 'ios')
-rw-r--r--ios/main.m368
1 files changed, 238 insertions, 130 deletions
diff --git a/ios/main.m b/ios/main.m
index 4d23936a..1719a074 100644
--- a/ios/main.m
+++ b/ios/main.m
@@ -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;