X-Git-Url: https://git.saurik.com/cydia.git/blobdiff_plain/263b91b496228fdb5d0d0b0866b933630dd691fb..e55154830092f12b08a8b721d15a1e4aa54d789e:/UICaboodle/BrowserView.m diff --git a/UICaboodle/BrowserView.m b/UICaboodle/BrowserView.m index e7dd58be..fbec7b7c 100644 --- a/UICaboodle/BrowserView.m +++ b/UICaboodle/BrowserView.m @@ -1,7 +1,9 @@ #include +#include + /* Indirect Delegate {{{ */ -@interface IndirectDelegate : NSProxy { +@interface IndirectDelegate : NSObject { _transient volatile id delegate_; } @@ -20,11 +22,71 @@ return self; } +- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { + if (delegate_ != nil) + return [delegate_ webView:sender didClearWindowObject:window forFrame:frame]; +} + +- (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame { + if (delegate_ != nil) + return [delegate_ webView:sender didCommitLoadForFrame:frame]; +} + +- (void) webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { + if (delegate_ != nil) + return [delegate_ webView:sender didFailLoadWithError:error forFrame:frame]; +} + +- (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { + if (delegate_ != nil) + return [delegate_ webView:sender didFailProvisionalLoadWithError:error forFrame:frame]; +} + +- (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame { + if (delegate_ != nil) + return [delegate_ webView:sender didFinishLoadForFrame:frame]; +} + +- (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame { + if (delegate_ != nil) + return [delegate_ webView:sender didReceiveTitle:title forFrame:frame]; +} + +- (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame { + if (delegate_ != nil) + return [delegate_ webView:sender didStartProvisionalLoadForFrame:frame]; +} + +- (void) webView:(WebView *)sender resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)source { + if (delegate_ != nil) + return [delegate_ webView:sender resource:identifier didReceiveAuthenticationChallenge:challenge fromDataSource:source]; +} + +- (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)source { + if (delegate_ != nil) + return [delegate_ webView:sender resource:identifier willSendRequest:request redirectResponse:redirectResponse fromDataSource:source]; + return nil; +} + +- (IMP) methodForSelector:(SEL)sel { + if (IMP method = [super methodForSelector:sel]) + return method; + fprintf(stderr, "methodForSelector:[%s] == NULL\n", sel_getName(sel)); + return NULL; +} + - (BOOL) respondsToSelector:(SEL)sel { - return delegate_ == nil ? FALSE : [delegate_ respondsToSelector:sel]; + if ([super respondsToSelector:sel]) + return YES; + // XXX: WebThreadCreateNSInvocation returns nil + //fprintf(stderr, "[%s]R?%s\n", class_getName(self->isa), sel_getName(sel)); + return delegate_ == nil ? NO : [delegate_ respondsToSelector:sel]; } - (NSMethodSignature *) methodSignatureForSelector:(SEL)sel { + if (NSMethodSignature *method = [super methodSignatureForSelector:sel]) + return method; + //fprintf(stderr, "[%s]S?%s\n", class_getName(self->isa), sel_getName(sel)); if (delegate_ != nil) if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel]) return sig; @@ -49,6 +111,29 @@ - (void) _setLayoutInterval:(float)interval; @end +@interface WebScriptObject (Cydia) + +- (unsigned) count; +- (id) objectAtIndex:(unsigned)index; + +@end + +@implementation WebScriptObject (Cydia) + +- (unsigned) count { + id length([self valueForKey:@"length"]); + if ([length respondsToSelector:@selector(intValue)]) + return [length intValue]; + else + return 0; +} + +- (id) objectAtIndex:(unsigned)index { + return [self webScriptValueAtIndex:index]; +} + +@end + /* Web Scripting {{{ */ @interface CydiaObject : NSObject { id indirect_; @@ -70,8 +155,26 @@ } return self; } ++ (NSArray *) _attributeKeys { + return [NSArray arrayWithObjects:@"device", nil]; +} + +- (NSArray *) attributeKeys { + return [[self class] _attributeKeys]; +} + ++ (BOOL) isKeyExcludedFromWebScript:(const char *)name { + return ![[self _attributeKeys] containsObject:[NSString stringWithUTF8String:name]] && [super isKeyExcludedFromWebScript:name]; +} + +- (NSString *) device { + return [[UIDevice currentDevice] uniqueIdentifier]; +} + + (NSString *) webScriptNameForSelector:(SEL)selector { - if (selector == @selector(getPackageById:)) + if (selector == @selector(close)) + return @"close"; + else if (selector == @selector(getPackageById:)) return @"getPackageById"; else if (selector == @selector(setAutoPopup:)) return @"setAutoPopup"; @@ -79,8 +182,20 @@ return @"setButtonImage"; else if (selector == @selector(setButtonTitle:withStyle:toFunction:)) return @"setButtonTitle"; + else if (selector == @selector(setFinishHook:)) + return @"setFinishHook"; + else if (selector == @selector(setPopupHook:)) + return @"setPopupHook"; + else if (selector == @selector(setSpecial:)) + return @"setSpecial"; + else if (selector == @selector(setViewportWidth:)) + return @"setViewportWidth"; else if (selector == @selector(supports:)) return @"supports"; + else if (selector == @selector(stringWithFormat:arguments:)) + return @"format"; + else if (selector == @selector(localizedStringForKey:value:table:)) + return @"localize"; else if (selector == @selector(du:)) return @"du"; else if (selector == @selector(statfs:)) @@ -125,7 +240,8 @@ _assert(dup2(fds[1], 1) != -1); _assert(close(fds[0]) != -1); _assert(close(fds[1]) != -1); - execlp("du", "du", "-s", [path UTF8String], NULL); + /* XXX: this should probably not use du */ + execl("/usr/libexec/cydia/du", "du", "-s", [path UTF8String], NULL); exit(1); _assert(false); } @@ -157,6 +273,10 @@ return value; } +- (void) close { + [indirect_ close]; +} + - (void) setAutoPopup:(BOOL)popup { [indirect_ setAutoPopup:popup]; } @@ -169,6 +289,37 @@ [indirect_ setButtonTitle:button withStyle:style toFunction:function]; } +- (void) setSpecial:(id)function { + [indirect_ setSpecial:function]; +} + +- (void) setFinishHook:(id)function { + [indirect_ setFinishHook:function]; +} + +- (void) setPopupHook:(id)function { + [indirect_ setPopupHook:function]; +} + +- (void) setViewportWidth:(float)width { + [indirect_ setViewportWidth:width]; +} + +- (NSString *) stringWithFormat:(NSString *)format arguments:(WebScriptObject *)arguments { + //NSLog(@"SWF:\"%@\" A:%@", format, [arguments description]); + unsigned count([arguments count]); + id values[count]; + for (unsigned i(0); i != count; ++i) + values[i] = [arguments objectAtIndex:i]; + return [[[NSString alloc] initWithFormat:format arguments:reinterpret_cast(values)] autorelease]; +} + +- (NSString *) localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)table { + if (reinterpret_cast(table) == [WebUndefined undefined]) + table = nil; + return [[NSBundle mainBundle] localizedStringForKey:key value:value table:table]; +} + @end /* }}} */ @@ -179,13 +330,15 @@ #endif - (void) dealloc { -#if ForSaurik +#if LogBrowser NSLog(@"[BrowserView dealloc]"); #endif if (challenge_ != nil) [challenge_ release]; + WebThreadLock(); + WebView *webview = [webview_ webView]; [webview setFrameLoadDelegate:nil]; [webview setResourceLoadDelegate:nil]; @@ -195,13 +348,20 @@ [webview setDownloadDelegate:nil]; + /* XXX: these are set by UIWebDocumentView [webview _setFormDelegate:nil]; [webview _setUIKitDelegate:nil]; - [webview setWebMailDelegate:nil]; - [webview setEditingDelegate:nil]; + [webview setEditingDelegate:nil];*/ + + /* XXX: no one sets this, ever + [webview setWebMailDelegate:nil];*/ [webview_ setDelegate:nil]; [webview_ setGestureDelegate:nil]; + [webview_ setFormEditingDelegate:nil]; + [webview_ setInteractionDelegate:nil]; + + [indirect_ setDelegate:nil]; //NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; @@ -214,9 +374,10 @@ [webview_ release]; #endif - [indirect_ setDelegate:nil]; [indirect_ release]; + WebThreadUnlock(); + [cydia_ release]; [scroller_ setDelegate:nil]; @@ -227,6 +388,12 @@ [style_ release]; if (function_ != nil) [function_ release]; + if (finish_ != nil) + [finish_ release]; + if (closer_ != nil) + [closer_ release]; + if (special_ != nil) + [special_ release]; [scroller_ release]; [indicator_ release]; @@ -266,7 +433,10 @@ - (void) loadRequest:(NSURLRequest *)request { pushed_ = true; error_ = false; + + WebThreadLock(); [webview_ loadRequest:request]; + WebThreadUnlock(); } - (void) reloadURL { @@ -277,8 +447,8 @@ [self loadRequest:request_]; else { UIActionSheet *sheet = [[[UIActionSheet alloc] - initWithTitle:@"Are you sure you want to submit this form again?" - buttons:[NSArray arrayWithObjects:@"Cancel", @"Submit", nil] + initWithTitle:CYLocalize("RESUBMIT_FORM") + buttons:[NSArray arrayWithObjects:CYLocalize("CANCEL"), CYLocalize("SUBMIT"), nil] defaultButtonIndex:0 delegate:self context:@"submit" @@ -297,8 +467,48 @@ return webview_; } +/* XXX: WebThreadLock? */ +- (void) _fixScroller:(CGRect)bounds { + float extra; + if (!editing_) + extra = 0; + else { + UIFormAssistant *assistant([UIFormAssistant sharedFormAssistant]); + CGRect peripheral([assistant peripheralFrame]); +#if LogBrowser + NSLog(@"per:%f", peripheral.size.height); +#endif + extra = peripheral.size.height; + } + + CGRect subrect([scroller_ frame]); + subrect.size.height -= extra; + [scroller_ setScrollerIndicatorSubrect:subrect]; + + NSSize visible(NSMakeSize(subrect.size.width, subrect.size.height)); + [webview_ setValue:[NSValue valueWithSize:visible] forGestureAttribute:UIGestureAttributeVisibleSize]; + + CGSize size(size_); + size.height += extra; + [scroller_ setContentSize:size]; + + [scroller_ releaseRubberBandIfNecessary]; +} + +- (void) fixScroller { + CGRect bounds([webview_ documentBounds]); +#if TrackResize + NSLog(@"_fs:(%f,%f+%f,%f)", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height); +#endif + [self _fixScroller:bounds]; +} + - (void) view:(UIView *)sender didSetFrame:(CGRect)frame { - [scroller_ setContentSize:frame.size]; + size_ = frame.size; +#if TrackResize + NSLog(@"dsf:(%f,%f+%f,%f)", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height); +#endif + [self _fixScroller:frame]; } - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old { @@ -314,13 +524,21 @@ - (void) _pushPage { if (pushed_) return; - [self autorelease]; + // WTR: [self autorelease]; pushed_ = true; [book_ pushPage:self]; } -- (BOOL) getSpecial:(NSURL *)url { -#if ForSaurik +- (void) swapPage:(RVPage *)page { + [page setDelegate:delegate_]; + if (pushed_) + [book_ swapPage:page]; + else + [book_ pushPage:page]; +} + +- (BOOL) getSpecial:(NSURL *)url swap:(BOOL)swap { +#if LogBrowser NSLog(@"getSpecial:%@", url); #endif @@ -339,7 +557,10 @@ return false; if (page != nil) - [self pushPage:page]; + if (swap) + [self swapPage:page]; + else + [self pushPage:page]; return true; } @@ -354,10 +575,11 @@ - (void) webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame { if (![self _allowJavaScriptPanel]) return; + [self retain]; UIActionSheet *sheet = [[[UIActionSheet alloc] initWithTitle:nil - buttons:[NSArray arrayWithObjects:@"OK", nil] + buttons:[NSArray arrayWithObjects:CYLocalize("OK"), nil] defaultButtonIndex:0 delegate:self context:@"alert" @@ -370,12 +592,13 @@ - (BOOL) webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame { if (![self _allowJavaScriptPanel]) return NO; + [self retain]; UIActionSheet *sheet = [[[UIActionSheet alloc] initWithTitle:nil - buttons:[NSArray arrayWithObjects:@"OK", @"Cancel", nil] + buttons:[NSArray arrayWithObjects:CYLocalize("OK"), CYLocalize("Cancel"), nil] defaultButtonIndex:0 - delegate:self + delegate:indirect_ context:@"confirm" ] autorelease]; @@ -390,6 +613,8 @@ NSNumber *confirm([confirm_ autorelease]); confirm_ = nil; + + [self autorelease]; return [confirm boolValue]; } @@ -397,6 +622,12 @@ popup_ = popup; } +- (void) setSpecial:(id)function { + if (special_ != nil) + [special_ autorelease]; + special_ = function == nil ? nil : [function retain]; +} + - (void) setButtonImage:(NSString *)button withStyle:(NSString *)style toFunction:(id)function { if (button_ != nil) [button_ autorelease]; @@ -409,6 +640,8 @@ if (function_ != nil) [function_ autorelease]; function_ = function == nil ? nil : [function retain]; + + [self reloadButtons]; } - (void) setButtonTitle:(NSString *)button withStyle:(NSString *)style toFunction:(id)function { @@ -423,12 +656,43 @@ if (function_ != nil) [function_ autorelease]; function_ = function == nil ? nil : [function retain]; + + [self reloadButtons]; +} + +- (void) setFinishHook:(id)function { + if (finish_ != nil) + [finish_ autorelease]; + finish_ = function == nil ? nil : [function retain]; +} + +- (void) setPopupHook:(id)function { + if (closer_ != nil) + [closer_ autorelease]; + closer_ = function == nil ? nil : [function retain]; +} + +- (void) webView:(WebView *)sender willBeginEditingFormElement:(id)element { + editing_ = true; +} + +- (void) webView:(WebView *)sender didBeginEditingFormElement:(id)element { + [self fixScroller]; +} + +- (void) webViewDidEndEditingFormElements:(WebView *)sender { + editing_ = false; + [self fixScroller]; } - (void) webViewClose:(WebView *)sender { [book_ close]; } +- (void) close { + [book_ close]; +} + - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame { [window setValue:cydia_ forKey:@"cydia"]; } @@ -438,13 +702,13 @@ } - (void) webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)name decisionListener:(id)listener { -#if ForSaurik +#if LogBrowser NSLog(@"nwa:%@", name); #endif if (NSURL *url = [request URL]) { if (name == nil) unknown: { - if (![self getSpecial:url]) { + if (![self getSpecial:url swap:NO]) { NSString *scheme([[url scheme] lowercaseString]); if ([scheme isEqualToString:@"mailto"]) [delegate_ openMailToURL:url]; @@ -453,24 +717,30 @@ } else if ([name isEqualToString:@"_open"]) [delegate_ openURL:url]; else if ([name isEqualToString:@"_popup"]) { - RVBook *book([[[RVPopUpBook alloc] initWithFrame:[delegate_ popUpBounds]] autorelease]); - - RVPage *page([delegate_ pageForURL:url hasTag:NULL]); - if (page == nil) { - /* XXX: call createWebViewWithRequest instead? */ + NSString *scheme([[url scheme] lowercaseString]); + if ([scheme isEqualToString:@"mailto"]) + [delegate_ openMailToURL:url]; + else { + RVBook *book([[[RVPopUpBook alloc] initWithFrame:[delegate_ popUpBounds]] autorelease]); + [book setHook:indirect_]; + + RVPage *page([delegate_ pageForURL:url hasTag:NULL]); + if (page == nil) { + /* XXX: call createWebViewWithRequest instead? */ + + [self setBackButtonTitle:title_]; + + BrowserView *browser([[[BrowserView alloc] initWithBook:book] autorelease]); + [browser loadURL:url]; + page = browser; + } - [self setBackButtonTitle:title_]; + [book setDelegate:delegate_]; + [page setDelegate:delegate_]; - BrowserView *browser([[[BrowserView alloc] initWithBook:book] autorelease]); - [browser loadURL:url]; - page = browser; + [book setPage:page]; + [book_ pushBook:book]; } - - [book setDelegate:delegate_]; - [page setDelegate:delegate_]; - - [book setPage:page]; - [book_ pushBook:book]; } else goto unknown; [listener ignore]; @@ -478,13 +748,15 @@ [listener use]; } -- (void) webView:(WebView *)webView decidePolicyForMIMEType:(NSString *)type request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { +- (void) webView:(WebView *)sender decidePolicyForMIMEType:(NSString *)type request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id)listener { if ([WebView canShowMIMEType:type]) [listener use]; else { // XXX: handle more mime types! [listener ignore]; - if (frame == [webView mainFrame]) + + WebView *webview([webview_ webView]); + if (frame == [webview mainFrame]) [UIApp openURL:[request URL]]; } } @@ -502,26 +774,34 @@ if (request_ != nil) [request_ autorelease]; request_ = [request retain]; -#if ForSaurik +#if LogBrowser NSLog(@"dpn:%@", request_); #endif } [listener use]; - /* XXX: maybe only the main frame? */ - [self _pushPage]; + + WebView *webview([webview_ webView]); + if (frame == [webview mainFrame]) + [self _pushPage]; return; } -#if ForSaurik +#if LogBrowser else NSLog(@"nav:%@:%@", url, [action description]); #endif - const NSArray *capability(reinterpret_cast(GSSystemGetCapability(kGSDisplayIdentifiersCapability))); + const NSArray *capability; + +#if 0 // XXX:3:GSSystemCopyCapability + capability = reinterpret_cast(GSSystemGetCapability(kGSDisplayIdentifiersCapability)); +#else + capability = nil; +#endif - if ( + if (capability != nil && ( [capability containsObject:@"com.apple.Maps"] && [url mapsURL] || [capability containsObject:@"com.apple.youtube"] && [url youTubeURL] - ) { + )) { open: [UIApp openURL:url]; goto ignore; @@ -529,14 +809,14 @@ int store(_not(int)); if (NSURL *itms = [url itmsURL:&store]) { -#if ForSaurik +#if LogBrowser NSLog(@"itms#%@#%u#%@", url, store, itms); #endif - if ( + if (capability != nil && ( store == 1 && [capability containsObject:@"com.apple.MobileStore"] || store == 2 && [capability containsObject:@"com.apple.AppStore"] - ) { + )) { url = itms; goto open; } @@ -554,7 +834,7 @@ goto ignore; } - if ([self getSpecial:url]) + if ([self getSpecial:url swap:YES]) goto ignore; else if ([WebView _canHandleRequest:request]) goto use; @@ -571,9 +851,10 @@ - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button { NSString *context([sheet context]); - if ([context isEqualToString:@"alert"]) + if ([context isEqualToString:@"alert"]) { + [self autorelease]; [sheet dismiss]; - else if ([context isEqualToString:@"confirm"]) { + } else if ([context isEqualToString:@"confirm"]) { switch (button) { case 1: confirm_ = [NSNumber numberWithBool:YES]; @@ -616,8 +897,11 @@ break; case 2: - if (request_ != nil) + if (request_ != nil) { + WebThreadLock(); [webview_ loadRequest:request_]; + WebThreadUnlock(); + } break; default: @@ -638,7 +922,7 @@ UIActionSheet *sheet = [[[UIActionSheet alloc] initWithTitle:realm - buttons:[NSArray arrayWithObjects:@"Login", @"Cancel", nil] + buttons:[NSArray arrayWithObjects:CYLocalize("LOGIN"), CYLocalize("CANCEL"), nil] defaultButtonIndex:0 delegate:self context:@"challenge" @@ -646,8 +930,8 @@ [sheet setNumberOfRows:1]; - [sheet addTextFieldWithValue:@"" label:@"username"]; - [sheet addTextFieldWithValue:@"" label:@"password"]; + [sheet addTextFieldWithValue:@"" label:CYLocalize("USERNAME")]; + [sheet addTextFieldWithValue:@"" label:CYLocalize("PASSWORD")]; UITextField *username([sheet textFieldAtIndex:0]); { UITextInputTraits *traits([username textInputTraits]); @@ -676,21 +960,22 @@ - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request windowFeatures:(NSDictionary *)features { //- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request userGesture:(BOOL)gesture { -#if ForSaurik +#if LogBrowser NSLog(@"cwv:%@ (%@): %@", request, title_, features == nil ? @"{}" : [features description]); //NSLog(@"cwv:%@ (%@): %@", request, title_, gesture ? @"Yes" : @"No"); #endif NSNumber *value([features objectForKey:@"width"]); - float width(value == nil ? [BrowserView defaultWidth] : [value floatValue]); + float width(value == nil ? 0 : [value floatValue]); RVBook *book(!popup_ ? book_ : [[[RVPopUpBook alloc] initWithFrame:[delegate_ popUpBounds]] autorelease]); /* XXX: deal with cydia:// pages */ BrowserView *browser([[[BrowserView alloc] initWithBook:book forWidth:width] autorelease]); - if (features == nil && popup_) { + if (features != nil && popup_) { [book setDelegate:delegate_]; + [book setHook:indirect_]; [browser setDelegate:delegate_]; [browser loadRequest:request]; @@ -723,55 +1008,84 @@ } - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame { - if ([frame parentFrame] != nil) - return; + if ([loading_ count] == 0) + [self retain]; + [loading_ addObject:[NSValue valueWithNonretainedObject:frame]]; - reloading_ = false; - loading_ = true; - [self reloadButtons]; + if ([frame parentFrame] == nil) { + [webview_ resignFirstResponder]; - if (title_ != nil) { - [title_ release]; - title_ = nil; - } + reloading_ = false; - if (button_ != nil) { - [button_ release]; - button_ = nil; - } + if (title_ != nil) { + [title_ release]; + title_ = nil; + } - if (style_ != nil) { - [style_ release]; - style_ = nil; - } + if (button_ != nil) { + [button_ release]; + button_ = nil; + } - if (function_ != nil) { - [function_ release]; - function_ = nil; - } + if (style_ != nil) { + [style_ release]; + style_ = nil; + } - [book_ reloadTitleForPage:self]; + if (function_ != nil) { + [function_ release]; + function_ = nil; + } - [scroller_ scrollPointVisibleAtTopLeft:CGPointZero]; + if (finish_ != nil) { + [finish_ release]; + finish_ = nil; + } + + if (closer_ != nil) { + [closer_ release]; + closer_ = nil; + } - CGRect webrect = [scroller_ bounds]; - webrect.size.height = 0; - [webview_ setFrame:webrect]; + if (special_ != nil) { + [special_ release]; + special_ = nil; + } + + [book_ reloadTitleForPage:self]; + + [scroller_ scrollPointVisibleAtTopLeft:CGPointZero]; + + if ([scroller_ respondsToSelector:@selector(setZoomScale:duration:)]) + [scroller_ setZoomScale:1 duration:0]; + else + [scroller_ setZoomScale:1 animated:NO]; + + CGRect webrect = [scroller_ bounds]; + webrect.size.height = 0; + [webview_ setFrame:webrect]; + } + + [self reloadButtons]; } - (void) _finishLoading { - if (!reloading_) { - loading_ = false; - [self reloadButtons]; - } + size_t count([loading_ count]); + if (count == 0) + [self autorelease]; + if (reloading_ || count != 0) + return; + if (finish_ != nil) + [self callFunction:finish_]; + [self reloadButtons]; } -- (bool) _loading { - return loading_; +- (bool) isLoading { + return [loading_ count] != 0; } - (void) reloadButtons { - if ([self _loading]) + if ([self isLoading]) [indicator_ startAnimation]; else [indicator_ stopAnimation]; @@ -791,6 +1105,7 @@ } - (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame { + [self _pushPage]; return [webview_ webView:sender didCommitLoadForFrame:frame]; } @@ -799,9 +1114,10 @@ } - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame { - if ([frame parentFrame] == nil) { - [self _finishLoading]; + [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]]; + [self _finishLoading]; + if ([frame parentFrame] == nil) { if (DOMDocument *document = [frame DOMDocument]) if (DOMNodeList *bodies = [document getElementsByTagName:@"body"]) for (DOMHTMLBodyElement *body in bodies) { @@ -846,31 +1162,78 @@ return [webview_ webView:sender didFinishLoadForFrame:frame]; } -- (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { - if ([frame parentFrame] != nil) - return; +- (void) _didFailWithError:(NSError *)error forFrame:(WebFrame *)frame { + if ([frame parentFrame] == nil) + [self autorelease]; + + [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]]; + [self _finishLoading]; + if (reloading_) return; - [self _finishLoading]; - [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", - [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString], - [[error localizedDescription] stringByAddingPercentEscapes] - ]]]; + if ([frame parentFrame] == nil) { + [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@", + [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString], + [[error localizedDescription] stringByAddingPercentEscapes] + ]]]; + + error_ = true; + } +} + +- (void) webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { + [self _didFailWithError:error forFrame:frame]; +} - error_ = true; +- (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame { + [self _didFailWithError:error forFrame:frame]; } - (void) webView:(WebView *)sender addMessageToConsole:(NSDictionary *)dictionary { -#if ForSaurik +#if LogBrowser || ForSaurik lprintf("Console:%s\n", [[dictionary description] UTF8String]); #endif } +/* XXX: fix this stupid include file +- (void) webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(WebSecurityOrigin *)origin database:(NSString *)database { + [origin setQuota:0x500000]; +}*/ + +- (void) _setTileDrawingEnabled:(BOOL)enabled { + //[webview_ setTileDrawingEnabled:enabled]; +} + +- (void) setViewportWidth:(float)width { + width_ = width ? width != 0 : [[self class] defaultWidth]; + [webview_ setViewportSize:CGSizeMake(width_, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10]; +} + +- (void) willStartGesturesInView:(UIView *)view forEvent:(GSEventRef)event { + [self _setTileDrawingEnabled:NO]; +} + +- (void) didFinishGesturesInView:(UIView *)view forEvent:(GSEventRef)event { + [self _setTileDrawingEnabled:YES]; + [webview_ redrawScaledDocument]; +} + +- (void) scrollerWillStartDragging:(UIScroller *)scroller { + [self _setTileDrawingEnabled:NO]; +} + +- (void) scrollerDidEndDragging:(UIScroller *)scroller willSmoothScroll:(BOOL)smooth { + [self _setTileDrawingEnabled:YES]; +} + +- (void) scrollerDidEndDragging:(UIScroller *)scroller { + [self _setTileDrawingEnabled:YES]; +} + - (id) initWithBook:(RVBook *)book forWidth:(float)width { if ((self = [super initWithBook:book]) != nil) { - loading_ = false; - width_ = width; + loading_ = [[NSMutableSet alloc] initWithCapacity:3]; popup_ = false; struct CGRect bounds = [self bounds]; @@ -878,22 +1241,31 @@ scroller_ = [[UIScroller alloc] initWithFrame:bounds]; [self addSubview:scroller_]; - [scroller_ setShowBackgroundShadow:NO]; [scroller_ setFixedBackgroundPattern:YES]; [scroller_ setBackgroundColor:[UIColor pinStripeColor]]; [scroller_ setScrollingEnabled:YES]; - [scroller_ setAdjustForContentSizeChange:YES]; [scroller_ setClipsSubviews:YES]; [scroller_ setAllowsRubberBanding:YES]; - [scroller_ setScrollDecelerationFactor:0.99]; + [scroller_ setDelegate:self]; + [scroller_ setBounces:YES]; + [scroller_ setScrollHysteresis:8]; + [scroller_ setThumbDetectionEnabled:NO]; + [scroller_ setDirectionalScrolling:YES]; + [scroller_ setScrollDecelerationFactor:0.99]; /* 0.989324 */ + [scroller_ setEventMode:YES]; + [scroller_ setShowBackgroundShadow:NO]; /* YES */ + [scroller_ setAllowsRubberBanding:YES]; /* Vertical */ + [scroller_ setAdjustForContentSizeChange:YES]; /* NO */ CGRect webrect = [scroller_ bounds]; webrect.size.height = 0; WebView *webview; + WebThreadLock(); + #if RecycleWebViews webview_ = [Documents_ lastObject]; if (webview_ != nil) { @@ -920,7 +1292,11 @@ [webview_ setDrawsGrid:NO]; [webview_ setLogsTilingChanges:NO]; [webview_ setTileMinificationFilter:kCAFilterNearest]; - [webview_ setDetectsPhoneNumbers:NO]; + if ([webview_ respondsToSelector:@selector(setDataDetectorTypes:)]) + /* XXX: abstractify */ + [webview_ setDataDetectorTypes:0x80000000]; + else + [webview_ setDetectsPhoneNumbers:NO]; [webview_ setAutoresizes:YES]; [webview_ setMinimumScale:0.25f forDocumentTypes:0x10]; @@ -936,7 +1312,8 @@ [webview_ _setDocumentType:0x4]; - [webview_ setZoomsFocusedFormControl:YES]; + if ([webview_ respondsToSelector:@selector(UIWebDocumentView:)]) + [webview_ setZoomsFocusedFormControl:YES]; [webview_ setContentsPosition:7]; [webview_ setEnabledGestures:0xa]; [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeIsZoomRubberBandEnabled]; @@ -947,21 +1324,21 @@ [webview _setUsesLoaderCache:YES]; [webview setGroupName:@"CydiaGroup"]; - [webview _setLayoutInterval:0]; + if ([webview respondsToSelector:@selector(_setLayoutInterval:)]) + [webview _setLayoutInterval:0]; } - [webview_ setViewportSize:CGSizeMake(width_, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10]; + [self setViewportWidth:width]; [webview_ setDelegate:self]; [webview_ setGestureDelegate:self]; + [webview_ setFormEditingDelegate:self]; + [webview_ setInteractionDelegate:self]; + [scroller_ addSubview:webview_]; //NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; - CGSize indsize = [UIProgressIndicator defaultSizeForStyle:UIProgressIndicatorStyleMediumWhite]; - indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 12, indsize.width, indsize.height)]; - [indicator_ setStyle:UIProgressIndicatorStyleMediumWhite]; - Package *package([[Database sharedInstance] packageWithName:@"cydia"]); NSString *application = package == nil ? @"Cydia" : [NSString stringWithFormat:@"Cydia/%@", @@ -975,71 +1352,98 @@ if (Safari_ != nil) application = [NSString stringWithFormat:@"%@ Safari/%@", application, Safari_]; - /* XXX: lookup application directory? */ - /*if (NSDictionary *safari = [NSDictionary dictionaryWithContentsOfFile:@"/Applications/MobileSafari.app/Info.plist"]) - if (NSString *version = [safari objectForKey:@"SafariProductVersion"]) - application = [NSString stringWithFormat:@"Version/%@ %@", version, application];*/ - [webview setApplicationNameForUserAgent:application]; indirect_ = [[IndirectDelegate alloc] initWithDelegate:self]; cydia_ = [[CydiaObject alloc] initWithDelegate:indirect_]; - [webview setFrameLoadDelegate:self]; + [webview setFrameLoadDelegate:indirect_]; [webview setResourceLoadDelegate:indirect_]; - [webview setUIDelegate:self]; - [webview setScriptDebugDelegate:self]; - [webview setPolicyDelegate:self]; + [webview setUIDelegate:indirect_]; + [webview setScriptDebugDelegate:indirect_]; + [webview setPolicyDelegate:indirect_]; + + WebThreadUnlock(); + + CGSize indsize = [UIProgressIndicator defaultSizeForStyle:UIProgressIndicatorStyleMediumWhite]; + indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 12, indsize.width, indsize.height)]; + [indicator_ setStyle:UIProgressIndicatorStyleMediumWhite]; [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight]; [scroller_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight]; + + /*UIWebView *test([[[UIWebView alloc] initWithFrame:[self bounds]] autorelease]); + [test loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.saurik.com/"]]]; + [self addSubview:test];*/ } return self; } - (id) initWithBook:(RVBook *)book { - return [self initWithBook:book forWidth:[[self class] defaultWidth]]; + return [self initWithBook:book forWidth:0]; } -- (void) didFinishGesturesInView:(UIView *)view forEvent:(id)event { - [webview_ redrawScaledDocument]; +- (NSString *) stringByEvaluatingJavaScriptFromString:(NSString *)script { + WebThreadLock(); + WebView *webview([webview_ webView]); + NSString *string([webview stringByEvaluatingJavaScriptFromString:script]); + WebThreadUnlock(); + return string; } -- (void) _rightButtonClicked { - if (function_ == nil) { - reloading_ = true; - [self reloadURL]; - } else { - WebView *webview([webview_ webView]); - WebFrame *frame([webview mainFrame]); - - id _private(MSHookIvar(webview, "_private")); - WebCore::Page *page(_private == nil ? NULL : MSHookIvar(_private, "page")); - WebCore::Settings *settings(page == NULL ? NULL : page->settings()); - - bool no; - if (settings == NULL) - no = 0; - else { - no = settings->JavaScriptCanOpenWindowsAutomatically(); - settings->setJavaScriptCanOpenWindowsAutomatically(true); - } +- (void) callFunction:(WebScriptObject *)function { + WebThreadLock(); + + WebView *webview([webview_ webView]); + WebFrame *frame([webview mainFrame]); - [delegate_ clearFirstResponder]; - JSObjectRef function([function_ JSObject]); - JSGlobalContextRef context([frame globalContext]); - JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL); + id _private(MSHookIvar(webview, "_private")); + WebCore::Page *page(_private == nil ? NULL : MSHookIvar(_private, "page")); + WebCore::Settings *settings(page == NULL ? NULL : page->settings()); - if (settings != NULL) - settings->setJavaScriptCanOpenWindowsAutomatically(no); + bool no; + if (settings == NULL) + no = 0; + else { + no = settings->JavaScriptCanOpenWindowsAutomatically(); + settings->setJavaScriptCanOpenWindowsAutomatically(true); } + + [delegate_ clearFirstResponder]; + JSObjectRef object([function JSObject]); + JSGlobalContextRef context([frame globalContext]); + JSObjectCallAsFunction(context, object, NULL, 0, NULL, NULL); + + if (settings != NULL) + settings->setJavaScriptCanOpenWindowsAutomatically(no); + + WebThreadUnlock(); +} + +- (void) didCloseBook:(RVBook *)book { + if (closer_ != nil) + [self callFunction:closer_]; +} + +- (void) __rightButtonClicked { + reloading_ = true; + [self reloadURL]; +} + +- (void) _rightButtonClicked { +#if !AlwaysReload + if (function_ != nil) + [self callFunction:function_]; + else +#endif + [self __rightButtonClicked]; } - (id) _rightButtonTitle { - return button_ != nil ? button_ : @"Reload"; + return CYLocalize("RELOAD"); } - (id) rightButtonTitle { - return [self _loading] ? @"" : [self _rightButtonTitle]; + return [self isLoading] ? @"" : button_ != nil ? button_ : [self _rightButtonTitle]; } - (UINavigationButtonStyle) rightButtonStyle { @@ -1057,11 +1461,11 @@ } - (NSString *) title { - return title_ == nil ? @"Loading" : title_; + return title_ == nil ? CYLocalize("LOADING") : title_; } - (NSString *) backButtonTitle { - return @"Browser"; + return CYLocalize("BROWSER"); } - (void) setPageActive:(BOOL)active {