From d4a69b3f24c3697cb0e77b7685468423c0949a71 Mon Sep 17 00:00:00 2001 From: Paul Gardiner Date: Tue, 24 Sep 2013 16:58:27 +0100 Subject: iOS: add reflow mode --- platform/ios/Classes/MuDocumentController.h | 5 +- platform/ios/Classes/MuDocumentController.m | 112 +++++-- platform/ios/Classes/MuPageView.h | 46 +-- platform/ios/Classes/MuPageView.m | 464 -------------------------- platform/ios/Classes/MuPageViewNormal.h | 41 +++ platform/ios/Classes/MuPageViewNormal.m | 466 +++++++++++++++++++++++++++ platform/ios/Classes/MuPageViewReflow.h | 20 ++ platform/ios/Classes/MuPageViewReflow.m | 136 ++++++++ platform/ios/MuPDF.xcodeproj/project.pbxproj | 54 +++- 9 files changed, 801 insertions(+), 543 deletions(-) delete mode 100644 platform/ios/Classes/MuPageView.m create mode 100644 platform/ios/Classes/MuPageViewNormal.h create mode 100644 platform/ios/Classes/MuPageViewNormal.m create mode 100644 platform/ios/Classes/MuPageViewReflow.h create mode 100644 platform/ios/Classes/MuPageViewReflow.m diff --git a/platform/ios/Classes/MuDocumentController.h b/platform/ios/Classes/MuDocumentController.h index b15d629a..3ec981f8 100644 --- a/platform/ios/Classes/MuDocumentController.h +++ b/platform/ios/Classes/MuDocumentController.h @@ -16,17 +16,19 @@ #import "MuOutlineController.h" #import "MuDocRef.h" -@interface MuDocumentController : UIViewController +@interface MuDocumentController : UIViewController { fz_document *doc; MuDocRef *docRef; NSString *key; + BOOL reflowMode; MuOutlineController *outline; UIScrollView *canvas; UILabel *indicator; UISlider *slider; UISearchBar *searchBar; UIBarButtonItem *nextButton, *prevButton, *cancelButton, *searchButton, *outlineButton, *linkButton; + UIBarButtonItem *reflowButton; UIBarButtonItem *sliderWrapper; int searchPage; int cancelSearch; @@ -35,6 +37,7 @@ int height; int current; // currently visible page int scroll_animating; // stop view updates during scrolling animations + float scale; // scale applied to views (only used in reflow mode) } - (id) initWithFilename: (NSString*)nsfilename document: (MuDocRef *)aDoc; - (void) createPageView: (int)number; diff --git a/platform/ios/Classes/MuDocumentController.m b/platform/ios/Classes/MuDocumentController.m index 0b4f7d2e..29a9aadc 100644 --- a/platform/ios/Classes/MuDocumentController.m +++ b/platform/ios/Classes/MuDocumentController.m @@ -6,14 +6,17 @@ // #include "common.h" -#import "MuPageView.h" +#import "MuPageViewNormal.h" +#import "MuPageViewReflow.h" #import "MuDocumentController.h" #define GAP 20 #define INDICATOR_Y -44-24 #define SLIDER_W (width - GAP - 24) #define SEARCH_W (width - GAP - 170) +#define MIN_SCALE (1.0) +#define MAX_SCALE (5.0) static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_outline *outline, int level) { @@ -68,6 +71,11 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out return self; } +- (UIBarButtonItem *) resourceBasedButton:(NSString *)resource withAction:(SEL)selector +{ + return [[UIBarButtonItem alloc] initWithImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:resource ofType:@"png"]] style:UIBarButtonItemStylePlain target:self action:selector]; +} + - (void) loadView { [[NSUserDefaults standardUserDefaults] setObject: key forKey: @"OpenDocumentKey"]; @@ -87,7 +95,18 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out [canvas setShowsVerticalScrollIndicator: NO]; [canvas setDelegate: self]; - [canvas addGestureRecognizer: [[[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(onTap:)] autorelease]]; + UITapGestureRecognizer *tapRecog = [[UITapGestureRecognizer alloc] initWithTarget: self action: @selector(onTap:)]; + tapRecog.delegate = self; + [canvas addGestureRecognizer: tapRecog]; + [tapRecog release]; + // In reflow mode, we need to track pinch gestures on the canvas and pass + // the scale changes to the subviews. + UIPinchGestureRecognizer *pinchRecog = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(onPinch:)]; + pinchRecog.delegate = self; + [canvas addGestureRecognizer:pinchRecog]; + [pinchRecog release]; + + scale = 1.0; scroll_animating = NO; @@ -115,26 +134,14 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out // Set up the buttons on the navigation and search bar if (outline) { - outlineButton = [[UIBarButtonItem alloc] - initWithBarButtonSystemItem: UIBarButtonSystemItemBookmarks - target:self action:@selector(onShowOutline:)]; + outlineButton = [self resourceBasedButton:@"ic_list" withAction:@selector(onShowOutline:)]; } - linkButton = [[UIBarButtonItem alloc] - initWithBarButtonSystemItem: UIBarButtonSystemItemAction - target:self action:@selector(onToggleLinks:)]; - cancelButton = [[UIBarButtonItem alloc] - initWithTitle: @"Cancel" style: UIBarButtonItemStyleBordered - target:self action:@selector(onCancelSearch:)]; - searchButton = [[UIBarButtonItem alloc] - initWithBarButtonSystemItem: UIBarButtonSystemItemSearch - target:self action:@selector(onShowSearch:)]; - prevButton = [[UIBarButtonItem alloc] - initWithBarButtonSystemItem: UIBarButtonSystemItemRewind - target:self action:@selector(onSearchPrev:)]; - nextButton = [[UIBarButtonItem alloc] - initWithBarButtonSystemItem: UIBarButtonSystemItemFastForward - target:self action:@selector(onSearchNext:)]; - + linkButton = [self resourceBasedButton:@"ic_link" withAction:@selector(onToggleLinks:)]; + cancelButton = [self resourceBasedButton:@"ic_cancel" withAction:@selector(onCancelSearch:)]; + searchButton = [self resourceBasedButton:@"ic_magnifying_glass" withAction:@selector(onShowSearch:)]; + prevButton = [self resourceBasedButton:@"ic_arrow_left" withAction:@selector(onSearchPrev:)]; + nextButton = [self resourceBasedButton:@"ic_arrow_right" withAction:@selector(onSearchNext:)]; + reflowButton = [self resourceBasedButton:@"ic_reflow" withAction:@selector(onToggleReflow:)]; searchBar = [[UISearchBar alloc] initWithFrame: CGRectMake(0,0,50,32)]; [searchBar setPlaceholder: @"Search"]; [searchBar setDelegate: self]; @@ -145,7 +152,7 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out [nextButton setEnabled: NO]; [[self navigationItem] setRightBarButtonItems: - [NSArray arrayWithObjects: searchButton, linkButton, outlineButton, nil]]; + [NSArray arrayWithObjects: searchButton, outlineButton, reflowButton, linkButton, nil]]; // TODO: add activityindicator to search bar @@ -159,6 +166,7 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out [indicator release]; indicator = nil; [slider release]; slider = nil; [sliderWrapper release]; sliderWrapper = nil; + [reflowButton release]; reflowButton = nil; [searchBar release]; searchBar = nil; [outlineButton release]; outlineButton = nil; [searchButton release]; searchButton = nil; @@ -204,13 +212,13 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out [canvas setContentSize: CGSizeMake(fz_count_pages(doc) * max_width, height)]; [canvas setContentOffset: CGPointMake(current * width, 0)]; - for (MuPageView *view in [canvas subviews]) { + for (UIView *view in [canvas subviews]) { if ([view number] == current) { [view setFrame: CGRectMake([view number] * width, 0, width-GAP, height)]; [view willRotate]; } } - for (MuPageView *view in [canvas subviews]) { + for (UIView *view in [canvas subviews]) { if ([view number] != current) { [view setFrame: CGRectMake([view number] * width, 0, width-GAP, height)]; [view willRotate]; @@ -279,7 +287,7 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out - (void) onToggleLinks: (id)sender { showLinks = !showLinks; - for (MuPageView *view in [canvas subviews]) + for (UIView *view in [canvas subviews]) { if (showLinks) [view showLinks]; @@ -288,12 +296,19 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out } } +- (void) onToggleReflow: (id)sender +{ + reflowMode = !reflowMode; + [[canvas subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; + [self scrollViewDidScroll:canvas]; +} + - (void) onShowSearch: (id)sender { - [[self navigationItem] setTitleView: searchBar]; [[self navigationItem] setRightBarButtonItems: [NSArray arrayWithObjects: nextButton, prevButton, nil]]; [[self navigationItem] setLeftBarButtonItem: cancelButton]; + [[self navigationItem] setTitleView: searchBar]; [searchBar becomeFirstResponder]; } @@ -311,7 +326,7 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out - (void) resetSearch { searchPage = -1; - for (MuPageView *view in [canvas subviews]) + for (UIView *view in [canvas subviews]) [view clearSearchResults]; } @@ -320,7 +335,7 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out printf("search found match on page %d\n", number); searchPage = number; [self gotoPage: number animated: NO]; - for (MuPageView *view in [canvas subviews]) + for (UIView *view in [canvas subviews]) if ([view number] == number) [view showSearchResults: count]; else @@ -430,6 +445,13 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out [self gotoPage: number animated: NO]; } +- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer +{ + // For reflow mode, we load UIWebViews into the canvas. Returning YES + // here prevents them stealing our tap and pinch events. + return YES; +} + - (void) onTap: (UITapGestureRecognizer*)sender { CGPoint p = [sender locationInView: canvas]; @@ -450,6 +472,24 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out } } +- (void) onPinch:(UIPinchGestureRecognizer*)sender +{ + if (sender.state == UIGestureRecognizerStateBegan) + sender.scale = scale; + + if (sender.scale < MIN_SCALE) + sender.scale = MIN_SCALE; + + if (sender.scale > MAX_SCALE) + sender.scale = MAX_SCALE; + + if (sender.state == UIGestureRecognizerStateEnded) + scale = sender.scale; + + for (UIView *view in [canvas subviews]) + [view setScale:sender.scale]; +} + - (void) scrollViewWillBeginDragging: (UIScrollView *)scrollView { [self hideNavigationBar]; @@ -474,13 +514,13 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out // swap the distant page views out NSMutableSet *invisiblePages = [[NSMutableSet alloc] init]; - for (MuPageView *view in [canvas subviews]) { + for (UIView *view in [canvas subviews]) { if ([view number] != current) [view resetZoomAnimated: YES]; if ([view number] < current - 2 || [view number] > current + 2) [invisiblePages addObject: view]; } - for (MuPageView *view in invisiblePages) + for (UIView *view in invisiblePages) [view removeFromSuperview]; [invisiblePages release]; // don't bother recycling them... @@ -498,11 +538,15 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out if (number < 0 || number >= fz_count_pages(doc)) return; int found = 0; - for (MuPageView *view in [canvas subviews]) + for (UIView *view in [canvas subviews]) if ([view number] == number) found = 1; if (!found) { - MuPageView *view = [[MuPageView alloc] initWithFrame: CGRectMake(number * width, 0, width-GAP, height) document: docRef page: number]; + UIView *view + = reflowMode + ? [[MuPageViewReflow alloc] initWithFrame:CGRectMake(number * width, 0, width-GAP, height) document:docRef page:number] + : [[MuPageViewNormal alloc] initWithFrame:CGRectMake(number * width, 0, width-GAP, height) document:docRef page:number]; + [view setScale:scale]; [canvas addSubview: view]; if (showLinks) [view showLinks]; @@ -533,7 +577,7 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out [UIView setAnimationDelegate: self]; [UIView setAnimationDidStopSelector: @selector(onGotoPageFinished)]; - for (MuPageView *view in [canvas subviews]) + for (UIView *view in [canvas subviews]) [view resetZoomAnimated: NO]; [canvas setContentOffset: CGPointMake(number * width, 0)]; @@ -542,7 +586,7 @@ static void flattenOutline(NSMutableArray *titles, NSMutableArray *pages, fz_out [UIView commitAnimations]; } else { - for (MuPageView *view in [canvas subviews]) + for (UIView *view in [canvas subviews]) [view resetZoomAnimated: NO]; [canvas setContentOffset: CGPointMake(number * width, 0)]; } diff --git a/platform/ios/Classes/MuPageView.h b/platform/ios/Classes/MuPageView.h index 58d1c8a7..963a4aa0 100644 --- a/platform/ios/Classes/MuPageView.h +++ b/platform/ios/Classes/MuPageView.h @@ -7,41 +7,13 @@ #import -#undef ABS -#undef MIN -#undef MAX - -#include "mupdf/fitz.h" - -#import "MuDocRef.h" -#include "MuHitView.h" - -@interface MuPageView : UIScrollView -{ - MuDocRef *docRef; - fz_document *doc; - fz_page *page; - int number; - UIActivityIndicatorView *loadingView; - UIImageView *imageView; - UIImageView *tileView; - MuHitView *hitView; - MuHitView *linkView; - CGSize pageSize; - CGRect tileFrame; - float tileScale; - BOOL cancel; -} -- (id) initWithFrame: (CGRect)frame document: (MuDocRef*)aDoc page: (int)aNumber; -- (void) displayImage: (UIImage*)image; -- (void) resizeImage; -- (void) loadPage; -- (void) loadTile; -- (void) willRotate; -- (void) resetZoomAnimated: (BOOL)animated; -- (void) showSearchResults: (int)count; -- (void) clearSearchResults; -- (void) showLinks; -- (void) hideLinks; -- (int) number; +@protocol MuPageView +-(int) number; +-(void) willRotate; +-(void) showLinks; +-(void) hideLinks; +-(void) showSearchResults: (int)count; +-(void) clearSearchResults; +-(void) resetZoomAnimated: (BOOL)animated; +-(void) setScale:(float)scale; @end diff --git a/platform/ios/Classes/MuPageView.m b/platform/ios/Classes/MuPageView.m deleted file mode 100644 index 6fa17f54..00000000 --- a/platform/ios/Classes/MuPageView.m +++ /dev/null @@ -1,464 +0,0 @@ -// -// MuPageView.m -// MuPDF -// -// Copyright (c) 2013 Artifex Software, Inc. All rights reserved. -// - -#include "common.h" - -static CGSize measurePage(fz_document *doc, fz_page *page) -{ - CGSize pageSize; - fz_rect bounds; - fz_bound_page(doc, page, &bounds); - pageSize.width = bounds.x1 - bounds.x0; - pageSize.height = bounds.y1 - bounds.y0; - return pageSize; -} - -static void releasePixmap(void *info, const void *data, size_t size) -{ - if (queue) - dispatch_async(queue, ^{ - fz_drop_pixmap(ctx, info); - }); - else - fz_drop_pixmap(ctx, info); -} - -static UIImage *newImageWithPixmap(fz_pixmap *pix) -{ - unsigned char *samples = fz_pixmap_samples(ctx, pix); - int w = fz_pixmap_width(ctx, pix); - int h = fz_pixmap_height(ctx, pix); - CGDataProviderRef cgdata = CGDataProviderCreateWithData(pix, samples, w * 4 * h, releasePixmap); - CGColorSpaceRef cgcolor = CGColorSpaceCreateDeviceRGB(); - CGImageRef cgimage = CGImageCreate(w, h, 8, 32, 4 * w, - cgcolor, kCGBitmapByteOrderDefault, - cgdata, NULL, NO, kCGRenderingIntentDefault); - UIImage *image = [[UIImage alloc] - initWithCGImage: cgimage - scale: screenScale - orientation: UIImageOrientationUp]; - CGDataProviderRelease(cgdata); - CGColorSpaceRelease(cgcolor); - CGImageRelease(cgimage); - return image; -} - -static UIImage *renderPage(fz_document *doc, fz_page *page, CGSize screenSize) -{ - CGSize pageSize; - fz_irect bbox; - fz_matrix ctm; - fz_device *dev; - fz_pixmap *pix; - CGSize scale; - - screenSize.width *= screenScale; - screenSize.height *= screenScale; - - pageSize = measurePage(doc, page); - scale = fitPageToScreen(pageSize, screenSize); - fz_scale(&ctm, scale.width, scale.height); - bbox = (fz_irect){0, 0, pageSize.width * scale.width, pageSize.height * scale.height}; - - pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), &bbox); - fz_clear_pixmap_with_value(ctx, pix, 255); - - dev = fz_new_draw_device(ctx, pix); - fz_run_page(doc, page, dev, &ctm, NULL); - fz_free_device(dev); - - return newImageWithPixmap(pix); -} - -static UIImage *renderTile(fz_document *doc, fz_page *page, CGSize screenSize, CGRect tileRect, float zoom) -{ - CGSize pageSize; - fz_irect bbox; - fz_matrix ctm; - fz_device *dev; - fz_pixmap *pix; - CGSize scale; - - screenSize.width *= screenScale; - screenSize.height *= screenScale; - tileRect.origin.x *= screenScale; - tileRect.origin.y *= screenScale; - tileRect.size.width *= screenScale; - tileRect.size.height *= screenScale; - - pageSize = measurePage(doc, page); - scale = fitPageToScreen(pageSize, screenSize); - fz_scale(&ctm, scale.width * zoom, scale.height * zoom); - - bbox.x0 = tileRect.origin.x; - bbox.y0 = tileRect.origin.y; - bbox.x1 = tileRect.origin.x + tileRect.size.width; - bbox.y1 = tileRect.origin.y + tileRect.size.height; - - pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), &bbox); - fz_clear_pixmap_with_value(ctx, pix, 255); - - dev = fz_new_draw_device(ctx, pix); - fz_run_page(doc, page, dev, &ctm, NULL); - fz_free_device(dev); - - return newImageWithPixmap(pix); -} - -#import "MuPageView.h" - -@implementation MuPageView - -- (id) initWithFrame: (CGRect)frame document: (MuDocRef *)aDoc page: (int)aNumber -{ - self = [super initWithFrame: frame]; - if (self) { - docRef = [aDoc retain]; - doc = docRef->doc; - number = aNumber; - cancel = NO; - - [self setShowsVerticalScrollIndicator: NO]; - [self setShowsHorizontalScrollIndicator: NO]; - [self setDecelerationRate: UIScrollViewDecelerationRateFast]; - [self setDelegate: self]; - - // zoomDidFinish/Begin events fire before bounce animation completes, - // making a mess when we rearrange views during the animation. - [self setBouncesZoom: NO]; - - [self resetZoomAnimated: NO]; - - // TODO: use a one shot timer to delay the display of this? - loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; - [loadingView startAnimating]; - [self addSubview: loadingView]; - - [self loadPage]; - } - return self; -} - -- (void) dealloc -{ - // dealloc can trigger in background thread when the queued block is - // our last owner, and releases us on completion. - // Send the dealloc back to the main thread so we don't mess up UIKit. - if (dispatch_get_current_queue() != dispatch_get_main_queue()) { - __block id block_self = self; // don't auto-retain self! - dispatch_async(dispatch_get_main_queue(), ^{ [block_self dealloc]; }); - } else { - __block fz_page *block_page = page; - __block fz_document *block_doc = docRef->doc; - dispatch_async(queue, ^{ - if (block_page) - fz_free_page(block_doc, block_page); - block_page = nil; - }); - [docRef release]; - [linkView release]; - [hitView release]; - [tileView release]; - [loadingView release]; - [imageView release]; - [super dealloc]; - } -} - -- (int) number -{ - return number; -} - -- (void) showLinks -{ - if (!linkView) { - dispatch_async(queue, ^{ - if (!page) - page = fz_load_page(doc, number); - fz_link *links = fz_load_links(doc, page); - dispatch_async(dispatch_get_main_queue(), ^{ - linkView = [[MuHitView alloc] initWithLinks: links forDocument: doc]; - dispatch_async(queue, ^{ - fz_drop_link(ctx, links); - }); - if (imageView) { - [linkView setFrame: [imageView frame]]; - [linkView setPageSize: pageSize]; - } - [self addSubview: linkView]; - }); - }); - } -} - -- (void) hideLinks -{ - [linkView removeFromSuperview]; - [linkView release]; - linkView = nil; -} - -- (void) showSearchResults: (int)count -{ - if (hitView) { - [hitView removeFromSuperview]; - [hitView release]; - hitView = nil; - } - hitView = [[MuHitView alloc] initWithSearchResults: count forDocument: doc]; - if (imageView) { - [hitView setFrame: [imageView frame]]; - [hitView setPageSize: pageSize]; - } - [self addSubview: hitView]; -} - -- (void) clearSearchResults -{ - if (hitView) { - [hitView removeFromSuperview]; - [hitView release]; - hitView = nil; - } -} - -- (void) resetZoomAnimated: (BOOL)animated -{ - // discard tile and any pending tile jobs - tileFrame = CGRectZero; - tileScale = 1; - if (tileView) { - [tileView removeFromSuperview]; - [tileView release]; - tileView = nil; - } - - [self setMinimumZoomScale: 1]; - [self setMaximumZoomScale: 5]; - [self setZoomScale: 1 animated: animated]; -} - -- (void) removeFromSuperview -{ - cancel = YES; - [super removeFromSuperview]; -} - -- (void) loadPage -{ - if (number < 0 || number >= fz_count_pages(doc)) - return; - dispatch_async(queue, ^{ - if (!cancel) { - printf("render page %d\n", number); - if (!page) - page = fz_load_page(doc, number); - CGSize size = measurePage(doc, page); - UIImage *image = renderPage(doc, page, self.bounds.size); - dispatch_async(dispatch_get_main_queue(), ^{ - pageSize = size; - [self displayImage: image]; - [image release]; - }); - } else { - printf("cancel page %d\n", number); - } - }); -} - -- (void) displayImage: (UIImage*)image -{ - if (loadingView) { - [loadingView removeFromSuperview]; - [loadingView release]; - loadingView = nil; - } - - if (hitView) - [hitView setPageSize: pageSize]; - - if (!imageView) { - imageView = [[UIImageView alloc] initWithImage: image]; - imageView.opaque = YES; - [self addSubview: imageView]; - if (hitView) - [self bringSubviewToFront: hitView]; - } else { - [imageView setImage: image]; - } - - [self resizeImage]; -} - -- (void) resizeImage -{ - if (imageView) { - CGSize imageSize = imageView.image.size; - CGSize scale = fitPageToScreen(imageSize, self.bounds.size); - if (fabs(scale.width - 1) > 0.1) { - CGRect frame = [imageView frame]; - frame.size.width = imageSize.width * scale.width; - frame.size.height = imageSize.height * scale.height; - [imageView setFrame: frame]; - - printf("resized view; queuing up a reload (%d)\n", number); - dispatch_async(queue, ^{ - dispatch_async(dispatch_get_main_queue(), ^{ - CGSize scale = fitPageToScreen(imageView.image.size, self.bounds.size); - if (fabs(scale.width - 1) > 0.01) - [self loadPage]; - }); - }); - } else { - [imageView sizeToFit]; - } - - [self setContentSize: imageView.frame.size]; - - [self layoutIfNeeded]; - } - -} - -- (void) willRotate -{ - if (imageView) { - [self resetZoomAnimated: NO]; - [self resizeImage]; - } -} - -- (void) layoutSubviews -{ - [super layoutSubviews]; - - // center the image as it becomes smaller than the size of the screen - - CGSize boundsSize = self.bounds.size; - CGRect frameToCenter = loadingView ? loadingView.frame : imageView.frame; - - // center horizontally - if (frameToCenter.size.width < boundsSize.width) - frameToCenter.origin.x = floor((boundsSize.width - frameToCenter.size.width) / 2); - else - frameToCenter.origin.x = 0; - - // center vertically - if (frameToCenter.size.height < boundsSize.height) - frameToCenter.origin.y = floor((boundsSize.height - frameToCenter.size.height) / 2); - else - frameToCenter.origin.y = 0; - - if (loadingView) - loadingView.frame = frameToCenter; - else - imageView.frame = frameToCenter; - - if (hitView && imageView) - [hitView setFrame: [imageView frame]]; -} - -- (UIView*) viewForZoomingInScrollView: (UIScrollView*)scrollView -{ - return imageView; -} - -- (void) loadTile -{ - CGSize screenSize = self.bounds.size; - - tileFrame.origin = self.contentOffset; - tileFrame.size = self.bounds.size; - tileFrame = CGRectIntersection(tileFrame, imageView.frame); - tileScale = self.zoomScale; - - CGRect frame = tileFrame; - float scale = tileScale; - - CGRect viewFrame = frame; - if (self.contentOffset.x < imageView.frame.origin.x) - viewFrame.origin.x = 0; - if (self.contentOffset.y < imageView.frame.origin.y) - viewFrame.origin.y = 0; - - if (scale < 1.01) - return; - - dispatch_async(queue, ^{ - __block BOOL isValid; - dispatch_sync(dispatch_get_main_queue(), ^{ - isValid = CGRectEqualToRect(frame, tileFrame) && scale == tileScale; - }); - if (!isValid) { - printf("cancel tile\n"); - return; - } - - if (!page) - page = fz_load_page(doc, number); - - printf("render tile\n"); - UIImage *image = renderTile(doc, page, screenSize, viewFrame, scale); - - dispatch_async(dispatch_get_main_queue(), ^{ - isValid = CGRectEqualToRect(frame, tileFrame) && scale == tileScale; - if (isValid) { - tileFrame = CGRectZero; - tileScale = 1; - if (tileView) { - [tileView removeFromSuperview]; - [tileView release]; - tileView = nil; - } - - tileView = [[UIImageView alloc] initWithFrame: frame]; - [tileView setImage: image]; - [self addSubview: tileView]; - if (hitView) - [self bringSubviewToFront: hitView]; - } else { - printf("discard tile\n"); - } - [image release]; - }); - }); -} - -- (void) scrollViewDidScrollToTop:(UIScrollView *)scrollView { [self loadTile]; } -- (void) scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { [self loadTile]; } -- (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView { [self loadTile]; } -- (void) scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate -{ - if (!decelerate) - [self loadTile]; -} - -- (void) scrollViewWillBeginZooming: (UIScrollView*)scrollView withView: (UIView*)view -{ - // discard tile and any pending tile jobs - tileFrame = CGRectZero; - tileScale = 1; - if (tileView) { - [tileView removeFromSuperview]; - [tileView release]; - tileView = nil; - } -} - -- (void) scrollViewDidEndZooming: (UIScrollView*)scrollView withView: (UIView*)view atScale: (float)scale -{ - [self loadTile]; -} - -- (void) scrollViewDidZoom: (UIScrollView*)scrollView -{ - if (hitView && imageView) - [hitView setFrame: [imageView frame]]; -} - -@end diff --git a/platform/ios/Classes/MuPageViewNormal.h b/platform/ios/Classes/MuPageViewNormal.h new file mode 100644 index 00000000..1bd626fd --- /dev/null +++ b/platform/ios/Classes/MuPageViewNormal.h @@ -0,0 +1,41 @@ +// +// MuPageView.h +// MuPDF +// +// Copyright (c) 2013 Artifex Software, Inc. All rights reserved. +// + +#import + +#undef ABS +#undef MIN +#undef MAX + +#include "mupdf/fitz.h" + +#import "MuHitView.h" +#import "MuPageView.h" +#import "MuDocRef.h" + +@interface MuPageViewNormal : UIScrollView +{ + MuDocRef *docRef; + fz_document *doc; + fz_page *page; + int number; + UIActivityIndicatorView *loadingView; + UIImageView *imageView; + UIImageView *tileView; + MuHitView *hitView; + MuHitView *linkView; + CGSize pageSize; + CGRect tileFrame; + float tileScale; + BOOL cancel; +} +- (id) initWithFrame: (CGRect)frame document: (MuDocRef *)aDoc page: (int)aNumber; +- (void) displayImage: (UIImage*)image; +- (void) resizeImage; +- (void) loadPage; +- (void) loadTile; +@end diff --git a/platform/ios/Classes/MuPageViewNormal.m b/platform/ios/Classes/MuPageViewNormal.m new file mode 100644 index 00000000..8cec8f02 --- /dev/null +++ b/platform/ios/Classes/MuPageViewNormal.m @@ -0,0 +1,466 @@ +// +// MuPageView.m +// MuPDF +// +// Copyright (c) 2013 Artifex Software, Inc. All rights reserved. +// + +#include "common.h" + +static CGSize measurePage(fz_document *doc, fz_page *page) +{ + CGSize pageSize; + fz_rect bounds; + fz_bound_page(doc, page, &bounds); + pageSize.width = bounds.x1 - bounds.x0; + pageSize.height = bounds.y1 - bounds.y0; + return pageSize; +} + +static void releasePixmap(void *info, const void *data, size_t size) +{ + if (queue) + dispatch_async(queue, ^{ + fz_drop_pixmap(ctx, info); + }); + else + fz_drop_pixmap(ctx, info); +} + +static UIImage *newImageWithPixmap(fz_pixmap *pix) +{ + unsigned char *samples = fz_pixmap_samples(ctx, pix); + int w = fz_pixmap_width(ctx, pix); + int h = fz_pixmap_height(ctx, pix); + CGDataProviderRef cgdata = CGDataProviderCreateWithData(pix, samples, w * 4 * h, releasePixmap); + CGColorSpaceRef cgcolor = CGColorSpaceCreateDeviceRGB(); + CGImageRef cgimage = CGImageCreate(w, h, 8, 32, 4 * w, + cgcolor, kCGBitmapByteOrderDefault, + cgdata, NULL, NO, kCGRenderingIntentDefault); + UIImage *image = [[UIImage alloc] + initWithCGImage: cgimage + scale: screenScale + orientation: UIImageOrientationUp]; + CGDataProviderRelease(cgdata); + CGColorSpaceRelease(cgcolor); + CGImageRelease(cgimage); + return image; +} + +static UIImage *renderPage(fz_document *doc, fz_page *page, CGSize screenSize) +{ + CGSize pageSize; + fz_irect bbox; + fz_matrix ctm; + fz_device *dev; + fz_pixmap *pix; + CGSize scale; + + screenSize.width *= screenScale; + screenSize.height *= screenScale; + + pageSize = measurePage(doc, page); + scale = fitPageToScreen(pageSize, screenSize); + fz_scale(&ctm, scale.width, scale.height); + bbox = (fz_irect){0, 0, pageSize.width * scale.width, pageSize.height * scale.height}; + + pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), &bbox); + fz_clear_pixmap_with_value(ctx, pix, 255); + + dev = fz_new_draw_device(ctx, pix); + fz_run_page(doc, page, dev, &ctm, NULL); + fz_free_device(dev); + + return newImageWithPixmap(pix); +} + +static UIImage *renderTile(fz_document *doc, fz_page *page, CGSize screenSize, CGRect tileRect, float zoom) +{ + CGSize pageSize; + fz_irect bbox; + fz_matrix ctm; + fz_device *dev; + fz_pixmap *pix; + CGSize scale; + + screenSize.width *= screenScale; + screenSize.height *= screenScale; + tileRect.origin.x *= screenScale; + tileRect.origin.y *= screenScale; + tileRect.size.width *= screenScale; + tileRect.size.height *= screenScale; + + pageSize = measurePage(doc, page); + scale = fitPageToScreen(pageSize, screenSize); + fz_scale(&ctm, scale.width * zoom, scale.height * zoom); + + bbox.x0 = tileRect.origin.x; + bbox.y0 = tileRect.origin.y; + bbox.x1 = tileRect.origin.x + tileRect.size.width; + bbox.y1 = tileRect.origin.y + tileRect.size.height; + + pix = fz_new_pixmap_with_bbox(ctx, fz_device_rgb(ctx), &bbox); + fz_clear_pixmap_with_value(ctx, pix, 255); + + dev = fz_new_draw_device(ctx, pix); + fz_run_page(doc, page, dev, &ctm, NULL); + fz_free_device(dev); + + return newImageWithPixmap(pix); +} + +#import "MuPageViewNormal.h" + +@implementation MuPageViewNormal + +- (id) initWithFrame: (CGRect)frame document: (MuDocRef *)aDoc page: (int)aNumber +{ + self = [super initWithFrame: frame]; + if (self) { + docRef = [aDoc retain]; + doc = docRef->doc; + number = aNumber; + cancel = NO; + + [self setShowsVerticalScrollIndicator: NO]; + [self setShowsHorizontalScrollIndicator: NO]; + [self setDecelerationRate: UIScrollViewDecelerationRateFast]; + [self setDelegate: self]; + + // zoomDidFinish/Begin events fire before bounce animation completes, + // making a mess when we rearrange views during the animation. + [self setBouncesZoom: NO]; + + [self resetZoomAnimated: NO]; + + // TODO: use a one shot timer to delay the display of this? + loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; + [loadingView startAnimating]; + [self addSubview: loadingView]; + + [self loadPage]; + } + return self; +} + +- (void) dealloc +{ + // dealloc can trigger in background thread when the queued block is + // our last owner, and releases us on completion. + // Send the dealloc back to the main thread so we don't mess up UIKit. + if (dispatch_get_current_queue() != dispatch_get_main_queue()) { + __block id block_self = self; // don't auto-retain self! + dispatch_async(dispatch_get_main_queue(), ^{ [block_self dealloc]; }); + } else { + __block fz_page *block_page = page; + __block fz_document *block_doc = docRef->doc; + dispatch_async(queue, ^{ + if (block_page) + fz_free_page(block_doc, block_page); + block_page = nil; + }); + [docRef release]; + [linkView release]; + [hitView release]; + [tileView release]; + [loadingView release]; + [imageView release]; + [super dealloc]; + } +} + +- (int) number +{ + return number; +} + +- (void) showLinks +{ + if (!linkView) { + dispatch_async(queue, ^{ + if (!page) + page = fz_load_page(doc, number); + fz_link *links = fz_load_links(doc, page); + dispatch_async(dispatch_get_main_queue(), ^{ + linkView = [[MuHitView alloc] initWithLinks: links forDocument: doc]; + dispatch_async(queue, ^{ + fz_drop_link(ctx, links); + }); + if (imageView) { + [linkView setFrame: [imageView frame]]; + [linkView setPageSize: pageSize]; + } + [self addSubview: linkView]; + }); + }); + } +} + +- (void) hideLinks +{ + [linkView removeFromSuperview]; + [linkView release]; + linkView = nil; +} + +- (void) showSearchResults: (int)count +{ + if (hitView) { + [hitView removeFromSuperview]; + [hitView release]; + hitView = nil; + } + hitView = [[MuHitView alloc] initWithSearchResults: count forDocument: doc]; + if (imageView) { + [hitView setFrame: [imageView frame]]; + [hitView setPageSize: pageSize]; + } + [self addSubview: hitView]; +} + +- (void) clearSearchResults +{ + if (hitView) { + [hitView removeFromSuperview]; + [hitView release]; + hitView = nil; + } +} + +- (void) resetZoomAnimated: (BOOL)animated +{ + // discard tile and any pending tile jobs + tileFrame = CGRectZero; + tileScale = 1; + if (tileView) { + [tileView removeFromSuperview]; + [tileView release]; + tileView = nil; + } + + [self setMinimumZoomScale: 1]; + [self setMaximumZoomScale: 5]; + [self setZoomScale: 1 animated: animated]; +} + +- (void) removeFromSuperview +{ + cancel = YES; + [super removeFromSuperview]; +} + +- (void) loadPage +{ + if (number < 0 || number >= fz_count_pages(doc)) + return; + dispatch_async(queue, ^{ + if (!cancel) { + printf("render page %d\n", number); + if (!page) + page = fz_load_page(doc, number); + CGSize size = measurePage(doc, page); + UIImage *image = renderPage(doc, page, self.bounds.size); + dispatch_async(dispatch_get_main_queue(), ^{ + pageSize = size; + [self displayImage: image]; + [image release]; + }); + } else { + printf("cancel page %d\n", number); + } + }); +} + +- (void) displayImage: (UIImage*)image +{ + if (loadingView) { + [loadingView removeFromSuperview]; + [loadingView release]; + loadingView = nil; + } + + if (hitView) + [hitView setPageSize: pageSize]; + + if (!imageView) { + imageView = [[UIImageView alloc] initWithImage: image]; + imageView.opaque = YES; + [self addSubview: imageView]; + if (hitView) + [self bringSubviewToFront: hitView]; + } else { + [imageView setImage: image]; + } + + [self resizeImage]; +} + +- (void) resizeImage +{ + if (imageView) { + CGSize imageSize = imageView.image.size; + CGSize scale = fitPageToScreen(imageSize, self.bounds.size); + if (fabs(scale.width - 1) > 0.1) { + CGRect frame = [imageView frame]; + frame.size.width = imageSize.width * scale.width; + frame.size.height = imageSize.height * scale.height; + [imageView setFrame: frame]; + + printf("resized view; queuing up a reload (%d)\n", number); + dispatch_async(queue, ^{ + dispatch_async(dispatch_get_main_queue(), ^{ + CGSize scale = fitPageToScreen(imageView.image.size, self.bounds.size); + if (fabs(scale.width - 1) > 0.01) + [self loadPage]; + }); + }); + } else { + [imageView sizeToFit]; + } + + [self setContentSize: imageView.frame.size]; + + [self layoutIfNeeded]; + } + +} + +- (void) willRotate +{ + if (imageView) { + [self resetZoomAnimated: NO]; + [self resizeImage]; + } +} + +- (void) layoutSubviews +{ + [super layoutSubviews]; + + // center the image as it becomes smaller than the size of the screen + + CGSize boundsSize = self.bounds.size; + CGRect frameToCenter = loadingView ? loadingView.frame : imageView.frame; + + // center horizontally + if (frameToCenter.size.width < boundsSize.width) + frameToCenter.origin.x = floor((boundsSize.width - frameToCenter.size.width) / 2); + else + frameToCenter.origin.x = 0; + + // center vertically + if (frameToCenter.size.height < boundsSize.height) + frameToCenter.origin.y = floor((boundsSize.height - frameToCenter.size.height) / 2); + else + frameToCenter.origin.y = 0; + + if (loadingView) + loadingView.frame = frameToCenter; + else + imageView.frame = frameToCenter; + + if (hitView && imageView) + [hitView setFrame: [imageView frame]]; +} + +- (UIView*) viewForZoomingInScrollView: (UIScrollView*)scrollView +{ + return imageView; +} + +- (void) loadTile +{ + CGSize screenSize = self.bounds.size; + + tileFrame.origin = self.contentOffset; + tileFrame.size = self.bounds.size; + tileFrame = CGRectIntersection(tileFrame, imageView.frame); + tileScale = self.zoomScale; + + CGRect frame = tileFrame; + float scale = tileScale; + + CGRect viewFrame = frame; + if (self.contentOffset.x < imageView.frame.origin.x) + viewFrame.origin.x = 0; + if (self.contentOffset.y < imageView.frame.origin.y) + viewFrame.origin.y = 0; + + if (scale < 1.01) + return; + + dispatch_async(queue, ^{ + __block BOOL isValid; + dispatch_sync(dispatch_get_main_queue(), ^{ + isValid = CGRectEqualToRect(frame, tileFrame) && scale == tileScale; + }); + if (!isValid) { + printf("cancel tile\n"); + return; + } + + if (!page) + page = fz_load_page(doc, number); + + printf("render tile\n"); + UIImage *image = renderTile(doc, page, screenSize, viewFrame, scale); + + dispatch_async(dispatch_get_main_queue(), ^{ + isValid = CGRectEqualToRect(frame, tileFrame) && scale == tileScale; + if (isValid) { + tileFrame = CGRectZero; + tileScale = 1; + if (tileView) { + [tileView removeFromSuperview]; + [tileView release]; + tileView = nil; + } + + tileView = [[UIImageView alloc] initWithFrame: frame]; + [tileView setImage: image]; + [self addSubview: tileView]; + if (hitView) + [self bringSubviewToFront: hitView]; + } else { + printf("discard tile\n"); + } + [image release]; + }); + }); +} + +- (void) scrollViewDidScrollToTop:(UIScrollView *)scrollView { [self loadTile]; } +- (void) scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { [self loadTile]; } +- (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView { [self loadTile]; } +- (void) scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate +{ + if (!decelerate) + [self loadTile]; +} + +- (void) scrollViewWillBeginZooming: (UIScrollView*)scrollView withView: (UIView*)view +{ + // discard tile and any pending tile jobs + tileFrame = CGRectZero; + tileScale = 1; + if (tileView) { + [tileView removeFromSuperview]; + [tileView release]; + tileView = nil; + } +} + +- (void) scrollViewDidEndZooming: (UIScrollView*)scrollView withView: (UIView*)view atScale: (float)scale +{ + [self loadTile]; +} + +- (void) scrollViewDidZoom: (UIScrollView*)scrollView +{ + if (hitView && imageView) + [hitView setFrame: [imageView frame]]; +} + +- (void) setScale:(float)scale {} + +@end diff --git a/platform/ios/Classes/MuPageViewReflow.h b/platform/ios/Classes/MuPageViewReflow.h new file mode 100644 index 00000000..28638bc8 --- /dev/null +++ b/platform/ios/Classes/MuPageViewReflow.h @@ -0,0 +1,20 @@ +// +// MuPageViewReflow.h +// MuPDF +// +// Copyright (c) 2013 Artifex Software, Inc. All rights reserved. +// + +#import +#import "MuDocRef.h" +#import "MuPageView.h" + +@interface MuPageViewReflow : UIWebView +{ + int number; + float scale; +} + +-(id) initWithFrame:(CGRect)frame document:(MuDocRef *)aDoc page:(int)aNumber; + +@end diff --git a/platform/ios/Classes/MuPageViewReflow.m b/platform/ios/Classes/MuPageViewReflow.m new file mode 100644 index 00000000..541731fb --- /dev/null +++ b/platform/ios/Classes/MuPageViewReflow.m @@ -0,0 +1,136 @@ +// +// MuPageViewReflow.m +// MuPDF +// +// Copyright (c) 2013 Artifex Software, Inc. All rights reserved. +// + +#include "common.h" +#import "MuPageViewReflow.h" + +NSString *textAsHtml(fz_document *doc, int pageNum) +{ + NSString *str = nil; + fz_page *page = NULL; + fz_text_sheet *sheet = NULL; + fz_text_page *text = NULL; + fz_device *dev = NULL; + fz_matrix ctm; + fz_buffer *buf = NULL; + fz_output *out = NULL; + + fz_var(page); + fz_var(sheet); + fz_var(text); + fz_var(dev); + fz_var(buf); + fz_var(out); + + fz_try(ctx) + { + int b, l, s, c; + + ctm = fz_identity; + sheet = fz_new_text_sheet(ctx); + text = fz_new_text_page(ctx); + dev = fz_new_text_device(ctx, sheet, text); + page = fz_load_page(doc, pageNum); + fz_run_page(doc, page, dev, &ctm, NULL); + fz_free_device(dev); + dev = NULL; + + fz_analyze_text(ctx, sheet, text); + + buf = fz_new_buffer(ctx, 256); + out = fz_new_output_with_buffer(ctx, buf); + fz_printf(out, "\n"); + fz_printf(out, "\n"); + fz_printf(out, "
"); + fz_print_text_page_html(ctx, out, text); + fz_printf(out, "
\n"); + fz_printf(out, "\n\n"); + fz_close_output(out); + out = NULL; + + str = [[[NSString alloc] initWithBytes:buf->data length:buf->len encoding:NSUTF8StringEncoding] autorelease]; + } + fz_always(ctx) + { + fz_free_text_page(ctx, text); + fz_free_text_sheet(ctx, sheet); + fz_free_device(dev); + fz_close_output(out); + fz_drop_buffer(ctx, buf); + fz_free_page(doc, page); + } + fz_catch(ctx) + { + str = nil; + } + + return str; +} + +@implementation MuPageViewReflow + +- (id)initWithFrame:(CGRect)frame document:(MuDocRef *)aDoc page:(int)aNumber +{ + self = [super initWithFrame:frame]; + if (self) { + number = aNumber; + scale = 1.0; + self.scalesPageToFit = NO; + [self setDelegate:self]; + dispatch_async(queue, ^{ + __block NSString *cont = [textAsHtml(aDoc->doc, aNumber) retain]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self loadHTMLString:cont baseURL:nil]; + }); + }); + } + return self; +} + +-(void) webViewDidFinishLoad:(UIWebView *)webView +{ + [self stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.getElementById('content').style.zoom=\"%f\"", scale]]; +} + +-(void) dealloc +{ + [self setDelegate:nil]; + [super dealloc]; +} + +-(int) number +{ + return number; +} + +-(void) willRotate {} +-(void) showLinks {} +-(void) hideLinks {} +-(void) showSearchResults: (int)count {} +-(void) clearSearchResults {} +-(void) resetZoomAnimated: (BOOL)animated +{ + [self.scrollView setContentOffset:CGPointZero animated:NO]; +} + +-(void) setScale:(float)aFloat +{ + scale = aFloat; + [self stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.getElementById('content').style.zoom=\"%f\"", scale]]; +} + +@end diff --git a/platform/ios/MuPDF.xcodeproj/project.pbxproj b/platform/ios/MuPDF.xcodeproj/project.pbxproj index d905e32d..487f439d 100644 --- a/platform/ios/MuPDF.xcodeproj/project.pbxproj +++ b/platform/ios/MuPDF.xcodeproj/project.pbxproj @@ -31,10 +31,18 @@ DA1C68AB17E86A500061F586 /* MuLibraryController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1C689917E85E8E0061F586 /* MuLibraryController.m */; }; DA1C68AD17E86A500061F586 /* MuOutlineController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1C689D17E861020061F586 /* MuOutlineController.m */; }; DA1C68AF17E86A500061F586 /* MuHitView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1C689F17E861870061F586 /* MuHitView.m */; }; - DA1C68B117E86A500061F586 /* MuPageView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1C68A517E863C70061F586 /* MuPageView.m */; }; + DA1C68B117E86A500061F586 /* MuPageViewNormal.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1C68A517E863C70061F586 /* MuPageViewNormal.m */; }; DA1C68B317E86A500061F586 /* MuDocumentController.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1C68A717E864180061F586 /* MuDocumentController.m */; }; DA1C68B517E86A500061F586 /* MuAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1C68A917E864CB0061F586 /* MuAppDelegate.m */; }; DA1C68C417E8969C0061F586 /* common.m in Sources */ = {isa = PBXBuildFile; fileRef = DA1C68C317E8969C0061F586 /* common.m */; }; + DAA6E56F17F03F96002B1E4E /* MuPageViewReflow.m in Sources */ = {isa = PBXBuildFile; fileRef = DAA6E56E17F03AAE002B1E4E /* MuPageViewReflow.m */; }; + DAB9F4BB17F1B24000117D2E /* ic_arrow_left.png in Resources */ = {isa = PBXBuildFile; fileRef = DAB9F4B517F1B24000117D2E /* ic_arrow_left.png */; }; + DAB9F4BC17F1B24000117D2E /* ic_arrow_right.png in Resources */ = {isa = PBXBuildFile; fileRef = DAB9F4B617F1B24000117D2E /* ic_arrow_right.png */; }; + DAB9F4BD17F1B24000117D2E /* ic_cancel.png in Resources */ = {isa = PBXBuildFile; fileRef = DAB9F4B717F1B24000117D2E /* ic_cancel.png */; }; + DAB9F4BE17F1B24000117D2E /* ic_link.png in Resources */ = {isa = PBXBuildFile; fileRef = DAB9F4B817F1B24000117D2E /* ic_link.png */; }; + DAB9F4BF17F1B24000117D2E /* ic_list.png in Resources */ = {isa = PBXBuildFile; fileRef = DAB9F4B917F1B24000117D2E /* ic_list.png */; }; + DAB9F4C017F1B24000117D2E /* ic_magnifying_glass.png in Resources */ = {isa = PBXBuildFile; fileRef = DAB9F4BA17F1B24000117D2E /* ic_magnifying_glass.png */; }; + DAB9F4C217F1CB6D00117D2E /* ic_reflow.png in Resources */ = {isa = PBXBuildFile; fileRef = DAB9F4C117F1CB6D00117D2E /* ic_reflow.png */; }; DABDEF5A17EC484A00AC35F1 /* MuDocRef.m in Sources */ = {isa = PBXBuildFile; fileRef = DABDEF5917EC484A00AC35F1 /* MuDocRef.m */; }; /* End PBXBuildFile section */ @@ -78,16 +86,26 @@ DA1C689D17E861020061F586 /* MuOutlineController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MuOutlineController.m; path = Classes/MuOutlineController.m; sourceTree = ""; }; DA1C689E17E861870061F586 /* MuHitView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MuHitView.h; path = Classes/MuHitView.h; sourceTree = ""; }; DA1C689F17E861870061F586 /* MuHitView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MuHitView.m; path = Classes/MuHitView.m; sourceTree = ""; }; - DA1C68A417E863C70061F586 /* MuPageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MuPageView.h; path = Classes/MuPageView.h; sourceTree = ""; }; - DA1C68A517E863C70061F586 /* MuPageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MuPageView.m; path = Classes/MuPageView.m; sourceTree = ""; }; + DA1C68A417E863C70061F586 /* MuPageViewNormal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MuPageViewNormal.h; path = Classes/MuPageViewNormal.h; sourceTree = ""; }; + DA1C68A517E863C70061F586 /* MuPageViewNormal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MuPageViewNormal.m; path = Classes/MuPageViewNormal.m; sourceTree = ""; }; DA1C68A617E864180061F586 /* MuDocumentController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MuDocumentController.h; path = Classes/MuDocumentController.h; sourceTree = ""; }; DA1C68A717E864180061F586 /* MuDocumentController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MuDocumentController.m; path = Classes/MuDocumentController.m; sourceTree = ""; }; DA1C68A817E864CB0061F586 /* MuAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MuAppDelegate.h; path = Classes/MuAppDelegate.h; sourceTree = ""; }; DA1C68A917E864CB0061F586 /* MuAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MuAppDelegate.m; path = Classes/MuAppDelegate.m; sourceTree = ""; }; DA1C68C217E8968C0061F586 /* common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = ""; }; DA1C68C317E8969C0061F586 /* common.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = common.m; sourceTree = ""; }; + DAA6E56D17F03AAE002B1E4E /* MuPageViewReflow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MuPageViewReflow.h; path = Classes/MuPageViewReflow.h; sourceTree = ""; }; + DAA6E56E17F03AAE002B1E4E /* MuPageViewReflow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MuPageViewReflow.m; path = Classes/MuPageViewReflow.m; sourceTree = ""; }; + DAB9F4B517F1B24000117D2E /* ic_arrow_left.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ic_arrow_left.png; path = "../android/res/drawable-ldpi/ic_arrow_left.png"; sourceTree = ""; }; + DAB9F4B617F1B24000117D2E /* ic_arrow_right.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ic_arrow_right.png; path = "../android/res/drawable-ldpi/ic_arrow_right.png"; sourceTree = ""; }; + DAB9F4B717F1B24000117D2E /* ic_cancel.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ic_cancel.png; path = "../android/res/drawable-ldpi/ic_cancel.png"; sourceTree = ""; }; + DAB9F4B817F1B24000117D2E /* ic_link.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ic_link.png; path = "../android/res/drawable-ldpi/ic_link.png"; sourceTree = ""; }; + DAB9F4B917F1B24000117D2E /* ic_list.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ic_list.png; path = "../android/res/drawable-ldpi/ic_list.png"; sourceTree = ""; }; + DAB9F4BA17F1B24000117D2E /* ic_magnifying_glass.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ic_magnifying_glass.png; path = "../android/res/drawable-ldpi/ic_magnifying_glass.png"; sourceTree = ""; }; + DAB9F4C117F1CB6D00117D2E /* ic_reflow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = ic_reflow.png; path = "../android/res/drawable-ldpi/ic_reflow.png"; sourceTree = ""; }; DABDEF5817EC484A00AC35F1 /* MuDocRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MuDocRef.h; path = Classes/MuDocRef.h; sourceTree = ""; }; DABDEF5917EC484A00AC35F1 /* MuDocRef.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MuDocRef.m; path = Classes/MuDocRef.m; sourceTree = ""; }; + DADD8D6917EB24C000C49E0B /* MuPageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MuPageView.h; path = Classes/MuPageView.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -116,6 +134,7 @@ children = ( DA1C68C317E8969C0061F586 /* common.m */, DA1C68C217E8968C0061F586 /* common.h */, + 96C8ED001779A88E00A30AF4 /* main.m */, DA1C689717E85E4A0061F586 /* Classes */, 968E1E461779A54F0050CEA3 /* Resources */, 968E1E3F1779A54F0050CEA3 /* Frameworks */, @@ -151,13 +170,19 @@ 968E1E461779A54F0050CEA3 /* Resources */ = { isa = PBXGroup; children = ( + DAB9F4C117F1CB6D00117D2E /* ic_reflow.png */, + DAB9F4B517F1B24000117D2E /* ic_arrow_left.png */, + DAB9F4B617F1B24000117D2E /* ic_arrow_right.png */, + DAB9F4B717F1B24000117D2E /* ic_cancel.png */, + DAB9F4B817F1B24000117D2E /* ic_link.png */, + DAB9F4B917F1B24000117D2E /* ic_list.png */, + DAB9F4BA17F1B24000117D2E /* ic_magnifying_glass.png */, 96E1CDE71779A60700FCF717 /* Icon-72.png */, 96E1CDE81779A60700FCF717 /* Icon-72@2x.png */, 96E1CDE91779A60700FCF717 /* Icon.png */, 96E1CDEA1779A60700FCF717 /* Icon@2x.png */, 96E1CDEB1779A60700FCF717 /* iTunesArtwork.png */, 96E1CDEC1779A60700FCF717 /* x_alt_blue.png */, - 96C8ED001779A88E00A30AF4 /* main.m */, 96E1CDED1779A60700FCF717 /* x_alt_blue@2x.png */, 968E1E481779A54F0050CEA3 /* Info.plist */, 968E1E521779A54F0050CEA3 /* Default.png */, @@ -176,14 +201,17 @@ DA1C689D17E861020061F586 /* MuOutlineController.m */, DA1C689E17E861870061F586 /* MuHitView.h */, DA1C689F17E861870061F586 /* MuHitView.m */, - DA1C68A417E863C70061F586 /* MuPageView.h */, - DA1C68A517E863C70061F586 /* MuPageView.m */, + DA1C68A417E863C70061F586 /* MuPageViewNormal.h */, + DA1C68A517E863C70061F586 /* MuPageViewNormal.m */, DA1C68A617E864180061F586 /* MuDocumentController.h */, DA1C68A717E864180061F586 /* MuDocumentController.m */, DA1C68A817E864CB0061F586 /* MuAppDelegate.h */, DA1C68A917E864CB0061F586 /* MuAppDelegate.m */, + DADD8D6917EB24C000C49E0B /* MuPageView.h */, DABDEF5817EC484A00AC35F1 /* MuDocRef.h */, DABDEF5917EC484A00AC35F1 /* MuDocRef.m */, + DAA6E56D17F03AAE002B1E4E /* MuPageViewReflow.h */, + DAA6E56E17F03AAE002B1E4E /* MuPageViewReflow.m */, ); name = Classes; sourceTree = ""; @@ -270,6 +298,13 @@ 96E1CDF21779A60700FCF717 /* iTunesArtwork.png in Resources */, 96E1CDF31779A60700FCF717 /* x_alt_blue.png in Resources */, 96E1CDF41779A60700FCF717 /* x_alt_blue@2x.png in Resources */, + DAB9F4BB17F1B24000117D2E /* ic_arrow_left.png in Resources */, + DAB9F4BC17F1B24000117D2E /* ic_arrow_right.png in Resources */, + DAB9F4BD17F1B24000117D2E /* ic_cancel.png in Resources */, + DAB9F4BE17F1B24000117D2E /* ic_link.png in Resources */, + DAB9F4BF17F1B24000117D2E /* ic_list.png in Resources */, + DAB9F4C017F1B24000117D2E /* ic_magnifying_glass.png in Resources */, + DAB9F4C217F1CB6D00117D2E /* ic_reflow.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -303,10 +338,11 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DAA6E56F17F03F96002B1E4E /* MuPageViewReflow.m in Sources */, DA1C68AB17E86A500061F586 /* MuLibraryController.m in Sources */, DA1C68AD17E86A500061F586 /* MuOutlineController.m in Sources */, DA1C68AF17E86A500061F586 /* MuHitView.m in Sources */, - DA1C68B117E86A500061F586 /* MuPageView.m in Sources */, + DA1C68B117E86A500061F586 /* MuPageViewNormal.m in Sources */, DA1C68B317E86A500061F586 /* MuDocumentController.m in Sources */, DA1C68B517E86A500061F586 /* MuAppDelegate.m in Sources */, 96C8ED011779A88E00A30AF4 /* main.m in Sources */, @@ -358,8 +394,10 @@ isa = XCBuildConfiguration; buildSettings = { INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 6.1; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; USER_HEADER_SEARCH_PATHS = ../../include; }; name = Debug; @@ -368,8 +406,10 @@ isa = XCBuildConfiguration; buildSettings = { INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 6.1; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; USER_HEADER_SEARCH_PATHS = ../../include; }; name = Release; -- cgit v1.2.3