summaryrefslogtreecommitdiff
path: root/ios
diff options
context:
space:
mode:
authorTor Andersson <tor.andersson@artifex.com>2011-10-27 19:12:19 +0200
committerTor Andersson <tor.andersson@artifex.com>2011-11-01 23:46:57 +0100
commit9630fd9145d4d5c3a46dc51dde4a433d3a7b6c9a (patch)
tree5084e69b62acba5ed24b35bd3eedcd7304397e74 /ios
parentec4f3a97478dafba2338a3fb1dbb01abbe69b7d6 (diff)
downloadmupdf-9630fd9145d4d5c3a46dc51dde4a433d3a7b6c9a.tar.xz
Show "loading" message while rendering in background.
Diffstat (limited to 'ios')
-rw-r--r--ios/MuPDF.xcodeproj/project.pbxproj4
-rw-r--r--ios/loading.pngbin0 -> 3258 bytes
-rw-r--r--ios/main.m319
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
new file mode 100644
index 00000000..42b54e70
--- /dev/null
+++ b/ios/loading.png
Binary files differ
diff --git a/ios/main.m b/ios/main.m
index 78dadde3..6669668c 100644
--- a/ios/main.m
+++ b/ios/main.m
@@ -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");
}