blob: 35c4186a9c6fd825ef99b17bc311d6061f6d4e49 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.browser;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.cocoa.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
@SuppressWarnings({"rawtypes"})
class WebKit extends WebBrowser {
WebView webView;
WebPreferences preferences;
SWTWebViewDelegate delegate;
boolean loadingText, untrustedText;
String lastHoveredLinkURL, lastNavigateURL;
String html;
long /*int*/ identifier;
int resourceCount;
String url = ""; //$NON-NLS-1$
Point location;
Point size;
boolean statusBar = true, toolBar = true, ignoreDispose;
int lastMouseMoveX, lastMouseMoveY;
//TEMPORARY CODE
// boolean doit;
static long /*int*/ delegateClass;
static boolean Initialized;
// the following Callbacks are never freed
static Callback Callback3, Callback4, Callback5, Callback6, Callback7;
static final int MIN_SIZE = 16;
static final int MAX_PROGRESS = 100;
static final String WebElementLinkURLKey = "WebElementLinkURL"; //$NON-NLS-1$
static final String AGENT_STRING = "Safari/522.0"; /* Safari version on OSX 10.5 initial release */ //$NON-NLS-1$
static final String URI_FILEROOT = "file:///"; //$NON-NLS-1$
static final String PROTOCOL_FILE = "file://"; //$NON-NLS-1$
static final String PROTOCOL_HTTP = "http://"; //$NON-NLS-1$
static final String ABOUT_BLANK = "about:blank"; //$NON-NLS-1$
static final String HEADER_SETCOOKIE = "Set-Cookie"; //$NON-NLS-1$
static final String POST = "POST"; //$NON-NLS-1$
static final String USER_AGENT = "user-agent"; //$NON-NLS-1$
static final String ADD_WIDGET_KEY = "org.eclipse.swt.internal.addWidget"; //$NON-NLS-1$
static final String WEBKIT_EVENTS_FIX_KEY = "org.eclipse.swt.internal.webKitEventsFix"; //$NON-NLS-1$
static final byte[] SWT_OBJECT = {'S', 'W', 'T', '_', 'O', 'B', 'J', 'E', 'C', 'T', '\0'};
/* event strings */
static final String DOMEVENT_KEYUP = "keyup"; //$NON-NLS-1$
static final String DOMEVENT_KEYDOWN = "keydown"; //$NON-NLS-1$
static final String DOMEVENT_MOUSEDOWN = "mousedown"; //$NON-NLS-1$
static final String DOMEVENT_MOUSEUP = "mouseup"; //$NON-NLS-1$
static final String DOMEVENT_MOUSEMOVE = "mousemove"; //$NON-NLS-1$
static final String DOMEVENT_MOUSEWHEEL = "mousewheel"; //$NON-NLS-1$
static {
NativeClearSessions = new Runnable() {
public void run() {
NSHTTPCookieStorage storage = NSHTTPCookieStorage.sharedHTTPCookieStorage();
NSArray cookies = storage.cookies();
int count = (int)/*64*/cookies.count ();
for (int i = 0; i < count; i++) {
NSHTTPCookie cookie = new NSHTTPCookie(cookies.objectAtIndex(i));
if (cookie.isSessionOnly()) {
storage.deleteCookie(cookie);
}
}
}
};
NativeGetCookie = new Runnable () {
public void run () {
NSHTTPCookieStorage storage = NSHTTPCookieStorage.sharedHTTPCookieStorage ();
NSURL url = NSURL.URLWithString (NSString.stringWith (CookieUrl));
NSArray cookies = storage.cookiesForURL (url);
int count = (int)/*64*/cookies.count ();
if (count == 0) return;
NSString name = NSString.stringWith (CookieName);
for (int i = 0; i < count; i++) {
NSHTTPCookie current = new NSHTTPCookie (cookies.objectAtIndex (i));
if (current.name ().compare (name) == OS.NSOrderedSame) {
CookieValue = current.value ().getString ();
return;
}
}
}
};
NativeSetCookie = new Runnable () {
public void run () {
NSURL url = NSURL.URLWithString (NSString.stringWith (CookieUrl));
NSMutableDictionary headers = NSMutableDictionary.dictionaryWithCapacity (1);
headers.setValue (NSString.stringWith (CookieValue), NSString.stringWith (HEADER_SETCOOKIE));
NSArray cookies = NSHTTPCookie.cookiesWithResponseHeaderFields (headers, url);
if (cookies.count () == 0) return;
NSHTTPCookieStorage storage = NSHTTPCookieStorage.sharedHTTPCookieStorage ();
NSHTTPCookie cookie = new NSHTTPCookie (cookies.objectAtIndex (0));
storage.setCookie (cookie);
CookieResult = true;
}
};
if (NativePendingCookies != null) {
SetPendingCookies (NativePendingCookies);
}
NativePendingCookies = null;
}
public void create (Composite parent, int style) {
if (delegateClass == 0) {
Class webKitClass = this.getClass();
Callback3 = new Callback(webKitClass, "browserProc", 3); //$NON-NLS-1$
long /*int*/ proc3 = Callback3.getAddress();
if (proc3 == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
Callback4 = new Callback(webKitClass, "browserProc", 4); //$NON-NLS-1$
long /*int*/ proc4 = Callback4.getAddress();
if (proc4 == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
Callback5 = new Callback(webKitClass, "browserProc", 5); //$NON-NLS-1$
long /*int*/ proc5 = Callback5.getAddress();
if (proc5 == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
Callback6 = new Callback(webKitClass, "browserProc", 6); //$NON-NLS-1$
long /*int*/ proc6 = Callback6.getAddress();
if (proc6 == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
Callback7 = new Callback(webKitClass, "browserProc", 7); //$NON-NLS-1$
long /*int*/ proc7 = Callback7.getAddress();
if (proc7 == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
long /*int*/ setFrameProc = OS.CALLBACK_webView_setFrame_(proc4);
if (setFrameProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
String className = "SWTWebViewDelegate"; //$NON-NLS-1$
byte[] types = {'*','\0'};
int size = C.PTR_SIZEOF, align = C.PTR_SIZEOF == 4 ? 2 : 3;
delegateClass = OS.objc_allocateClassPair (OS.class_NSObject, className, 0);
OS.class_addIvar(delegateClass, SWT_OBJECT, size, (byte)align, types);
OS.class_addMethod(delegateClass, OS.sel_webView_didChangeLocationWithinPageForFrame_, proc4, "@:@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_didFailProvisionalLoadWithError_forFrame_, proc5, "@:@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_didFinishLoadForFrame_, proc4, "@:@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_didReceiveTitle_forFrame_, proc5, "@:@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_didStartProvisionalLoadForFrame_, proc4, "@:@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_didCommitLoadForFrame_, proc4, "@:@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_resource_didFinishLoadingFromDataSource_, proc5, "@:@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_resource_didReceiveAuthenticationChallenge_fromDataSource_, proc6, "@:@@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_resource_didFailLoadingWithError_fromDataSource_, proc6, "@:@@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_identifierForInitialRequest_fromDataSource_, proc5, "@:@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_resource_willSendRequest_redirectResponse_fromDataSource_, proc7, "@:@@@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_createWebViewWithRequest_, proc4, "@:@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webViewShow_, proc3, "@:@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webViewClose_, proc3, "@:@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_contextMenuItemsForElement_defaultMenuItems_, proc5, "@:@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_setStatusBarVisible_, proc4, "@:@B"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_setResizable_, proc4, "@:@B"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_setToolbarsVisible_, proc4, "@:@B"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_setStatusText_, proc4, "@:@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webViewFocus_, proc3, "@:@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webViewUnfocus_, proc3, "@:@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_runBeforeUnloadConfirmPanelWithMessage_initiatedByFrame_, proc5, "@:@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_runJavaScriptAlertPanelWithMessage_, proc4, "@:@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_runJavaScriptAlertPanelWithMessage_initiatedByFrame_, proc5, "@:@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_runJavaScriptConfirmPanelWithMessage_, proc4, "@:@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_runJavaScriptConfirmPanelWithMessage_initiatedByFrame_, proc5, "@:@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_runOpenPanelForFileButtonWithResultListener_, proc4, "@:@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_mouseDidMoveOverElement_modifierFlags_, proc5, "@:@@I"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_printFrameView_, proc4, "@:@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_decidePolicyForMIMEType_request_frame_decisionListener_, proc7, "@:@@@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_decidePolicyForNavigationAction_request_frame_decisionListener_, proc7, "@:@@@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener_, proc7, "@:@@@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_unableToImplementPolicyWithError_frame_, proc5, "@:@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_download_decideDestinationWithSuggestedFilename_, proc4, "@:@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_handleEvent_, proc3, "@:@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_setFrame_, setFrameProc, "@:@{NSRect}"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_webView_windowScriptObjectAvailable_, proc4, "@:@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_callJava, proc6, "@:@@@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_callRunBeforeUnloadConfirmPanelWithMessage, proc4, "@:@@"); //$NON-NLS-1$
OS.class_addMethod(delegateClass, OS.sel_createPanelDidEnd, proc5, "@:@@@"); //$NON-NLS-1$
OS.objc_registerClassPair(delegateClass);
long /*int*/ metaClass = OS.objc_getMetaClass (className);
OS.class_addMethod(metaClass, OS.sel_isSelectorExcludedFromWebScript_, proc3, "@:@"); //$NON-NLS-1$
OS.class_addMethod(metaClass, OS.sel_webScriptNameForSelector_, proc3, "@:@"); //$NON-NLS-1$
}
/*
* Override the default event mechanism to not send key events so
* that the browser can send them by listening to the DOM instead.
*/
browser.setData(WEBKIT_EVENTS_FIX_KEY);
WebView webView = (WebView)new WebView().alloc();
if (webView == null) SWT.error(SWT.ERROR_NO_HANDLES);
webView.initWithFrame(browser.view.frame(), null, null);
webView.setAutoresizingMask(OS.NSViewWidthSizable | OS.NSViewHeightSizable);
if (webView.respondsToSelector(OS.sel__setDashboardBehavior)) {
OS.objc_msgSend(webView.id, OS.sel__setDashboardBehavior, 2, 1);
}
final SWTWebViewDelegate delegate = (SWTWebViewDelegate)new SWTWebViewDelegate().alloc().init();
Display display = browser.getDisplay();
display.setData(ADD_WIDGET_KEY, new Object[] {delegate, browser});
this.delegate = delegate;
this.webView = webView;
browser.view.addSubview(webView);
Listener listener = new Listener() {
public void handleEvent(Event e) {
switch (e.type) {
case SWT.FocusIn:
WebKit.this.webView.window().makeFirstResponder(WebKit.this.webView);
break;
case SWT.Dispose: {
/* make this handler run after other dispose listeners */
if (ignoreDispose) {
ignoreDispose = false;
break;
}
ignoreDispose = true;
browser.notifyListeners (e.type, e);
e.type = SWT.NONE;
/* Browser could have been disposed by one of the Dispose listeners */
if (!browser.isDisposed()) {
/* invoke onbeforeunload handlers */
if (!browser.isClosing) {
close (false);
}
e.display.setData(ADD_WIDGET_KEY, new Object[] {delegate, null});
}
WebKit.this.webView.setFrameLoadDelegate(null);
WebKit.this.webView.setResourceLoadDelegate(null);
WebKit.this.webView.setUIDelegate(null);
WebKit.this.webView.setPolicyDelegate(null);
WebKit.this.webView.setDownloadDelegate(null);
WebKit.this.webView.release();
WebKit.this.webView = null;
WebKit.this.delegate.release();
WebKit.this.delegate = null;
html = null;
lastHoveredLinkURL = lastNavigateURL = null;
Enumeration elements = functions.elements ();
while (elements.hasMoreElements ()) {
((BrowserFunction)elements.nextElement ()).dispose (false);
}
functions = null;
if (preferences != null) preferences.release ();
preferences = null;
break;
}
}
}
};
browser.addListener(SWT.Dispose, listener);
browser.addListener(SWT.KeyDown, listener); /* needed for tabbing into the Browser */
browser.addListener(SWT.FocusIn, listener);
webView.setFrameLoadDelegate(delegate);
webView.setResourceLoadDelegate(delegate);
webView.setUIDelegate(delegate);
webView.setPolicyDelegate(delegate);
webView.setDownloadDelegate(delegate);
webView.setApplicationNameForUserAgent(NSString.stringWith(AGENT_STRING));
if (!Initialized) {
Initialized = true;
/* disable applets */
WebPreferences.standardPreferences().setJavaEnabled(false);
}
}
public boolean back() {
html = null;
return webView.goBack();
}
static long /*int*/ browserProc(long /*int*/ id, long /*int*/ sel, long /*int*/ arg0) {
if (id == delegateClass) {
if (sel == OS.sel_isSelectorExcludedFromWebScript_) {
return isSelectorExcludedFromWebScript (arg0) ? 1 : 0;
} else if (sel == OS.sel_webScriptNameForSelector_) {
return webScriptNameForSelector (arg0);
}
}
Display d = Display.getCurrent();
if (d == null || d.isDisposed()) return 0;
Widget widget = d.findWidget(id);
if (widget == null) return 0;
WebKit webKit = (WebKit)((Browser)widget).webBrowser;
if (sel == OS.sel_webViewShow_) {
webKit.webViewShow(arg0);
} else if (sel == OS.sel_webViewClose_) {
webKit.webViewClose(arg0);
} else if (sel == OS.sel_webViewFocus_) {
webKit.webViewFocus(arg0);
} else if (sel == OS.sel_webViewUnfocus_) {
webKit.webViewUnfocus(arg0);
} else if (sel == OS.sel_handleEvent_) {
webKit.handleEvent(arg0);
}
return 0;
}
static long /*int*/ browserProc(long /*int*/ id, long /*int*/ sel, long /*int*/ arg0, long /*int*/ arg1) {
Display d = Display.getCurrent();
if (d == null || d.isDisposed()) return 0;
Widget widget = d.findWidget(id);
if (widget == null) return 0;
WebKit webKit = (WebKit)((Browser)widget).webBrowser;
if (sel == OS.sel_webView_didChangeLocationWithinPageForFrame_) {
webKit.webView_didChangeLocationWithinPageForFrame(arg0, arg1);
} else if (sel == OS.sel_webView_didFinishLoadForFrame_) {
webKit.webView_didFinishLoadForFrame(arg0, arg1);
} else if (sel == OS.sel_webView_didStartProvisionalLoadForFrame_) {
webKit.webView_didStartProvisionalLoadForFrame(arg0, arg1);
} else if (sel == OS.sel_webView_didCommitLoadForFrame_) {
webKit.webView_didCommitLoadForFrame(arg0, arg1);
} else if (sel == OS.sel_webView_setFrame_) {
webKit.webView_setFrame(arg0, arg1);
} else if (sel == OS.sel_webView_createWebViewWithRequest_) {
return webKit.webView_createWebViewWithRequest(arg0, arg1);
} else if (sel == OS.sel_webView_setStatusBarVisible_) {
webKit.webView_setStatusBarVisible(arg0, arg1 != 0);
} else if (sel == OS.sel_webView_setResizable_) {
webKit.webView_setResizable(arg0, arg1 != 0);
} else if (sel == OS.sel_webView_setStatusText_) {
webKit.webView_setStatusText(arg0, arg1);
} else if (sel == OS.sel_webView_setToolbarsVisible_) {
webKit.webView_setToolbarsVisible(arg0, arg1 != 0);
} else if (sel == OS.sel_webView_runJavaScriptAlertPanelWithMessage_) {
webKit.webView_runJavaScriptAlertPanelWithMessage(arg0, arg1);
} else if (sel == OS.sel_webView_runJavaScriptConfirmPanelWithMessage_) {
return webKit.webView_runJavaScriptConfirmPanelWithMessage(arg0, arg1);
} else if (sel == OS.sel_webView_runOpenPanelForFileButtonWithResultListener_) {
webKit.webView_runOpenPanelForFileButtonWithResultListener(arg0, arg1);
} else if (sel == OS.sel_download_decideDestinationWithSuggestedFilename_) {
webKit.download_decideDestinationWithSuggestedFilename(arg0, arg1);
} else if (sel == OS.sel_webView_printFrameView_) {
webKit.webView_printFrameView(arg0, arg1);
} else if (sel == OS.sel_webView_windowScriptObjectAvailable_) {
webKit.webView_windowScriptObjectAvailable (arg0, arg1);
} else if (sel == OS.sel_callRunBeforeUnloadConfirmPanelWithMessage) {
return webKit.callRunBeforeUnloadConfirmPanelWithMessage (arg0, arg1).id;
}
return 0;
}
static long /*int*/ browserProc(long /*int*/ id, long /*int*/ sel, long /*int*/ arg0, long /*int*/ arg1, long /*int*/ arg2) {
Display d = Display.getCurrent();
if (d == null || d.isDisposed()) return 0;
Widget widget = d.findWidget(id);
if (widget == null) return 0;
WebKit webKit = (WebKit)((Browser)widget).webBrowser;
if (sel == OS.sel_webView_didFailProvisionalLoadWithError_forFrame_) {
webKit.webView_didFailProvisionalLoadWithError_forFrame(arg0, arg1, arg2);
} else if (sel == OS.sel_webView_didReceiveTitle_forFrame_) {
webKit.webView_didReceiveTitle_forFrame(arg0, arg1, arg2);
} else if (sel == OS.sel_webView_resource_didFinishLoadingFromDataSource_) {
webKit.webView_resource_didFinishLoadingFromDataSource(arg0, arg1, arg2);
} else if (sel == OS.sel_webView_identifierForInitialRequest_fromDataSource_) {
return webKit.webView_identifierForInitialRequest_fromDataSource(arg0, arg1, arg2);
} else if (sel == OS.sel_webView_contextMenuItemsForElement_defaultMenuItems_) {
return webKit.webView_contextMenuItemsForElement_defaultMenuItems(arg0, arg1, arg2);
} else if (sel == OS.sel_webView_mouseDidMoveOverElement_modifierFlags_) {
webKit.webView_mouseDidMoveOverElement_modifierFlags(arg0, arg1, arg2);
} else if (sel == OS.sel_webView_unableToImplementPolicyWithError_frame_) {
webKit.webView_unableToImplementPolicyWithError_frame(arg0, arg1, arg2);
} else if (sel == OS.sel_webView_runBeforeUnloadConfirmPanelWithMessage_initiatedByFrame_) {
return webKit.webView_runBeforeUnloadConfirmPanelWithMessage_initiatedByFrame(arg0, arg1, arg2) ? 1 : 0;
} else if (sel == OS.sel_webView_runJavaScriptAlertPanelWithMessage_initiatedByFrame_) {
webKit.webView_runJavaScriptAlertPanelWithMessage(arg0, arg1);
} else if (sel == OS.sel_webView_runJavaScriptConfirmPanelWithMessage_initiatedByFrame_) {
return webKit.webView_runJavaScriptConfirmPanelWithMessage(arg0, arg1);
} else if (sel == OS.sel_createPanelDidEnd) {
webKit.createPanelDidEnd(arg0, arg1, arg2);
}
return 0;
}
static long /*int*/ browserProc(long /*int*/ id, long /*int*/ sel, long /*int*/ arg0, long /*int*/ arg1, long /*int*/ arg2, long /*int*/ arg3) {
Display d = Display.getCurrent();
if (d == null || d.isDisposed()) return 0;
Widget widget = d.findWidget(id);
if (widget == null) return 0;
WebKit webKit = (WebKit)((Browser)widget).webBrowser;
if (sel == OS.sel_webView_resource_didFailLoadingWithError_fromDataSource_) {
webKit.webView_resource_didFailLoadingWithError_fromDataSource(arg0, arg1, arg2, arg3);
} else if (sel == OS.sel_webView_resource_didReceiveAuthenticationChallenge_fromDataSource_) {
webKit.webView_resource_didReceiveAuthenticationChallenge_fromDataSource(arg0, arg1, arg2, arg3);
} else if (sel == OS.sel_callJava) {
id result = webKit.callJava(arg0, arg1, arg2, arg3);
return result == null ? 0 : result.id;
}
return 0;
}
static long /*int*/ browserProc(long /*int*/ id, long /*int*/ sel, long /*int*/ arg0, long /*int*/ arg1, long /*int*/ arg2, long /*int*/ arg3, long /*int*/ arg4) {
Display d = Display.getCurrent();
if (d == null || d.isDisposed()) return 0;
Widget widget = d.findWidget(id);
if (widget == null) return 0;
WebKit webKit = (WebKit)((Browser)widget).webBrowser;
if (sel == OS.sel_webView_resource_willSendRequest_redirectResponse_fromDataSource_) {
return webKit.webView_resource_willSendRequest_redirectResponse_fromDataSource(arg0, arg1, arg2, arg3, arg4);
} else if (sel == OS.sel_webView_decidePolicyForMIMEType_request_frame_decisionListener_) {
webKit.webView_decidePolicyForMIMEType_request_frame_decisionListener(arg0, arg1, arg2, arg3, arg4);
} else if (sel == OS.sel_webView_decidePolicyForNavigationAction_request_frame_decisionListener_) {
webKit.webView_decidePolicyForNavigationAction_request_frame_decisionListener(arg0, arg1, arg2, arg3, arg4);
} else if (sel == OS.sel_webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener_) {
webKit.webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener(arg0, arg1, arg2, arg3, arg4);
}
return 0;
}
static boolean isSelectorExcludedFromWebScript (long /*int*/ aSelector) {
return !(aSelector == OS.sel_callJava || aSelector == OS.sel_callRunBeforeUnloadConfirmPanelWithMessage);
}
static long /*int*/ webScriptNameForSelector (long /*int*/ aSelector) {
if (aSelector == OS.sel_callJava) {
return NSString.stringWith ("callJava").id; //$NON-NLS-1$
}
if (aSelector == OS.sel_callRunBeforeUnloadConfirmPanelWithMessage) {
return NSString.stringWith ("callRunBeforeUnloadConfirmPanelWithMessage").id; //$NON-NLS-1$
}
return 0;
}
public boolean close () {
return close (true);
}
boolean close (boolean showPrompters) {
if (!jsEnabled) return true;
String functionName = EXECUTE_ID + "CLOSE"; // $NON-NLS-1$
StringBuffer buffer = new StringBuffer ("function "); // $NON-NLS-1$
buffer.append (functionName);
buffer.append ("(win) {\n"); // $NON-NLS-1$
buffer.append ("var fn = win.onbeforeunload; if (fn != null) {try {var str = fn(); "); // $NON-NLS-1$
if (showPrompters) {
buffer.append ("if (str != null) { "); // $NON-NLS-1$
buffer.append ("var result = window.external.callRunBeforeUnloadConfirmPanelWithMessage(str);"); // $NON-NLS-1$
buffer.append ("if (!result) return false;}"); // $NON-NLS-1$
}
buffer.append ("} catch (e) {}}"); // $NON-NLS-1$
buffer.append ("try {for (var i = 0; i < win.frames.length; i++) {var result = "); // $NON-NLS-1$
buffer.append (functionName);
buffer.append ("(win.frames[i]); if (!result) return false;}} catch (e) {} return true;"); // $NON-NLS-1$
buffer.append ("\n};"); // $NON-NLS-1$
execute (buffer.toString ());
Boolean result = (Boolean)evaluate ("return " + functionName +"(window);"); // $NON-NLS-1$ // $NON-NLS-2$
if (result == null) return false;
return result.booleanValue ();
}
public boolean execute (String script) {
WebFrame frame = webView.mainFrame();
long /*int*/ context = frame.globalContext();
byte[] bytes = null;
try {
bytes = (script + '\0').getBytes("UTF-8"); //$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
bytes = (script + '\0').getBytes();
}
long /*int*/ scriptString = OS.JSStringCreateWithUTF8CString(bytes);
try {
bytes = (getUrl() + '\0').getBytes("UTF-8"); //$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
bytes = (getUrl() + '\0').getBytes();
}
long /*int*/ urlString = OS.JSStringCreateWithUTF8CString(bytes);
long /*int*/ result = OS.JSEvaluateScript(context, scriptString, 0, urlString, 0, null);
OS.JSStringRelease(urlString);
OS.JSStringRelease(scriptString);
return result != 0;
}
public boolean forward () {
html = null;
return webView.goForward();
}
public String getBrowserType () {
return "webkit"; //$NON-NLS-1$
}
public String getText() {
WebFrame mainFrame = webView.mainFrame();
WebDataSource dataSource = mainFrame.dataSource();
if (dataSource == null) return ""; //$NON-NLS-1$
WebDocumentRepresentation representation = dataSource.representation();
if (representation == null) return ""; //$NON-NLS-1$
NSString source = representation.documentSource();
if (source == null) return ""; //$NON-NLS-1$
return source.getString();
}
public String getUrl() {
/* WebKit auto-navigates to about:blank at startup */
if (url.length() == 0) return ABOUT_BLANK;
return url;
}
public boolean isBackEnabled() {
return webView.canGoBack();
}
public boolean isForwardEnabled() {
return webView.canGoForward();
}
public void refresh() {
html = null;
webView.reload(null);
}
public boolean setText(String html, boolean trusted) {
/*
* If this.html is not null then the about:blank page is already being loaded,
* so no navigate is required. Just set the html that is to be shown.
*/
boolean blankLoading = this.html != null;
this.html = html;
untrustedText = !trusted;
if (blankLoading) return true;
NSURL inURL = NSURL.URLWithString(NSString.stringWith (ABOUT_BLANK));
NSURLRequest request = NSURLRequest.requestWithURL(inURL);
WebFrame mainFrame = webView.mainFrame();
mainFrame.loadRequest(request);
return true;
}
public boolean setUrl(String url, String postData, String[] headers) {
html = null;
lastNavigateURL = url;
if (url.indexOf('/') == 0) {
url = PROTOCOL_FILE + url;
} else if (url.indexOf(':') == -1) {
url = PROTOCOL_HTTP + url;
}
NSString str = NSString.stringWith(url);
NSString unescapedStr = NSString.stringWith("%#"); //$NON-NLS-1$
long /*int*/ ptr = OS.CFURLCreateStringByAddingPercentEscapes(0, str.id, unescapedStr.id, 0, OS.kCFStringEncodingUTF8);
NSString escapedString = new NSString(ptr);
NSURL inURL = NSURL.URLWithString(escapedString);
OS.CFRelease(ptr);
NSMutableURLRequest request = (NSMutableURLRequest)NSMutableURLRequest.requestWithURL(inURL);
if (postData != null) {
request.setHTTPMethod(NSString.stringWith(POST));
byte[] bytes = postData.getBytes();
NSData data = NSData.dataWithBytes(bytes, bytes.length);
request.setHTTPBody(data);
}
if (headers != null) {
for (int i = 0; i < headers.length; i++) {
String current = headers[i];
if (current != null) {
int index = current.indexOf(':');
if (index != -1) {
String key = current.substring(0, index).trim();
String value = current.substring(index + 1).trim();
if (key.length() > 0 && value.length() > 0) {
if (key.equalsIgnoreCase(USER_AGENT)) {
/*
* Feature of WebKit. The user-agent header value cannot be overridden
* here. The workaround is to temporarily set the value on the WebView
* and then remove it after the loading of the request has begun.
*/
webView.setCustomUserAgent(NSString.stringWith(value));
} else {
request.setValue(NSString.stringWith(value), NSString.stringWith(key));
}
}
}
}
}
}
WebFrame mainFrame = webView.mainFrame();
mainFrame.loadRequest(request);
webView.setCustomUserAgent(null);
return true;
}
public void stop() {
html = null;
webView.stopLoading(null);
}
boolean translateMnemonics() {
return false;
}
/* WebFrameLoadDelegate */
void webView_didChangeLocationWithinPageForFrame(long /*int*/ sender, long /*int*/ frameID) {
WebFrame frame = new WebFrame(frameID);
WebDataSource dataSource = frame.dataSource();
NSURLRequest request = dataSource.request();
NSURL url = request.URL();
NSString s = url.absoluteString();
int length = (int)/*64*/s.length();
if (length == 0) return;
String url2 = s.getString();
/*
* If the URI indicates that the page is being rendered from memory
* (via setText()) then set it to about:blank to be consistent with IE.
*/
if (url2.equals (URI_FILEROOT)) {
url2 = ABOUT_BLANK;
} else {
length = URI_FILEROOT.length ();
if (url2.startsWith (URI_FILEROOT) && url2.charAt (length) == '#') {
url2 = ABOUT_BLANK + url2.substring (length);
}
}
final Display display = browser.getDisplay();
boolean top = frameID == webView.mainFrame().id;
if (top) {
StatusTextEvent statusText = new StatusTextEvent(browser);
statusText.display = display;
statusText.widget = browser;
statusText.text = url2;
for (int i = 0; i < statusTextListeners.length; i++) {
statusTextListeners[i].changed(statusText);
}
}
LocationEvent location = new LocationEvent(browser);
location.display = display;
location.widget = browser;
location.location = url2;
location.top = top;
for (int i = 0; i < locationListeners.length; i++) {
locationListeners[i].changed(location);
}
}
void webView_didFailProvisionalLoadWithError_forFrame(long /*int*/ sender, long /*int*/ error, long /*int*/ frame) {
if (frame == webView.mainFrame().id) {
/*
* Feature on WebKit. The identifier is used here as a marker for the events
* related to the top frame and the URL changes related to that top frame as
* they should appear on the location bar of a browser. It is expected to reset
* the identifier to 0 when the event didFinishLoadingFromDataSource related to
* the identifierForInitialRequest event is received. However, WebKit fires
* the didFinishLoadingFromDataSource event before the entire content of the
* top frame is loaded. It is possible to receive multiple willSendRequest
* events in this interval, causing the Browser widget to send unwanted
* Location.changing events. For this reason, the identifier is reset to 0
* when the top frame has either finished loading (didFinishLoadForFrame
* event) or failed (didFailProvisionalLoadWithError).
*/
identifier = 0;
}
NSError nserror = new NSError(error);
long /*int*/ errorCode = nserror.code();
if (OS.NSURLErrorBadURL < errorCode) return;
NSURL failingURL = null;
NSDictionary info = nserror.userInfo();
if (info != null) {
id id = info.valueForKey(NSString.stringWith("NSErrorFailingURLKey")); //$NON-NLS-1$
if (id != null) failingURL = new NSURL(id);
}
if (failingURL != null && OS.NSURLErrorServerCertificateNotYetValid <= errorCode && errorCode <= OS.NSURLErrorSecureConnectionFailed) {
/* handle invalid certificate error */
id certificates = info.objectForKey(NSString.stringWith("NSErrorPeerCertificateChainKey")); //$NON-NLS-1$
long /*int*/[] policySearch = new long /*int*/[1];
long /*int*/[] policyRef = new long /*int*/[1];
long /*int*/[] trustRef = new long /*int*/[1];
boolean success = false;
int result = OS.SecPolicySearchCreate(OS.CSSM_CERT_X_509v3, 0, 0, policySearch);
if (result == 0 && policySearch[0] != 0) {
result = OS.SecPolicySearchCopyNext(policySearch[0], policyRef);
if (result == 0 && policyRef[0] != 0) {
result = OS.SecTrustCreateWithCertificates(certificates.id, policyRef[0], trustRef);
if (result == 0 && trustRef[0] != 0) {
SFCertificateTrustPanel panel = SFCertificateTrustPanel.sharedCertificateTrustPanel();
String failingUrlString = failingURL.absoluteString().getString();
String message = Compatibility.getMessage("SWT_InvalidCert_Message", new Object[] {failingUrlString}); //$NON-NLS-1$
panel.setAlternateButtonTitle(NSString.stringWith(Compatibility.getMessage("SWT_Cancel"))); //$NON-NLS-1$
panel.setShowsHelp(true);
failingURL.retain();
NSWindow window = browser.getShell().view.window();
panel.beginSheetForWindow(window, delegate, OS.sel_createPanelDidEnd, failingURL.id, trustRef[0], NSString.stringWith(message));
success = true;
}
}
}
if (trustRef[0] != 0) OS.CFRelease(trustRef[0]);
if (policyRef[0] != 0) OS.CFRelease(policyRef[0]);
if (policySearch[0] != 0) OS.CFRelease(policySearch[0]);
if (success) return;
}
/* handle other types of errors */
NSString description = nserror.localizedDescription();
if (description != null) {
String descriptionString = description.getString();
String message = failingURL != null ? failingURL.absoluteString().getString() + "\n\n" : ""; //$NON-NLS-1$ //$NON-NLS-2$
message += Compatibility.getMessage ("SWT_Page_Load_Failed", new Object[] {descriptionString}); //$NON-NLS-1$
MessageBox messageBox = new MessageBox(browser.getShell(), SWT.OK | SWT.ICON_ERROR);
messageBox.setMessage(message);
messageBox.open();
}
}
void createPanelDidEnd(long /*int*/ sheet, long /*int*/ returnCode, long /*int*/ contextInfo) {
NSURL failingURL = new NSURL(contextInfo);
failingURL.autorelease();
if (returnCode != OS.NSFileHandlingPanelOKButton) return; /* nothing more to do */
long /*int*/ method = OS.class_getClassMethod(OS.class_NSURLRequest, OS.sel_setAllowsAnyHTTPSCertificate);
if (method != 0) {
OS.objc_msgSend(OS.class_NSURLRequest, OS.sel_setAllowsAnyHTTPSCertificate, 1, failingURL.host().id);
setUrl(failingURL.absoluteString().getString(), null, null);
}
}
void webView_didFinishLoadForFrame(long /*int*/ sender, long /*int*/ frameID) {
if (frameID == webView.mainFrame().id) {
/*
* If html is not null then there is html from a previous setText() call
* waiting to be set into the about:blank page once it has completed loading.
*/
if (html != null) {
if (getUrl().startsWith(ABOUT_BLANK)) {
loadingText = true;
NSString string = NSString.stringWith(html);
NSString URLString;
if (untrustedText) {
URLString = NSString.stringWith(ABOUT_BLANK);
} else {
URLString = NSString.stringWith(URI_FILEROOT);
}
NSURL URL = NSURL.URLWithString(URLString);
WebFrame mainFrame = webView.mainFrame();
mainFrame.loadHTMLString(string, URL);
html = null;
}
}
/*
* The loadHTMLString() invocation above will trigger a second webView_didFinishLoadForFrame
* callback when it is completed. If text was just set into the browser then wait for this
* second callback to come before sending the title or completed events.
*/
if (!loadingText) {
/*
* To be consistent with other platforms a title event should be fired when a
* page has completed loading. A page with a <title> tag will do this
* automatically when the didReceiveTitle callback is received. However a page
* without a <title> tag will not do this by default, so fire the event
* here with the page's url as the title.
*/
Display display = browser.getDisplay();
WebFrame frame = new WebFrame(frameID);
WebDataSource dataSource = frame.dataSource();
if (dataSource != null) {
NSString title = dataSource.pageTitle();
if (title == null) { /* page has no title */
TitleEvent newEvent = new TitleEvent(browser);
newEvent.display = display;
newEvent.widget = browser;
newEvent.title = getUrl();
for (int i = 0; i < titleListeners.length; i++) {
titleListeners[i].changed(newEvent);
}
if (browser.isDisposed()) return;
}
}
ProgressEvent progress = new ProgressEvent(browser);
progress.display = display;
progress.widget = browser;
progress.current = MAX_PROGRESS;
progress.total = MAX_PROGRESS;
for (int i = 0; i < progressListeners.length; i++) {
progressListeners[i].completed(progress);
}
}
loadingText = false;
if (browser.isDisposed()) return;
/*
* Feature on WebKit. The identifier is used here as a marker for the events
* related to the top frame and the URL changes related to that top frame as
* they should appear on the location bar of a browser. It is expected to reset
* the identifier to 0 when the event didFinishLoadingFromDataSource related to
* the identifierForInitialRequest event is received. However, WebKit fires
* the didFinishLoadingFromDataSource event before the entire content of the
* top frame is loaded. It is possible to receive multiple willSendRequest
* events in this interval, causing the Browser widget to send unwanted
* Location.changing events. For this reason, the identifier is reset to 0
* when the top frame has either finished loading (didFinishLoadForFrame
* event) or failed (didFailProvisionalLoadWithError).
*/
identifier = 0;
}
}
void hookDOMKeyListeners(long /*int*/ frameID) {
WebFrame frame = new WebFrame(frameID);
DOMDocument document = frame.DOMDocument();
if (document == null) return;
NSString type = NSString.stringWith(DOMEVENT_KEYDOWN);
document.addEventListener(type, delegate, false);
type = NSString.stringWith(DOMEVENT_KEYUP);
document.addEventListener(type, delegate, false);
}
void hookDOMMouseListeners(long /*int*/ frameID) {
WebFrame frame = new WebFrame(frameID);
DOMDocument document = frame.DOMDocument();
if (document == null) return;
NSString type = NSString.stringWith(DOMEVENT_MOUSEDOWN);
document.addEventListener(type, delegate, false);
type = NSString.stringWith(DOMEVENT_MOUSEUP);
document.addEventListener(type, delegate, false);
type = NSString.stringWith(DOMEVENT_MOUSEMOVE);
document.addEventListener(type, delegate, false);
type = NSString.stringWith(DOMEVENT_MOUSEWHEEL);
document.addEventListener(type, delegate, false);
}
void webView_didReceiveTitle_forFrame(long /*int*/ sender, long /*int*/ titleID, long /*int*/ frameID) {
if (frameID == webView.mainFrame().id) {
NSString title = new NSString(titleID);
String newTitle = title.getString();
TitleEvent newEvent = new TitleEvent(browser);
newEvent.display = browser.getDisplay();
newEvent.widget = browser;
newEvent.title = newTitle;
for (int i = 0; i < titleListeners.length; i++) {
titleListeners[i].changed(newEvent);
}
}
}
void webView_didStartProvisionalLoadForFrame(long /*int*/ sender, long /*int*/ frameID) {
/*
* This code is intentionally commented. WebFrameLoadDelegate:didStartProvisionalLoadForFrame is
* called before WebResourceLoadDelegate:willSendRequest and
* WebFrameLoadDelegate:didCommitLoadForFrame. The resource count is reset when didCommitLoadForFrame
* is received for the top frame.
*/
// if (frameID == webView.mainFrame().id) {
// /* reset resource status variables */
// resourceCount= 0;
// }
}
void webView_didCommitLoadForFrame(long /*int*/ sender, long /*int*/ frameID) {
WebFrame frame = new WebFrame(frameID);
WebDataSource dataSource = frame.dataSource();
NSURLRequest request = dataSource.request();
NSURL url = request.URL();
NSString s = url.absoluteString();
int length = (int)/*64*/s.length();
if (length == 0) return;
String url2 = s.getString();
/*
* If the URI indicates that the page is being rendered from memory
* (via setText()) then set it to about:blank to be consistent with IE.
*/
if (url2.equals (URI_FILEROOT)) {
url2 = ABOUT_BLANK;
} else {
length = URI_FILEROOT.length ();
if (url2.startsWith (URI_FILEROOT) && url2.charAt (length) == '#') {
url2 = ABOUT_BLANK + url2.substring (length);
}
}
Display display = browser.getDisplay();
boolean top = frameID == webView.mainFrame().id;
if (top) {
/* reset resource status variables */
resourceCount = 0;
this.url = url2;
/*
* Each invocation of setText() causes webView_didCommitLoadForFrame to be invoked
* twice, once for the initial navigate to about:blank, and once for the auto-navigate
* to about:blank that WebKit does when loadHTMLString is invoked. If this is the
* first webView_didCommitLoadForFrame callback received for a setText() invocation
* then do not send any events or re-install registered BrowserFunctions.
*/
if (url2.startsWith(ABOUT_BLANK) && html != null) return;
/* re-install registered functions */
Enumeration elements = functions.elements ();
while (elements.hasMoreElements ()) {
BrowserFunction function = (BrowserFunction)elements.nextElement ();
execute (function.functionString);
}
ProgressEvent progress = new ProgressEvent(browser);
progress.display = display;
progress.widget = browser;
progress.current = 1;
progress.total = MAX_PROGRESS;
for (int i = 0; i < progressListeners.length; i++) {
progressListeners[i].changed(progress);
}
if (browser.isDisposed()) return;
StatusTextEvent statusText = new StatusTextEvent(browser);
statusText.display = display;
statusText.widget = browser;
statusText.text = url2;
for (int i = 0; i < statusTextListeners.length; i++) {
statusTextListeners[i].changed(statusText);
}
if (browser.isDisposed()) return;
hookDOMKeyListeners(frameID);
}
hookDOMMouseListeners(frameID);
LocationEvent location = new LocationEvent(browser);
location.display = display;
location.widget = browser;
location.location = url2;
location.top = top;
for (int i = 0; i < locationListeners.length; i++) {
locationListeners[i].changed(location);
}
}
void webView_windowScriptObjectAvailable (long /*int*/ webView, long /*int*/ windowScriptObject) {
NSObject scriptObject = new NSObject (windowScriptObject);
NSString key = NSString.stringWith ("external"); //$NON-NLS-1$
scriptObject.setValue (delegate, key);
}
/* WebResourceLoadDelegate */
void webView_resource_didFinishLoadingFromDataSource(long /*int*/ sender, long /*int*/ identifier, long /*int*/ dataSource) {
/*
* Feature on WebKit. The identifier is used here as a marker for the events
* related to the top frame and the URL changes related to that top frame as
* they should appear on the location bar of a browser. It is expected to reset
* the identifier to 0 when the event didFinishLoadingFromDataSource related to
* the identifierForInitialRequest event is received. However, WebKit fires
* the didFinishLoadingFromDataSource event before the entire content of the
* top frame is loaded. It is possible to receive multiple willSendRequest
* events in this interval, causing the Browser widget to send unwanted
* Location.changing events. For this reason, the identifier is reset to 0
* when the top frame has either finished loading (didFinishLoadForFrame
* event) or failed (didFailProvisionalLoadWithError).
*/
// this code is intentionally commented
//if (this.identifier == identifier) this.identifier = 0;
}
void webView_resource_didFailLoadingWithError_fromDataSource(long /*int*/ sender, long /*int*/ identifier, long /*int*/ error, long /*int*/ dataSource) {
/*
* Feature on WebKit. The identifier is used here as a marker for the events
* related to the top frame and the URL changes related to that top frame as
* they should appear on the location bar of a browser. It is expected to reset
* the identifier to 0 when the event didFinishLoadingFromDataSource related to
* the identifierForInitialRequest event is received. However, WebKit fires
* the didFinishLoadingFromDataSource event before the entire content of the
* top frame is loaded. It is possible to receive multiple willSendRequest
* events in this interval, causing the Browser widget to send unwanted
* Location.changing events. For this reason, the identifier is reset to 0
* when the top frame has either finished loading (didFinishLoadForFrame
* event) or failed (didFailProvisionalLoadWithError).
*/
// this code is intentionally commented
//if (this.identifier == identifier) this.identifier = 0;
}
void webView_resource_didReceiveAuthenticationChallenge_fromDataSource (long /*int*/ sender, long /*int*/ identifier, long /*int*/ challenge, long /*int*/ dataSource) {
NSURLAuthenticationChallenge nsChallenge = new NSURLAuthenticationChallenge (challenge);
/*
* Do not invoke the listeners if this challenge has been failed too many
* times because a listener is likely giving incorrect credentials repeatedly
* and will do so indefinitely.
*/
if (nsChallenge.previousFailureCount () < 3) {
for (int i = 0; i < authenticationListeners.length; i++) {
AuthenticationEvent event = new AuthenticationEvent (browser);
event.location = lastNavigateURL;
authenticationListeners[i].authenticate (event);
if (!event.doit) {
id challengeSender = nsChallenge.sender ();
OS.objc_msgSend (challengeSender.id, OS.sel_cancelAuthenticationChallenge_, challenge);
return;
}
if (event.user != null && event.password != null) {
id challengeSender = nsChallenge.sender ();
NSString user = NSString.stringWith (event.user);
NSString password = NSString.stringWith (event.password);
NSURLCredential credential = NSURLCredential.credentialWithUser (user, password, OS.NSURLCredentialPersistenceForSession);
OS.objc_msgSend (challengeSender.id, OS.sel_useCredential_forAuthenticationChallenge_, credential.id, challenge);
return;
}
}
}
/* no listener handled the challenge, so try to invoke the native panel */
long /*int*/ cls = OS.class_WebPanelAuthenticationHandler;
if (cls != 0) {
long /*int*/ method = OS.class_getClassMethod (cls, OS.sel_sharedHandler);
if (method != 0) {
long /*int*/ handler = OS.objc_msgSend (cls, OS.sel_sharedHandler);
if (handler != 0) {
OS.objc_msgSend (handler, OS.sel_startAuthentication, challenge, webView.window ().id);
return;
}
}
}
/* the native panel was not available, so show a custom dialog */
String[] userReturn = new String[1], passwordReturn = new String[1];
NSURLCredential proposedCredential = nsChallenge.proposedCredential ();
if (proposedCredential != null) {
userReturn[0] = proposedCredential.user ().getString ();
if (proposedCredential.hasPassword ()) {
passwordReturn[0] = proposedCredential.password ().getString ();
}
}
NSURLProtectionSpace space = nsChallenge.protectionSpace ();
String host = space.host ().getString () + ':' + space.port ();
String realm = space.realm ().getString ();
boolean result = showAuthenticationDialog (userReturn, passwordReturn, host, realm);
if (!result) {
id challengeSender = nsChallenge.sender ();
OS.objc_msgSend (challengeSender.id, OS.sel_cancelAuthenticationChallenge_, challenge);
return;
}
id challengeSender = nsChallenge.sender ();
NSString user = NSString.stringWith (userReturn[0]);
NSString password = NSString.stringWith (passwordReturn[0]);
NSURLCredential credential = NSURLCredential.credentialWithUser (user, password, OS.NSURLCredentialPersistenceForSession);
OS.objc_msgSend (challengeSender.id, OS.sel_useCredential_forAuthenticationChallenge_, credential.id, challenge);
}
boolean showAuthenticationDialog (final String[] user, final String[] password, String host, String realm) {
final Shell shell = new Shell (browser.getShell ());
shell.setLayout (new GridLayout ());
String title = SWT.getMessage ("SWT_Authentication_Required"); //$NON-NLS-1$
shell.setText (title);
Label label = new Label (shell, SWT.WRAP);
label.setText (Compatibility.getMessage ("SWT_Enter_Username_and_Password", new String[] {realm, host})); //$NON-NLS-1$
GridData data = new GridData ();
Monitor monitor = browser.getMonitor ();
int maxWidth = monitor.getBounds ().width * 2 / 3;
int width = label.computeSize (SWT.DEFAULT, SWT.DEFAULT).x;
data.widthHint = Math.min (width, maxWidth);
data.horizontalAlignment = GridData.FILL;
data.grabExcessHorizontalSpace = true;
label.setLayoutData (data);
Label userLabel = new Label (shell, SWT.NONE);
userLabel.setText (SWT.getMessage ("SWT_Username")); //$NON-NLS-1$
final Text userText = new Text (shell, SWT.BORDER);
if (user[0] != null) userText.setText (user[0]);
data = new GridData ();
data.horizontalAlignment = GridData.FILL;
data.grabExcessHorizontalSpace = true;
userText.setLayoutData (data);
Label passwordLabel = new Label (shell, SWT.NONE);
passwordLabel.setText (SWT.getMessage ("SWT_Password")); //$NON-NLS-1$
final Text passwordText = new Text (shell, SWT.PASSWORD | SWT.BORDER);
if (password[0] != null) passwordText.setText (password[0]);
data = new GridData ();
data.horizontalAlignment = GridData.FILL;
data.grabExcessHorizontalSpace = true;
passwordText.setLayoutData (data);
final boolean[] result = new boolean[1];
final Button[] buttons = new Button[2];
Listener listener = new Listener() {
public void handleEvent(Event event) {
user[0] = userText.getText();
password[0] = passwordText.getText();
result[0] = event.widget == buttons[1];
shell.close();
}
};
Composite composite = new Composite (shell, SWT.NONE);
data = new GridData ();
data.horizontalAlignment = GridData.END;
composite.setLayoutData (data);
composite.setLayout (new GridLayout (2, true));
buttons[0] = new Button (composite, SWT.PUSH);
buttons[0].setText (SWT.getMessage("SWT_Cancel")); //$NON-NLS-1$
buttons[0].setLayoutData (new GridData (GridData.FILL_HORIZONTAL));
buttons[0].addListener (SWT.Selection, listener);
buttons[1] = new Button (composite, SWT.PUSH);
buttons[1].setText (SWT.getMessage("SWT_OK")); //$NON-NLS-1$
buttons[1].setLayoutData (new GridData (GridData.FILL_HORIZONTAL));
buttons[1].addListener (SWT.Selection, listener);
shell.setDefaultButton (buttons[1]);
shell.pack ();
shell.open ();
Display display = browser.getDisplay ();
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ()) display.sleep ();
}
return result[0];
}
long /*int*/ webView_identifierForInitialRequest_fromDataSource(long /*int*/ sender, long /*int*/ request, long /*int*/ dataSourceID) {
ProgressEvent progress = new ProgressEvent(browser);
progress.display = browser.getDisplay();
progress.widget = browser;
progress.current = resourceCount;
progress.total = Math.max(resourceCount, MAX_PROGRESS);
for (int i = 0; i < progressListeners.length; i++) {
progressListeners[i].changed(progress);
}
if (browser.isDisposed()) return 0;
NSNumber identifier = NSNumber.numberWithInt(resourceCount++);
if (this.identifier == 0) {
WebDataSource dataSource = new WebDataSource(dataSourceID);
WebFrame frame = dataSource.webFrame();
if (frame.id == webView.mainFrame().id) this.identifier = identifier.id;
}
return identifier.id;
}
long /*int*/ webView_resource_willSendRequest_redirectResponse_fromDataSource(long /*int*/ sender, long /*int*/ identifier, long /*int*/ request, long /*int*/ redirectResponse, long /*int*/ dataSource) {
NSURLRequest nsRequest = new NSURLRequest (request);
NSURL url = nsRequest.URL ();
if (url.isFileURL ()) {
NSMutableURLRequest newRequest = new NSMutableURLRequest (nsRequest.mutableCopy ());
newRequest.autorelease ();
newRequest.setCachePolicy (OS.NSURLRequestReloadIgnoringLocalCacheData);
return newRequest.id;
}
return request;
}
/* UIDelegate */
long /*int*/ webView_createWebViewWithRequest(long /*int*/ sender, long /*int*/ request) {
WindowEvent newEvent = new WindowEvent(browser);
newEvent.display = browser.getDisplay();
newEvent.widget = browser;
newEvent.required = true;
if (openWindowListeners != null) {
for (int i = 0; i < openWindowListeners.length; i++) {
openWindowListeners[i].open(newEvent);
}
}
WebView result = null;
Browser browser = null;
if (newEvent.browser != null && newEvent.browser.webBrowser instanceof WebKit) {
browser = newEvent.browser;
}
if (browser != null && !browser.isDisposed()) {
result = ((WebKit)browser.webBrowser).webView;
if (request != 0) {
WebFrame mainFrame = result.mainFrame();
mainFrame.loadRequest(new NSURLRequest(request));
}
}
return result != null ? result.id : 0;
}
void webViewShow(long /*int*/ sender) {
/*
* Feature on WebKit. WebKit expects the application to
* create a new Window using the Objective C Cocoa API in response
* to UIDelegate.createWebViewWithRequest. The application is then
* expected to use Objective C Cocoa API to make this window visible
* when receiving the UIDelegate.webViewShow message. For some reason,
* a window created with the Carbon API hosting the new browser instance
* does not redraw until it has been resized. The fix is to increase the
* size of the Shell and restore it to its initial size.
*/
Shell parent = browser.getShell();
Point pt = parent.getSize();
parent.setSize(pt.x+1, pt.y);
parent.setSize(pt.x, pt.y);
WindowEvent newEvent = new WindowEvent(browser);
newEvent.display = browser.getDisplay();
newEvent.widget = browser;
if (location != null) newEvent.location = location;
if (size != null) newEvent.size = size;
/*
* Feature in WebKit. WebKit's tool bar contains
* the address bar. The address bar is displayed
* if the tool bar is displayed. There is no separate
* notification for the address bar.
*
* Feature of OSX. The menu bar is always displayed.
* There is no notification to hide the menu bar.
*/
newEvent.addressBar = toolBar;
newEvent.menuBar = true;
newEvent.statusBar = statusBar;
newEvent.toolBar = toolBar;
for (int i = 0; i < visibilityWindowListeners.length; i++) {
visibilityWindowListeners[i].show(newEvent);
}
location = null;
size = null;
}
void webView_setFrame(long /*int*/ sender, long /*int*/ frame) {
NSRect rect = new NSRect();
OS.memmove(rect, frame, NSRect.sizeof);
/* convert to SWT system coordinates */
Rectangle bounds = browser.getDisplay().getBounds();
location = new Point((int)rect.x, bounds.height - (int)rect.y - (int)rect.height);
size = new Point((int)rect.width, (int)rect.height);
}
void webViewFocus(long /*int*/ sender) {
}
void webViewUnfocus(long /*int*/ sender) {
}
NSNumber callRunBeforeUnloadConfirmPanelWithMessage(long /*int*/ messageID, long /*int*/ arg) {
boolean result = webView_runBeforeUnloadConfirmPanelWithMessage_initiatedByFrame (0, messageID, 0);
return NSNumber.numberWithBool (result);
}
boolean webView_runBeforeUnloadConfirmPanelWithMessage_initiatedByFrame(long /*int*/ sender, long /*int*/ messageID, long /*int*/ frame) {
NSString message = new NSString(messageID);
StringBuffer text = new StringBuffer(Compatibility.getMessage("SWT_OnBeforeUnload_Message1")); //$NON-NLS-1$
text.append("\n\n"); //$NON-NLS-1$
text.append(message.getString());
text.append("\n\n"); //$NON-NLS-1$
text.append(Compatibility.getMessage("SWT_OnBeforeUnload_Message2")); //$NON-NLS-1$
MessageBox messageBox = new MessageBox(browser.getShell(), SWT.OK | SWT.CANCEL | SWT.ICON_QUESTION | SWT.SHEET);
messageBox.setMessage(text.toString());
return messageBox.open() == SWT.OK;
}
void webView_runJavaScriptAlertPanelWithMessage(long /*int*/ sender, long /*int*/ messageID) {
NSString message = new NSString(messageID);
String text = message.getString();
MessageBox messageBox = new MessageBox(browser.getShell(), SWT.OK | SWT.ICON_WARNING);
messageBox.setText("Javascript"); //$NON-NLS-1$
messageBox.setMessage(text);
messageBox.open();
}
int webView_runJavaScriptConfirmPanelWithMessage(long /*int*/ sender, long /*int*/ messageID) {
NSString message = new NSString(messageID);
String text = message.getString();
MessageBox messageBox = new MessageBox(browser.getShell(), SWT.OK | SWT.CANCEL | SWT.ICON_QUESTION);
messageBox.setText("Javascript"); //$NON-NLS-1$
messageBox.setMessage(text);
return messageBox.open() == SWT.OK ? 1 : 0;
}
void webView_runOpenPanelForFileButtonWithResultListener(long /*int*/ sender, long /*int*/ resultListenerID) {
FileDialog dialog = new FileDialog(browser.getShell(), SWT.NONE);
String result = dialog.open();
WebOpenPanelResultListener resultListener = new WebOpenPanelResultListener(resultListenerID);
if (result == null) {
resultListener.cancel();
return;
}
resultListener.chooseFilename(NSString.stringWith(result));
}
void webViewClose(long /*int*/ sender) {
Shell parent = browser.getShell();
WindowEvent newEvent = new WindowEvent(browser);
newEvent.display = browser.getDisplay();
newEvent.widget = browser;
for (int i = 0; i < closeWindowListeners.length; i++) {
closeWindowListeners[i].close(newEvent);
}
browser.dispose();
if (parent.isDisposed()) return;
/*
* Feature on WebKit. WebKit expects the application to
* create a new Window using the Objective C Cocoa API in response
* to UIDelegate.createWebViewWithRequest. The application is then
* expected to use Objective C Cocoa API to make this window visible
* when receiving the UIDelegate.webViewShow message. For some reason,
* a window created with the Carbon API hosting the new browser instance
* does not redraw until it has been resized. The fix is to increase the
* size of the Shell and restore it to its initial size.
*/
Point pt = parent.getSize();
parent.setSize(pt.x+1, pt.y);
parent.setSize(pt.x, pt.y);
}
long /*int*/ webView_contextMenuItemsForElement_defaultMenuItems(long /*int*/ sender, long /*int*/ element, long /*int*/ defaultMenuItems) {
Point pt = browser.getDisplay().getCursorLocation();
Event event = new Event();
event.x = pt.x;
event.y = pt.y;
browser.notifyListeners(SWT.MenuDetect, event);
Menu menu = browser.getMenu();
if (!event.doit) return 0;
if (menu != null && !menu.isDisposed()) {
if (event.x != pt.x || event.y != pt.y) {
menu.setLocation(event.x, event.y);
}
menu.setVisible(true);
return 0;
}
return defaultMenuItems;
}
void webView_setStatusBarVisible(long /*int*/ sender, boolean visible) {
/* Note. Webkit only emits the notification when the status bar should be hidden. */
statusBar = visible;
}
void webView_setStatusText(long /*int*/ sender, long /*int*/ textID) {
NSString text = new NSString(textID);
int length = (int)/*64*/text.length();
if (length == 0) return;
StatusTextEvent statusText = new StatusTextEvent(browser);
statusText.display = browser.getDisplay();
statusText.widget = browser;
statusText.text = text.getString();
for (int i = 0; i < statusTextListeners.length; i++) {
statusTextListeners[i].changed(statusText);
}
}
void webView_setResizable(long /*int*/ sender, boolean visible) {
}
void webView_setToolbarsVisible(long /*int*/ sender, boolean visible) {
/* Note. Webkit only emits the notification when the tool bar should be hidden. */
toolBar = visible;
}
void webView_mouseDidMoveOverElement_modifierFlags (long /*int*/ sender, long /*int*/ elementInformationID, long /*int*/ modifierFlags) {
if (elementInformationID == 0) return;
NSString key = NSString.stringWith(WebElementLinkURLKey);
NSDictionary elementInformation = new NSDictionary(elementInformationID);
id value = elementInformation.valueForKey(key);
if (value == null) {
/* not currently over a link */
if (lastHoveredLinkURL == null) return;
lastHoveredLinkURL = null;
StatusTextEvent statusText = new StatusTextEvent(browser);
statusText.display = browser.getDisplay();
statusText.widget = browser;
statusText.text = ""; //$NON-NLS-1$
for (int i = 0; i < statusTextListeners.length; i++) {
statusTextListeners[i].changed(statusText);
}
return;
}
NSString url = new NSURL(value.id).absoluteString();
int length = (int)/*64*/url.length();
String urlString;
if (length == 0) {
urlString = ""; //$NON-NLS-1$
} else {
urlString = url.getString();
}
if (urlString.equals(lastHoveredLinkURL)) return;
lastHoveredLinkURL = urlString;
StatusTextEvent statusText = new StatusTextEvent(browser);
statusText.display = browser.getDisplay();
statusText.widget = browser;
statusText.text = urlString;
for (int i = 0; i < statusTextListeners.length; i++) {
statusTextListeners[i].changed(statusText);
}
}
void webView_printFrameView (long /*int*/ sender, long /*int*/ frameViewID) {
WebFrameView view = new WebFrameView(frameViewID);
boolean viewPrint = view.documentViewShouldHandlePrint();
if (viewPrint) {
view.printDocumentView();
return;
}
NSPrintInfo info = NSPrintInfo.sharedPrintInfo();
NSPrintOperation operation = view.printOperationWithPrintInfo(info);
if (operation != null) operation.runOperation();
}
/* PolicyDelegate */
void webView_decidePolicyForMIMEType_request_frame_decisionListener(long /*int*/ sender, long /*int*/ type, long /*int*/ request, long /*int*/ frame, long /*int*/ listenerID) {
boolean canShow = WebView.canShowMIMEType(new NSString(type));
WebPolicyDecisionListener listener = new WebPolicyDecisionListener(listenerID);
if (canShow) {
listener.use();
} else {
listener.download();
}
}
void webView_decidePolicyForNavigationAction_request_frame_decisionListener(long /*int*/ sender, long /*int*/ actionInformation, long /*int*/ request, long /*int*/ frame, long /*int*/ listenerID) {
NSURL url = new NSURLRequest(request).URL();
WebPolicyDecisionListener listener = new WebPolicyDecisionListener(listenerID);
if (loadingText) {
/*
* WebKit is auto-navigating to about:blank in response to a loadHTMLString()
* invocation. This navigate should always proceed without sending an event
* since it is preceded by an explicit navigate to about:blank in setText().
*/
listener.use();
return;
}
if (url == null) {
/* indicates that a URL with an invalid format was specified */
listener.ignore();
return;
}
if (url.isFileURL() && getUrl().startsWith(ABOUT_BLANK) && untrustedText) {
/* indicates an attempt to access the local file system from untrusted content */
listener.ignore();
return;
}
NSString s = url.absoluteString();
String url2 = s.getString();
/*
* If the URI indicates that the page is being rendered from memory
* (via setText()) then set it to about:blank to be consistent with IE.
*/
if (url2.equals (URI_FILEROOT)) {
url2 = ABOUT_BLANK;
} else {
int length = URI_FILEROOT.length ();
if (url2.startsWith (URI_FILEROOT) && url2.charAt (length) == '#') {
url2 = ABOUT_BLANK + url2.substring (length);
}
}
LocationEvent newEvent = new LocationEvent(browser);
newEvent.display = browser.getDisplay();
newEvent.widget = browser;
newEvent.location = url2;
newEvent.doit = true;
if (locationListeners != null) {
for (int i = 0; i < locationListeners.length; i++) {
locationListeners[i].changing(newEvent);
}
}
if (newEvent.doit) {
if (jsEnabled != jsEnabledOnNextPage) {
jsEnabled = jsEnabledOnNextPage;
if (preferences == null) {
preferences = (WebPreferences)new WebPreferences ().alloc ().init ();
webView.setPreferences (preferences);
}
preferences.setJavaScriptEnabled (jsEnabled);
}
listener.use();
lastNavigateURL = url2;
} else {
listener.ignore();
}
}
void webView_decidePolicyForNewWindowAction_request_newFrameName_decisionListener(long /*int*/ sender, long /*int*/ actionInformation, long /*int*/ request, long /*int*/ frameName, long /*int*/ listenerID) {
WebPolicyDecisionListener listener = new WebPolicyDecisionListener(listenerID);
listener.use();
}
void webView_unableToImplementPolicyWithError_frame(long /*int*/ sender, long /*int*/ error, long /*int*/ frame) {
}
/* WebDownload */
void download_decideDestinationWithSuggestedFilename(long /*int*/ downloadId, long /*int*/ filename) {
NSString string = new NSString(filename);
String name = string.getString();
FileDialog dialog = new FileDialog(browser.getShell(), SWT.SAVE);
dialog.setText(SWT.getMessage ("SWT_FileDownload")); //$NON-NLS-1$
dialog.setFileName(name);
String path = dialog.open();
NSURLDownload download = new NSURLDownload(downloadId);
if (path == null) {
/* cancel pressed */
download.cancel();
return;
}
download.setDestination(NSString.stringWith(path), true);
}
/* DOMEventListener */
void handleEvent(long /*int*/ evtId) {
NSString string = new NSString(OS.objc_msgSend(evtId, OS.sel_type));
String type = string.getString();
if (DOMEVENT_KEYDOWN.equals(type) || DOMEVENT_KEYUP.equals(type)) {
DOMKeyboardEvent event = new DOMKeyboardEvent(evtId);
boolean ctrl = event.ctrlKey();
boolean shift = event.shiftKey();
boolean alt = event.altKey();
boolean meta = event.metaKey();
int keyCode = event.keyCode();
int charCode = event.charCode();
Event keyEvent = new Event();
keyEvent.widget = browser;
int eventType = DOMEVENT_KEYDOWN.equals(type) ? SWT.KeyDown : SWT.KeyUp;
keyEvent.type = eventType;
int translatedKey = translateKey (keyCode);
keyEvent.keyCode = translatedKey;
keyEvent.character = (char)charCode;
int stateMask = (alt ? SWT.ALT : 0) | (ctrl ? SWT.CTRL : 0) | (shift ? SWT.SHIFT : 0) | (meta ? SWT.COMMAND : 0);
keyEvent.stateMask = stateMask;
boolean doit = true;
if (keyEvent.type == SWT.KeyDown) {
doit = sendKeyEvent(keyEvent);
} else {
browser.notifyListeners(keyEvent.type, keyEvent);
doit = keyEvent.doit;
}
if (!doit) {
event.preventDefault();
} else {
if (eventType == SWT.KeyDown && stateMask == SWT.COMMAND) {
if (translatedKey == 'v') {
webView.paste (webView);
event.preventDefault();
} else if (translatedKey == 'c') {
webView.copy (webView);
event.preventDefault();
} else if (translatedKey == 'x') {
webView.cut (webView);
event.preventDefault();
}
}
}
return;
}
if (DOMEVENT_MOUSEWHEEL.equals(type)) {
DOMWheelEvent event = new DOMWheelEvent(evtId);
/*
* The position of mouse events is received in screen-relative coordinates
* in order to handle pages with frames, since frames express their event
* coordinates relative to themselves rather than relative to their top-
* level page. Convert screen-relative coordinates to be browser-relative.
*/
int screenX = event.screenX();
int screenY = event.screenY();
Point position = new Point(screenX, screenY);
position = browser.getDisplay().map(null, browser, position);
int delta = event.wheelDelta();
boolean ctrl = event.ctrlKey();
boolean shift = event.shiftKey();
boolean alt = event.altKey();
boolean meta = event.metaKey();
Event mouseEvent = new Event();
mouseEvent.type = SWT.MouseWheel;
mouseEvent.widget = browser;
mouseEvent.x = position.x; mouseEvent.y = position.y;
mouseEvent.count = delta / 120;
mouseEvent.stateMask = (alt ? SWT.ALT : 0) | (ctrl ? SWT.CTRL : 0) | (shift ? SWT.SHIFT : 0) | (meta ? SWT.COMMAND : 0);
browser.notifyListeners (mouseEvent.type, mouseEvent);
return;
}
/* mouse event */
DOMMouseEvent event = new DOMMouseEvent(evtId);
/*
* The position of mouse events is received in screen-relative coordinates
* in order to handle pages with frames, since frames express their event
* coordinates relative to themselves rather than relative to their top-
* level page. Convert screen-relative coordinates to be browser-relative.
*/
int screenX = event.screenX();
int screenY = event.screenY();
Point position = new Point(screenX, screenY);
position = browser.getDisplay().map(null, browser, position);
int detail = event.detail();
int button = event.button();
boolean ctrl = event.ctrlKey();
boolean shift = event.shiftKey();
boolean alt = event.altKey();
boolean meta = event.metaKey();
Event mouseEvent = new Event ();
mouseEvent.widget = browser;
mouseEvent.x = position.x; mouseEvent.y = position.y;
mouseEvent.stateMask = (alt ? SWT.ALT : 0) | (ctrl ? SWT.CTRL : 0) | (shift ? SWT.SHIFT : 0) | (meta ? SWT.COMMAND : 0);
if (DOMEVENT_MOUSEDOWN.equals (type)) {
mouseEvent.type = SWT.MouseDown;
mouseEvent.button = button + 1;
mouseEvent.count = detail;
} else if (DOMEVENT_MOUSEUP.equals (type)) {
mouseEvent.type = SWT.MouseUp;
mouseEvent.button = button + 1;
mouseEvent.count = detail;
switch (mouseEvent.button) {
case 1: mouseEvent.stateMask |= SWT.BUTTON1; break;
case 2: mouseEvent.stateMask |= SWT.BUTTON2; break;
case 3: mouseEvent.stateMask |= SWT.BUTTON3; break;
case 4: mouseEvent.stateMask |= SWT.BUTTON4; break;
case 5: mouseEvent.stateMask |= SWT.BUTTON5; break;
}
} else if (DOMEVENT_MOUSEMOVE.equals (type)) {
/*
* Bug in WebKit. Spurious and redundant mousemove events are received in
* various contexts, including following every MouseUp. The workaround is
* to not fire MouseMove events whose x and y values match the last MouseMove
*/
if (mouseEvent.x == lastMouseMoveX && mouseEvent.y == lastMouseMoveY) return;
mouseEvent.type = SWT.MouseMove;
lastMouseMoveX = mouseEvent.x; lastMouseMoveY = mouseEvent.y;
}
browser.notifyListeners (mouseEvent.type, mouseEvent);
if (detail == 2 && DOMEVENT_MOUSEDOWN.equals (type)) {
mouseEvent = new Event ();
mouseEvent.widget = browser;
mouseEvent.x = position.x; mouseEvent.y = position.y;
mouseEvent.stateMask = (alt ? SWT.ALT : 0) | (ctrl ? SWT.CTRL : 0) | (shift ? SWT.SHIFT : 0) | (meta ? SWT.COMMAND : 0);
mouseEvent.type = SWT.MouseDoubleClick;
mouseEvent.button = button + 1;
mouseEvent.count = detail;
browser.notifyListeners (mouseEvent.type, mouseEvent);
}
}
/* external */
Object convertToJava (long /*int*/ value) {
NSObject object = new NSObject (value);
long /*int*/ clazz = OS.objc_lookUpClass ("NSString"); //$NON-NLS-1$
if (object.isKindOfClass (clazz)) {
NSString string = new NSString (value);
return string.getString ();
}
clazz = OS.objc_lookUpClass ("NSNumber"); //$NON-NLS-1$
if (object.isKindOfClass (clazz)) {
NSNumber number = new NSNumber (value);
long /*int*/ ptr = number.objCType ();
byte[] type = new byte[1];
OS.memmove (type, ptr, 1);
if (type[0] == 'c' || type[0] == 'B') {
return new Boolean (number.boolValue ());
}
if ("islqISLQfd".indexOf (type[0]) != -1) { //$NON-NLS-1$
return new Double (number.doubleValue ());
}
}
clazz = OS.objc_lookUpClass ("WebScriptObject"); //$NON-NLS-1$
if (object.isKindOfClass (clazz)) {
WebScriptObject script = new WebScriptObject (value);
id id = script.valueForKey (NSString.stringWith ("length")); //$NON-NLS-1$
if (id == null) { /* not a JS array */
SWT.error (SWT.ERROR_INVALID_ARGUMENT);
}
int length = new NSNumber (id).intValue ();
Object[] arguments = new Object[length];
for (int i = 0; i < length; i++) {
id current = script.webScriptValueAtIndex (i);
if (current != null) {
arguments[i] = convertToJava (current.id);
}
}
return arguments;
}
clazz = OS.objc_lookUpClass ("WebUndefined"); //$NON-NLS-1$
if (object.isKindOfClass (clazz)) {
return null;
}
SWT.error (SWT.ERROR_INVALID_ARGUMENT);
return null;
}
NSObject convertToJS (Object value) {
if (value == null) {
long /*int*/ result = OS.objc_msgSend (OS.class_NSNull, OS.sel_null);
return result != 0 ? new NSObject (result) : null;
}
if (value instanceof String) {
return NSString.stringWith ((String)value);
}
if (value instanceof Boolean) {
return NSNumber.numberWithBool (((Boolean)value).booleanValue ());
}
if (value instanceof Number) {
return NSNumber.numberWithDouble (((Number)value).doubleValue ());
}
if (value instanceof Object[]) {
Object[] arrayValue = (Object[]) value;
int length = arrayValue.length;
NSMutableArray array = NSMutableArray.arrayWithCapacity (length);
for (int i = 0; i < length; i++) {
Object currentObject = arrayValue[i];
array.addObject (convertToJS (currentObject));
}
return array;
}
SWT.error (SWT.ERROR_INVALID_RETURN_VALUE);
return null;
}
NSObject callJava (long /*int*/ index, long /*int*/ token, long /*int*/ args, long /*int*/ arg1) {
Object returnValue = null;
NSObject object = new NSObject (index);
long /*int*/ clazz = OS.objc_lookUpClass ("NSNumber"); //$NON-NLS-1$
if (object.isKindOfClass (clazz)) {
NSNumber number = new NSNumber (index);
Object key = new Integer (number.intValue ());
object = new NSObject (token);
clazz = OS.objc_lookUpClass ("NSString"); //$NON-NLS-1$
if (object.isKindOfClass (clazz)) {
NSString tokenString = new NSString (token);
BrowserFunction function = (BrowserFunction)functions.get (key);
if (function != null && tokenString.getString ().equals (function.token)) {
try {
Object temp = convertToJava (args);
if (temp instanceof Object[]) {
Object[] arguments = (Object[])temp;
try {
returnValue = function.function (arguments);
} catch (Exception e) {
/* exception during function invocation */
returnValue = WebBrowser.CreateErrorString (e.getLocalizedMessage ());
}
}
} catch (IllegalArgumentException e) {
/* invalid argument value type */
if (function.isEvaluate) {
/* notify the evaluate function so that a java exception can be thrown */
function.function (new String[] {WebBrowser.CreateErrorString (new SWTException (SWT.ERROR_INVALID_RETURN_VALUE).getLocalizedMessage ())});
}
returnValue = WebBrowser.CreateErrorString (e.getLocalizedMessage ());
}
}
}
}
try {
return convertToJS (returnValue);
} catch (SWTException e) {
/* invalid return value type */
return convertToJS (WebBrowser.CreateErrorString (e.getLocalizedMessage ()));
}
}
}