]> git.saurik.com Git - cydia.git/blame - UICaboodle/BrowserView.mm
Finished implement Cydia Token, fixed width rendering, hide unsupported roles from...
[cydia.git] / UICaboodle / BrowserView.mm
CommitLineData
3cb572d2
JF
1#include <UICaboodle/BrowserView.h>
2#include <UICaboodle/UCLocalize.h>
61b13cae
JF
3
4#import <QuartzCore/CALayer.h>
5// XXX: fix the minimum requirement
6extern NSString * const kCAFilterNearest;
bde2d79b 7
9d7f5e2d 8#include <WebCore/WebCoreThread.h>
4825688a 9#include <WebKit/WebPreferences-WebPrivate.h>
9d7f5e2d 10
61b13cae
JF
11#include "substrate.h"
12
d4f84362 13#define ForSaurik 1
017b2b71 14
5d8f1006
JF
15static CFArrayRef (*$GSSystemCopyCapability)(CFStringRef);
16static CFArrayRef (*$GSSystemGetCapability)(CFStringRef);
d4f84362
JF
17static Class $UIFormAssistant;
18static Class $UIWebBrowserView;
5d8f1006 19
61b13cae
JF
20@interface NSString (UIKit)
21- (NSString *) stringByAddingPercentEscapes;
22@end
23
04700693 24/* Indirect Delegate {{{ */
9d7f5e2d 25@interface IndirectDelegate : NSObject {
04700693
JF
26 _transient volatile id delegate_;
27}
28
29- (void) setDelegate:(id)delegate;
30- (id) initWithDelegate:(id)delegate;
31@end
32
33@implementation IndirectDelegate
34
35- (void) setDelegate:(id)delegate {
36 delegate_ = delegate;
37}
38
39- (id) initWithDelegate:(id)delegate {
40 delegate_ = delegate;
41 return self;
42}
43
9d7f5e2d
JF
44- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
45 if (delegate_ != nil)
46 return [delegate_ webView:sender didClearWindowObject:window forFrame:frame];
47}
48
49- (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
50 if (delegate_ != nil)
51 return [delegate_ webView:sender didCommitLoadForFrame:frame];
52}
53
54- (void) webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
55 if (delegate_ != nil)
56 return [delegate_ webView:sender didFailLoadWithError:error forFrame:frame];
57}
58
59- (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
60 if (delegate_ != nil)
61 return [delegate_ webView:sender didFailProvisionalLoadWithError:error forFrame:frame];
62}
63
64- (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
65 if (delegate_ != nil)
66 return [delegate_ webView:sender didFinishLoadForFrame:frame];
67}
68
69- (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
70 if (delegate_ != nil)
71 return [delegate_ webView:sender didReceiveTitle:title forFrame:frame];
72}
73
74- (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
75 if (delegate_ != nil)
76 return [delegate_ webView:sender didStartProvisionalLoadForFrame:frame];
77}
78
79- (void) webView:(WebView *)sender resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)source {
80 if (delegate_ != nil)
81 return [delegate_ webView:sender resource:identifier didReceiveAuthenticationChallenge:challenge fromDataSource:source];
82}
83
84- (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)source {
85 if (delegate_ != nil)
86 return [delegate_ webView:sender resource:identifier willSendRequest:request redirectResponse:redirectResponse fromDataSource:source];
87 return nil;
88}
89
90- (IMP) methodForSelector:(SEL)sel {
91 if (IMP method = [super methodForSelector:sel])
92 return method;
93 fprintf(stderr, "methodForSelector:[%s] == NULL\n", sel_getName(sel));
94 return NULL;
95}
96
04700693 97- (BOOL) respondsToSelector:(SEL)sel {
9d7f5e2d
JF
98 if ([super respondsToSelector:sel])
99 return YES;
100 // XXX: WebThreadCreateNSInvocation returns nil
101 //fprintf(stderr, "[%s]R?%s\n", class_getName(self->isa), sel_getName(sel));
102 return delegate_ == nil ? NO : [delegate_ respondsToSelector:sel];
04700693
JF
103}
104
105- (NSMethodSignature *) methodSignatureForSelector:(SEL)sel {
9d7f5e2d
JF
106 if (NSMethodSignature *method = [super methodSignatureForSelector:sel])
107 return method;
108 //fprintf(stderr, "[%s]S?%s\n", class_getName(self->isa), sel_getName(sel));
04700693
JF
109 if (delegate_ != nil)
110 if (NSMethodSignature *sig = [delegate_ methodSignatureForSelector:sel])
111 return sig;
112 // XXX: I fucking hate Apple so very very bad
113 return [NSMethodSignature signatureWithObjCTypes:"v@:"];
114}
115
116- (void) forwardInvocation:(NSInvocation *)inv {
117 SEL sel = [inv selector];
118 if (delegate_ != nil && [delegate_ respondsToSelector:sel])
119 [inv invokeWithTarget:delegate_];
120}
121
122@end
123/* }}} */
124
61b13cae 125@interface WebView (UICaboodle)
bde2d79b
JF
126- (void) setScriptDebugDelegate:(id)delegate;
127- (void) _setFormDelegate:(id)delegate;
128- (void) _setUIKitDelegate:(id)delegate;
129- (void) setWebMailDelegate:(id)delegate;
130- (void) _setLayoutInterval:(float)interval;
131@end
132
61b13cae 133@implementation WebScriptObject (UICaboodle)
9d7f5e2d
JF
134
135- (unsigned) count {
136 id length([self valueForKey:@"length"]);
137 if ([length respondsToSelector:@selector(intValue)])
138 return [length intValue];
139 else
140 return 0;
141}
142
143- (id) objectAtIndex:(unsigned)index {
144 return [self webScriptValueAtIndex:index];
145}
146
147@end
148
d4f84362 149#define ShowInternals 1
6981ccdf 150#define LogBrowser 0
4825688a
JF
151
152#define lprintf(args...) fprintf(stderr, args)
153
bde2d79b
JF
154@implementation BrowserView
155
5a5c1e4b 156#if ShowInternals
4825688a 157#include "UICaboodle/UCInternal.h"
bde2d79b
JF
158#endif
159
4825688a 160+ (void) _initialize {
4825688a
JF
161 [WebView enableWebThread];
162
163 WebPreferences *preferences([WebPreferences standardPreferences]);
164 [preferences setCacheModel:WebCacheModelDocumentBrowser];
165 [preferences setOfflineWebApplicationCacheEnabled:YES];
166
167 [WebPreferences _setInitialDefaultTextEncodingToSystemEncoding];
5d8f1006
JF
168
169 $GSSystemCopyCapability = reinterpret_cast<CFArrayRef (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemCopyCapability"));
170 $GSSystemGetCapability = reinterpret_cast<CFArrayRef (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemGetCapability"));
d4f84362
JF
171 $UIFormAssistant = objc_getClass("UIFormAssistant");
172
173 $UIWebBrowserView = objc_getClass("UIWebBrowserView");
174 if ($UIWebBrowserView == nil)
175 $UIWebBrowserView = objc_getClass("UIWebDocumentView");
4825688a
JF
176}
177
bde2d79b 178- (void) dealloc {
1ce016d4 179#if LogBrowser
7b00c562
JF
180 NSLog(@"[BrowserView dealloc]");
181#endif
5a5c1e4b 182
bde2d79b
JF
183 if (challenge_ != nil)
184 [challenge_ release];
185
9d7f5e2d
JF
186 WebThreadLock();
187
bde2d79b
JF
188 WebView *webview = [webview_ webView];
189 [webview setFrameLoadDelegate:nil];
190 [webview setResourceLoadDelegate:nil];
191 [webview setUIDelegate:nil];
192 [webview setScriptDebugDelegate:nil];
193 [webview setPolicyDelegate:nil];
194
9d7f5e2d 195 /* XXX: these are set by UIWebDocumentView
4825688a 196 [webview setDownloadDelegate:nil];
bde2d79b
JF
197 [webview _setFormDelegate:nil];
198 [webview _setUIKitDelegate:nil];
9d7f5e2d
JF
199 [webview setEditingDelegate:nil];*/
200
201 /* XXX: no one sets this, ever
202 [webview setWebMailDelegate:nil];*/
bde2d79b
JF
203
204 [webview_ setDelegate:nil];
205 [webview_ setGestureDelegate:nil];
d4f84362
JF
206
207 if ([webview_ respondsToSelector:@selector(setFormEditingDelegate:)])
208 [webview_ setFormEditingDelegate:nil];
209
dcc55b8b 210 [webview_ setInteractionDelegate:nil];
bde2d79b 211
9d7f5e2d
JF
212 [indirect_ setDelegate:nil];
213
bde2d79b
JF
214 //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
215
216 [webview close];
217
218#if RecycleWebViews
219 [webview_ removeFromSuperview];
220 [Documents_ addObject:[webview_ autorelease]];
221#else
222 [webview_ release];
223#endif
224
bde2d79b
JF
225 [indirect_ release];
226
9d7f5e2d
JF
227 WebThreadUnlock();
228
bde2d79b
JF
229 [scroller_ setDelegate:nil];
230
231 if (button_ != nil)
232 [button_ release];
233 if (style_ != nil)
234 [style_ release];
235 if (function_ != nil)
236 [function_ release];
9d7f5e2d
JF
237 if (finish_ != nil)
238 [finish_ release];
1ce016d4
JF
239 if (closer_ != nil)
240 [closer_ release];
9d7f5e2d
JF
241 if (special_ != nil)
242 [special_ release];
bde2d79b
JF
243
244 [scroller_ release];
245 [indicator_ release];
246 if (confirm_ != nil)
247 [confirm_ release];
0fc560b6
JF
248 if (sensitive_ != nil)
249 [sensitive_ release];
bde2d79b
JF
250 if (title_ != nil)
251 [title_ release];
252 [super dealloc];
253}
254
255- (void) loadURL:(NSURL *)url cachePolicy:(NSURLRequestCachePolicy)policy {
256 [self loadRequest:[NSURLRequest
257 requestWithURL:url
258 cachePolicy:policy
259 timeoutInterval:30.0
260 ]];
261}
262
263- (void) loadURL:(NSURL *)url {
264 [self loadURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy];
265}
266
bde2d79b
JF
267- (void) loadRequest:(NSURLRequest *)request {
268 pushed_ = true;
f4772bd1 269 error_ = false;
9d7f5e2d
JF
270
271 WebThreadLock();
bde2d79b 272 [webview_ loadRequest:request];
9d7f5e2d 273 WebThreadUnlock();
bde2d79b
JF
274}
275
276- (void) reloadURL {
bde2d79b
JF
277 if (request_ == nil)
278 return;
279
280 if ([request_ HTTPBody] == nil && [request_ HTTPBodyStream] == nil)
f4772bd1 281 [self loadRequest:request_];
bde2d79b
JF
282 else {
283 UIActionSheet *sheet = [[[UIActionSheet alloc]
61b13cae
JF
284 initWithTitle:UCLocalize("RESUBMIT_FORM")
285 buttons:[NSArray arrayWithObjects:UCLocalize("CANCEL"), UCLocalize("SUBMIT"), nil]
bde2d79b
JF
286 defaultButtonIndex:0
287 delegate:self
288 context:@"submit"
289 ] autorelease];
290
291 [sheet setNumberOfRows:1];
292 [sheet popupAlertAnimated:YES];
293 }
294}
295
296- (WebView *) webView {
297 return [webview_ webView];
298}
299
5a5c1e4b
JF
300- (UIWebDocumentView *) documentView {
301 return webview_;
302}
303
9d7f5e2d
JF
304/* XXX: WebThreadLock? */
305- (void) _fixScroller:(CGRect)bounds {
dcc55b8b 306 float extra;
d4f84362
JF
307
308 if (!editing_ || $UIFormAssistant == nil)
dcc55b8b
JF
309 extra = 0;
310 else {
d4f84362 311 UIFormAssistant *assistant([$UIFormAssistant sharedFormAssistant]);
dcc55b8b 312 CGRect peripheral([assistant peripheralFrame]);
1ce016d4 313#if LogBrowser
dcc55b8b 314 NSLog(@"per:%f", peripheral.size.height);
5889429e 315#endif
dcc55b8b
JF
316 extra = peripheral.size.height;
317 }
318
319 CGRect subrect([scroller_ frame]);
320 subrect.size.height -= extra;
dcc55b8b 321
d4f84362
JF
322 if ([scroller_ respondsToSelector:@selector(setScrollerIndicatorSubrect:)])
323 [scroller_ setScrollerIndicatorSubrect:subrect];
324
325 [webview_ setValue:[NSValue valueWithSize:NSMakeSize(subrect.size.width, subrect.size.height)] forGestureAttribute:UIGestureAttributeVisibleSize];
5889429e 326
dcc55b8b
JF
327 CGSize size(size_);
328 size.height += extra;
329 [scroller_ setContentSize:size];
5889429e 330
d4f84362
JF
331 if ([scroller_ respondsToSelector:@selector(releaseRubberBandIfNecessary)])
332 [scroller_ releaseRubberBandIfNecessary];
dcc55b8b
JF
333}
334
9d7f5e2d
JF
335- (void) fixScroller {
336 CGRect bounds([webview_ documentBounds]);
e9fde613 337#if TrackResize
9d7f5e2d
JF
338 NSLog(@"_fs:(%f,%f+%f,%f)", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
339#endif
340 [self _fixScroller:bounds];
341}
342
bde2d79b 343- (void) view:(UIView *)sender didSetFrame:(CGRect)frame {
dcc55b8b 344 size_ = frame.size;
e9fde613 345#if TrackResize
5889429e
JF
346 NSLog(@"dsf:(%f,%f+%f,%f)", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
347#endif
9d7f5e2d 348 [self _fixScroller:frame];
bde2d79b
JF
349}
350
351- (void) view:(UIView *)sender didSetFrame:(CGRect)frame oldFrame:(CGRect)old {
352 [self view:sender didSetFrame:frame];
353}
354
355- (void) pushPage:(RVPage *)page {
bde2d79b 356 [page setDelegate:delegate_];
2517c95f 357 [self setBackButtonTitle:title_];
5a5c1e4b 358 [book_ pushPage:page];
bde2d79b
JF
359}
360
a55054a2
JF
361- (void) _pushPage {
362 if (pushed_)
363 return;
9d7f5e2d 364 // WTR: [self autorelease];
a55054a2
JF
365 pushed_ = true;
366 [book_ pushPage:self];
367}
368
5889429e
JF
369- (void) swapPage:(RVPage *)page {
370 [page setDelegate:delegate_];
371 if (pushed_)
372 [book_ swapPage:page];
373 else
374 [book_ pushPage:page];
375}
376
b8de369a 377- (BOOL) getSpecial:(NSURL *)url swap:(BOOL)swap {
1ce016d4 378#if LogBrowser
a55054a2
JF
379 NSLog(@"getSpecial:%@", url);
380#endif
381
61b13cae 382 if (RVPage *page = [delegate_ pageForURL:url hasTag:NULL]) {
b8de369a
JF
383 if (swap)
384 [self swapPage:page];
385 else
386 [self pushPage:page];
61b13cae
JF
387
388 return true;
389 } else
390 return false;
bde2d79b
JF
391}
392
4825688a
JF
393- (void) formAssistant:(id)sender didBeginEditingFormNode:(id)node {
394}
395
396- (void) formAssistant:(id)sender didEndEditingFormNode:(id)node {
397 [self fixScroller];
398}
399
5a5c1e4b 400- (void) webViewShow:(WebView *)sender {
5b2d5cf3 401 /* XXX: this is where I cry myself to sleep */
5a5c1e4b
JF
402}
403
7b00c562
JF
404- (bool) _allowJavaScriptPanel {
405 return true;
406}
407
0fc560b6 408- (bool) allowSensitiveRequests {
61b13cae 409 return [self _allowJavaScriptPanel];
0fc560b6
JF
410}
411
412- (void) _promptForSensitive:(NSMutableArray *)array {
413 NSString *name([array objectAtIndex:0]);
414
415 UIActionSheet *sheet = [[[UIActionSheet alloc]
416 initWithTitle:nil
61b13cae 417 buttons:[NSArray arrayWithObjects:UCLocalize("YES"), UCLocalize("NO"), nil]
0fc560b6
JF
418 defaultButtonIndex:0
419 delegate:indirect_
420 context:@"sensitive"
421 ] autorelease];
422
423 NSString *host(@"XXX");
424
425 [sheet setNumberOfRows:1];
426 [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]];
427 [sheet popupAlertAnimated:YES];
428
429 NSRunLoop *loop([NSRunLoop currentRunLoop]);
430 NSDate *future([NSDate distantFuture]);
431
432 while (sensitive_ == nil && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
433
434 NSNumber *sensitive([sensitive_ autorelease]);
435 sensitive_ = nil;
436
437 [self autorelease];
438 [array replaceObjectAtIndex:0 withObject:sensitive];
439}
440
441- (bool) promptForSensitive:(NSString *)name {
442 if (![self allowSensitiveRequests])
443 return false;
444
445 NSMutableArray *array([NSMutableArray arrayWithCapacity:1]);
446 [array addObject:name];
447
448 [self performSelectorOnMainThread:@selector(_promptForSensitive:) withObject:array waitUntilDone:YES];
449 return [[array lastObject] boolValue];
450}
451
bde2d79b 452- (void) webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
263b91b4 453 if (![self _allowJavaScriptPanel])
7b00c562 454 return;
b452841e 455 [self retain];
b456f1c9 456
bde2d79b
JF
457 UIActionSheet *sheet = [[[UIActionSheet alloc]
458 initWithTitle:nil
61b13cae 459 buttons:[NSArray arrayWithObjects:UCLocalize("OK"), nil]
bde2d79b
JF
460 defaultButtonIndex:0
461 delegate:self
462 context:@"alert"
463 ] autorelease];
464
465 [sheet setBodyText:message];
466 [sheet popupAlertAnimated:YES];
467}
468
469- (BOOL) webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
7b00c562
JF
470 if (![self _allowJavaScriptPanel])
471 return NO;
b452841e 472 [self retain];
7b00c562 473
bde2d79b
JF
474 UIActionSheet *sheet = [[[UIActionSheet alloc]
475 initWithTitle:nil
61b13cae 476 buttons:[NSArray arrayWithObjects:UCLocalize("OK"), UCLocalize("CANCEL"), nil]
bde2d79b 477 defaultButtonIndex:0
b456f1c9 478 delegate:indirect_
bde2d79b
JF
479 context:@"confirm"
480 ] autorelease];
481
482 [sheet setNumberOfRows:1];
483 [sheet setBodyText:message];
484 [sheet popupAlertAnimated:YES];
485
486 NSRunLoop *loop([NSRunLoop currentRunLoop]);
487 NSDate *future([NSDate distantFuture]);
488
489 while (confirm_ == nil && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
490
491 NSNumber *confirm([confirm_ autorelease]);
492 confirm_ = nil;
b452841e
JF
493
494 [self autorelease];
bde2d79b
JF
495 return [confirm boolValue];
496}
497
7b00c562
JF
498- (void) setAutoPopup:(BOOL)popup {
499 popup_ = popup;
500}
501
9d7f5e2d
JF
502- (void) setSpecial:(id)function {
503 if (special_ != nil)
504 [special_ autorelease];
505 special_ = function == nil ? nil : [function retain];
1ce016d4
JF
506}
507
bde2d79b
JF
508- (void) setButtonImage:(NSString *)button withStyle:(NSString *)style toFunction:(id)function {
509 if (button_ != nil)
510 [button_ autorelease];
511 button_ = button == nil ? nil : [[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:button]]] retain];
512
513 if (style_ != nil)
514 [style_ autorelease];
515 style_ = style == nil ? nil : [style retain];
516
517 if (function_ != nil)
518 [function_ autorelease];
519 function_ = function == nil ? nil : [function retain];
1ce016d4
JF
520
521 [self reloadButtons];
bde2d79b
JF
522}
523
524- (void) setButtonTitle:(NSString *)button withStyle:(NSString *)style toFunction:(id)function {
525 if (button_ != nil)
526 [button_ autorelease];
527 button_ = button == nil ? nil : [button retain];
528
529 if (style_ != nil)
530 [style_ autorelease];
531 style_ = style == nil ? nil : [style retain];
532
533 if (function_ != nil)
534 [function_ autorelease];
535 function_ = function == nil ? nil : [function retain];
1ce016d4
JF
536
537 [self reloadButtons];
bde2d79b 538}
bde2d79b 539
9d7f5e2d
JF
540- (void) setFinishHook:(id)function {
541 if (finish_ != nil)
542 [finish_ autorelease];
543 finish_ = function == nil ? nil : [function retain];
544}
545
546- (void) setPopupHook:(id)function {
547 if (closer_ != nil)
548 [closer_ autorelease];
549 closer_ = function == nil ? nil : [function retain];
550}
551
61b13cae 552- (void) _openMailToURL:(NSURL *)url {
61b13cae 553 [UIApp openURL:url];// asPanel:YES];
61b13cae
JF
554}
555
dcc55b8b
JF
556- (void) webView:(WebView *)sender willBeginEditingFormElement:(id)element {
557 editing_ = true;
558}
559
560- (void) webView:(WebView *)sender didBeginEditingFormElement:(id)element {
9d7f5e2d 561 [self fixScroller];
dcc55b8b
JF
562}
563
564- (void) webViewDidEndEditingFormElements:(WebView *)sender {
565 editing_ = false;
9d7f5e2d 566 [self fixScroller];
dcc55b8b
JF
567}
568
04700693
JF
569- (void) webViewClose:(WebView *)sender {
570 [book_ close];
571}
572
7afcea1c
JF
573- (void) close {
574 [book_ close];
575}
576
bde2d79b 577- (void) webView:(WebView *)sender didClearWindowObject:(WebScriptObject *)window forFrame:(WebFrame *)frame {
bde2d79b
JF
578}
579
580- (void) webView:(WebView *)sender unableToImplementPolicyWithError:(NSError *)error frame:(WebFrame *)frame {
581 NSLog(@"err:%@", error);
582}
583
584- (void) webView:(WebView *)sender decidePolicyForNewWindowAction:(NSDictionary *)action request:(NSURLRequest *)request newFrameName:(NSString *)name decisionListener:(id<WebPolicyDecisionListener>)listener {
1ce016d4 585#if LogBrowser
5a5c1e4b 586 NSLog(@"nwa:%@", name);
7b00c562 587#endif
5a5c1e4b 588
bde2d79b 589 if (NSURL *url = [request URL]) {
04700693 590 if (name == nil) unknown: {
b8de369a 591 if (![self getSpecial:url swap:NO]) {
04700693
JF
592 NSString *scheme([[url scheme] lowercaseString]);
593 if ([scheme isEqualToString:@"mailto"])
61b13cae 594 [self _openMailToURL:url];
04700693
JF
595 else goto use;
596 }
597 } else if ([name isEqualToString:@"_open"])
bde2d79b 598 [delegate_ openURL:url];
04700693 599 else if ([name isEqualToString:@"_popup"]) {
3ac7a20a
JF
600 NSString *scheme([[url scheme] lowercaseString]);
601 if ([scheme isEqualToString:@"mailto"])
61b13cae 602 [self _openMailToURL:url];
3ac7a20a
JF
603 else {
604 RVBook *book([[[RVPopUpBook alloc] initWithFrame:[delegate_ popUpBounds]] autorelease]);
605 [book setHook:indirect_];
04700693 606
3ac7a20a
JF
607 RVPage *page([delegate_ pageForURL:url hasTag:NULL]);
608 if (page == nil) {
609 /* XXX: call createWebViewWithRequest instead? */
5a5c1e4b 610
3ac7a20a 611 [self setBackButtonTitle:title_];
5a5c1e4b 612
85021801 613 BrowserView *browser([[[class_ alloc] initWithBook:book] autorelease]);
3ac7a20a
JF
614 [browser loadURL:url];
615 page = browser;
616 }
bde2d79b 617
3ac7a20a
JF
618 [book setDelegate:delegate_];
619 [page setDelegate:delegate_];
0a7e5478 620
3ac7a20a
JF
621 [book setPage:page];
622 [book_ pushBook:book];
623 }
04700693 624 } else goto unknown;
bde2d79b
JF
625
626 [listener ignore];
627 } else use:
628 [listener use];
629}
630
5889429e 631- (void) webView:(WebView *)sender decidePolicyForMIMEType:(NSString *)type request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
bde2d79b
JF
632 if ([WebView canShowMIMEType:type])
633 [listener use];
634 else {
635 // XXX: handle more mime types!
636 [listener ignore];
5889429e
JF
637
638 WebView *webview([webview_ webView]);
639 if (frame == [webview mainFrame])
bde2d79b
JF
640 [UIApp openURL:[request URL]];
641 }
642}
643
644- (void) webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)action request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
645 if (request == nil) ignore: {
646 [listener ignore];
647 return;
648 }
649
650 NSURL *url([request URL]);
5d8f1006 651 NSString *host([url host]);
bde2d79b
JF
652
653 if (url == nil) use: {
f4772bd1 654 if (!error_ && [frame parentFrame] == nil) {
bde2d79b
JF
655 if (request_ != nil)
656 [request_ autorelease];
657 request_ = [request retain];
1ce016d4 658#if LogBrowser
bde2d79b 659 NSLog(@"dpn:%@", request_);
04700693 660#endif
bde2d79b
JF
661 }
662
663 [listener use];
5889429e
JF
664
665 WebView *webview([webview_ webView]);
666 if (frame == [webview mainFrame])
667 [self _pushPage];
bde2d79b
JF
668 return;
669 }
1ce016d4 670#if LogBrowser
bde2d79b
JF
671 else NSLog(@"nav:%@:%@", url, [action description]);
672#endif
673
9d7f5e2d
JF
674 const NSArray *capability;
675
5d8f1006
JF
676 if ($GSSystemCopyCapability != NULL) {
677 capability = reinterpret_cast<const NSArray *>((*$GSSystemCopyCapability)(kGSDisplayIdentifiersCapability));
678 capability = [capability autorelease];
679 } else if ($GSSystemGetCapability != NULL) {
680 capability = reinterpret_cast<const NSArray *>((*$GSSystemGetCapability)(kGSDisplayIdentifiersCapability));
681 } else
682 capability = nil;
683
684 NSURL *open(nil);
bde2d79b 685
9d7f5e2d 686 if (capability != nil && (
5d8f1006
JF
687 [url isGoogleMapsURL] && [capability containsObject:@"com.apple.Maps"] && (open = [url mapsURL]) != nil||
688 [host hasSuffix:@"youtube.com"] && [capability containsObject:@"com.apple.youtube"] && (open = [url youTubeURL]) != nil ||
689 [url respondsToSelector:@selector(phobosURL)] && (open = [url phobosURL]) != nil
9d7f5e2d 690 )) {
5d8f1006 691 url = open;
bde2d79b
JF
692 open:
693 [UIApp openURL:url];
694 goto ignore;
695 }
696
697 int store(_not(int));
698 if (NSURL *itms = [url itmsURL:&store]) {
1ce016d4 699#if LogBrowser
bde2d79b 700 NSLog(@"itms#%@#%u#%@", url, store, itms);
7b00c562
JF
701#endif
702
9d7f5e2d 703 if (capability != nil && (
bde2d79b
JF
704 store == 1 && [capability containsObject:@"com.apple.MobileStore"] ||
705 store == 2 && [capability containsObject:@"com.apple.AppStore"]
9d7f5e2d 706 )) {
bde2d79b
JF
707 url = itms;
708 goto open;
709 }
710 }
711
712 NSString *scheme([[url scheme] lowercaseString]);
713
714 if ([scheme isEqualToString:@"tel"]) {
715 // XXX: intelligence
716 goto open;
717 }
718
719 if ([scheme isEqualToString:@"mailto"]) {
61b13cae 720 [self _openMailToURL:url];
bde2d79b
JF
721 goto ignore;
722 }
723
b8de369a 724 if ([self getSpecial:url swap:YES])
bde2d79b
JF
725 goto ignore;
726 else if ([WebView _canHandleRequest:request])
727 goto use;
728 else if ([url isSpringboardHandledURL])
729 goto open;
730 else
731 goto use;
732}
733
734- (void) webView:(WebView *)sender setStatusText:(NSString *)text {
735 //lprintf("Status:%s\n", [text UTF8String]);
736}
737
bde2d79b
JF
738- (void) alertSheet:(UIActionSheet *)sheet buttonClicked:(int)button {
739 NSString *context([sheet context]);
740
b456f1c9
JF
741 if ([context isEqualToString:@"alert"]) {
742 [self autorelease];
bde2d79b 743 [sheet dismiss];
b456f1c9 744 } else if ([context isEqualToString:@"confirm"]) {
bde2d79b
JF
745 switch (button) {
746 case 1:
747 confirm_ = [NSNumber numberWithBool:YES];
748 break;
749
750 case 2:
751 confirm_ = [NSNumber numberWithBool:NO];
752 break;
753 }
754
0fc560b6
JF
755 [sheet dismiss];
756 } else if ([context isEqualToString:@"sensitive"]) {
757 switch (button) {
758 case 1:
759 sensitive_ = [NSNumber numberWithBool:YES];
760 break;
761
762 case 2:
763 sensitive_ = [NSNumber numberWithBool:NO];
764 break;
765 }
766
bde2d79b
JF
767 [sheet dismiss];
768 } else if ([context isEqualToString:@"challenge"]) {
769 id<NSURLAuthenticationChallengeSender> sender([challenge_ sender]);
770
771 switch (button) {
772 case 1: {
773 NSString *username([[sheet textFieldAtIndex:0] text]);
774 NSString *password([[sheet textFieldAtIndex:1] text]);
775
776 NSURLCredential *credential([NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistenceForSession]);
777
778 [sender useCredential:credential forAuthenticationChallenge:challenge_];
779 } break;
780
781 case 2:
782 [sender cancelAuthenticationChallenge:challenge_];
783 break;
784
6981ccdf 785 _nodefault
bde2d79b
JF
786 }
787
788 [challenge_ release];
789 challenge_ = nil;
790
791 [sheet dismiss];
792 } else if ([context isEqualToString:@"submit"]) {
793 switch (button) {
794 case 1:
795 break;
796
797 case 2:
9d7f5e2d
JF
798 if (request_ != nil) {
799 WebThreadLock();
bde2d79b 800 [webview_ loadRequest:request_];
9d7f5e2d
JF
801 WebThreadUnlock();
802 }
bde2d79b
JF
803 break;
804
6981ccdf 805 _nodefault
bde2d79b
JF
806 }
807
808 [sheet dismiss];
809 }
810}
811
812- (void) webView:(WebView *)sender resource:(id)identifier didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge fromDataSource:(WebDataSource *)source {
813 challenge_ = [challenge retain];
814
815 NSURLProtectionSpace *space([challenge protectionSpace]);
816 NSString *realm([space realm]);
817 if (realm == nil)
818 realm = @"";
819
820 UIActionSheet *sheet = [[[UIActionSheet alloc]
821 initWithTitle:realm
61b13cae 822 buttons:[NSArray arrayWithObjects:UCLocalize("LOGIN"), UCLocalize("CANCEL"), nil]
bde2d79b
JF
823 defaultButtonIndex:0
824 delegate:self
825 context:@"challenge"
826 ] autorelease];
827
828 [sheet setNumberOfRows:1];
829
61b13cae
JF
830 [sheet addTextFieldWithValue:@"" label:UCLocalize("USERNAME")];
831 [sheet addTextFieldWithValue:@"" label:UCLocalize("PASSWORD")];
bde2d79b
JF
832
833 UITextField *username([sheet textFieldAtIndex:0]); {
834 UITextInputTraits *traits([username textInputTraits]);
835 [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone];
836 [traits setAutocorrectionType:UITextAutocorrectionTypeNo];
837 [traits setKeyboardType:UIKeyboardTypeASCIICapable];
838 [traits setReturnKeyType:UIReturnKeyNext];
839 }
840
841 UITextField *password([sheet textFieldAtIndex:1]); {
842 UITextInputTraits *traits([password textInputTraits]);
843 [traits setAutocapitalizationType:UITextAutocapitalizationTypeNone];
844 [traits setAutocorrectionType:UITextAutocorrectionTypeNo];
845 [traits setKeyboardType:UIKeyboardTypeASCIICapable];
846 // XXX: UIReturnKeyDone
847 [traits setReturnKeyType:UIReturnKeyNext];
848 [traits setSecureTextEntry:YES];
849 }
850
851 [sheet popupAlertAnimated:YES];
852}
853
854- (NSURLRequest *) webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)source {
61b13cae 855 return request;
bde2d79b
JF
856}
857
5a5c1e4b 858- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request windowFeatures:(NSDictionary *)features {
7b00c562 859//- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request userGesture:(BOOL)gesture {
1ce016d4 860#if LogBrowser
7b00c562
JF
861 NSLog(@"cwv:%@ (%@): %@", request, title_, features == nil ? @"{}" : [features description]);
862 //NSLog(@"cwv:%@ (%@): %@", request, title_, gesture ? @"Yes" : @"No");
5a5c1e4b 863#endif
bde2d79b 864
7b00c562 865 NSNumber *value([features objectForKey:@"width"]);
5889429e 866 float width(value == nil ? 0 : [value floatValue]);
7b00c562
JF
867
868 RVBook *book(!popup_ ? book_ : [[[RVPopUpBook alloc] initWithFrame:[delegate_ popUpBounds]] autorelease]);
869
870 /* XXX: deal with cydia:// pages */
85021801 871 BrowserView *browser([[[class_ alloc] initWithBook:book forWidth:width] autorelease]);
7b00c562 872
b456f1c9 873 if (features != nil && popup_) {
7b00c562 874 [book setDelegate:delegate_];
1ce016d4 875 [book setHook:indirect_];
7b00c562
JF
876 [browser setDelegate:delegate_];
877
878 [browser loadRequest:request];
a55054a2 879
7b00c562
JF
880 [book setPage:browser];
881 [book_ pushBook:book];
882 } else if (request == nil) {
a55054a2
JF
883 [self setBackButtonTitle:title_];
884 [browser setDelegate:delegate_];
885 [browser retain];
886 } else {
887 [self pushPage:browser];
888 [browser loadRequest:request];
889 }
890
bde2d79b
JF
891 return [browser webView];
892}
893
894- (WebView *) webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
5a5c1e4b 895 return [self webView:sender createWebViewWithRequest:request windowFeatures:nil];
7b00c562 896 //return [self webView:sender createWebViewWithRequest:request userGesture:YES];
bde2d79b
JF
897}
898
899- (void) webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame {
900 if ([frame parentFrame] != nil)
901 return;
902
903 title_ = [title retain];
904 [book_ reloadTitleForPage:self];
905}
906
907- (void) webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame {
017b2b71
JF
908 /*if ([loading_ count] == 0)
909 [self retain];*/
b452841e 910 [loading_ addObject:[NSValue valueWithNonretainedObject:frame]];
bde2d79b 911
9d7f5e2d
JF
912 if ([frame parentFrame] == nil) {
913 [webview_ resignFirstResponder];
5889429e 914
9d7f5e2d 915 reloading_ = false;
bde2d79b 916
9d7f5e2d
JF
917 if (title_ != nil) {
918 [title_ release];
919 title_ = nil;
920 }
bde2d79b 921
9d7f5e2d
JF
922 if (button_ != nil) {
923 [button_ release];
924 button_ = nil;
925 }
bde2d79b 926
9d7f5e2d
JF
927 if (style_ != nil) {
928 [style_ release];
929 style_ = nil;
930 }
bde2d79b 931
9d7f5e2d
JF
932 if (function_ != nil) {
933 [function_ release];
934 function_ = nil;
935 }
bde2d79b 936
9d7f5e2d
JF
937 if (finish_ != nil) {
938 [finish_ release];
939 finish_ = nil;
940 }
1ce016d4 941
9d7f5e2d
JF
942 if (closer_ != nil) {
943 [closer_ release];
944 closer_ = nil;
945 }
946
947 if (special_ != nil) {
948 [special_ release];
949 special_ = nil;
950 }
bde2d79b 951
9d7f5e2d
JF
952 [book_ reloadTitleForPage:self];
953
d4f84362
JF
954 CGRect webrect = [scroller_ bounds];
955 webrect.size.height = 1;
956 [webview_ setFrame:webrect];
957
958 if ([scroller_ respondsToSelector:@selector(scrollPointVisibleAtTopLeft:)])
959 [scroller_ scrollPointVisibleAtTopLeft:CGPointZero];
960 else
961 [scroller_ scrollRectToVisible:CGRectZero animated:NO];
9d7f5e2d
JF
962
963 if ([scroller_ respondsToSelector:@selector(setZoomScale:duration:)])
964 [scroller_ setZoomScale:1 duration:0];
f4cd7e8b
JF
965 else if ([scroller_ respondsToSelector:@selector(_setZoomScale:duration:)])
966 [scroller_ _setZoomScale:1 duration:0];
967 /*else if ([scroller_ respondsToSelector:@selector(setZoomScale:animated:)])
968 [scroller_ setZoomScale:1 animated:NO];*/
9d7f5e2d
JF
969 }
970
971 [self reloadButtons];
bde2d79b
JF
972}
973
974- (void) _finishLoading {
b452841e 975 size_t count([loading_ count]);
017b2b71
JF
976 /*if (count == 0)
977 [self autorelease];*/
b452841e 978 if (reloading_ || count != 0)
9d7f5e2d
JF
979 return;
980 if (finish_ != nil)
981 [self callFunction:finish_];
982 [self reloadButtons];
bde2d79b
JF
983}
984
1ce016d4 985- (bool) isLoading {
9d7f5e2d 986 return [loading_ count] != 0;
bde2d79b
JF
987}
988
989- (void) reloadButtons {
1ce016d4 990 if ([self isLoading])
bde2d79b
JF
991 [indicator_ startAnimation];
992 else
993 [indicator_ stopAnimation];
994 [super reloadButtons];
995}
996
997- (BOOL) webView:(WebView *)sender shouldScrollToPoint:(struct CGPoint)point forFrame:(WebFrame *)frame {
998 return [webview_ webView:sender shouldScrollToPoint:point forFrame:frame];
999}
1000
1001- (void) webView:(WebView *)sender didReceiveViewportArguments:(id)arguments forFrame:(WebFrame *)frame {
1002 return [webview_ webView:sender didReceiveViewportArguments:arguments forFrame:frame];
1003}
1004
1005- (void) webView:(WebView *)sender needsScrollNotifications:(id)notifications forFrame:(WebFrame *)frame {
1006 return [webview_ webView:sender needsScrollNotifications:notifications forFrame:frame];
1007}
1008
1009- (void) webView:(WebView *)sender didCommitLoadForFrame:(WebFrame *)frame {
10c3a9c1 1010 [self _pushPage];
bde2d79b
JF
1011 return [webview_ webView:sender didCommitLoadForFrame:frame];
1012}
1013
1014- (void) webView:(WebView *)sender didReceiveDocTypeForFrame:(WebFrame *)frame {
1015 return [webview_ webView:sender didReceiveDocTypeForFrame:frame];
1016}
1017
1018- (void) webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame {
b452841e 1019 [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
9d7f5e2d 1020 [self _finishLoading];
bde2d79b 1021
9d7f5e2d 1022 if ([frame parentFrame] == nil) {
bde2d79b
JF
1023 if (DOMDocument *document = [frame DOMDocument])
1024 if (DOMNodeList<NSFastEnumeration> *bodies = [document getElementsByTagName:@"body"])
1025 for (DOMHTMLBodyElement *body in bodies) {
1026 DOMCSSStyleDeclaration *style([document getComputedStyle:body pseudoElement:nil]);
1027
1028 bool colored(false);
1029
1030 if (DOMCSSPrimitiveValue *color = static_cast<DOMCSSPrimitiveValue *>([style getPropertyCSSValue:@"background-color"])) {
f4772bd1
JF
1031 if ([color primitiveType] == DOM_CSS_RGBCOLOR) {
1032 DOMRGBColor *rgb([color getRGBColorValue]);
1033
1034 float red([[rgb red] getFloatValue:DOM_CSS_NUMBER]);
1035 float green([[rgb green] getFloatValue:DOM_CSS_NUMBER]);
1036 float blue([[rgb blue] getFloatValue:DOM_CSS_NUMBER]);
1037 float alpha([[rgb alpha] getFloatValue:DOM_CSS_NUMBER]);
1038
1039 UIColor *uic(nil);
1040
1041 if (red == 0xc7 && green == 0xce && blue == 0xd5)
1042 uic = [UIColor pinStripeColor];
1043 else if (alpha != 0)
1044 uic = [UIColor
1045 colorWithRed:(red / 255)
1046 green:(green / 255)
1047 blue:(blue / 255)
1048 alpha:alpha
1049 ];
1050
1051 if (uic != nil) {
1052 colored = true;
1053 [scroller_ setBackgroundColor:uic];
1054 }
bde2d79b
JF
1055 }
1056 }
1057
1058 if (!colored)
1059 [scroller_ setBackgroundColor:[UIColor pinStripeColor]];
1060 break;
1061 }
1062 }
1063
1064 return [webview_ webView:sender didFinishLoadForFrame:frame];
1065}
1066
9d7f5e2d 1067- (void) _didFailWithError:(NSError *)error forFrame:(WebFrame *)frame {
017b2b71
JF
1068 _trace();
1069 /*if ([frame parentFrame] == nil)
1070 [self autorelease];*/
9d7f5e2d 1071
b452841e 1072 [loading_ removeObject:[NSValue valueWithNonretainedObject:frame]];
bde2d79b
JF
1073 [self _finishLoading];
1074
b452841e
JF
1075 if (reloading_)
1076 return;
1077
9d7f5e2d
JF
1078 if ([frame parentFrame] == nil) {
1079 [self loadURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?%@",
1080 [[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"error" ofType:@"html"]] absoluteString],
1081 [[error localizedDescription] stringByAddingPercentEscapes]
1082 ]]];
1083
1084 error_ = true;
1085 }
1086}
f4772bd1 1087
9d7f5e2d
JF
1088- (void) webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
1089 [self _didFailWithError:error forFrame:frame];
d4f84362
JF
1090 if ([webview_ respondsToSelector:@selector(webView:didFailLoadWithError:forFrame:)])
1091 [webview_ webView:sender didFailLoadWithError:error forFrame:frame];
9d7f5e2d
JF
1092}
1093
1094- (void) webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame {
1095 [self _didFailWithError:error forFrame:frame];
bde2d79b
JF
1096}
1097
1098- (void) webView:(WebView *)sender addMessageToConsole:(NSDictionary *)dictionary {
1ce016d4 1099#if LogBrowser || ForSaurik
bde2d79b
JF
1100 lprintf("Console:%s\n", [[dictionary description] UTF8String]);
1101#endif
1102}
1103
d4f84362
JF
1104- (void) webView:(WebView *)sender didReceiveMessage:(NSDictionary *)dictionary {
1105#if LogBrowser || ForSaurik
1106 lprintf("Console:%s\n", [[dictionary description] UTF8String]);
1107#endif
1108 if ([webview_ respondsToSelector:@selector(webView:didReceiveMessage:)])
1109 [webview_ webView:sender didReceiveMessage:dictionary];
1110}
1111
1112- (void) webView:(id)sender willCloseFrame:(id)frame {
1113 if ([webview_ respondsToSelector:@selector(webView:willCloseFrame:)])
1114 [webview_ webView:sender willCloseFrame:frame];
1115}
1116
1117- (void) webView:(id)sender didFinishDocumentLoadForFrame:(id)frame {
1118 if ([webview_ respondsToSelector:@selector(webView:didFinishDocumentLoadForFrame:)])
1119 [webview_ webView:sender didFinishDocumentLoadForFrame:frame];
1120}
1121
1122- (void) webView:(id)sender didFirstLayoutInFrame:(id)frame {
1123 if ([webview_ respondsToSelector:@selector(webView:didFirstLayoutInFrame:)])
1124 [webview_ webView:sender didFirstLayoutInFrame:frame];
1125}
1126
1127- (void) webViewFormEditedStatusHasChanged:(id)changed {
1128 if ([webview_ respondsToSelector:@selector(webViewFormEditedStatusHasChanged:)])
1129 [webview_ webViewFormEditedStatusHasChanged:changed];
1130}
1131
1132- (void) webView:(id)sender formStateDidFocusNode:(id)formState {
1133 if ([webview_ respondsToSelector:@selector(webView:formStateDidFocusNode:)])
1134 [webview_ webView:sender formStateDidFocusNode:formState];
1135}
1136
1137- (void) webView:(id)sender formStateDidBlurNode:(id)formState {
1138 if ([webview_ respondsToSelector:@selector(webView:formStateDidBlurNode:)])
1139 [webview_ webView:sender formStateDidBlurNode:formState];
1140}
1141
9d7f5e2d
JF
1142/* XXX: fix this stupid include file
1143- (void) webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(WebSecurityOrigin *)origin database:(NSString *)database {
1144 [origin setQuota:0x500000];
1145}*/
1146
d4f84362
JF
1147- (void) webViewDidLayout:(id)sender {
1148 [webview_ webViewDidLayout:sender];
1149}
1150
1151- (void) webView:(id)sender didFirstVisuallyNonEmptyLayoutInFrame:(id)frame {
1152 [webview_ webView:sender didFirstVisuallyNonEmptyLayoutInFrame:frame];
1153}
1154
1155- (void) webView:(id)sender saveStateToHistoryItem:(id)item forFrame:(id)frame {
1156 [webview_ webView:sender saveStateToHistoryItem:item forFrame:frame];
1157}
1158
1159- (void) webView:(id)sender restoreStateFromHistoryItem:(id)item forFrame:(id)frame force:(BOOL)force {
1160 [webview_ webView:sender restoreStateFromHistoryItem:item forFrame:frame force:force];
1161}
1162
1163- (void) webView:(id)sender attachRootLayer:(id)layer {
1164 [webview_ webView:sender attachRootLayer:layer];
1165}
1166
1167- (id) webView:(id)sender plugInViewWithArguments:(id)arguments fromPlugInPackage:(id)package {
1168 return [webview_ webView:sender plugInViewWithArguments:arguments fromPlugInPackage:package];
1169}
1170
1171- (void) webView:(id)sender willShowFullScreenForPlugInView:(id)view {
1172 [webview_ webView:sender willShowFullScreenForPlugInView:view];
1173}
1174
1175- (void) webView:(id)sender didHideFullScreenForPlugInView:(id)view {
1176 [webview_ webView:sender didHideFullScreenForPlugInView:view];
1177}
1178
1179- (void) webView:(id)sender willAddPlugInView:(id)view {
1180 [webview_ webView:sender willAddPlugInView:view];
1181}
1182
1183- (void) webView:(id)sender didObserveDeferredContentChange:(int)change forFrame:(id)frame {
1184 [webview_ webView:sender didObserveDeferredContentChange:change forFrame:frame];
1185}
1186
1187- (void) webViewDidPreventDefaultForEvent:(id)sender {
1188 [webview_ webViewDidPreventDefaultForEvent:sender];
1189}
1190
9d7f5e2d
JF
1191- (void) _setTileDrawingEnabled:(BOOL)enabled {
1192 //[webview_ setTileDrawingEnabled:enabled];
1193}
1194
dcc55b8b 1195- (void) setViewportWidth:(float)width {
0a523b5a 1196 width_ = width != 0 ? width : [[self class] defaultWidth];
dcc55b8b
JF
1197 [webview_ setViewportSize:CGSizeMake(width_, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10];
1198}
1199
9d7f5e2d
JF
1200- (void) willStartGesturesInView:(UIView *)view forEvent:(GSEventRef)event {
1201 [self _setTileDrawingEnabled:NO];
1202}
1203
1204- (void) didFinishGesturesInView:(UIView *)view forEvent:(GSEventRef)event {
1205 [self _setTileDrawingEnabled:YES];
1206 [webview_ redrawScaledDocument];
1207}
1208
1209- (void) scrollerWillStartDragging:(UIScroller *)scroller {
1210 [self _setTileDrawingEnabled:NO];
1211}
1212
1213- (void) scrollerDidEndDragging:(UIScroller *)scroller willSmoothScroll:(BOOL)smooth {
1214 [self _setTileDrawingEnabled:YES];
1215}
1216
1217- (void) scrollerDidEndDragging:(UIScroller *)scroller {
1218 [self _setTileDrawingEnabled:YES];
1219}
1220
85021801 1221- (id) initWithBook:(RVBook *)book forWidth:(float)width ofClass:(Class)_class {
bde2d79b 1222 if ((self = [super initWithBook:book]) != nil) {
85021801 1223 class_ = _class;
9d7f5e2d 1224 loading_ = [[NSMutableSet alloc] initWithCapacity:3];
7b00c562 1225 popup_ = false;
bde2d79b
JF
1226
1227 struct CGRect bounds = [self bounds];
1228
d4f84362 1229 scroller_ = [[UIScrollView alloc] initWithFrame:bounds];
bde2d79b
JF
1230 [self addSubview:scroller_];
1231
bde2d79b
JF
1232 [scroller_ setFixedBackgroundPattern:YES];
1233 [scroller_ setBackgroundColor:[UIColor pinStripeColor]];
1234
1235 [scroller_ setScrollingEnabled:YES];
bde2d79b 1236 [scroller_ setClipsSubviews:YES];
d4f84362
JF
1237
1238 if (false)
1239 [scroller_ setAllowsRubberBanding:YES];
9d7f5e2d 1240
bde2d79b 1241 [scroller_ setDelegate:self];
9d7f5e2d 1242 [scroller_ setBounces:YES];
d4f84362
JF
1243
1244 if (false) {
1245 [scroller_ setScrollHysteresis:8];
1246 [scroller_ setThumbDetectionEnabled:NO];
1247 [scroller_ setDirectionalScrolling:YES];
1248 [scroller_ setScrollDecelerationFactor:0.99]; /* 0.989324 */
1249 [scroller_ setEventMode:YES];
1250 }
1251
9d7f5e2d 1252 [scroller_ setShowBackgroundShadow:NO]; /* YES */
d4f84362
JF
1253 //[scroller_ setAllowsRubberBanding:YES]; /* Vertical */
1254
1255 if (false)
1256 [scroller_ setAdjustForContentSizeChange:YES]; /* NO */
bde2d79b
JF
1257
1258 CGRect webrect = [scroller_ bounds];
1259 webrect.size.height = 0;
1260
1261 WebView *webview;
1262
9d7f5e2d
JF
1263 WebThreadLock();
1264
bde2d79b
JF
1265#if RecycleWebViews
1266 webview_ = [Documents_ lastObject];
1267 if (webview_ != nil) {
1268 webview_ = [webview_ retain];
1269 webview = [webview_ webView];
1270 [Documents_ removeLastObject];
1271 [webview_ setFrame:webrect];
1272 } else {
1273#else
1274 if (true) {
1275#endif
d4f84362 1276 webview_ = [[$UIWebBrowserView alloc] initWithFrame:webrect];
bde2d79b
JF
1277 webview = [webview_ webView];
1278
1279 // XXX: this is terribly (too?) expensive
1280 //[webview_ setDrawsBackground:NO];
1281 [webview setPreferencesIdentifier:@"Cydia"];
1282
1283 [webview_ setTileSize:CGSizeMake(webrect.size.width, 500)];
1284
4825688a
JF
1285 if ([webview_ respondsToSelector:@selector(enableReachability)])
1286 [webview_ enableReachability];
d4f84362
JF
1287 if ([webview_ respondsToSelector:@selector(setAllowsMessaging:)])
1288 [webview_ setAllowsMessaging:YES];
4825688a
JF
1289 if ([webview_ respondsToSelector:@selector(useSelectionAssistantWithMode:)])
1290 [webview_ useSelectionAssistantWithMode:0];
1291
bde2d79b
JF
1292 [webview_ setTilingEnabled:YES];
1293 [webview_ setDrawsGrid:NO];
1294 [webview_ setLogsTilingChanges:NO];
1295 [webview_ setTileMinificationFilter:kCAFilterNearest];
4825688a 1296
9d7f5e2d
JF
1297 if ([webview_ respondsToSelector:@selector(setDataDetectorTypes:)])
1298 /* XXX: abstractify */
1299 [webview_ setDataDetectorTypes:0x80000000];
1300 else
1301 [webview_ setDetectsPhoneNumbers:NO];
4825688a 1302
bde2d79b
JF
1303 [webview_ setAutoresizes:YES];
1304
1305 [webview_ setMinimumScale:0.25f forDocumentTypes:0x10];
7b00c562 1306 [webview_ setMaximumScale:5.00f forDocumentTypes:0x10];
bde2d79b 1307 [webview_ setInitialScale:UIWebViewScalesToFitScale forDocumentTypes:0x10];
7b00c562 1308 //[webview_ setViewportSize:CGSizeMake(980, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x10];
bde2d79b
JF
1309
1310 [webview_ setViewportSize:CGSizeMake(320, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x2];
1311
7b00c562 1312 [webview_ setMinimumScale:1.00f forDocumentTypes:0x8];
bde2d79b
JF
1313 [webview_ setInitialScale:UIWebViewScalesToFitScale forDocumentTypes:0x8];
1314 [webview_ setViewportSize:CGSizeMake(320, UIWebViewGrowsAndShrinksToFitHeight) forDocumentTypes:0x8];
1315
1316 [webview_ _setDocumentType:0x4];
1317
d4f84362 1318 if ([webview_ respondsToSelector:@selector(setZoomsFocusedFormControl:)])
9d7f5e2d 1319 [webview_ setZoomsFocusedFormControl:YES];
bde2d79b
JF
1320 [webview_ setContentsPosition:7];
1321 [webview_ setEnabledGestures:0xa];
1322 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeIsZoomRubberBandEnabled];
1323 [webview_ setValue:[NSNumber numberWithBool:YES] forGestureAttribute:UIGestureAttributeUpdatesScroller];
1324
1325 [webview_ setSmoothsFonts:YES];
7b00c562 1326 [webview_ setAllowsImageSheet:YES];
bde2d79b 1327 [webview _setUsesLoaderCache:YES];
7b00c562
JF
1328
1329 [webview setGroupName:@"CydiaGroup"];
4825688a
JF
1330
1331 WebPreferences *preferences([webview preferences]);
1332
9d7f5e2d
JF
1333 if ([webview respondsToSelector:@selector(_setLayoutInterval:)])
1334 [webview _setLayoutInterval:0];
4825688a
JF
1335 else
1336 [preferences _setLayoutInterval:0];
bde2d79b
JF
1337 }
1338
dcc55b8b 1339 [self setViewportWidth:width];
7b00c562 1340
bde2d79b
JF
1341 [webview_ setDelegate:self];
1342 [webview_ setGestureDelegate:self];
d4f84362
JF
1343
1344 if ([webview_ respondsToSelector:@selector(setFormEditingDelegate:)])
1345 [webview_ setFormEditingDelegate:self];
1346
dcc55b8b
JF
1347 [webview_ setInteractionDelegate:self];
1348
bde2d79b
JF
1349 [scroller_ addSubview:webview_];
1350
1351 //NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
1352
bde2d79b
JF
1353 indirect_ = [[IndirectDelegate alloc] initWithDelegate:self];
1354
9d7f5e2d 1355 [webview setFrameLoadDelegate:indirect_];
4825688a 1356 [webview setPolicyDelegate:indirect_];
bde2d79b 1357 [webview setResourceLoadDelegate:indirect_];
9d7f5e2d 1358 [webview setUIDelegate:indirect_];
4825688a
JF
1359
1360 /* XXX: do not turn this on under penalty of extreme pain */
1361 [webview setScriptDebugDelegate:nil];
9d7f5e2d
JF
1362
1363 WebThreadUnlock();
1364
1365 CGSize indsize = [UIProgressIndicator defaultSizeForStyle:UIProgressIndicatorStyleMediumWhite];
d4f84362 1366 indicator_ = [[UIProgressIndicator alloc] initWithFrame:CGRectMake(bounds.size.width - 39, 12, indsize.width, indsize.height)];
9d7f5e2d 1367 [indicator_ setStyle:UIProgressIndicatorStyleMediumWhite];
bde2d79b
JF
1368
1369 [self setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
1370 [scroller_ setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
9d7f5e2d
JF
1371
1372 /*UIWebView *test([[[UIWebView alloc] initWithFrame:[self bounds]] autorelease]);
1373 [test loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.saurik.com/"]]];
1374 [self addSubview:test];*/
bde2d79b
JF
1375 } return self;
1376}
1377
85021801
JF
1378- (id) initWithBook:(RVBook *)book forWidth:(float)width {
1379 return [self initWithBook:book forWidth:width ofClass:[self class]];
1380}
1381
7b00c562 1382- (id) initWithBook:(RVBook *)book {
5889429e 1383 return [self initWithBook:book forWidth:0];
7b00c562
JF
1384}
1385
9d7f5e2d
JF
1386- (NSString *) stringByEvaluatingJavaScriptFromString:(NSString *)script {
1387 WebThreadLock();
1388 WebView *webview([webview_ webView]);
1389 NSString *string([webview stringByEvaluatingJavaScriptFromString:script]);
1390 WebThreadUnlock();
1391 return string;
bde2d79b
JF
1392}
1393
1ce016d4 1394- (void) callFunction:(WebScriptObject *)function {
9d7f5e2d
JF
1395 WebThreadLock();
1396
1ce016d4
JF
1397 WebView *webview([webview_ webView]);
1398 WebFrame *frame([webview mainFrame]);
bde2d79b 1399
1ce016d4
JF
1400 id _private(MSHookIvar<id>(webview, "_private"));
1401 WebCore::Page *page(_private == nil ? NULL : MSHookIvar<WebCore::Page *>(_private, "page"));
1402 WebCore::Settings *settings(page == NULL ? NULL : page->settings());
bde2d79b 1403
1ce016d4
JF
1404 bool no;
1405 if (settings == NULL)
1406 no = 0;
1407 else {
1408 no = settings->JavaScriptCanOpenWindowsAutomatically();
1409 settings->setJavaScriptCanOpenWindowsAutomatically(true);
bde2d79b 1410 }
1ce016d4 1411
61b13cae
JF
1412 if (UIWindow *window = [self window])
1413 if (UIResponder *responder = [window firstResponder])
1414 [responder resignFirstResponder];
1415
1ce016d4
JF
1416 JSObjectRef object([function JSObject]);
1417 JSGlobalContextRef context([frame globalContext]);
1418 JSObjectCallAsFunction(context, object, NULL, 0, NULL, NULL);
1419
1420 if (settings != NULL)
9d7f5e2d
JF
1421 settings->setJavaScriptCanOpenWindowsAutomatically(no);
1422
1423 WebThreadUnlock();
1ce016d4
JF
1424}
1425
1426- (void) didCloseBook:(RVBook *)book {
1427 if (closer_ != nil)
1428 [self callFunction:closer_];
1429}
1430
1431- (void) __rightButtonClicked {
1432 reloading_ = true;
1433 [self reloadURL];
1434}
1435
1436- (void) _rightButtonClicked {
9d7f5e2d
JF
1437#if !AlwaysReload
1438 if (function_ != nil)
1ce016d4 1439 [self callFunction:function_];
9d7f5e2d
JF
1440 else
1441#endif
1442 [self __rightButtonClicked];
bde2d79b
JF
1443}
1444
1445- (id) _rightButtonTitle {
61b13cae 1446 return UCLocalize("RELOAD");
bde2d79b
JF
1447}
1448
1449- (id) rightButtonTitle {
1ce016d4 1450 return [self isLoading] ? @"" : button_ != nil ? button_ : [self _rightButtonTitle];
bde2d79b
JF
1451}
1452
1453- (UINavigationButtonStyle) rightButtonStyle {
1454 if (style_ == nil) normal:
1455 return UINavigationButtonStyleNormal;
1456 else if ([style_ isEqualToString:@"Normal"])
1457 return UINavigationButtonStyleNormal;
1458 else if ([style_ isEqualToString:@"Back"])
1459 return UINavigationButtonStyleBack;
1460 else if ([style_ isEqualToString:@"Highlighted"])
1461 return UINavigationButtonStyleHighlighted;
1462 else if ([style_ isEqualToString:@"Destructive"])
1463 return UINavigationButtonStyleDestructive;
1464 else goto normal;
1465}
1466
1467- (NSString *) title {
61b13cae 1468 return title_ == nil ? UCLocalize("LOADING") : title_;
bde2d79b
JF
1469}
1470
1471- (NSString *) backButtonTitle {
61b13cae 1472 return UCLocalize("BROWSER");
bde2d79b
JF
1473}
1474
1475- (void) setPageActive:(BOOL)active {
1476 if (!active)
1477 [indicator_ removeFromSuperview];
1478 else
1479 [[book_ navigationBar] addSubview:indicator_];
1480}
1481
1482- (void) resetViewAnimated:(BOOL)animated {
1483}
1484
1485- (void) setPushed:(bool)pushed {
1486 pushed_ = pushed;
1487}
1488
7b00c562
JF
1489+ (float) defaultWidth {
1490 return 980;
1491}
1492
bde2d79b 1493@end