1 #include <UICaboodle/BrowserView.h>
2 #include <UICaboodle/UCLocalize.h>
4 #import <QuartzCore/CALayer.h>
5 // XXX: fix the minimum requirement
6 extern NSString * const kCAFilterNearest;
8 #include <WebCore/WebCoreThread.h>
10 #include "substrate.h"
12 @interface NSString (UIKit)
13 - (NSString *) stringByAddingPercentEscapes;
16 /* Indirect Delegate {{{ */
17 @interface IndirectDelegate : NSObject {
18 _transient volatile id delegate_;
21 - (void) setDelegate:(id)delegate;
22 - (id) initWithDelegate:(id)delegate;
25 @implementation IndirectDelegate
27 - (void) setDelegate:(id)delegate {
31 - (id) initWithDelegate:(id)delegate {
36 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
38 return [delegate_ webView:sender didClearWindowObject:window forFrame:frame];
41 - (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
43 return [delegate_ webView:sender didCommitLoadForFrame:frame];
46 - (void) webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
48 return [delegate_ webView:sender didFailLoadWithError:error forFrame:frame];
51 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
53 return [delegate_ webView:sender didFailProvisionalLoadWithError:error forFrame:frame];
56 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
58 return [delegate_ webView:sender didFinishLoadForFrame:frame];
61 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
63 return [delegate_ webView:sender didReceiveTitle:title forFrame:frame];
66 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
68 return [delegate_ webView:sender didStartProvisionalLoadForFrame:frame];
71 - (void) webView:(WebView *)sender resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)source {
73 return [delegate_ webView:sender resource:identifier didReceiveAuthenticationChallenge:challenge fromDataSource:source];
76 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)source {
78 return [delegate_ webView:sender resource:identifier willSendRequest:request redirectResponse:redirectResponse fromDataSource:source];
82 - (IMP) methodForSelector:(SEL)sel {
83 if (IMP method = [super methodForSelector:sel])
85 fprintf(stderr, "methodForSelector:[%s] == NULL\n", sel_getName(sel));
89 - (BOOL) respondsToSelector:(SEL)sel {
90 if ([super respondsToSelector:sel])
92 // XXX: WebThreadCreateNSInvocation returns nil
93 //fprintf(stderr, "[%s]R?%s\n", class_getName(self->isa), sel_getName(sel));
94 return delegate_ == nil ? NO : [delegate_ respondsToSelector:sel];
97 - (NSMethodSignature *) methodSignatureForSelector:(SEL)sel {
98 if (NSMethodSignature *method = [super methodSignatureForSelector:sel])
100 //fprintf(stderr, "[%s]S?%s\n", class_getName(self->isa), sel_getName(sel));
101 if (delegate_ != nil)
102 if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel])
104 // XXX: I fucking hate Apple so very very bad
105 return [NSMethodSignature signatureWithObjCTypes:"v@:"];
108 - (void) forwardInvocation:(NSInvocation *)inv {
109 SEL sel = [inv selector];
110 if (delegate_ != nil && [delegate_ respondsToSelector:sel])
111 [inv invokeWithTarget:delegate_];
117 @interface WebView (UICaboodle)
118 - (void) setScriptDebugDelegate:(id)delegate;
119 - (void) _setFormDelegate:(id)delegate;
120 - (void) _setUIKitDelegate:(id)delegate;
121 - (void) setWebMailDelegate:(id)delegate;
122 - (void) _setLayoutInterval:(float)interval;
125 @implementation WebScriptObject (UICaboodle)
128 id length([self valueForKey:@"length"]);
129 if ([length respondsToSelector:@selector(intValue)])
130 return [length intValue];
135 - (id) objectAtIndex:(unsigned)index {
136 return [self webScriptValueAtIndex:index];
142 /* Mail Composition {{{ */
143 @interface MailToView : PopUpView {
144 MailComposeController *controller_;
147 - (id) initWithView:(UIView *)view delegate:(id)delegate url:(NSURL *)url;
151 @implementation MailToView
154 [controller_ release];
158 - (void) mailComposeControllerWillAttemptToSend:(MailComposeController *)controller {
162 - (void) mailComposeControllerDidAttemptToSend:(MailComposeController *)controller mailDelivery:(id)delivery {
163 NSLog(@"did:%@", delivery);
164 // [UIApp setStatusBarShowsProgress:NO];
165 if ([controller error]){
166 NSArray *buttons = [NSArray arrayWithObjects:UCLocalize("OK"), nil];
167 UIActionSheet *mailAlertSheet = [[UIActionSheet alloc] initWithTitle:UCLocalize("ERROR") buttons:buttons defaultButtonIndex:0 delegate:self context:self];
168 [mailAlertSheet setBodyText:[controller error]];
169 [mailAlertSheet popupAlertAnimated:YES];
174 NSLog(@"%@", [controller_ error]);
175 NSArray *buttons = [NSArray arrayWithObjects:UCLocalize("OK"), nil];
176 UIActionSheet *mailAlertSheet = [[UIActionSheet alloc] initWithTitle:UCLocalize("ERROR") buttons:buttons defaultButtonIndex:0 delegate:self context:self];
177 [mailAlertSheet setBodyText:[controller_ error]];
178 [mailAlertSheet popupAlertAnimated:YES];
181 - (void) deliverMessage { _pooled
185 if (![controller_ deliverMessage])
186 [self performSelectorOnMainThread:@selector(showError) withObject:nil waitUntilDone:NO];
189 - (void) mailComposeControllerCompositionFinished:(MailComposeController *)controller {
190 if ([controller_ needsDelivery])
191 [NSThread detachNewThreadSelector:@selector(deliverMessage) toTarget:self withObject:nil];
196 - (id) initWithView:(UIView *)view delegate:(id)delegate url:(NSURL *)url {
197 if ((self = [super initWithView:view delegate:delegate]) != nil) {
198 controller_ = [[MailComposeController alloc] initForContentSize:[overlay_ bounds].size];
199 [controller_ setDelegate:self];
200 [controller_ initializeUI];
201 [controller_ setupForURL:url];
203 UIView *view([controller_ view]);
204 [overlay_ addSubview:view];
212 @implementation BrowserView
215 #include "Internals.h"
220 NSLog(@"[BrowserView dealloc]");
223 if (challenge_ != nil)
224 [challenge_ release];
228 WebView *webview = [webview_ webView];
229 [webview setFrameLoadDelegate:nil];
230 [webview setResourceLoadDelegate:nil];
231 [webview setUIDelegate:nil];
232 [webview setScriptDebugDelegate:nil];
233 [webview setPolicyDelegate:nil];
235 [webview setDownloadDelegate:nil];
237 /* XXX: these are set by UIWebDocumentView
238 [webview _setFormDelegate:nil];
239 [webview _setUIKitDelegate:nil];
240 [webview setEditingDelegate:nil];*/
242 /* XXX: no one sets this, ever
243 [webview setWebMailDelegate:nil];*/
245 [webview_ setDelegate:nil];
246 [webview_ setGestureDelegate:nil];
247 [webview_ setFormEditingDelegate:nil];
248 [webview_ setInteractionDelegate:nil];
250 [indirect_ setDelegate:nil];
252 //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
257 [webview_ removeFromSuperview];
258 [Documents_ addObject:[webview_ autorelease]];
267 [scroller_ setDelegate:nil];
273 if (function_ != nil)
283 [indicator_ release];
286 if (sensitive_ != nil)
287 [sensitive_ release];
293 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
294 [self loadRequest:[NSURLRequest
301 - (void) loadURL:(NSURL *)url {
302 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
305 - (void) loadRequest:(NSURLRequest *)request {
310 [webview_ loadRequest:request];
318 if ([request_ HTTPBody] == nil && [request_ HTTPBodyStream] == nil)
319 [self loadRequest:request_];
321 UIActionSheet *sheet = [[[UIActionSheet alloc]
322 initWithTitle:UCLocalize("RESUBMIT_FORM")
323 buttons:[NSArray arrayWithObjects:UCLocalize("CANCEL"), UCLocalize("SUBMIT"), nil]
329 [sheet setNumberOfRows:1];
330 [sheet popupAlertAnimated:YES];
334 - (WebView *) webView {
335 return [webview_ webView];
338 - (UIWebDocumentView *) documentView {
342 /* XXX: WebThreadLock? */
343 - (void) _fixScroller:(CGRect)bounds {
348 UIFormAssistant *assistant([UIFormAssistant sharedFormAssistant]);
349 CGRect peripheral([assistant peripheralFrame]);
351 NSLog(@"per:%f", peripheral.size.height);
353 extra = peripheral.size.height;
356 CGRect subrect([scroller_ frame]);
357 subrect.size.height -= extra;
358 [scroller_ setScrollerIndicatorSubrect:subrect];
360 NSSize visible(NSMakeSize(subrect.size.width, subrect.size.height));
361 [webview_ setValue:[NSValue valueWithSize:visible] forGestureAttribute:UIGestureAttributeVisibleSize];
364 size.height += extra;
365 [scroller_ setContentSize:size];
367 [scroller_ releaseRubberBandIfNecessary];
370 - (void) fixScroller {
371 CGRect bounds([webview_ documentBounds]);
373 NSLog(@"_fs:(%f,%f+%f,%f)", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
375 [self _fixScroller:bounds];
378 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
381 NSLog(@"dsf:(%f,%f+%f,%f)", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
383 [self _fixScroller:frame];
386 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
387 [self view:sender didSetFrame:frame];
390 - (void) pushPage:(RVPage *)page {
391 [page setDelegate:delegate_];
392 [self setBackButtonTitle:title_];
393 [book_ pushPage:page];
399 // WTR: [self autorelease];
401 [book_ pushPage:self];
404 - (void) swapPage:(RVPage *)page {
405 [page setDelegate:delegate_];
407 [book_ swapPage:page];
409 [book_ pushPage:page];
412 - (BOOL) getSpecial:(NSURL *)url swap:(BOOL)swap {
414 NSLog(@"getSpecial:%@", url);
417 if (RVPage *page = [delegate_ pageForURL:url hasTag:NULL]) {
419 [self swapPage:page];
421 [self pushPage:page];
428 - (void) webViewShow:(WebView *)sender {
429 /* XXX: this is where I cry myself to sleep */
432 - (bool) _allowJavaScriptPanel {
436 - (bool) allowSensitiveRequests {
437 return [self _allowJavaScriptPanel];
440 - (void) _promptForSensitive:(NSMutableArray *)array {
441 NSString *name([array objectAtIndex:0]);
443 UIActionSheet *sheet = [[[UIActionSheet alloc]
445 buttons:[NSArray arrayWithObjects:UCLocalize("YES"), UCLocalize("NO"), nil]
451 NSString *host(@"XXX");
453 [sheet setNumberOfRows:1];
454 [sheet setBodyText:[NSString stringWithFormat:@"The website at %@ is requesting your phone's %@. This is almost certainly for product licensing purposes. Will you allow this?", host, name]];
455 [sheet popupAlertAnimated:YES];
457 NSRunLoop *loop([NSRunLoop currentRunLoop]);
458 NSDate *future([NSDate distantFuture]);
460 while (sensitive_ == nil && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
462 NSNumber *sensitive([sensitive_ autorelease]);
466 [array replaceObjectAtIndex:0 withObject:sensitive];
469 - (bool) promptForSensitive:(NSString *)name {
470 if (![self allowSensitiveRequests])
473 NSMutableArray *array([NSMutableArray arrayWithCapacity:1]);
474 [array addObject:name];
476 [self performSelectorOnMainThread:@selector(_promptForSensitive:) withObject:array waitUntilDone:YES];
477 return [[array lastObject] boolValue];
480 - (void) webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
481 if (![self _allowJavaScriptPanel])
485 UIActionSheet *sheet = [[[UIActionSheet alloc]
487 buttons:[NSArray arrayWithObjects:UCLocalize("OK"), nil]
493 [sheet setBodyText:message];
494 [sheet popupAlertAnimated:YES];
497 - (BOOL) webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
498 if (![self _allowJavaScriptPanel])
502 UIActionSheet *sheet = [[[UIActionSheet alloc]
504 buttons:[NSArray arrayWithObjects:UCLocalize("OK"), UCLocalize("CANCEL"), nil]
510 [sheet setNumberOfRows:1];
511 [sheet setBodyText:message];
512 [sheet popupAlertAnimated:YES];
514 NSRunLoop *loop([NSRunLoop currentRunLoop]);
515 NSDate *future([NSDate distantFuture]);
517 while (confirm_ == nil && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
519 NSNumber *confirm([confirm_ autorelease]);
523 return [confirm boolValue];
526 - (void) setAutoPopup:(BOOL)popup {
530 - (void) setSpecial:(id)function {
532 [special_ autorelease];
533 special_ = function == nil ? nil : [function retain];
536 - (void) setButtonImage:(NSString *)button withStyle:(NSString *)style toFunction:(id)function {
538 [button_ autorelease];
539 button_ = button == nil ? nil : [[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:button]]] retain];
542 [style_ autorelease];
543 style_ = style == nil ? nil : [style retain];
545 if (function_ != nil)
546 [function_ autorelease];
547 function_ = function == nil ? nil : [function retain];
549 [self reloadButtons];
552 - (void) setButtonTitle:(NSString *)button withStyle:(NSString *)style toFunction:(id)function {
554 [button_ autorelease];
555 button_ = button == nil ? nil : [button retain];
558 [style_ autorelease];
559 style_ = style == nil ? nil : [style retain];
561 if (function_ != nil)
562 [function_ autorelease];
563 function_ = function == nil ? nil : [function retain];
565 [self reloadButtons];
568 - (void) setFinishHook:(id)function {
570 [finish_ autorelease];
571 finish_ = function == nil ? nil : [function retain];
574 - (void) setPopupHook:(id)function {
576 [closer_ autorelease];
577 closer_ = function == nil ? nil : [function retain];
580 - (void) _openMailToURL:(NSURL *)url {
581 // XXX: this makes me sad
583 [[[MailToView alloc] initWithView:underlay_ delegate:self url:url] autorelease];
585 [UIApp openURL:url];// asPanel:YES];
589 - (void) webView:(WebView *)sender willBeginEditingFormElement:(id)element {
593 - (void) webView:(WebView *)sender didBeginEditingFormElement:(id)element {
597 - (void) webViewDidEndEditingFormElements:(WebView *)sender {
602 - (void) webViewClose:(WebView *)sender {
610 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
613 - (void) webView:(WebView *)sender unableToImplementPolicyWithError:(NSError *)error frame:(WebFrame *)frame {
614 NSLog(@"err:%@", error);
617 - (void) webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)name decisionListener:(id<WebPolicyDecisionListener>)listener {
619 NSLog(@"nwa:%@", name);
622 if (NSURL *url = [request URL]) {
623 if (name == nil) unknown: {
624 if (![self getSpecial:url swap:NO]) {
625 NSString *scheme([[url scheme] lowercaseString]);
626 if ([scheme isEqualToString:@"mailto"])
627 [self _openMailToURL:url];
630 } else if ([name isEqualToString:@"_open"])
631 [delegate_ openURL:url];
632 else if ([name isEqualToString:@"_popup"]) {
633 NSString *scheme([[url scheme] lowercaseString]);
634 if ([scheme isEqualToString:@"mailto"])
635 [self _openMailToURL:url];
637 RVBook *book([[[RVPopUpBook alloc] initWithFrame:[delegate_ popUpBounds]] autorelease]);
638 [book setHook:indirect_];
640 RVPage *page([delegate_ pageForURL:url hasTag:NULL]);
642 /* XXX: call createWebViewWithRequest instead? */
644 [self setBackButtonTitle:title_];
646 BrowserView *browser([[[BrowserView alloc] initWithBook:book] autorelease]);
647 [browser loadURL:url];
651 [book setDelegate:delegate_];
652 [page setDelegate:delegate_];
655 [book_ pushBook:book];
664 - (void) webView:(WebView *)sender decidePolicyForMIMEType:(NSString *)type request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
665 if ([WebView canShowMIMEType:type])
668 // XXX: handle more mime types!
671 WebView *webview([webview_ webView]);
672 if (frame == [webview mainFrame])
673 [UIApp openURL:[request URL]];
677 - (void) webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
678 if (request == nil) ignore: {
683 NSURL *url([request URL]);
685 if (url == nil) use: {
686 if (!error_ && [frame parentFrame] == nil) {
688 [request_ autorelease];
689 request_ = [request retain];
691 NSLog(@"dpn:%@", request_);
697 WebView *webview([webview_ webView]);
698 if (frame == [webview mainFrame])
703 else NSLog(@"nav:%@:%@", url, [action description]);
706 const NSArray *capability;
708 #if 0 // XXX:3:GSSystemCopyCapability
709 capability = reinterpret_cast<const NSArray *>(GSSystemGetCapability(kGSDisplayIdentifiersCapability));
714 if (capability != nil && (
715 [capability containsObject:@"com.apple.Maps"] && [url mapsURL] ||
716 [capability containsObject:@"com.apple.youtube"] && [url youTubeURL]
723 int store(_not(int));
724 if (NSURL *itms = [url itmsURL:&store]) {
726 NSLog(@"itms#%@#%u#%@", url, store, itms);
729 if (capability != nil && (
730 store == 1 && [capability containsObject:@"com.apple.MobileStore"] ||
731 store == 2 && [capability containsObject:@"com.apple.AppStore"]
738 NSString *scheme([[url scheme] lowercaseString]);
740 if ([scheme isEqualToString:@"tel"]) {
745 if ([scheme isEqualToString:@"mailto"]) {
746 [self _openMailToURL:url];
750 if ([self getSpecial:url swap:YES])
752 else if ([WebView _canHandleRequest:request])
754 else if ([url isSpringboardHandledURL])
760 - (void) webView:(WebView *)sender setStatusText:(NSString *)text {
761 //lprintf("Status:%s\n", [text UTF8String]);
764 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
765 NSString *context([sheet context]);
767 if ([context isEqualToString:@"alert"]) {
770 } else if ([context isEqualToString:@"confirm"]) {
773 confirm_ = [NSNumber numberWithBool:YES];
777 confirm_ = [NSNumber numberWithBool:NO];
782 } else if ([context isEqualToString:@"sensitive"]) {
785 sensitive_ = [NSNumber numberWithBool:YES];
789 sensitive_ = [NSNumber numberWithBool:NO];
794 } else if ([context isEqualToString:@"challenge"]) {
795 id<NSURLAuthenticationChallengeSender> sender([challenge_ sender]);
799 NSString *username([[sheet textFieldAtIndex:0] text]);
800 NSString *password([[sheet textFieldAtIndex:1] text]);
802 NSURLCredential *credential([NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistenceForSession]);
804 [sender useCredential:credential forAuthenticationChallenge:challenge_];
808 [sender cancelAuthenticationChallenge:challenge_];
815 [challenge_ release];
819 } else if ([context isEqualToString:@"submit"]) {
825 if (request_ != nil) {
827 [webview_ loadRequest:request_];
840 - (void) webView:(WebView *)sender resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)source {
841 challenge_ = [challenge retain];
843 NSURLProtectionSpace *space([challenge protectionSpace]);
844 NSString *realm([space realm]);
848 UIActionSheet *sheet = [[[UIActionSheet alloc]
850 buttons:[NSArray arrayWithObjects:UCLocalize("LOGIN"), UCLocalize("CANCEL"), nil]
856 [sheet setNumberOfRows:1];
858 [sheet addTextFieldWithValue:@"" label:UCLocalize("USERNAME")];
859 [sheet addTextFieldWithValue:@"" label:UCLocalize("PASSWORD")];
861 UITextField *username([sheet textFieldAtIndex:0]); {
862 UITextInputTraits *traits([username textInputTraits]);
863 [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone];
864 [traits setAutocorrectionType:UITextAutocorrectionTypeNo];
865 [traits setKeyboardType:UIKeyboardTypeASCIICapable];
866 [traits setReturnKeyType:UIReturnKeyNext];
869 UITextField *password([sheet textFieldAtIndex:1]); {
870 UITextInputTraits *traits([password textInputTraits]);
871 [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone];
872 [traits setAutocorrectionType:UITextAutocorrectionTypeNo];
873 [traits setKeyboardType:UIKeyboardTypeASCIICapable];
874 // XXX: UIReturnKeyDone
875 [traits setReturnKeyType:UIReturnKeyNext];
876 [traits setSecureTextEntry:YES];
879 [sheet popupAlertAnimated:YES];
882 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)source {
886 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request windowFeatures:(NSDictionary *)features {
887 //- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request userGesture:(BOOL)gesture {
889 NSLog(@"cwv:%@ (%@): %@", request, title_, features == nil ? @"{}" : [features description]);
890 //NSLog(@"cwv:%@ (%@): %@", request, title_, gesture ? @"Yes" : @"No");
893 NSNumber *value([features objectForKey:@"width"]);
894 float width(value == nil ? 0 : [value floatValue]);
896 RVBook *book(!popup_ ? book_ : [[[RVPopUpBook alloc] initWithFrame:[delegate_ popUpBounds]] autorelease]);
898 /* XXX: deal with cydia:// pages */
899 BrowserView *browser([[[BrowserView alloc] initWithBook:book forWidth:width] autorelease]);
901 if (features != nil && popup_) {
902 [book setDelegate:delegate_];
903 [book setHook:indirect_];
904 [browser setDelegate:delegate_];
906 [browser loadRequest:request];
908 [book setPage:browser];
909 [book_ pushBook:book];
910 } else if (request == nil) {
911 [self setBackButtonTitle:title_];
912 [browser setDelegate:delegate_];
915 [self pushPage:browser];
916 [browser loadRequest:request];
919 return [browser webView];
922 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
923 return [self webView:sender createWebViewWithRequest:request windowFeatures:nil];
924 //return [self webView:sender createWebViewWithRequest:request userGesture:YES];
927 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
928 if ([frame parentFrame] != nil)
931 title_ = [title retain];
932 [book_ reloadTitleForPage:self];
935 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
936 if ([loading_ count] == 0)
938 [loading_ addObject:[NSValue valueWithNonretainedObject:frame]];
940 if ([frame parentFrame] == nil) {
941 [webview_ resignFirstResponder];
950 if (button_ != nil) {
960 if (function_ != nil) {
965 if (finish_ != nil) {
970 if (closer_ != nil) {
975 if (special_ != nil) {
980 [book_ reloadTitleForPage:self];
982 [scroller_ scrollPointVisibleAtTopLeft:CGPointZero];
984 if ([scroller_ respondsToSelector:@selector(setZoomScale:duration:)])
985 [scroller_ setZoomScale:1 duration:0];
986 else if ([scroller_ respondsToSelector:@selector(_setZoomScale:duration:)])
987 [scroller_ _setZoomScale:1 duration:0];
988 /*else if ([scroller_ respondsToSelector:@selector(setZoomScale:animated:)])
989 [scroller_ setZoomScale:1 animated:NO];*/
991 CGRect webrect = [scroller_ bounds];
992 webrect.size.height = 0;
993 [webview_ setFrame:webrect];
996 [self reloadButtons];
999 - (void) _finishLoading {
1000 size_t count([loading_ count]);
1003 if (reloading_ || count != 0)
1006 [self callFunction:finish_];
1007 [self reloadButtons];
1010 - (bool) isLoading {
1011 return [loading_ count] != 0;
1014 - (void) reloadButtons {
1015 if ([self isLoading])
1016 [indicator_ startAnimation];
1018 [indicator_ stopAnimation];
1019 [super reloadButtons];
1022 - (BOOL) webView:(WebView *)sender shouldScrollToPoint:(struct CGPoint)point forFrame:(WebFrame *)frame {
1023 return [webview_ webView:sender shouldScrollToPoint:point forFrame:frame];
1026 - (void) webView:(WebView *)sender didReceiveViewportArguments:(id)arguments forFrame:(WebFrame *)frame {
1027 return [webview_ webView:sender didReceiveViewportArguments:arguments forFrame:frame];
1030 - (void) webView:(WebView *)sender needsScrollNotifications:(id)notifications forFrame:(WebFrame *)frame {
1031 return [webview_ webView:sender needsScrollNotifications:notifications forFrame:frame];
1034 - (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
1036 return [webview_ webView:sender didCommitLoadForFrame:frame];
1039 - (void) webView:(WebView *)sender didReceiveDocTypeForFrame:(WebFrame *)frame {
1040 return [webview_ webView:sender didReceiveDocTypeForFrame:frame];
1043 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
1044 [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
1045 [self _finishLoading];
1047 if ([frame parentFrame] == nil) {
1048 if (DOMDocument *document = [frame DOMDocument])
1049 if (DOMNodeList<NSFastEnumeration> *bodies = [document getElementsByTagName:@"body"])
1050 for (DOMHTMLBodyElement *body in bodies) {
1051 DOMCSSStyleDeclaration *style([document getComputedStyle:body pseudoElement:nil]);
1053 bool colored(false);
1055 if (DOMCSSPrimitiveValue *color = static_cast<DOMCSSPrimitiveValue *>([style getPropertyCSSValue:@"background-color"])) {
1056 if ([color primitiveType] == DOM_CSS_RGBCOLOR) {
1057 DOMRGBColor *rgb([color getRGBColorValue]);
1059 float red([[rgb red] getFloatValue:DOM_CSS_NUMBER]);
1060 float green([[rgb green] getFloatValue:DOM_CSS_NUMBER]);
1061 float blue([[rgb blue] getFloatValue:DOM_CSS_NUMBER]);
1062 float alpha([[rgb alpha] getFloatValue:DOM_CSS_NUMBER]);
1066 if (red == 0xc7 && green == 0xce && blue == 0xd5)
1067 uic = [UIColor pinStripeColor];
1068 else if (alpha != 0)
1070 colorWithRed:(red / 255)
1078 [scroller_ setBackgroundColor:uic];
1084 [scroller_ setBackgroundColor:[UIColor pinStripeColor]];
1089 return [webview_ webView:sender didFinishLoadForFrame:frame];
1092 - (void) _didFailWithError:(NSError *)error forFrame:(WebFrame *)frame {
1093 if ([frame parentFrame] == nil)
1096 [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
1097 [self _finishLoading];
1102 if ([frame parentFrame] == nil) {
1103 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
1104 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
1105 [[error localizedDescription] stringByAddingPercentEscapes]
1112 - (void) webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
1113 [self _didFailWithError:error forFrame:frame];
1116 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
1117 [self _didFailWithError:error forFrame:frame];
1120 - (void) webView:(WebView *)sender addMessageToConsole:(NSDictionary *)dictionary {
1121 #if LogBrowser || ForSaurik
1122 lprintf("Console:%s\n", [[dictionary description] UTF8String]);
1126 /* XXX: fix this stupid include file
1127 - (void) webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(WebSecurityOrigin *)origin database:(NSString *)database {
1128 [origin setQuota:0x500000];
1131 - (void) _setTileDrawingEnabled:(BOOL)enabled {
1132 //[webview_ setTileDrawingEnabled:enabled];
1135 - (void) setViewportWidth:(float)width {
1136 width_ = width ? width != 0 : [[self class] defaultWidth];
1137 [webview_ setViewportSize:CGSizeMake(width_, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10];
1140 - (void) willStartGesturesInView:(UIView *)view forEvent:(GSEventRef)event {
1141 [self _setTileDrawingEnabled:NO];
1144 - (void) didFinishGesturesInView:(UIView *)view forEvent:(GSEventRef)event {
1145 [self _setTileDrawingEnabled:YES];
1146 [webview_ redrawScaledDocument];
1149 - (void) scrollerWillStartDragging:(UIScroller *)scroller {
1150 [self _setTileDrawingEnabled:NO];
1153 - (void) scrollerDidEndDragging:(UIScroller *)scroller willSmoothScroll:(BOOL)smooth {
1154 [self _setTileDrawingEnabled:YES];
1157 - (void) scrollerDidEndDragging:(UIScroller *)scroller {
1158 [self _setTileDrawingEnabled:YES];
1161 - (id) initWithBook:(RVBook *)book forWidth:(float)width {
1162 if ((self = [super initWithBook:book]) != nil) {
1163 loading_ = [[NSMutableSet alloc] initWithCapacity:3];
1166 struct CGRect bounds = [self bounds];
1168 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
1169 [self addSubview:scroller_];
1171 [scroller_ setFixedBackgroundPattern:YES];
1172 [scroller_ setBackgroundColor:[UIColor pinStripeColor]];
1174 [scroller_ setScrollingEnabled:YES];
1175 [scroller_ setClipsSubviews:YES];
1176 [scroller_ setAllowsRubberBanding:YES];
1178 [scroller_ setDelegate:self];
1179 [scroller_ setBounces:YES];
1180 [scroller_ setScrollHysteresis:8];
1181 [scroller_ setThumbDetectionEnabled:NO];
1182 [scroller_ setDirectionalScrolling:YES];
1183 [scroller_ setScrollDecelerationFactor:0.99]; /* 0.989324 */
1184 [scroller_ setEventMode:YES];
1185 [scroller_ setShowBackgroundShadow:NO]; /* YES */
1186 [scroller_ setAllowsRubberBanding:YES]; /* Vertical */
1187 [scroller_ setAdjustForContentSizeChange:YES]; /* NO */
1189 CGRect webrect = [scroller_ bounds];
1190 webrect.size.height = 0;
1197 webview_ = [Documents_ lastObject];
1198 if (webview_ != nil) {
1199 webview_ = [webview_ retain];
1200 webview = [webview_ webView];
1201 [Documents_ removeLastObject];
1202 [webview_ setFrame:webrect];
1207 webview_ = [[UIWebDocumentView alloc] initWithFrame:webrect];
1208 webview = [webview_ webView];
1210 // XXX: this is terribly (too?) expensive
1211 //[webview_ setDrawsBackground:NO];
1212 [webview setPreferencesIdentifier:@"Cydia"];
1214 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
1216 [webview_ setAllowsMessaging:YES];
1218 [webview_ setTilingEnabled:YES];
1219 [webview_ setDrawsGrid:NO];
1220 [webview_ setLogsTilingChanges:NO];
1221 [webview_ setTileMinificationFilter:kCAFilterNearest];
1222 if ([webview_ respondsToSelector:@selector(setDataDetectorTypes:)])
1223 /* XXX: abstractify */
1224 [webview_ setDataDetectorTypes:0x80000000];
1226 [webview_ setDetectsPhoneNumbers:NO];
1227 [webview_ setAutoresizes:YES];
1229 [webview_ setMinimumScale:0.25f forDocumentTypes:0x10];
1230 [webview_ setMaximumScale:5.00f forDocumentTypes:0x10];
1231 [webview_ setInitialScale:UIWebViewScalesToFitScale forDocumentTypes:0x10];
1232 //[webview_ setViewportSize:CGSizeMake(980, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10];
1234 [webview_ setViewportSize:CGSizeMake(320, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x2];
1236 [webview_ setMinimumScale:1.00f forDocumentTypes:0x8];
1237 [webview_ setInitialScale:UIWebViewScalesToFitScale forDocumentTypes:0x8];
1238 [webview_ setViewportSize:CGSizeMake(320, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x8];
1240 [webview_ _setDocumentType:0x4];
1242 if ([webview_ respondsToSelector:@selector(UIWebDocumentView:)])
1243 [webview_ setZoomsFocusedFormControl:YES];
1244 [webview_ setContentsPosition:7];
1245 [webview_ setEnabledGestures:0xa];
1246 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeIsZoomRubberBandEnabled];
1247 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeUpdatesScroller];
1249 [webview_ setSmoothsFonts:YES];
1250 [webview_ setAllowsImageSheet:YES];
1251 [webview _setUsesLoaderCache:YES];
1253 [webview setGroupName:@"CydiaGroup"];
1254 if ([webview respondsToSelector:@selector(_setLayoutInterval:)])
1255 [webview _setLayoutInterval:0];
1258 [self setViewportWidth:width];
1260 [webview_ setDelegate:self];
1261 [webview_ setGestureDelegate:self];
1262 [webview_ setFormEditingDelegate:self];
1263 [webview_ setInteractionDelegate:self];
1265 [scroller_ addSubview:webview_];
1267 //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
1269 indirect_ = [[IndirectDelegate alloc] initWithDelegate:self];
1271 [webview setFrameLoadDelegate:indirect_];
1272 [webview setResourceLoadDelegate:indirect_];
1273 [webview setUIDelegate:indirect_];
1274 [webview setScriptDebugDelegate:indirect_];
1275 [webview setPolicyDelegate:indirect_];
1279 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:UIProgressIndicatorStyleMediumWhite];
1280 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 12, indsize.width, indsize.height)];
1281 [indicator_ setStyle:UIProgressIndicatorStyleMediumWhite];
1283 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
1284 [scroller_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
1286 /*UIWebView *test([[[UIWebView alloc] initWithFrame:[self bounds]] autorelease]);
1287 [test loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.saurik.com/"]]];
1288 [self addSubview:test];*/
1292 - (id) initWithBook:(RVBook *)book {
1293 return [self initWithBook:book forWidth:0];
1296 - (NSString *) stringByEvaluatingJavaScriptFromString:(NSString *)script {
1298 WebView *webview([webview_ webView]);
1299 NSString *string([webview stringByEvaluatingJavaScriptFromString:script]);
1304 - (void) callFunction:(WebScriptObject *)function {
1307 WebView *webview([webview_ webView]);
1308 WebFrame *frame([webview mainFrame]);
1310 id _private(MSHookIvar<id>(webview, "_private"));
1311 WebCore::Page *page(_private == nil ? NULL : MSHookIvar<WebCore::Page *>(_private, "page"));
1312 WebCore::Settings *settings(page == NULL ? NULL : page->settings());
1315 if (settings == NULL)
1318 no = settings->JavaScriptCanOpenWindowsAutomatically();
1319 settings->setJavaScriptCanOpenWindowsAutomatically(true);
1322 if (UIWindow *window = [self window])
1323 if (UIResponder *responder = [window firstResponder])
1324 [responder resignFirstResponder];
1326 JSObjectRef object([function JSObject]);
1327 JSGlobalContextRef context([frame globalContext]);
1328 JSObjectCallAsFunction(context, object, NULL, 0, NULL, NULL);
1330 if (settings != NULL)
1331 settings->setJavaScriptCanOpenWindowsAutomatically(no);
1336 - (void) didCloseBook:(RVBook *)book {
1338 [self callFunction:closer_];
1341 - (void) __rightButtonClicked {
1346 - (void) _rightButtonClicked {
1348 if (function_ != nil)
1349 [self callFunction:function_];
1352 [self __rightButtonClicked];
1355 - (id) _rightButtonTitle {
1356 return UCLocalize("RELOAD");
1359 - (id) rightButtonTitle {
1360 return [self isLoading] ? @"" : button_ != nil ? button_ : [self _rightButtonTitle];
1363 - (UINavigationButtonStyle) rightButtonStyle {
1364 if (style_ == nil) normal:
1365 return UINavigationButtonStyleNormal;
1366 else if ([style_ isEqualToString:@"Normal"])
1367 return UINavigationButtonStyleNormal;
1368 else if ([style_ isEqualToString:@"Back"])
1369 return UINavigationButtonStyleBack;
1370 else if ([style_ isEqualToString:@"Highlighted"])
1371 return UINavigationButtonStyleHighlighted;
1372 else if ([style_ isEqualToString:@"Destructive"])
1373 return UINavigationButtonStyleDestructive;
1377 - (NSString *) title {
1378 return title_ == nil ? UCLocalize("LOADING") : title_;
1381 - (NSString *) backButtonTitle {
1382 return UCLocalize("BROWSER");
1385 - (void) setPageActive:(BOOL)active {
1387 [indicator_ removeFromSuperview];
1389 [[book_ navigationBar] addSubview:indicator_];
1392 - (void) resetViewAnimated:(BOOL)animated {
1395 - (void) setPushed:(bool)pushed {
1399 + (float) defaultWidth {