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>
9 #include <WebKit/WebPreferences-WebPrivate.h>
11 #include "substrate.h"
15 static CFArrayRef (*$GSSystemCopyCapability)(CFStringRef);
16 static CFArrayRef (*$GSSystemGetCapability)(CFStringRef);
18 @interface NSString (UIKit)
19 - (NSString *) stringByAddingPercentEscapes;
22 /* Indirect Delegate {{{ */
23 @interface IndirectDelegate : NSObject {
24 _transient volatile id delegate_;
27 - (void) setDelegate:(id)delegate;
28 - (id) initWithDelegate:(id)delegate;
31 @implementation IndirectDelegate
33 - (void) setDelegate:(id)delegate {
37 - (id) initWithDelegate:(id)delegate {
42 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
44 return [delegate_ webView:sender didClearWindowObject:window forFrame:frame];
47 - (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
49 return [delegate_ webView:sender didCommitLoadForFrame:frame];
52 - (void) webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
54 return [delegate_ webView:sender didFailLoadWithError:error forFrame:frame];
57 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
59 return [delegate_ webView:sender didFailProvisionalLoadWithError:error forFrame:frame];
62 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
64 return [delegate_ webView:sender didFinishLoadForFrame:frame];
67 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
69 return [delegate_ webView:sender didReceiveTitle:title forFrame:frame];
72 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
74 return [delegate_ webView:sender didStartProvisionalLoadForFrame:frame];
77 - (void) webView:(WebView *)sender resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)source {
79 return [delegate_ webView:sender resource:identifier didReceiveAuthenticationChallenge:challenge fromDataSource:source];
82 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)source {
84 return [delegate_ webView:sender resource:identifier willSendRequest:request redirectResponse:redirectResponse fromDataSource:source];
88 - (IMP) methodForSelector:(SEL)sel {
89 if (IMP method = [super methodForSelector:sel])
91 fprintf(stderr, "methodForSelector:[%s] == NULL\n", sel_getName(sel));
95 - (BOOL) respondsToSelector:(SEL)sel {
96 if ([super respondsToSelector:sel])
98 // XXX: WebThreadCreateNSInvocation returns nil
99 //fprintf(stderr, "[%s]R?%s\n", class_getName(self->isa), sel_getName(sel));
100 return delegate_ == nil ? NO : [delegate_ respondsToSelector:sel];
103 - (NSMethodSignature *) methodSignatureForSelector:(SEL)sel {
104 if (NSMethodSignature *method = [super methodSignatureForSelector:sel])
106 //fprintf(stderr, "[%s]S?%s\n", class_getName(self->isa), sel_getName(sel));
107 if (delegate_ != nil)
108 if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel])
110 // XXX: I fucking hate Apple so very very bad
111 return [NSMethodSignature signatureWithObjCTypes:"v@:"];
114 - (void) forwardInvocation:(NSInvocation *)inv {
115 SEL sel = [inv selector];
116 if (delegate_ != nil && [delegate_ respondsToSelector:sel])
117 [inv invokeWithTarget:delegate_];
123 @interface WebView (UICaboodle)
124 - (void) setScriptDebugDelegate:(id)delegate;
125 - (void) _setFormDelegate:(id)delegate;
126 - (void) _setUIKitDelegate:(id)delegate;
127 - (void) setWebMailDelegate:(id)delegate;
128 - (void) _setLayoutInterval:(float)interval;
131 @implementation WebScriptObject (UICaboodle)
134 id length([self valueForKey:@"length"]);
135 if ([length respondsToSelector:@selector(intValue)])
136 return [length intValue];
141 - (id) objectAtIndex:(unsigned)index {
142 return [self webScriptValueAtIndex:index];
147 #define ShowInternals 0
150 #define lprintf(args...) fprintf(stderr, args)
152 @implementation BrowserView
155 #include "UICaboodle/UCInternal.h"
158 + (void) _initialize {
159 [WebView enableWebThread];
161 WebPreferences *preferences([WebPreferences standardPreferences]);
162 [preferences setCacheModel:WebCacheModelDocumentBrowser];
163 [preferences setOfflineWebApplicationCacheEnabled:YES];
165 [WebPreferences _setInitialDefaultTextEncodingToSystemEncoding];
167 $GSSystemCopyCapability = reinterpret_cast<CFArrayRef (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemCopyCapability"));
168 $GSSystemGetCapability = reinterpret_cast<CFArrayRef (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemGetCapability"));
173 NSLog(@"[BrowserView dealloc]");
176 if (challenge_ != nil)
177 [challenge_ release];
181 WebView *webview = [webview_ webView];
182 [webview setFrameLoadDelegate:nil];
183 [webview setResourceLoadDelegate:nil];
184 [webview setUIDelegate:nil];
185 [webview setScriptDebugDelegate:nil];
186 [webview setPolicyDelegate:nil];
188 /* XXX: these are set by UIWebDocumentView
189 [webview setDownloadDelegate:nil];
190 [webview _setFormDelegate:nil];
191 [webview _setUIKitDelegate:nil];
192 [webview setEditingDelegate:nil];*/
194 /* XXX: no one sets this, ever
195 [webview setWebMailDelegate:nil];*/
197 [webview_ setDelegate:nil];
198 [webview_ setGestureDelegate:nil];
199 [webview_ setFormEditingDelegate:nil];
200 [webview_ setInteractionDelegate:nil];
202 [indirect_ setDelegate:nil];
204 //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
209 [webview_ removeFromSuperview];
210 [Documents_ addObject:[webview_ autorelease]];
219 [scroller_ setDelegate:nil];
225 if (function_ != nil)
235 [indicator_ release];
238 if (sensitive_ != nil)
239 [sensitive_ release];
245 - (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
246 [self loadRequest:[NSURLRequest
253 - (void) loadURL:(NSURL *)url {
254 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
257 - (void) loadRequest:(NSURLRequest *)request {
262 [webview_ loadRequest:request];
270 if ([request_ HTTPBody] == nil && [request_ HTTPBodyStream] == nil)
271 [self loadRequest:request_];
273 UIActionSheet *sheet = [[[UIActionSheet alloc]
274 initWithTitle:UCLocalize("RESUBMIT_FORM")
275 buttons:[NSArray arrayWithObjects:UCLocalize("CANCEL"), UCLocalize("SUBMIT"), nil]
281 [sheet setNumberOfRows:1];
282 [sheet popupAlertAnimated:YES];
286 - (WebView *) webView {
287 return [webview_ webView];
290 - (UIWebDocumentView *) documentView {
294 /* XXX: WebThreadLock? */
295 - (void) _fixScroller:(CGRect)bounds {
300 UIFormAssistant *assistant([UIFormAssistant sharedFormAssistant]);
301 CGRect peripheral([assistant peripheralFrame]);
303 NSLog(@"per:%f", peripheral.size.height);
305 extra = peripheral.size.height;
308 CGRect subrect([scroller_ frame]);
309 subrect.size.height -= extra;
310 [scroller_ setScrollerIndicatorSubrect:subrect];
312 NSSize visible(NSMakeSize(subrect.size.width, subrect.size.height));
313 [webview_ setValue:[NSValue valueWithSize:visible] forGestureAttribute:UIGestureAttributeVisibleSize];
316 size.height += extra;
317 [scroller_ setContentSize:size];
319 [scroller_ releaseRubberBandIfNecessary];
322 - (void) fixScroller {
323 CGRect bounds([webview_ documentBounds]);
325 NSLog(@"_fs:(%f,%f+%f,%f)", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
327 [self _fixScroller:bounds];
330 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
333 NSLog(@"dsf:(%f,%f+%f,%f)", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
335 [self _fixScroller:frame];
338 - (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
339 [self view:sender didSetFrame:frame];
342 - (void) pushPage:(RVPage *)page {
343 [page setDelegate:delegate_];
344 [self setBackButtonTitle:title_];
345 [book_ pushPage:page];
351 // WTR: [self autorelease];
353 [book_ pushPage:self];
356 - (void) swapPage:(RVPage *)page {
357 [page setDelegate:delegate_];
359 [book_ swapPage:page];
361 [book_ pushPage:page];
364 - (BOOL) getSpecial:(NSURL *)url swap:(BOOL)swap {
366 NSLog(@"getSpecial:%@", url);
369 if (RVPage *page = [delegate_ pageForURL:url hasTag:NULL]) {
371 [self swapPage:page];
373 [self pushPage:page];
380 - (void) formAssistant:(id)sender didBeginEditingFormNode:(id)node {
383 - (void) formAssistant:(id)sender didEndEditingFormNode:(id)node {
387 - (void) webViewShow:(WebView *)sender {
388 /* XXX: this is where I cry myself to sleep */
391 - (bool) _allowJavaScriptPanel {
395 - (bool) allowSensitiveRequests {
396 return [self _allowJavaScriptPanel];
399 - (void) _promptForSensitive:(NSMutableArray *)array {
400 NSString *name([array objectAtIndex:0]);
402 UIActionSheet *sheet = [[[UIActionSheet alloc]
404 buttons:[NSArray arrayWithObjects:UCLocalize("YES"), UCLocalize("NO"), nil]
410 NSString *host(@"XXX");
412 [sheet setNumberOfRows:1];
413 [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]];
414 [sheet popupAlertAnimated:YES];
416 NSRunLoop *loop([NSRunLoop currentRunLoop]);
417 NSDate *future([NSDate distantFuture]);
419 while (sensitive_ == nil && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
421 NSNumber *sensitive([sensitive_ autorelease]);
425 [array replaceObjectAtIndex:0 withObject:sensitive];
428 - (bool) promptForSensitive:(NSString *)name {
429 if (![self allowSensitiveRequests])
432 NSMutableArray *array([NSMutableArray arrayWithCapacity:1]);
433 [array addObject:name];
435 [self performSelectorOnMainThread:@selector(_promptForSensitive:) withObject:array waitUntilDone:YES];
436 return [[array lastObject] boolValue];
439 - (void) webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
440 if (![self _allowJavaScriptPanel])
444 UIActionSheet *sheet = [[[UIActionSheet alloc]
446 buttons:[NSArray arrayWithObjects:UCLocalize("OK"), nil]
452 [sheet setBodyText:message];
453 [sheet popupAlertAnimated:YES];
456 - (BOOL) webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
457 if (![self _allowJavaScriptPanel])
461 UIActionSheet *sheet = [[[UIActionSheet alloc]
463 buttons:[NSArray arrayWithObjects:UCLocalize("OK"), UCLocalize("CANCEL"), nil]
469 [sheet setNumberOfRows:1];
470 [sheet setBodyText:message];
471 [sheet popupAlertAnimated:YES];
473 NSRunLoop *loop([NSRunLoop currentRunLoop]);
474 NSDate *future([NSDate distantFuture]);
476 while (confirm_ == nil && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
478 NSNumber *confirm([confirm_ autorelease]);
482 return [confirm boolValue];
485 - (void) setAutoPopup:(BOOL)popup {
489 - (void) setSpecial:(id)function {
491 [special_ autorelease];
492 special_ = function == nil ? nil : [function retain];
495 - (void) setButtonImage:(NSString *)button withStyle:(NSString *)style toFunction:(id)function {
497 [button_ autorelease];
498 button_ = button == nil ? nil : [[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:button]]] retain];
501 [style_ autorelease];
502 style_ = style == nil ? nil : [style retain];
504 if (function_ != nil)
505 [function_ autorelease];
506 function_ = function == nil ? nil : [function retain];
508 [self reloadButtons];
511 - (void) setButtonTitle:(NSString *)button withStyle:(NSString *)style toFunction:(id)function {
513 [button_ autorelease];
514 button_ = button == nil ? nil : [button retain];
517 [style_ autorelease];
518 style_ = style == nil ? nil : [style retain];
520 if (function_ != nil)
521 [function_ autorelease];
522 function_ = function == nil ? nil : [function retain];
524 [self reloadButtons];
527 - (void) setFinishHook:(id)function {
529 [finish_ autorelease];
530 finish_ = function == nil ? nil : [function retain];
533 - (void) setPopupHook:(id)function {
535 [closer_ autorelease];
536 closer_ = function == nil ? nil : [function retain];
539 - (void) _openMailToURL:(NSURL *)url {
540 [UIApp openURL:url];// asPanel:YES];
543 - (void) webView:(WebView *)sender willBeginEditingFormElement:(id)element {
547 - (void) webView:(WebView *)sender didBeginEditingFormElement:(id)element {
551 - (void) webViewDidEndEditingFormElements:(WebView *)sender {
556 - (void) webViewClose:(WebView *)sender {
564 - (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
567 - (void) webView:(WebView *)sender unableToImplementPolicyWithError:(NSError *)error frame:(WebFrame *)frame {
568 NSLog(@"err:%@", error);
571 - (void) webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)name decisionListener:(id<WebPolicyDecisionListener>)listener {
573 NSLog(@"nwa:%@", name);
576 if (NSURL *url = [request URL]) {
577 if (name == nil) unknown: {
578 if (![self getSpecial:url swap:NO]) {
579 NSString *scheme([[url scheme] lowercaseString]);
580 if ([scheme isEqualToString:@"mailto"])
581 [self _openMailToURL:url];
584 } else if ([name isEqualToString:@"_open"])
585 [delegate_ openURL:url];
586 else if ([name isEqualToString:@"_popup"]) {
587 NSString *scheme([[url scheme] lowercaseString]);
588 if ([scheme isEqualToString:@"mailto"])
589 [self _openMailToURL:url];
591 RVBook *book([[[RVPopUpBook alloc] initWithFrame:[delegate_ popUpBounds]] autorelease]);
592 [book setHook:indirect_];
594 RVPage *page([delegate_ pageForURL:url hasTag:NULL]);
596 /* XXX: call createWebViewWithRequest instead? */
598 [self setBackButtonTitle:title_];
600 BrowserView *browser([[[class_ alloc] initWithBook:book] autorelease]);
601 [browser loadURL:url];
605 [book setDelegate:delegate_];
606 [page setDelegate:delegate_];
609 [book_ pushBook:book];
618 - (void) webView:(WebView *)sender decidePolicyForMIMEType:(NSString *)type request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
619 if ([WebView canShowMIMEType:type])
622 // XXX: handle more mime types!
625 WebView *webview([webview_ webView]);
626 if (frame == [webview mainFrame])
627 [UIApp openURL:[request URL]];
631 - (void) webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
632 if (request == nil) ignore: {
637 NSURL *url([request URL]);
638 NSString *host([url host]);
640 if (url == nil) use: {
641 if (!error_ && [frame parentFrame] == nil) {
643 [request_ autorelease];
644 request_ = [request retain];
646 NSLog(@"dpn:%@", request_);
652 WebView *webview([webview_ webView]);
653 if (frame == [webview mainFrame])
658 else NSLog(@"nav:%@:%@", url, [action description]);
661 const NSArray *capability;
663 if ($GSSystemCopyCapability != NULL) {
664 capability = reinterpret_cast<const NSArray *>((*$GSSystemCopyCapability)(kGSDisplayIdentifiersCapability));
665 capability = [capability autorelease];
666 } else if ($GSSystemGetCapability != NULL) {
667 capability = reinterpret_cast<const NSArray *>((*$GSSystemGetCapability)(kGSDisplayIdentifiersCapability));
673 if (capability != nil && (
674 [url isGoogleMapsURL] && [capability containsObject:@"com.apple.Maps"] && (open = [url mapsURL]) != nil||
675 [host hasSuffix:@"youtube.com"] && [capability containsObject:@"com.apple.youtube"] && (open = [url youTubeURL]) != nil ||
676 [url respondsToSelector:@selector(phobosURL)] && (open = [url phobosURL]) != nil
684 int store(_not(int));
685 if (NSURL *itms = [url itmsURL:&store]) {
687 NSLog(@"itms#%@#%u#%@", url, store, itms);
690 if (capability != nil && (
691 store == 1 && [capability containsObject:@"com.apple.MobileStore"] ||
692 store == 2 && [capability containsObject:@"com.apple.AppStore"]
699 NSString *scheme([[url scheme] lowercaseString]);
701 if ([scheme isEqualToString:@"tel"]) {
706 if ([scheme isEqualToString:@"mailto"]) {
707 [self _openMailToURL:url];
711 if ([self getSpecial:url swap:YES])
713 else if ([WebView _canHandleRequest:request])
715 else if ([url isSpringboardHandledURL])
721 - (void) webView:(WebView *)sender setStatusText:(NSString *)text {
722 //lprintf("Status:%s\n", [text UTF8String]);
725 - (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
726 NSString *context([sheet context]);
728 if ([context isEqualToString:@"alert"]) {
731 } else if ([context isEqualToString:@"confirm"]) {
734 confirm_ = [NSNumber numberWithBool:YES];
738 confirm_ = [NSNumber numberWithBool:NO];
743 } else if ([context isEqualToString:@"sensitive"]) {
746 sensitive_ = [NSNumber numberWithBool:YES];
750 sensitive_ = [NSNumber numberWithBool:NO];
755 } else if ([context isEqualToString:@"challenge"]) {
756 id<NSURLAuthenticationChallengeSender> sender([challenge_ sender]);
760 NSString *username([[sheet textFieldAtIndex:0] text]);
761 NSString *password([[sheet textFieldAtIndex:1] text]);
763 NSURLCredential *credential([NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistenceForSession]);
765 [sender useCredential:credential forAuthenticationChallenge:challenge_];
769 [sender cancelAuthenticationChallenge:challenge_];
775 [challenge_ release];
779 } else if ([context isEqualToString:@"submit"]) {
785 if (request_ != nil) {
787 [webview_ loadRequest:request_];
799 - (void) webView:(WebView *)sender resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)source {
800 challenge_ = [challenge retain];
802 NSURLProtectionSpace *space([challenge protectionSpace]);
803 NSString *realm([space realm]);
807 UIActionSheet *sheet = [[[UIActionSheet alloc]
809 buttons:[NSArray arrayWithObjects:UCLocalize("LOGIN"), UCLocalize("CANCEL"), nil]
815 [sheet setNumberOfRows:1];
817 [sheet addTextFieldWithValue:@"" label:UCLocalize("USERNAME")];
818 [sheet addTextFieldWithValue:@"" label:UCLocalize("PASSWORD")];
820 UITextField *username([sheet textFieldAtIndex:0]); {
821 UITextInputTraits *traits([username textInputTraits]);
822 [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone];
823 [traits setAutocorrectionType:UITextAutocorrectionTypeNo];
824 [traits setKeyboardType:UIKeyboardTypeASCIICapable];
825 [traits setReturnKeyType:UIReturnKeyNext];
828 UITextField *password([sheet textFieldAtIndex:1]); {
829 UITextInputTraits *traits([password textInputTraits]);
830 [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone];
831 [traits setAutocorrectionType:UITextAutocorrectionTypeNo];
832 [traits setKeyboardType:UIKeyboardTypeASCIICapable];
833 // XXX: UIReturnKeyDone
834 [traits setReturnKeyType:UIReturnKeyNext];
835 [traits setSecureTextEntry:YES];
838 [sheet popupAlertAnimated:YES];
841 - (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)source {
845 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request windowFeatures:(NSDictionary *)features {
846 //- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request userGesture:(BOOL)gesture {
848 NSLog(@"cwv:%@ (%@): %@", request, title_, features == nil ? @"{}" : [features description]);
849 //NSLog(@"cwv:%@ (%@): %@", request, title_, gesture ? @"Yes" : @"No");
852 NSNumber *value([features objectForKey:@"width"]);
853 float width(value == nil ? 0 : [value floatValue]);
855 RVBook *book(!popup_ ? book_ : [[[RVPopUpBook alloc] initWithFrame:[delegate_ popUpBounds]] autorelease]);
857 /* XXX: deal with cydia:// pages */
858 BrowserView *browser([[[class_ alloc] initWithBook:book forWidth:width] autorelease]);
860 if (features != nil && popup_) {
861 [book setDelegate:delegate_];
862 [book setHook:indirect_];
863 [browser setDelegate:delegate_];
865 [browser loadRequest:request];
867 [book setPage:browser];
868 [book_ pushBook:book];
869 } else if (request == nil) {
870 [self setBackButtonTitle:title_];
871 [browser setDelegate:delegate_];
874 [self pushPage:browser];
875 [browser loadRequest:request];
878 return [browser webView];
881 - (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
882 return [self webView:sender createWebViewWithRequest:request windowFeatures:nil];
883 //return [self webView:sender createWebViewWithRequest:request userGesture:YES];
886 - (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
887 if ([frame parentFrame] != nil)
890 title_ = [title retain];
891 [book_ reloadTitleForPage:self];
894 - (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
895 /*if ([loading_ count] == 0)
897 [loading_ addObject:[NSValue valueWithNonretainedObject:frame]];
899 if ([frame parentFrame] == nil) {
900 [webview_ resignFirstResponder];
909 if (button_ != nil) {
919 if (function_ != nil) {
924 if (finish_ != nil) {
929 if (closer_ != nil) {
934 if (special_ != nil) {
939 [book_ reloadTitleForPage:self];
941 [scroller_ scrollPointVisibleAtTopLeft:CGPointZero];
943 if ([scroller_ respondsToSelector:@selector(setZoomScale:duration:)])
944 [scroller_ setZoomScale:1 duration:0];
945 else if ([scroller_ respondsToSelector:@selector(_setZoomScale:duration:)])
946 [scroller_ _setZoomScale:1 duration:0];
947 /*else if ([scroller_ respondsToSelector:@selector(setZoomScale:animated:)])
948 [scroller_ setZoomScale:1 animated:NO];*/
950 CGRect webrect = [scroller_ bounds];
951 webrect.size.height = 0;
952 [webview_ setFrame:webrect];
955 [self reloadButtons];
958 - (void) _finishLoading {
959 size_t count([loading_ count]);
961 [self autorelease];*/
962 if (reloading_ || count != 0)
965 [self callFunction:finish_];
966 [self reloadButtons];
970 return [loading_ count] != 0;
973 - (void) reloadButtons {
974 if ([self isLoading])
975 [indicator_ startAnimation];
977 [indicator_ stopAnimation];
978 [super reloadButtons];
981 - (BOOL) webView:(WebView *)sender shouldScrollToPoint:(struct CGPoint)point forFrame:(WebFrame *)frame {
982 return [webview_ webView:sender shouldScrollToPoint:point forFrame:frame];
985 - (void) webView:(WebView *)sender didReceiveViewportArguments:(id)arguments forFrame:(WebFrame *)frame {
986 return [webview_ webView:sender didReceiveViewportArguments:arguments forFrame:frame];
989 - (void) webView:(WebView *)sender needsScrollNotifications:(id)notifications forFrame:(WebFrame *)frame {
990 return [webview_ webView:sender needsScrollNotifications:notifications forFrame:frame];
993 - (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
995 return [webview_ webView:sender didCommitLoadForFrame:frame];
998 - (void) webView:(WebView *)sender didReceiveDocTypeForFrame:(WebFrame *)frame {
999 return [webview_ webView:sender didReceiveDocTypeForFrame:frame];
1002 - (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
1003 [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
1004 [self _finishLoading];
1006 if ([frame parentFrame] == nil) {
1007 if (DOMDocument *document = [frame DOMDocument])
1008 if (DOMNodeList<NSFastEnumeration> *bodies = [document getElementsByTagName:@"body"])
1009 for (DOMHTMLBodyElement *body in bodies) {
1010 DOMCSSStyleDeclaration *style([document getComputedStyle:body pseudoElement:nil]);
1012 bool colored(false);
1014 if (DOMCSSPrimitiveValue *color = static_cast<DOMCSSPrimitiveValue *>([style getPropertyCSSValue:@"background-color"])) {
1015 if ([color primitiveType] == DOM_CSS_RGBCOLOR) {
1016 DOMRGBColor *rgb([color getRGBColorValue]);
1018 float red([[rgb red] getFloatValue:DOM_CSS_NUMBER]);
1019 float green([[rgb green] getFloatValue:DOM_CSS_NUMBER]);
1020 float blue([[rgb blue] getFloatValue:DOM_CSS_NUMBER]);
1021 float alpha([[rgb alpha] getFloatValue:DOM_CSS_NUMBER]);
1025 if (red == 0xc7 && green == 0xce && blue == 0xd5)
1026 uic = [UIColor pinStripeColor];
1027 else if (alpha != 0)
1029 colorWithRed:(red / 255)
1037 [scroller_ setBackgroundColor:uic];
1043 [scroller_ setBackgroundColor:[UIColor pinStripeColor]];
1048 return [webview_ webView:sender didFinishLoadForFrame:frame];
1051 - (void) _didFailWithError:(NSError *)error forFrame:(WebFrame *)frame {
1053 /*if ([frame parentFrame] == nil)
1054 [self autorelease];*/
1056 [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
1057 [self _finishLoading];
1062 if ([frame parentFrame] == nil) {
1063 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
1064 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
1065 [[error localizedDescription] stringByAddingPercentEscapes]
1072 - (void) webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
1073 [self _didFailWithError:error forFrame:frame];
1076 - (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
1077 [self _didFailWithError:error forFrame:frame];
1080 - (void) webView:(WebView *)sender addMessageToConsole:(NSDictionary *)dictionary {
1081 #if LogBrowser || ForSaurik
1082 lprintf("Console:%s\n", [[dictionary description] UTF8String]);
1086 /* XXX: fix this stupid include file
1087 - (void) webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(WebSecurityOrigin *)origin database:(NSString *)database {
1088 [origin setQuota:0x500000];
1091 - (void) _setTileDrawingEnabled:(BOOL)enabled {
1092 //[webview_ setTileDrawingEnabled:enabled];
1095 - (void) setViewportWidth:(float)width {
1096 width_ = width != 0 ? width : [[self class] defaultWidth];
1097 [webview_ setViewportSize:CGSizeMake(width_, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10];
1100 - (void) willStartGesturesInView:(UIView *)view forEvent:(GSEventRef)event {
1101 [self _setTileDrawingEnabled:NO];
1104 - (void) didFinishGesturesInView:(UIView *)view forEvent:(GSEventRef)event {
1105 [self _setTileDrawingEnabled:YES];
1106 [webview_ redrawScaledDocument];
1109 - (void) scrollerWillStartDragging:(UIScroller *)scroller {
1110 [self _setTileDrawingEnabled:NO];
1113 - (void) scrollerDidEndDragging:(UIScroller *)scroller willSmoothScroll:(BOOL)smooth {
1114 [self _setTileDrawingEnabled:YES];
1117 - (void) scrollerDidEndDragging:(UIScroller *)scroller {
1118 [self _setTileDrawingEnabled:YES];
1121 - (id) initWithBook:(RVBook *)book forWidth:(float)width ofClass:(Class)_class {
1122 if ((self = [super initWithBook:book]) != nil) {
1124 loading_ = [[NSMutableSet alloc] initWithCapacity:3];
1127 struct CGRect bounds = [self bounds];
1129 scroller_ = [[UIScroller alloc] initWithFrame:bounds];
1130 [self addSubview:scroller_];
1132 [scroller_ setFixedBackgroundPattern:YES];
1133 [scroller_ setBackgroundColor:[UIColor pinStripeColor]];
1135 [scroller_ setScrollingEnabled:YES];
1136 [scroller_ setClipsSubviews:YES];
1137 [scroller_ setAllowsRubberBanding:YES];
1139 [scroller_ setDelegate:self];
1140 [scroller_ setBounces:YES];
1141 [scroller_ setScrollHysteresis:8];
1142 [scroller_ setThumbDetectionEnabled:NO];
1143 [scroller_ setDirectionalScrolling:YES];
1144 [scroller_ setScrollDecelerationFactor:0.99]; /* 0.989324 */
1145 [scroller_ setEventMode:YES];
1146 [scroller_ setShowBackgroundShadow:NO]; /* YES */
1147 [scroller_ setAllowsRubberBanding:YES]; /* Vertical */
1148 [scroller_ setAdjustForContentSizeChange:YES]; /* NO */
1150 CGRect webrect = [scroller_ bounds];
1151 webrect.size.height = 0;
1158 webview_ = [Documents_ lastObject];
1159 if (webview_ != nil) {
1160 webview_ = [webview_ retain];
1161 webview = [webview_ webView];
1162 [Documents_ removeLastObject];
1163 [webview_ setFrame:webrect];
1168 webview_ = [[UIWebDocumentView alloc] initWithFrame:webrect];
1169 webview = [webview_ webView];
1171 // XXX: this is terribly (too?) expensive
1172 //[webview_ setDrawsBackground:NO];
1173 [webview setPreferencesIdentifier:@"Cydia"];
1175 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
1177 if ([webview_ respondsToSelector:@selector(enableReachability)])
1178 [webview_ enableReachability];
1180 [webview_ setAllowsMessaging:YES];
1182 if ([webview_ respondsToSelector:@selector(useSelectionAssistantWithMode:)])
1183 [webview_ useSelectionAssistantWithMode:0];
1185 [webview_ setTilingEnabled:YES];
1186 [webview_ setDrawsGrid:NO];
1187 [webview_ setLogsTilingChanges:NO];
1188 [webview_ setTileMinificationFilter:kCAFilterNearest];
1190 if ([webview_ respondsToSelector:@selector(setDataDetectorTypes:)])
1191 /* XXX: abstractify */
1192 [webview_ setDataDetectorTypes:0x80000000];
1194 [webview_ setDetectsPhoneNumbers:NO];
1196 [webview_ setAutoresizes:YES];
1198 [webview_ setMinimumScale:0.25f forDocumentTypes:0x10];
1199 [webview_ setMaximumScale:5.00f forDocumentTypes:0x10];
1200 [webview_ setInitialScale:UIWebViewScalesToFitScale forDocumentTypes:0x10];
1201 //[webview_ setViewportSize:CGSizeMake(980, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10];
1203 [webview_ setViewportSize:CGSizeMake(320, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x2];
1205 [webview_ setMinimumScale:1.00f forDocumentTypes:0x8];
1206 [webview_ setInitialScale:UIWebViewScalesToFitScale forDocumentTypes:0x8];
1207 [webview_ setViewportSize:CGSizeMake(320, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x8];
1209 [webview_ _setDocumentType:0x4];
1211 if ([webview_ respondsToSelector:@selector(UIWebDocumentView:)])
1212 [webview_ setZoomsFocusedFormControl:YES];
1213 [webview_ setContentsPosition:7];
1214 [webview_ setEnabledGestures:0xa];
1215 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeIsZoomRubberBandEnabled];
1216 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeUpdatesScroller];
1218 [webview_ setSmoothsFonts:YES];
1219 [webview_ setAllowsImageSheet:YES];
1220 [webview _setUsesLoaderCache:YES];
1222 [webview setGroupName:@"CydiaGroup"];
1224 WebPreferences *preferences([webview preferences]);
1226 if ([webview respondsToSelector:@selector(_setLayoutInterval:)])
1227 [webview _setLayoutInterval:0];
1229 [preferences _setLayoutInterval:0];
1232 [self setViewportWidth:width];
1234 [webview_ setDelegate:self];
1235 [webview_ setGestureDelegate:self];
1236 [webview_ setFormEditingDelegate:self];
1237 [webview_ setInteractionDelegate:self];
1239 [scroller_ addSubview:webview_];
1241 //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
1243 indirect_ = [[IndirectDelegate alloc] initWithDelegate:self];
1245 [webview setFrameLoadDelegate:indirect_];
1246 [webview setPolicyDelegate:indirect_];
1247 [webview setResourceLoadDelegate:indirect_];
1248 [webview setUIDelegate:indirect_];
1250 /* XXX: do not turn this on under penalty of extreme pain */
1251 [webview setScriptDebugDelegate:nil];
1255 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:UIProgressIndicatorStyleMediumWhite];
1256 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(281, 12, indsize.width, indsize.height)];
1257 [indicator_ setStyle:UIProgressIndicatorStyleMediumWhite];
1259 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
1260 [scroller_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
1262 /*UIWebView *test([[[UIWebView alloc] initWithFrame:[self bounds]] autorelease]);
1263 [test loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.saurik.com/"]]];
1264 [self addSubview:test];*/
1268 - (id) initWithBook:(RVBook *)book forWidth:(float)width {
1269 return [self initWithBook:book forWidth:width ofClass:[self class]];
1272 - (id) initWithBook:(RVBook *)book {
1273 return [self initWithBook:book forWidth:0];
1276 - (NSString *) stringByEvaluatingJavaScriptFromString:(NSString *)script {
1278 WebView *webview([webview_ webView]);
1279 NSString *string([webview stringByEvaluatingJavaScriptFromString:script]);
1284 - (void) callFunction:(WebScriptObject *)function {
1287 WebView *webview([webview_ webView]);
1288 WebFrame *frame([webview mainFrame]);
1290 id _private(MSHookIvar<id>(webview, "_private"));
1291 WebCore::Page *page(_private == nil ? NULL : MSHookIvar<WebCore::Page *>(_private, "page"));
1292 WebCore::Settings *settings(page == NULL ? NULL : page->settings());
1295 if (settings == NULL)
1298 no = settings->JavaScriptCanOpenWindowsAutomatically();
1299 settings->setJavaScriptCanOpenWindowsAutomatically(true);
1302 if (UIWindow *window = [self window])
1303 if (UIResponder *responder = [window firstResponder])
1304 [responder resignFirstResponder];
1306 JSObjectRef object([function JSObject]);
1307 JSGlobalContextRef context([frame globalContext]);
1308 JSObjectCallAsFunction(context, object, NULL, 0, NULL, NULL);
1310 if (settings != NULL)
1311 settings->setJavaScriptCanOpenWindowsAutomatically(no);
1316 - (void) didCloseBook:(RVBook *)book {
1318 [self callFunction:closer_];
1321 - (void) __rightButtonClicked {
1326 - (void) _rightButtonClicked {
1328 if (function_ != nil)
1329 [self callFunction:function_];
1332 [self __rightButtonClicked];
1335 - (id) _rightButtonTitle {
1336 return UCLocalize("RELOAD");
1339 - (id) rightButtonTitle {
1340 return [self isLoading] ? @"" : button_ != nil ? button_ : [self _rightButtonTitle];
1343 - (UINavigationButtonStyle) rightButtonStyle {
1344 if (style_ == nil) normal:
1345 return UINavigationButtonStyleNormal;
1346 else if ([style_ isEqualToString:@"Normal"])
1347 return UINavigationButtonStyleNormal;
1348 else if ([style_ isEqualToString:@"Back"])
1349 return UINavigationButtonStyleBack;
1350 else if ([style_ isEqualToString:@"Highlighted"])
1351 return UINavigationButtonStyleHighlighted;
1352 else if ([style_ isEqualToString:@"Destructive"])
1353 return UINavigationButtonStyleDestructive;
1357 - (NSString *) title {
1358 return title_ == nil ? UCLocalize("LOADING") : title_;
1361 - (NSString *) backButtonTitle {
1362 return UCLocalize("BROWSER");
1365 - (void) setPageActive:(BOOL)active {
1367 [indicator_ removeFromSuperview];
1369 [[book_ navigationBar] addSubview:indicator_];
1372 - (void) resetViewAnimated:(BOOL)animated {
1375 - (void) setPushed:(bool)pushed {
1379 + (float) defaultWidth {