| /******************************************************************************* |
| * 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.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.internal.*; |
| import org.eclipse.swt.internal.carbon.*; |
| import org.eclipse.swt.internal.cocoa.*; |
| import org.eclipse.swt.layout.*; |
| import org.eclipse.swt.widgets.*; |
| |
| class WebKit extends WebBrowser { |
| |
| /* Objective-C WebView delegate */ |
| int delegate; |
| |
| /* Carbon HIView handle */ |
| int webViewHandle, webView; |
| int windowBoundsHandler; |
| int preferences; |
| |
| boolean loadingText, hasNewFocusElement, untrustedText; |
| String lastHoveredLinkURL, lastNavigateURL; |
| String html; |
| int identifier; |
| int resourceCount; |
| int lastMouseMoveX, lastMouseMoveY; |
| String url = ""; //$NON-NLS-1$ |
| Point location; |
| Point size; |
| boolean statusBar = true, toolBar = true, ignoreDispose; |
| //TEMPORARY CODE |
| // boolean doit; |
| |
| static boolean Initialized; |
| static Callback Callback3, 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/412.0"; /* Safari version on OSX 10.4 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 URI_APPLEWEBDATA = "applewebdata://"; //$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 BROWSER_WINDOW = "org.eclipse.swt.browser.Browser.Window"; //$NON-NLS-1$ |
| static final String WEBKIT_EVENTS_FIX_KEY = "org.eclipse.swt.internal.webKitEventsFix"; //$NON-NLS-1$ |
| |
| /* 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 final String DOMEVENT_FOCUSIN = "DOMFocusIn"; //$NON-NLS-1$ |
| static final String DOMEVENT_FOCUSOUT = "DOMFocusOut"; //$NON-NLS-1$ |
| |
| static { |
| Cocoa.WebInitForCarbon(); |
| |
| NativeClearSessions = new Runnable() { |
| public void run() { |
| int storage = Cocoa.objc_msgSend (Cocoa.C_NSHTTPCookieStorage, Cocoa.S_sharedHTTPCookieStorage); |
| int cookies = Cocoa.objc_msgSend (storage, Cocoa.S_cookies); |
| int count = Cocoa.objc_msgSend (cookies, Cocoa.S_count); |
| for (int i = 0; i < count; i++) { |
| int cookie = Cocoa.objc_msgSend (cookies, Cocoa.S_objectAtIndex, i); |
| boolean isSession = Cocoa.objc_msgSend (cookie, Cocoa.S_isSessionOnly) != 0; |
| if (isSession) { |
| Cocoa.objc_msgSend (storage, Cocoa.S_deleteCookie, cookie); |
| } |
| } |
| } |
| }; |
| |
| NativeGetCookie = new Runnable () { |
| public void run () { |
| int storage = Cocoa.objc_msgSend (Cocoa.C_NSHTTPCookieStorage, Cocoa.S_sharedHTTPCookieStorage); |
| int urlString = createNSString (CookieUrl); |
| int url = Cocoa.objc_msgSend (Cocoa.C_NSURL, Cocoa.S_URLWithString, urlString); |
| OS.CFRelease (urlString); |
| int cookies = Cocoa.objc_msgSend (storage, Cocoa.S_cookiesForURL, url); |
| int count = Cocoa.objc_msgSend (cookies, Cocoa.S_count); |
| if (count == 0) return; |
| |
| int name = createNSString (CookieName); |
| for (int i = 0; i < count; i++) { |
| int current = Cocoa.objc_msgSend (cookies, Cocoa.S_objectAtIndex, i); |
| int currentName = Cocoa.objc_msgSend (current, Cocoa.S_name); |
| if (Cocoa.objc_msgSend (currentName, Cocoa.S_compare, name) == Cocoa.NSOrderedSame) { |
| int value = Cocoa.objc_msgSend (current, Cocoa.S_value); |
| int length = OS.CFStringGetLength (value); |
| char[] buffer = new char[length]; |
| CFRange range = new CFRange (); |
| range.length = length; |
| OS.CFStringGetCharacters (value, range, buffer); |
| CookieValue = new String (buffer); |
| OS.CFRelease (name); |
| return; |
| } |
| } |
| OS.CFRelease (name); |
| } |
| }; |
| |
| NativeSetCookie = new Runnable () { |
| public void run () { |
| int urlString = createNSString(CookieUrl); |
| int url = Cocoa.objc_msgSend (Cocoa.C_NSURL, Cocoa.S_URLWithString, urlString); |
| OS.CFRelease (urlString); |
| |
| int value = createNSString (CookieValue); |
| int key = createNSString (HEADER_SETCOOKIE); |
| int headers = Cocoa.objc_msgSend (Cocoa.C_NSMutableDictionary, Cocoa.S_dictionaryWithCapacity, 1); |
| Cocoa.objc_msgSend (headers, Cocoa.S_setValue, value, key); |
| OS.CFRelease (key); |
| OS.CFRelease (value); |
| |
| int cookies = Cocoa.objc_msgSend (Cocoa.C_NSHTTPCookie, Cocoa.S_cookiesWithResponseHeaderFields, headers, url); |
| if (Cocoa.objc_msgSend (cookies, Cocoa.S_count) == 0) return; |
| int cookie = Cocoa.objc_msgSend (cookies, Cocoa.S_objectAtIndex, 0); |
| int storage = Cocoa.objc_msgSend (Cocoa.C_NSHTTPCookieStorage, Cocoa.S_sharedHTTPCookieStorage); |
| Cocoa.objc_msgSend (storage, Cocoa.S_setCookie, cookie); |
| CookieResult = true; |
| } |
| }; |
| |
| if (NativePendingCookies != null) { |
| SetPendingCookies (NativePendingCookies); |
| } |
| NativePendingCookies = null; |
| } |
| |
| public void create (Composite parent, int style) { |
| /* |
| * Note. Loading the webkit bundle on Jaguar causes a crash. |
| * The workaround is to detect any OS prior to 10.30 and fail |
| * without crashing. |
| */ |
| if (OS.VERSION < 0x1030) { |
| browser.dispose(); |
| SWT.error(SWT.ERROR_NO_HANDLES); |
| } |
| |
| /* |
| * Bug in WebKit on OSX 10.5 (Leopard) only. VoiceOver no longer follows focus when |
| * HIWebViewCreate is used to create a WebView. The VoiceOver cursor (activated by |
| * Control+Alt+arrows) continues to work, but keyboard focus is not tracked. The fix |
| * is to create the WebView with HICocoaViewCreate (api introduced in OSX 10.5) when |
| * running on OSX 10.5. |
| */ |
| int outControl[] = new int[1]; |
| if (OS.VERSION >= 0x1050) { |
| webView = Cocoa.objc_msgSend(Cocoa.objc_msgSend(Cocoa.C_WebView, Cocoa.S_alloc), Cocoa.S_initWithFrame_frameName_groupName, new NSRect(), 0, 0); |
| if (webView != 0) { |
| Cocoa.HICocoaViewCreate(webView, 0, outControl); |
| webViewHandle = outControl[0]; |
| Cocoa.objc_msgSend(webView, Cocoa.S_release); |
| } |
| } else { |
| Cocoa.HIWebViewCreate(outControl); |
| webViewHandle = outControl[0]; |
| if (webViewHandle != 0) { |
| webView = Cocoa.HIWebViewGetWebView(webViewHandle); |
| } |
| } |
| if (webViewHandle == 0) { |
| browser.dispose(); |
| SWT.error(SWT.ERROR_NO_HANDLES); |
| } |
| |
| Display display = browser.getDisplay(); |
| display.setData(ADD_WIDGET_KEY, new Object[] {new Integer(webViewHandle), browser}); |
| |
| /* |
| * WebKit's DOM listener api became functional in OSX 10.4. If OSX 10.4 or |
| * later is detected then override the default event mechanism to not send key |
| * events and some mouse events so that the browser can send them by listening |
| * to the DOM instead. |
| */ |
| if (!(OS.VERSION < 0x1040)) { |
| browser.setData(WEBKIT_EVENTS_FIX_KEY); |
| } |
| |
| /* |
| * Bug in WebKit. For some reason, every application must contain |
| * a visible window that has never had a WebView or mouse move events |
| * are not delivered. This seems to happen after a browser has been |
| * either hidden or disposed in any window. The fix is to create a |
| * single transparent overlay window that is disposed when the display |
| * is disposed. |
| */ |
| if (display.getData(BROWSER_WINDOW) == null) { |
| Rect bounds = new Rect (); |
| OS.SetRect (bounds, (short) 0, (short) 0, (short) 1, (short) 1); |
| final int[] outWindow = new int[1]; |
| OS.CreateNewWindow(OS.kOverlayWindowClass, 0, bounds, outWindow); |
| OS.ShowWindow(outWindow[0]); |
| OS.HIObjectSetAccessibilityIgnored (outWindow[0], true); |
| display.disposeExec(new Runnable() { |
| public void run() { |
| if (outWindow[0] != 0) { |
| OS.DisposeWindow(outWindow[0]); |
| } |
| outWindow[0] = 0; |
| } |
| }); |
| display.setData(BROWSER_WINDOW, outWindow); |
| } |
| |
| /* |
| * Bug in WebKit. The WebView does not draw properly if it is embedded as |
| * sub view of the browser handle. The fix is to add the web view to the |
| * window root control and resize it on top of the browser handle. |
| * |
| * Note that when the browser is reparented, the web view has to |
| * be reparented by hand by hooking kEventControlOwningWindowChanged. |
| */ |
| int window = OS.GetControlOwner(browser.handle); |
| int[] contentView = new int[1]; |
| OS.HIViewFindByID(OS.HIViewGetRoot(window), OS.kHIViewWindowContentID(), contentView); |
| OS.HIViewAddSubview(contentView[0], webViewHandle); |
| OS.HIViewChangeFeatures(webViewHandle, OS.kHIViewFeatureIsOpaque, 0); |
| |
| /* |
| * Bug in WebKit. The WebView does not receive mouse and key events when it is added |
| * to a visible top window. It is assumed that WebKit hooks its own event listener |
| * when the top window emits the kEventWindowShown event. The workaround is to send a |
| * fake kEventWindowShown event to the top window after the WebView has been added |
| * to the HIView (after the top window is visible) to give WebKit a chance to hook |
| * events. |
| */ |
| OS.HIViewSetVisible(webViewHandle, true); |
| if (browser.getShell().isVisible()) { |
| int[] showEvent = new int[1]; |
| OS.CreateEvent(0, OS.kEventClassWindow, OS.kEventWindowShown, 0.0, OS.kEventAttributeUserEvent, showEvent); |
| OS.SetEventParameter(showEvent[0], OS.kEventParamDirectObject, OS.typeWindowRef, 4, new int[] {OS.GetControlOwner(browser.handle)}); |
| OS.SendEventToEventTarget(showEvent[0], OS.GetWindowEventTarget(window)); |
| if (showEvent[0] != 0) OS.ReleaseEvent(showEvent[0]); |
| } |
| |
| /* |
| * This code is intentionally commented. Setting a group name is the right thing |
| * to do in order to avoid multiple open window requests. For some reason, WebKit |
| * crashes when requested to reopen the same window if that window was previously |
| * closed. This may be because that window was not correctly closed. |
| */ |
| // String groupName = "MyDocument"; //$NON-NLS-1$ |
| // int length = groupName.length(); |
| // char[] buffer = new char[length]; |
| // groupName.getChars(0, length, buffer, 0); |
| // int groupNameString = OS.CFStringCreateWithCharacters(0, buffer, length); |
| // // [webView setGroupName:@"MyDocument"]; |
| // WebKit.objc_msgSend(webView, WebKit.S_setGroupName, groupNameString); |
| // OS.CFRelease(groupNameString); |
| |
| final int notificationCenter = Cocoa.objc_msgSend(Cocoa.C_NSNotificationCenter, Cocoa.S_defaultCenter); |
| |
| Listener listener = new Listener() { |
| public void handleEvent(Event e) { |
| switch (e.type) { |
| 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; |
| |
| /* invoke onbeforeunload handlers */ |
| if (!browser.isClosing && !browser.isDisposed()) { |
| close (false); |
| } |
| |
| OS.RemoveEventHandler(windowBoundsHandler); |
| windowBoundsHandler = 0; |
| |
| e.display.setData(ADD_WIDGET_KEY, new Object[] {new Integer(webViewHandle), null}); |
| |
| Cocoa.objc_msgSend(webView, Cocoa.S_setFrameLoadDelegate, 0); |
| Cocoa.objc_msgSend(webView, Cocoa.S_setResourceLoadDelegate, 0); |
| Cocoa.objc_msgSend(webView, Cocoa.S_setUIDelegate, 0); |
| Cocoa.objc_msgSend(webView, Cocoa.S_setPolicyDelegate, 0); |
| Cocoa.objc_msgSend(webView, Cocoa.S_setDownloadDelegate, 0); |
| Cocoa.objc_msgSend(notificationCenter, Cocoa.S_removeObserver, delegate); |
| |
| Cocoa.objc_msgSend(delegate, Cocoa.S_release); |
| OS.DisposeControl(webViewHandle); |
| webView = webViewHandle = 0; |
| html = null; |
| lastHoveredLinkURL = lastNavigateURL = null; |
| |
| Enumeration elements = functions.elements (); |
| while (elements.hasMoreElements ()) { |
| ((BrowserFunction)elements.nextElement ()).dispose (false); |
| } |
| functions = null; |
| |
| if (preferences != 0) { |
| Cocoa.objc_msgSend (preferences, Cocoa.S_release); |
| } |
| preferences = 0; |
| break; |
| } |
| case SWT.FocusIn: { |
| hasNewFocusElement = true; |
| OS.SetKeyboardFocus(OS.GetControlOwner(browser.handle), webViewHandle, (short)-1); |
| break; |
| } |
| } |
| } |
| }; |
| browser.addListener(SWT.Dispose, listener); |
| browser.addListener(SWT.FocusIn, listener); |
| browser.addListener(SWT.KeyDown, listener); /* needed to make browser traversable */ |
| |
| if (Callback3 == null) Callback3 = new Callback(this.getClass(), "eventProc3", 3); //$NON-NLS-1$ |
| int callback3Address = Callback3.getAddress(); |
| if (callback3Address == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); |
| |
| int[] mask = new int[] { |
| OS.kEventClassKeyboard, OS.kEventRawKeyDown, |
| OS.kEventClassControl, OS.kEventControlDraw, |
| OS.kEventClassControl, OS.kEventControlGetClickActivation, |
| OS.kEventClassControl, OS.kEventControlSetCursor, |
| OS.kEventClassTextInput, OS.kEventTextInputUnicodeForKeyEvent, |
| }; |
| OS.InstallEventHandler(OS.GetControlEventTarget(webViewHandle), callback3Address, mask.length / 2, mask, webViewHandle, null); |
| int[] mask1 = new int[] { |
| OS.kEventClassControl, OS.kEventControlBoundsChanged, |
| OS.kEventClassControl, OS.kEventControlVisibilityChanged, |
| OS.kEventClassControl, OS.kEventControlOwningWindowChanged, |
| }; |
| OS.InstallEventHandler(OS.GetControlEventTarget(browser.handle), callback3Address, mask1.length / 2, mask1, browser.handle, null); |
| int[] mask2 = new int[] { |
| OS.kEventClassWindow, OS.kEventWindowBoundsChanged, |
| }; |
| int[] outRef = new int[1]; |
| OS.InstallEventHandler(OS.GetWindowEventTarget(window), callback3Address, mask2.length / 2, mask2, browser.handle, outRef); |
| windowBoundsHandler = outRef[0]; |
| |
| if (Callback7 == null) Callback7 = new Callback(this.getClass(), "eventProc7", 7); //$NON-NLS-1$ |
| int callback7Address = Callback7.getAddress(); |
| if (callback7Address == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); |
| |
| // delegate = [[WebResourceLoadDelegate alloc] init eventProc]; |
| delegate = Cocoa.objc_msgSend(Cocoa.C_WebKitDelegate, Cocoa.S_alloc); |
| delegate = Cocoa.objc_msgSend(delegate, Cocoa.S_initWithProc, callback7Address, webViewHandle); |
| |
| // [webView setFrameLoadDelegate:delegate]; |
| Cocoa.objc_msgSend(webView, Cocoa.S_setFrameLoadDelegate, delegate); |
| |
| // [webView setResourceLoadDelegate:delegate]; |
| Cocoa.objc_msgSend(webView, Cocoa.S_setResourceLoadDelegate, delegate); |
| |
| // [webView setUIDelegate:delegate]; |
| Cocoa.objc_msgSend(webView, Cocoa.S_setUIDelegate, delegate); |
| |
| /* register delegate for all notifications sent out from webview */ |
| Cocoa.objc_msgSend(notificationCenter, Cocoa.S_addObserver_selector_name_object, delegate, Cocoa.S_handleNotification, 0, webView); |
| |
| // [webView setPolicyDelegate:delegate]; |
| Cocoa.objc_msgSend(webView, Cocoa.S_setPolicyDelegate, delegate); |
| |
| // [webView setDownloadDelegate:delegate]; |
| Cocoa.objc_msgSend(webView, Cocoa.S_setDownloadDelegate, delegate); |
| |
| // [webView setApplicationNameForUserAgent:applicationName]; |
| int sHandle = createNSString(AGENT_STRING); |
| Cocoa.objc_msgSend(webView, Cocoa.S_setApplicationNameForUserAgent, sHandle); |
| OS.CFRelease(sHandle); |
| |
| if (OS.VERSION < 0x1050 && display.getActiveShell() == browser.getShell()) { |
| Cocoa.objc_msgSend(Cocoa.objc_msgSend(webView, Cocoa.S_window), Cocoa.S_makeKeyWindow); |
| } |
| |
| if (!Initialized) { |
| Initialized = true; |
| /* disable applets */ |
| int preferences = Cocoa.objc_msgSend(Cocoa.C_WebPreferences, Cocoa.S_standardPreferences); |
| Cocoa.objc_msgSend(preferences, Cocoa.S_setJavaEnabled, 0); |
| } |
| } |
| |
| static int eventProc3(int nextHandler, int theEvent, int userData) { |
| Widget widget = Display.getCurrent().findWidget(userData); |
| if (widget instanceof Browser) { |
| return ((WebKit)((Browser)widget).webBrowser).handleCallback(nextHandler, theEvent); |
| } |
| return OS.eventNotHandledErr; |
| } |
| |
| static int eventProc7(int webview, int userData, int selector, int arg0, int arg1, int arg2, int arg3) { |
| Widget widget = Display.getCurrent().findWidget(userData); |
| if (widget instanceof Browser) { |
| return ((WebKit)((Browser)widget).webBrowser).handleCallback(selector, arg0, arg1, arg2, arg3); |
| } |
| return 0; |
| } |
| |
| static int createNSString(String string) { |
| int length = string.length (); |
| char[] buffer = new char[length]; |
| string.getChars (0, length, buffer, 0); |
| return OS.CFStringCreateWithCharacters (0, buffer, length); |
| } |
| |
| static String getString (int ptr) { |
| int length = OS.CFStringGetLength (ptr); |
| char[] buffer = new char[length]; |
| CFRange range = new CFRange (); |
| range.length = length; |
| OS.CFStringGetCharacters (ptr, range, buffer); |
| return new String (buffer); |
| } |
| |
| public boolean back() { |
| html = null; |
| return Cocoa.objc_msgSend(webView, Cocoa.S_goBack) != 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) { |
| int frame = Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame); |
| int context = Cocoa.objc_msgSend(frame, Cocoa.S_globalContext); |
| |
| byte[] bytes = null; |
| try { |
| bytes = (script + '\0').getBytes("UTF-8"); //$NON-NLS-1$ |
| } catch (UnsupportedEncodingException e) { |
| bytes = (script + '\0').getBytes(); |
| } |
| int scriptString = OS.JSStringCreateWithUTF8CString(bytes); |
| |
| try { |
| bytes = (getUrl() + '\0').getBytes("UTF-8"); //$NON-NLS-1$ |
| } catch (UnsupportedEncodingException e) { |
| bytes = (getUrl() + '\0').getBytes(); |
| } |
| int urlString = OS.JSStringCreateWithUTF8CString(bytes); |
| |
| 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 Cocoa.objc_msgSend(webView, Cocoa.S_goForward) != 0; |
| } |
| |
| public String getBrowserType () { |
| return "webkit"; //$NON-NLS-1$ |
| } |
| |
| public String getText() { |
| int mainFrame = Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame); |
| int dataSource = Cocoa.objc_msgSend(mainFrame, Cocoa.S_dataSource); |
| if (dataSource == 0) return ""; //$NON-NLS-1$ |
| int representation = Cocoa.objc_msgSend(dataSource, Cocoa.S_representation); |
| if (representation == 0) return ""; //$NON-NLS-1$ |
| int source = Cocoa.objc_msgSend(representation, Cocoa.S_documentSource); |
| if (source == 0) return ""; //$NON-NLS-1$ |
| int length = OS.CFStringGetLength(source); |
| char[] buffer = new char[length]; |
| CFRange range = new CFRange(); |
| range.length = length; |
| OS.CFStringGetCharacters(source, range, buffer); |
| return new String(buffer); |
| } |
| |
| public String getUrl() { |
| /* WebKit auto-navigates to about:blank at startup */ |
| if (url.length() == 0) return ABOUT_BLANK; |
| |
| return url; |
| } |
| |
| int handleCallback(int nextHandler, int theEvent) { |
| int eventKind = OS.GetEventKind(theEvent); |
| switch (OS.GetEventClass(theEvent)) { |
| case OS.kEventClassControl: |
| switch (eventKind) { |
| case OS.kEventControlGetClickActivation: { |
| OS.SetEventParameter (theEvent, OS.kEventParamClickActivation, OS.typeClickActivationResult, 4, new int [] {OS.kActivateAndHandleClick}); |
| return OS.noErr; |
| } |
| case OS.kEventControlSetCursor: { |
| return OS.noErr; |
| } |
| case OS.kEventControlDraw: { |
| /* |
| * Bug on WebKit. The web view cannot be obscured by other views above it. |
| * This problem is specified in the apple documentation for HiWebViewCreate. |
| * The workaround is to don't draw the web view when it is not visible. |
| */ |
| if (!browser.isVisible ()) return OS.noErr; |
| break; |
| } |
| case OS.kEventControlOwningWindowChanged: { |
| /* Reparent the web view handler */ |
| int window = OS.GetControlOwner(browser.handle); |
| int[] contentView = new int[1]; |
| OS.HIViewFindByID(OS.HIViewGetRoot(window), OS.kHIViewWindowContentID(), contentView); |
| OS.HIViewAddSubview(contentView[0], webViewHandle); |
| |
| /* Reset the kEventWindowBoundsChanged handler */ |
| OS.RemoveEventHandler(windowBoundsHandler); |
| int[] mask2 = new int[] { |
| OS.kEventClassWindow, OS.kEventWindowBoundsChanged, |
| }; |
| int[] outRef = new int[1]; |
| OS.InstallEventHandler(OS.GetWindowEventTarget(window), Callback3.getAddress(), mask2.length / 2, mask2, browser.handle, outRef); |
| windowBoundsHandler = outRef[0]; |
| break; |
| } |
| case OS.kEventControlBoundsChanged: |
| case OS.kEventControlVisibilityChanged: { |
| /* |
| * Bug on WebKit. The web view cannot be obscured by other views above it. |
| * This problem is specified in the apple documentation for HiWebViewCreate. |
| * The workaround is to hook kEventControlVisibilityChanged on the browser |
| * and move the browser out of the screen when hidden and restore its bounds |
| * when shown. |
| */ |
| CGRect bounds = new CGRect(); |
| if (!browser.isVisible()) { |
| bounds.x = bounds.y = -MIN_SIZE; |
| bounds.width = bounds.height = MIN_SIZE; |
| OS.HIViewSetFrame(webViewHandle, bounds); |
| } else { |
| OS.HIViewGetBounds(browser.handle, bounds); |
| int[] contentView = new int[1]; |
| OS.HIViewFindByID(OS.HIViewGetRoot(OS.GetControlOwner(browser.handle)), OS.kHIViewWindowContentID(), contentView); |
| OS.HIViewConvertRect(bounds, browser.handle, contentView[0]); |
| /* |
| * Bug in WebKit. For some reason, the web view will display incorrectly or |
| * blank depending on its contents, if its size is set to a value smaller than |
| * MIN_SIZE. It will not display properly even after the size is made larger. |
| * The fix is to avoid setting sizes smaller than MIN_SIZE. |
| */ |
| if (bounds.width <= MIN_SIZE) bounds.width = MIN_SIZE; |
| if (bounds.height <= MIN_SIZE) bounds.height = MIN_SIZE; |
| OS.HIViewSetFrame(webViewHandle, bounds); |
| } |
| break; |
| } |
| } |
| case OS.kEventClassWindow: |
| switch (eventKind) { |
| case OS.kEventWindowBoundsChanged: |
| /* |
| * Bug on WebKit. Resizing the height of a Shell containing a Browser at |
| * a fixed location causes the Browser to redraw at a wrong location. |
| * The web view is a HIView container that internally hosts |
| * a Cocoa NSView that uses a coordinates system with the origin at the |
| * bottom left corner of a window instead of the coordinates system used |
| * in Carbon that starts at the top left corner. The workaround is to |
| * reposition the web view every time the Shell of the Browser is resized. |
| * |
| * Note the size should not be updated if the browser is hidden. |
| */ |
| if (browser.isVisible()) { |
| CGRect oldBounds = new CGRect(); |
| OS.GetEventParameter (theEvent, OS.kEventParamOriginalBounds, OS.typeHIRect, null, CGRect.sizeof, null, oldBounds); |
| CGRect bounds = new CGRect(); |
| OS.GetEventParameter (theEvent, OS.kEventParamCurrentBounds, OS.typeHIRect, null, CGRect.sizeof, null, bounds); |
| if (oldBounds.height == bounds.height) break; |
| OS.HIViewGetBounds(browser.handle, bounds); |
| int[] contentView = new int[1]; |
| OS.HIViewFindByID(OS.HIViewGetRoot(OS.GetControlOwner(browser.handle)), OS.kHIViewWindowContentID(), contentView); |
| OS.HIViewConvertRect(bounds, browser.handle, contentView[0]); |
| /* |
| * Bug in WebKit. For some reason, the web view will display incorrectly or |
| * blank depending on its contents, if its size is set to a value smaller than |
| * MIN_SIZE. It will not display properly even after the size is made larger. |
| * The fix is to avoid setting sizes smaller than MIN_SIZE. |
| */ |
| if (bounds.width <= MIN_SIZE) bounds.width = MIN_SIZE; |
| if (bounds.height <= MIN_SIZE) bounds.height = MIN_SIZE; |
| bounds.x++; |
| /* Note that the bounds needs to change */ |
| OS.HIViewSetFrame(webViewHandle, bounds); |
| bounds.x--; |
| OS.HIViewSetFrame(webViewHandle, bounds); |
| } |
| } |
| case OS.kEventClassKeyboard: |
| switch (eventKind) { |
| case OS.kEventRawKeyDown: { |
| /* |
| * Bug in WebKit. The WebView blocks the propagation of certain Carbon events |
| * such as kEventRawKeyDown. On the Mac, Carbon events propagate from the |
| * Focus Target Handler to the Control Target Handler, Window Target and finally |
| * the Application Target Handler. It is assumed that WebView hooks its events |
| * on the Window Target and does not pass kEventRawKeyDown to the next handler. |
| * Since kEventRawKeyDown events never make it to the Application Target Handler, |
| * the Application Target Handler never gets to emit kEventTextInputUnicodeForKeyEvent |
| * used by SWT to send a SWT.KeyDown event. |
| * The workaround is to hook kEventRawKeyDown on the Control Target Handler which gets |
| * called before the WebView hook on the Window Target Handler. Then, forward this event |
| * directly to the Application Target Handler. Note that if in certain conditions WebKit |
| * does not block the kEventRawKeyDown, then multiple kEventTextInputUnicodeForKeyEvent |
| * events might be generated as a result of this workaround. |
| */ |
| //TEMPORARY CODE |
| // doit = false; |
| // OS.SendEventToEventTarget(theEvent, OS.GetApplicationEventTarget()); |
| // if (!doit) return OS.noErr; |
| |
| int[] length = new int[1]; |
| int status = OS.GetEventParameter (theEvent, OS.kEventParamKeyUnicodes, OS.typeUnicodeText, null, 4, length, (char[])null); |
| if (status == OS.noErr && length[0] != 0) { |
| int[] modifiers = new int[1]; |
| OS.GetEventParameter (theEvent, OS.kEventParamKeyModifiers, OS.typeUInt32, null, 4, null, modifiers); |
| char[] chars = new char[1]; |
| OS.GetEventParameter (theEvent, OS.kEventParamKeyUnicodes, OS.typeUnicodeText, null, 2, null, chars); |
| if ((modifiers[0] & OS.cmdKey) != 0) { |
| switch (chars[0]) { |
| case 'v': { |
| Cocoa.objc_msgSend (webView, Cocoa.S_paste); |
| return OS.noErr; |
| } |
| case 'c': { |
| Cocoa.objc_msgSend (webView, Cocoa.S_copy); |
| return OS.noErr; |
| } |
| case 'x': { |
| Cocoa.objc_msgSend (webView, Cocoa.S_cut); |
| return OS.noErr; |
| } |
| } |
| } |
| } |
| /* |
| * Bug in Carbon. OSX crashes if a HICocoaView is disposed during a key event, |
| * presumably as a result of attempting to use it after its refcount has reached |
| * 0. The workaround is to temporarily add an extra ref to the view and its |
| * ancestor while the DOM listener is handling the event, in case the |
| * Browser gets disposed in a callback. |
| */ |
| int handle = webViewHandle, root = OS.HIViewGetSuperview (webViewHandle); |
| OS.CFRetain (handle); |
| OS.CFRetain (root); |
| int result = OS.CallNextEventHandler (nextHandler, theEvent); |
| OS.CFRelease (handle); |
| OS.CFRelease (root); |
| return result; |
| } |
| } |
| case OS.kEventClassTextInput: |
| switch (eventKind) { |
| case OS.kEventTextInputUnicodeForKeyEvent: { |
| /* |
| * Note. This event is received from the Window Target therefore after it was received |
| * by the Focus Target. The SWT.KeyDown event is sent by SWT on the Focus Target. If it |
| * is received here, then the SWT.KeyDown doit flag must have been left to the value |
| * true. For package visibility reasons we cannot access the doit flag directly. |
| * |
| * Sequence of events when the user presses a key down |
| * |
| * .Control Target - kEventRawKeyDown |
| * .forward to ApplicationEventTarget |
| * .Focus Target kEventTextInputUnicodeForKeyEvent - SWT emits SWT.KeyDown - |
| * blocks further propagation if doit false. Browser does not know directly about |
| * the doit flag value. |
| * .Window Target kEventTextInputUnicodeForKeyEvent - if received, Browser knows |
| * SWT.KeyDown is not blocked and event should be sent to WebKit |
| * Return from Control Target - kEventRawKeyDown: let the event go to WebKit if doit true |
| * (eventNotHandledErr) or stop it (noErr). |
| */ |
| //TEMPORARY CODE |
| // doit = true; |
| break; |
| } |
| } |
| } |
| return OS.eventNotHandledErr; |
| } |
| |
| /* Here we dispatch all WebView upcalls. */ |
| int handleCallback(int selector, int arg0, int arg1, int arg2, int arg3) { |
| int ret = 0; |
| // for meaning of selector see WebKitDelegate methods in webkit.c |
| switch (selector) { |
| case 1: didFailProvisionalLoadWithError(arg0, arg1); break; |
| case 2: didFinishLoadForFrame(arg0); break; |
| case 3: didReceiveTitle(arg0, arg1); break; |
| case 4: didStartProvisionalLoadForFrame(arg0); break; |
| case 5: didFinishLoadingFromDataSource(arg0, arg1); break; |
| case 6: didFailLoadingWithError(arg0, arg1, arg2); break; |
| case 7: ret = identifierForInitialRequest(arg0, arg1); break; |
| case 8: ret = willSendRequest(arg0, arg1, arg2, arg3); break; |
| case 9: handleNotification(arg0); break; |
| case 10: didCommitLoadForFrame(arg0); break; |
| case 11: ret = createWebViewWithRequest(arg0); break; |
| case 12: webViewShow(arg0); break; |
| case 13: setFrame(arg0); break; |
| case 14: webViewClose(); break; |
| case 15: ret = contextMenuItemsForElement(arg0, arg1); break; |
| case 16: setStatusBarVisible(arg0); break; |
| case 17: setResizable(arg0); break; |
| case 18: setToolbarsVisible(arg0); break; |
| case 19: decidePolicyForMIMEType(arg0, arg1, arg2, arg3); break; |
| case 20: decidePolicyForNavigationAction(arg0, arg1, arg2, arg3); break; |
| case 21: decidePolicyForNewWindowAction(arg0, arg1, arg2, arg3); break; |
| case 22: unableToImplementPolicyWithError(arg0, arg1); break; |
| case 23: setStatusText(arg0); break; |
| case 24: webViewFocus(); break; |
| case 25: webViewUnfocus(); break; |
| case 26: runJavaScriptAlertPanelWithMessage(arg0); break; |
| case 27: ret = runJavaScriptConfirmPanelWithMessage(arg0); break; |
| case 28: runOpenPanelForFileButtonWithResultListener(arg0); break; |
| case 29: decideDestinationWithSuggestedFilename(arg0, arg1); break; |
| case 30: mouseDidMoveOverElement(arg0, arg1); break; |
| case 31: didChangeLocationWithinPageForFrame(arg0); break; |
| case 32: handleEvent(arg0); break; |
| case 33: windowScriptObjectAvailable(arg0); break; |
| case 34: ret = callJava(arg0, arg1, arg2, arg3); break; |
| case 35: didReceiveAuthenticationChallengefromDataSource(arg0, arg1, arg2); break; |
| case 36: ret = runBeforeUnloadConfirmPanelWithMessage(arg0, arg1); break; |
| case 37: ret = callRunBeforeUnloadConfirmPanelWithMessage(arg0, arg1); break; |
| case 38: createPanelDidEnd(arg0, arg1, arg2); break; |
| } |
| return ret; |
| } |
| |
| public boolean isBackEnabled() { |
| return Cocoa.objc_msgSend(webView, Cocoa.S_canGoBack) != 0; |
| } |
| |
| public boolean isForwardEnabled() { |
| return Cocoa.objc_msgSend(webView, Cocoa.S_canGoForward) != 0; |
| } |
| |
| public void refresh() { |
| html = null; |
| Cocoa.objc_msgSend(webView, Cocoa.S_reload, 0); |
| } |
| |
| 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; |
| |
| int str = createNSString(ABOUT_BLANK); |
| int inURL = Cocoa.objc_msgSend(Cocoa.C_NSURL, Cocoa.S_URLWithString, str); /* autoreleased */ |
| OS.CFRelease (str); |
| int request = Cocoa.objc_msgSend(Cocoa.C_NSURLRequest, Cocoa.S_requestWithURL, inURL); |
| int mainFrame = Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame); |
| Cocoa.objc_msgSend(mainFrame, Cocoa.S_loadRequest, request); |
| return true; |
| } |
| |
| public boolean setUrl(String url, String postData, String[] headers) { |
| html = null; |
| |
| if (url.indexOf('/') == 0) { |
| url = PROTOCOL_FILE + url; |
| } else if (url.indexOf(':') == -1) { |
| url = PROTOCOL_HTTP + url; |
| } |
| |
| int inURL = 0; |
| int str = createNSString(url); |
| if (str != 0) { |
| char[] unescapedChars = new char[] {'%', '#'}; |
| int unescapedStr = OS.CFStringCreateWithCharacters(0, unescapedChars, unescapedChars.length); |
| int escapedStr = OS.CFURLCreateStringByAddingPercentEscapes(OS.kCFAllocatorDefault, str, unescapedStr, 0, OS.kCFStringEncodingUTF8); |
| if (escapedStr != 0) { |
| inURL = OS.CFURLCreateWithString(OS.kCFAllocatorDefault, escapedStr, 0); |
| OS.CFRelease(escapedStr); |
| } |
| if (unescapedStr != 0) OS.CFRelease(unescapedStr); |
| OS.CFRelease(str); |
| } |
| if (inURL == 0) return false; |
| |
| int request = Cocoa.objc_msgSend(Cocoa.C_NSMutableURLRequest, Cocoa.S_requestWithURL, inURL); |
| OS.CFRelease(inURL); |
| |
| if (postData != null) { |
| int post = createNSString(POST); |
| Cocoa.objc_msgSend(request, Cocoa.S_setHTTPMethod, post); |
| OS.CFRelease (post); |
| byte[] bytes = postData.getBytes(); |
| int data = Cocoa.objc_msgSend(Cocoa.C_NSData, Cocoa.S_dataWithBytes, bytes, bytes.length); |
| Cocoa.objc_msgSend(request, Cocoa.S_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. |
| */ |
| int string = createNSString(value); |
| Cocoa.objc_msgSend(webView, Cocoa.S_setCustomUserAgent, string); |
| OS.CFRelease (string); |
| } else { |
| int keyString = createNSString(key); |
| int valueString = createNSString(value); |
| Cocoa.objc_msgSend(request, Cocoa.S_setValueForHTTPHeaderField, valueString, keyString); |
| OS.CFRelease (valueString); |
| OS.CFRelease (keyString); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| int mainFrame = Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame); |
| Cocoa.objc_msgSend(mainFrame, Cocoa.S_loadRequest, request); |
| Cocoa.objc_msgSend(webView, Cocoa.S_setCustomUserAgent, 0); |
| return true; |
| } |
| |
| public void stop() { |
| html = null; |
| Cocoa.objc_msgSend(webView, Cocoa.S_stopLoading, 0); |
| } |
| |
| boolean translateMnemonics() { |
| return false; |
| } |
| |
| /* WebFrameLoadDelegate */ |
| void didChangeLocationWithinPageForFrame(int frame) { |
| //id url= [[[[frame provisionalDataSource] request] URL] absoluteString]; |
| int dataSource = Cocoa.objc_msgSend(frame, Cocoa.S_dataSource); |
| int request = Cocoa.objc_msgSend(dataSource, Cocoa.S_request); |
| int url = Cocoa.objc_msgSend(request, Cocoa.S_URL); |
| int s = Cocoa.objc_msgSend(url, Cocoa.S_absoluteString); |
| int length = OS.CFStringGetLength(s); |
| if (length == 0) return; |
| char[] buffer = new char[length]; |
| CFRange range = new CFRange(); |
| range.length = length; |
| OS.CFStringGetCharacters(s, range, buffer); |
| String url2 = new String(buffer); |
| /* |
| * 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 = frame == Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame); |
| 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 didFailProvisionalLoadWithError(int error, int frame) { |
| if (frame == Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame)) { |
| /* |
| * 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; |
| } |
| |
| int errorCode = Cocoa.objc_msgSend(error, Cocoa.S_code); |
| if (Cocoa.NSURLErrorBadURL < errorCode) return; |
| |
| int failingURL = 0; |
| int info = Cocoa.objc_msgSend(error, Cocoa.S_userInfo); |
| if (info != 0) { |
| int keyString = createNSString("NSErrorFailingURLKey"); //$NON-NLS-1$ |
| failingURL = Cocoa.objc_msgSend(info, Cocoa.S_valueForKey, keyString); |
| OS.CFRelease(keyString); |
| } |
| |
| if (failingURL != 0 && Cocoa.NSURLErrorServerCertificateNotYetValid <= errorCode && errorCode <= Cocoa.NSURLErrorSecureConnectionFailed) { |
| /* handle invalid certificate error */ |
| int keyString = createNSString("NSErrorPeerCertificateChainKey"); //$NON-NLS-1$ |
| int certificates = Cocoa.objc_msgSend(info, Cocoa.S_objectForKey, keyString); |
| OS.CFRelease(keyString); |
| |
| int[] policySearch = new int[1]; |
| int[] policyRef = new int[1]; |
| int[] trustRef = new 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, policyRef[0], trustRef); |
| if (result == 0 && trustRef[0] != 0) { |
| int panel = Cocoa.objc_msgSend(Cocoa.C_SFCertificateTrustPanel, Cocoa.S_sharedCertificateTrustPanel); |
| String failingUrlString = getString(Cocoa.objc_msgSend(failingURL, Cocoa.S_absoluteString)); |
| String message = Compatibility.getMessage("SWT_InvalidCert_Message", new Object[] {failingUrlString}); //$NON-NLS-1$ |
| int nsString = createNSString(Compatibility.getMessage("SWT_Cancel")); //$NON-NLS-1$ |
| Cocoa.objc_msgSend(panel, Cocoa.S_setAlternateButtonTitle, nsString); |
| OS.CFRelease(nsString); |
| Cocoa.objc_msgSend(panel, Cocoa.S_setShowsHelp, 1); |
| Cocoa.objc_msgSend(failingURL, Cocoa.S_retain); |
| int window = Cocoa.objc_msgSend(webView, Cocoa.S_window); |
| nsString = createNSString(message); |
| Cocoa.objc_msgSend(panel, Cocoa.S_beginSheetForWindow, window, delegate, Cocoa.S_createPanelDidEnd, failingURL, trustRef[0], nsString); |
| OS.CFRelease(nsString); |
| 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 */ |
| int description = Cocoa.objc_msgSend(error, Cocoa.S_localizedDescription); |
| if (description != 0) { |
| String descriptionString = getString(description); |
| String message = failingURL != 0 ? getString(Cocoa.objc_msgSend(failingURL, Cocoa.S_absoluteString)) + "\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(int sheet, int returnCode, int contextInfo) { |
| Cocoa.objc_msgSend(contextInfo, Cocoa.S_autorelease); |
| if (returnCode != Cocoa.NSFileHandlingPanelOKButton) return; /* nothing more to do */ |
| |
| long /*int*/ method = Cocoa.class_getClassMethod(Cocoa.C_NSURLRequest, Cocoa.S_setAllowsAnyHTTPSCertificate); |
| if (method != 0) { |
| int host = Cocoa.objc_msgSend(contextInfo, Cocoa.S_host); |
| int urlString = Cocoa.objc_msgSend(contextInfo, Cocoa.S_absoluteString); |
| Cocoa.objc_msgSend(Cocoa.C_NSURLRequest, Cocoa.S_setAllowsAnyHTTPSCertificate, 1, host); |
| setUrl(getString(urlString), null, null); |
| } |
| } |
| |
| void didFinishLoadForFrame(int frame) { |
| if (frame == Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame)) { |
| /* |
| * 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; |
| int htmlString = createNSString(html); |
| int urlString; |
| if (untrustedText) { |
| urlString = createNSString(ABOUT_BLANK); |
| } else { |
| urlString = createNSString(URI_FILEROOT); |
| } |
| int url = Cocoa.objc_msgSend(Cocoa.C_NSURL, Cocoa.S_URLWithString, urlString); /* autoreleased */ |
| int mainFrame = Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame); |
| Cocoa.objc_msgSend(mainFrame, Cocoa.S_loadHTMLStringBaseURL, htmlString, url); |
| OS.CFRelease(urlString); |
| OS.CFRelease(htmlString); |
| html = null; |
| } |
| } |
| |
| /* |
| * The loadHTMLStringBaseURL invocation above will trigger a second 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. |
| */ |
| final Display display = browser.getDisplay(); |
| int dataSource = Cocoa.objc_msgSend(frame, Cocoa.S_dataSource); |
| if (dataSource != 0) { |
| int title = Cocoa.objc_msgSend(dataSource, Cocoa.S_pageTitle); |
| if (title == 0) { /* page has no title */ |
| final 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. Howeever, 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 hookDOMFocusListeners(int frame) { |
| /* |
| * These listeners only need to be hooked for OSX 10.4 (Tiger). The WebKit on |
| * OSX < 10.4 does not send these DOM events, and tab traversals that exit |
| * WebKit are handled as of OSX 10.5 as a result of using HICocoaViewCreate, |
| * which makes these listeners unnecessary. |
| */ |
| if (!(0x1040 <= OS.VERSION && OS.VERSION < 0x1050)) return; |
| |
| int document = Cocoa.objc_msgSend(frame, Cocoa.S_DOMDocument); |
| if (document == 0) return; |
| |
| int ptr = createNSString(DOMEVENT_FOCUSIN); |
| Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0); |
| OS.CFRelease(ptr); |
| |
| ptr = createNSString(DOMEVENT_FOCUSOUT); |
| Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0); |
| OS.CFRelease(ptr); |
| } |
| |
| void hookDOMKeyListeners(int frame) { |
| /* |
| * WebKit's DOM listener api became functional in OSX 10.4, so if an earlier |
| * version than this is detected then do not hook the DOM listeners. |
| */ |
| if (OS.VERSION < 0x1040) return; |
| |
| int document = Cocoa.objc_msgSend(frame, Cocoa.S_DOMDocument); |
| if (document == 0) return; |
| |
| int ptr = createNSString(DOMEVENT_KEYDOWN); |
| Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0); |
| OS.CFRelease(ptr); |
| |
| ptr = createNSString(DOMEVENT_KEYUP); |
| Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0); |
| OS.CFRelease(ptr); |
| } |
| |
| void hookDOMMouseListeners(int frame) { |
| /* |
| * WebKit's DOM listener api became functional in OSX 10.4, so if an earlier |
| * version than this is detected then do not hook the DOM listeners. |
| */ |
| if (OS.VERSION < 0x1040) return; |
| |
| int document = Cocoa.objc_msgSend(frame, Cocoa.S_DOMDocument); |
| if (document == 0) return; |
| |
| int ptr = createNSString(DOMEVENT_MOUSEDOWN); |
| Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0); |
| OS.CFRelease(ptr); |
| |
| ptr = createNSString(DOMEVENT_MOUSEUP); |
| Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0); |
| OS.CFRelease(ptr); |
| |
| ptr = createNSString(DOMEVENT_MOUSEMOVE); |
| Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0); |
| OS.CFRelease(ptr); |
| |
| ptr = createNSString(DOMEVENT_MOUSEWHEEL); |
| Cocoa.objc_msgSend(document, Cocoa.S_addEventListener, ptr, delegate, 0); |
| OS.CFRelease(ptr); |
| } |
| |
| void didReceiveTitle(int title, int frame) { |
| if (frame == Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame)) { |
| int length = OS.CFStringGetLength(title); |
| char[] buffer = new char[length]; |
| CFRange range = new CFRange(); |
| range.length = length; |
| OS.CFStringGetCharacters(title, range, buffer); |
| String newTitle = new String(buffer); |
| 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 didStartProvisionalLoadForFrame(int frame) { |
| /* |
| * 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. |
| */ |
| // int webView = WebKit.HIWebViewGetWebView(webViewHandle); |
| // if (frame == WebKit.objc_msgSend(webView, WebKit.S_mainFrame)) { |
| // /* reset resource status variables */ |
| // resourceCount= 0; |
| // } |
| } |
| |
| void didCommitLoadForFrame(int frame) { |
| //id url= [[[[frame provisionalDataSource] request] URL] absoluteString]; |
| int dataSource = Cocoa.objc_msgSend(frame, Cocoa.S_dataSource); |
| int request = Cocoa.objc_msgSend(dataSource, Cocoa.S_request); |
| int url = Cocoa.objc_msgSend(request, Cocoa.S_URL); |
| int s = Cocoa.objc_msgSend(url, Cocoa.S_absoluteString); |
| int length = OS.CFStringGetLength(s); |
| if (length == 0) return; |
| char[] buffer = new char[length]; |
| CFRange range = new CFRange(); |
| range.length = length; |
| OS.CFStringGetCharacters(s, range, buffer); |
| String url2 = new String(buffer); |
| /* |
| * 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 = frame == Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame); |
| if (top) { |
| /* reset resource status variables */ |
| resourceCount = 0; |
| this.url = url2; |
| |
| /* |
| * Each invocation of setText() causes 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 loadHTMLStringBaseURL is invoked. If |
| * this is the first 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; |
| |
| Enumeration elements = functions.elements (); |
| while (elements.hasMoreElements ()) { |
| BrowserFunction function = (BrowserFunction)elements.nextElement (); |
| execute (function.functionString); |
| } |
| |
| final 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(frame); |
| } |
| |
| hookDOMFocusListeners(frame); |
| hookDOMMouseListeners(frame); |
| |
| 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 windowScriptObjectAvailable (int windowScriptObject) { |
| int str = createNSString("external"); //$NON-NLS-1$ |
| if (str != 0) { |
| Cocoa.objc_msgSend (windowScriptObject, Cocoa.S_setValue, delegate, str); |
| OS.CFRelease (str); |
| } |
| } |
| |
| /* WebResourceLoadDelegate */ |
| |
| void didFinishLoadingFromDataSource(int identifier, 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. Howeever, 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 didFailLoadingWithError(int identifier, int error, 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. Howeever, 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 didReceiveAuthenticationChallengefromDataSource (int identifier, int challenge, int dataSource) { |
| /* |
| * 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. |
| */ |
| int count = Cocoa.objc_msgSend (challenge, Cocoa.S_previousFailureCount); |
| if (count < 3) { |
| for (int i = 0; i < authenticationListeners.length; i++) { |
| AuthenticationEvent event = new AuthenticationEvent (browser); |
| event.location = lastNavigateURL; |
| authenticationListeners[i].authenticate (event); |
| if (!event.doit) { |
| int challengeSender = Cocoa.objc_msgSend (challenge, Cocoa.S_sender); |
| Cocoa.objc_msgSend (challengeSender, Cocoa.S_cancelAuthenticationChallenge, challenge); |
| return; |
| } |
| if (event.user != null && event.password != null) { |
| int challengeSender = Cocoa.objc_msgSend (challenge, Cocoa.S_sender); |
| int user = createNSString(event.user); |
| int password = createNSString(event.password); |
| int credential = Cocoa.objc_msgSend (Cocoa.C_NSURLCredential, Cocoa.S_credentialWithUser, user, password, Cocoa.NSURLCredentialPersistenceForSession); |
| Cocoa.objc_msgSend (challengeSender, Cocoa.S_useCredential, credential, challenge); |
| OS.CFRelease (password); |
| OS.CFRelease (user); |
| return; |
| } |
| } |
| } |
| |
| /* no listener handled the challenge, so try to invoke the native panel */ |
| int cls = Cocoa.C_WebPanelAuthenticationHandler; |
| if (cls != 0) { |
| int method = Cocoa.class_getClassMethod (cls, Cocoa.S_sharedHandler); |
| if (method != 0) { |
| int handler = Cocoa.objc_msgSend (cls, Cocoa.S_sharedHandler); |
| if (handler != 0) { |
| int window = Cocoa.objc_msgSend (webView, Cocoa.S_window); |
| Cocoa.objc_msgSend (handler, Cocoa.S_startAuthentication, challenge, window); |
| return; |
| } |
| } |
| } |
| |
| /* the native panel was not available, so show a custom dialog */ |
| String[] userReturn = new String[1], passwordReturn = new String[1]; |
| int proposedCredential = Cocoa.objc_msgSend (challenge, Cocoa.S_proposedCredential); |
| if (proposedCredential != 0) { |
| int user = Cocoa.objc_msgSend (proposedCredential, Cocoa.S_user); |
| userReturn[0] = getString (user); |
| boolean hasPassword = Cocoa.objc_msgSend (proposedCredential, Cocoa.S_hasPassword) != 0; |
| if (hasPassword) { |
| int password = Cocoa.objc_msgSend (proposedCredential, Cocoa.S_password); |
| passwordReturn[0] = getString (password); |
| } |
| } |
| |
| int space = Cocoa.objc_msgSend (challenge, Cocoa.S_protectionSpace); |
| int host = Cocoa.objc_msgSend (space, Cocoa.S_host); |
| String hostString = getString (host) + ':'; |
| int port = Cocoa.objc_msgSend (space, Cocoa.S_port); |
| hostString += port; |
| int realm = Cocoa.objc_msgSend (space, Cocoa.S_realm); |
| String realmString = getString (realm); |
| boolean result = showAuthenticationDialog (userReturn, passwordReturn, hostString, realmString); |
| int challengeSender = Cocoa.objc_msgSend (challenge, Cocoa.S_sender); |
| if (!result) { |
| Cocoa.objc_msgSend (challengeSender, Cocoa.S_cancelAuthenticationChallenge, challenge); |
| return; |
| } |
| |
| int user = createNSString(userReturn[0]); |
| int password = createNSString(passwordReturn[0]); |
| int credential = Cocoa.objc_msgSend (Cocoa.C_NSURLCredential, Cocoa.S_credentialWithUser, user, password, Cocoa.NSURLCredentialPersistenceForSession); |
| Cocoa.objc_msgSend (challengeSender, Cocoa.S_useCredential, credential, challenge); |
| OS.CFRelease (password); |
| OS.CFRelease (user); |
| } |
| |
| 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]; |
| } |
| |
| int identifierForInitialRequest(int request, int dataSource) { |
| final Display display = browser.getDisplay(); |
| final ProgressEvent progress = new ProgressEvent(browser); |
| progress.display = display; |
| 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; |
| |
| /* |
| * Note. numberWithInt uses autorelease. The resulting object |
| * does not need to be released. |
| * identifier = [NSNumber numberWithInt: resourceCount++] |
| */ |
| int identifier = Cocoa.objc_msgSend(Cocoa.C_NSNumber, Cocoa.S_numberWithInt, resourceCount++); |
| |
| if (this.identifier == 0) { |
| int frame = Cocoa.objc_msgSend(dataSource, Cocoa.S_webFrame); |
| if (frame == Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame)) this.identifier = identifier; |
| } |
| return identifier; |
| } |
| |
| int willSendRequest(int identifier, int request, int redirectResponse, int dataSource) { |
| int url = Cocoa.objc_msgSend (request, Cocoa.S_URL); |
| boolean isFileURL = Cocoa.objc_msgSend (url, Cocoa.S_isFileURL) != 0; |
| if (isFileURL) { |
| int newRequest = Cocoa.objc_msgSend (request, Cocoa.S_mutableCopy); |
| Cocoa.objc_msgSend (newRequest, Cocoa.S_autorelease); |
| Cocoa.objc_msgSend (newRequest, Cocoa.S_setCachePolicy, Cocoa.NSURLRequestReloadIgnoringLocalCacheData); |
| return newRequest; |
| } |
| return request; |
| } |
| |
| /* handleNotification */ |
| |
| void handleNotification(int notification) { |
| } |
| |
| /* UIDelegate */ |
| int createWebViewWithRequest(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); |
| } |
| } |
| |
| int webView = 0; |
| Browser browser = null; |
| if (newEvent.browser != null && newEvent.browser.webBrowser instanceof WebKit) { |
| browser = newEvent.browser; |
| } |
| if (browser != null && !browser.isDisposed()) { |
| webView = ((WebKit)browser.webBrowser).webView; |
| |
| if (request != 0) { |
| //mainFrame = [webView mainFrame]; |
| int mainFrame= Cocoa.objc_msgSend(webView, Cocoa.S_mainFrame); |
| |
| //[mainFrame loadRequest:request]; |
| Cocoa.objc_msgSend(mainFrame, Cocoa.S_loadRequest, request); |
| } |
| } |
| return webView; |
| } |
| |
| void webViewShow(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 setFrame(int frame) { |
| float[] dest = new float[4]; |
| OS.memmove(dest, frame, 16); |
| /* convert to SWT system coordinates */ |
| Rectangle bounds = browser.getDisplay().getBounds(); |
| location = new Point((int)dest[0], bounds.height - (int)dest[1] - (int)dest[3]); |
| size = new Point((int)dest[2], (int)dest[3]); |
| } |
| |
| void webViewFocus() { |
| } |
| |
| void webViewUnfocus() { |
| } |
| |
| int callRunBeforeUnloadConfirmPanelWithMessage(long /*int*/ messageID, long /*int*/ arg) { |
| int result = runBeforeUnloadConfirmPanelWithMessage (messageID, 0); |
| return Cocoa.objc_msgSend (Cocoa.C_NSNumber, Cocoa.S_numberWithBool, result); |
| } |
| |
| int runBeforeUnloadConfirmPanelWithMessage(int message, int frame) { |
| StringBuffer text = new StringBuffer(Compatibility.getMessage("SWT_OnBeforeUnload_Message1")); //$NON-NLS-1$ |
| text.append ("\n\n"); //$NON-NLS-1$ |
| int length = OS.CFStringGetLength(message); |
| char[] buffer = new char[length]; |
| CFRange range = new CFRange(); |
| range.length = length; |
| OS.CFStringGetCharacters(message, range, buffer); |
| text.append(new String(buffer)); |
| 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); |
| messageBox.setMessage(text.toString()); |
| return messageBox.open() == SWT.OK ? 1 : 0; |
| } |
| |
| void runJavaScriptAlertPanelWithMessage(int message) { |
| int length = OS.CFStringGetLength(message); |
| char[] buffer = new char[length]; |
| CFRange range = new CFRange(); |
| range.length = length; |
| OS.CFStringGetCharacters(message, range, buffer); |
| String text = new String(buffer); |
| |
| MessageBox messageBox = new MessageBox(browser.getShell(), SWT.OK | SWT.ICON_WARNING); |
| messageBox.setText("Javascript"); //$NON-NLS-1$ |
| messageBox.setMessage(text); |
| messageBox.open(); |
| } |
| |
| int runJavaScriptConfirmPanelWithMessage(int message) { |
| int length = OS.CFStringGetLength(message); |
| char[] buffer = new char[length]; |
| CFRange range = new CFRange(); |
| range.length = length; |
| OS.CFStringGetCharacters(message, range, buffer); |
| String text = new String(buffer); |
| |
| 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 runOpenPanelForFileButtonWithResultListener(int resultListener) { |
| FileDialog dialog = new FileDialog(browser.getShell(), SWT.NONE); |
| String result = dialog.open(); |
| if (result == null) { |
| Cocoa.objc_msgSend(resultListener, Cocoa.S_cancel); |
| return; |
| } |
| int filename = createNSString(result); |
| Cocoa.objc_msgSend(resultListener, Cocoa.S_chooseFilename, filename); |
| OS.CFRelease(filename); |
| } |
| |
| void webViewClose() { |
| 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); |
| } |
| |
| int contextMenuItemsForElement(int element, int defaultMenuItems) { |
| org.eclipse.swt.internal.carbon.Point pt = new org.eclipse.swt.internal.carbon.Point(); |
| OS.GetGlobalMouse(pt); |
| Event event = new Event(); |
| event.x = pt.h; |
| event.y = pt.v; |
| browser.notifyListeners(SWT.MenuDetect, event); |
| if (!event.doit || browser.isDisposed()) return 0; |
| Menu menu = browser.getMenu(); |
| if (menu != null && !menu.isDisposed()) { |
| if (event.x != pt.h || event.y != pt.v) { |
| menu.setLocation(event.x, event.y); |
| } |
| menu.setVisible(true); |
| return 0; |
| } |
| return defaultMenuItems; |
| } |
| |
| void setStatusBarVisible(int visible) { |
| /* Note. Webkit only emits the notification when the status bar should be hidden. */ |
| statusBar = visible != 0; |
| } |
| |
| void setStatusText(int text) { |
| int length = OS.CFStringGetLength(text); |
| if (length == 0) return; |
| char[] buffer = new char[length]; |
| CFRange range = new CFRange(); |
| range.length = length; |
| OS.CFStringGetCharacters(text, range, buffer); |
| |
| StatusTextEvent statusText = new StatusTextEvent(browser); |
| statusText.display = browser.getDisplay(); |
| statusText.widget = browser; |
| statusText.text = new String(buffer); |
| for (int i = 0; i < statusTextListeners.length; i++) { |
| statusTextListeners[i].changed(statusText); |
| } |
| } |
| |
| void setResizable(int visible) { |
| } |
| |
| void setToolbarsVisible(int visible) { |
| /* Note. Webkit only emits the notification when the tool bar should be hidden. */ |
| toolBar = visible != 0; |
| } |
| |
| void mouseDidMoveOverElement (int elementInformation, int modifierFlags) { |
| if (elementInformation == 0) return; |
| if (!browser.isEnabled ()) return; |
| |
| int key = createNSString(WebElementLinkURLKey); |
| int value = Cocoa.objc_msgSend(elementInformation, Cocoa.S_valueForKey, key); |
| OS.CFRelease(key); |
| if (value == 0) { |
| /* 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; |
| } |
| |
| int stringPtr = Cocoa.objc_msgSend(value, Cocoa.S_absoluteString); |
| int length = OS.CFStringGetLength(stringPtr); |
| String urlString; |
| if (length == 0) { |
| urlString = ""; //$NON-NLS-1$ |
| } else { |
| char[] chars = new char[length]; |
| CFRange range = new CFRange(); |
| range.length = length; |
| OS.CFStringGetCharacters(stringPtr, range, chars); |
| urlString = new String(chars); |
| } |
| 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); |
| } |
| } |
| |
| /* PolicyDelegate */ |
| |
| void decidePolicyForMIMEType(int type, int request, int frame, int listener) { |
| boolean canShow = Cocoa.objc_msgSend(Cocoa.C_WebView, Cocoa.S_canShowMIMEType, type) != 0; |
| Cocoa.objc_msgSend(listener, canShow ? Cocoa.S_use : Cocoa.S_download); |
| } |
| |
| void decidePolicyForNavigationAction(int actionInformation, int request, int frame, int listener) { |
| int url = Cocoa.objc_msgSend(request, Cocoa.S_URL); |
| 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(). |
| */ |
| Cocoa.objc_msgSend(listener, Cocoa.S_use); |
| return; |
| } |
| if (url == 0) { |
| /* indicates that a URL with an invalid format was specified */ |
| Cocoa.objc_msgSend(listener, Cocoa.S_ignore); |
| return; |
| } |
| boolean isFileURL = Cocoa.objc_msgSend(url, Cocoa.S_isFileURL) != 0; |
| if (isFileURL && getUrl().startsWith(ABOUT_BLANK) && untrustedText) { |
| /* indicates an attempt to access the local file system from untrusted content */ |
| Cocoa.objc_msgSend(listener, Cocoa.S_ignore); |
| return; |
| } |
| int s = Cocoa.objc_msgSend(url, Cocoa.S_absoluteString); |
| int length = OS.CFStringGetLength(s); |
| char[] buffer = new char[length]; |
| CFRange range = new CFRange(); |
| range.length = length; |
| OS.CFStringGetCharacters(s, range, buffer); |
| String url2 = new String(buffer); |
| /* |
| * 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); |
| } |
| } |
| |
| if (url2.startsWith (URI_APPLEWEBDATA)) { |
| /* listeners should not be notified of internal transitions like this */ |
| Cocoa.objc_msgSend(listener, Cocoa.S_use); |
| } else { |
| 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 == 0) { |
| preferences = Cocoa.objc_msgSend (Cocoa.C_WebPreferences, Cocoa.S_alloc); |
| Cocoa.objc_msgSend (preferences, Cocoa.S_init); |
| Cocoa.objc_msgSend (webView, Cocoa.S_setPreferences, preferences); |
| } |
| Cocoa.objc_msgSend (preferences, Cocoa.S_setJavaScriptEnabled, jsEnabled ? 1 : 0); |
| } |
| lastNavigateURL = url2; |
| } |
| Cocoa.objc_msgSend(listener, newEvent.doit ? Cocoa.S_use : Cocoa.S_ignore); |
| } |
| } |
| |
| void decidePolicyForNewWindowAction(int actionInformation, int request, int frameName, int listener) { |
| Cocoa.objc_msgSend(listener, Cocoa.S_use); |
| } |
| |
| void unableToImplementPolicyWithError(int error, int frame) { |
| } |
| |
| /* WebDownload */ |
| |
| void decideDestinationWithSuggestedFilename (int download, int filename) { |
| int length = OS.CFStringGetLength(filename); |
| char[] buffer = new char[length]; |
| CFRange range = new CFRange(); |
| range.length = length; |
| OS.CFStringGetCharacters(filename, range, buffer); |
| String name = new String(buffer); |
| |
| /* |
| * Bug in WebKit. As of OSX 10.5.5, showing the file dialog here invokes this |
| * callback a second time when the file dialog runs the event loop, which |
| * always leads to a crash. The workaround is to choose a location to save |
| * the file without showing the file dialog. |
| */ |
| String path = null; |
| if (OS.VERSION >= 0x1055) { |
| int array = Cocoa.NSSearchPathForDirectoriesInDomains (Cocoa.NSDesktopDirectory, Cocoa.NSAllDomainsMask, true); |
| int count = Cocoa.objc_msgSend (array, Cocoa.S_count); |
| if (count == 0) { /* should never happen */ |
| array = Cocoa.NSSearchPathForDirectoriesInDomains (Cocoa.NSDownloadsDirectory, Cocoa.NSAllDomainsMask, true); |
| count = Cocoa.objc_msgSend (array, Cocoa.S_count); |
| if (count == 0) { |
| array = Cocoa.NSSearchPathForDirectoriesInDomains (Cocoa.NSDocumentDirectory, Cocoa.NSAllDomainsMask, true); |
| count = Cocoa.objc_msgSend (array, Cocoa.S_count); |
| if (count == 0) { |
| Cocoa.objc_msgSend (download, Cocoa.S_cancel); |
| return; |
| } |
| } |
| } |
| int string = Cocoa.objc_msgSend (array, Cocoa.S_objectAtIndex, 0); |
| length = OS.CFStringGetLength (string); |
| buffer = new char[length]; |
| range = new CFRange (); |
| range.length = length; |
| OS.CFStringGetCharacters (string, range, buffer); |
| path = new String (buffer) + '/' + name; |
| } else { |
| FileDialog dialog = new FileDialog(browser.getShell(), SWT.SAVE); |
| dialog.setText(SWT.getMessage ("SWT_FileDownload")); //$NON-NLS-1$ |
| dialog.setFileName(name); |
| path = dialog.open(); |
| } |
| |
| if (path == null) { |
| /* cancel pressed */ |
| Cocoa.objc_msgSend(download, Cocoa.S_cancel); |
| return; |
| } |
| int result = createNSString(path); |
| Cocoa.objc_msgSend(download, Cocoa.S_setDestinationAllowOverwrite, result, 1); |
| OS.CFRelease(result); |
| } |
| |
| /* DOMEventListener */ |
| |
| void handleEvent(int evt) { |
| if (!browser.isEnabled ()) return; |
| |
| int type = Cocoa.objc_msgSend(evt, Cocoa.S_type); |
| int length = OS.CFStringGetLength(type); |
| char[] buffer = new char[length]; |
| CFRange range = new CFRange(); |
| range.length = length; |
| OS.CFStringGetCharacters(type, range, buffer); |
| String typeString = new String(buffer); |
| |
| if (typeString.equals(DOMEVENT_FOCUSIN)) { |
| hasNewFocusElement = true; |
| return; |
| } |
| if (typeString.equals(DOMEVENT_FOCUSOUT)) { |
| hasNewFocusElement = false; |
| return; |
| } |
| |
| boolean ctrl = Cocoa.objc_msgSend(evt, Cocoa.S_ctrlKey) != 0; |
| boolean shift = Cocoa.objc_msgSend(evt, Cocoa.S_shiftKey) != 0; |
| boolean alt = Cocoa.objc_msgSend(evt, Cocoa.S_altKey) != 0; |
| boolean meta = Cocoa.objc_msgSend(evt, Cocoa.S_metaKey) != 0; |
| |
| if (DOMEVENT_KEYDOWN.equals(typeString) || DOMEVENT_KEYUP.equals(typeString)) { |
| int keyCode = Cocoa.objc_msgSend(evt, Cocoa.S_keyCode); |
| int charCode = Cocoa.objc_msgSend(evt, Cocoa.S_charCode); |
| |
| Event keyEvent = new Event(); |
| keyEvent.widget = browser; |
| if (DOMEVENT_KEYDOWN.equals(typeString)) { |
| keyEvent.type = SWT.KeyDown; |
| } else { |
| keyEvent.type = SWT.KeyUp; |
| } |
| keyEvent.keyCode = translateKey(keyCode); |
| /* |
| * WebKit maps the Delete key's character to 0xf728. Detect |
| * this key and set its character to SWT.DEL so that the |
| * Browser's key events are consistent with other controls. |
| */ |
| if (keyEvent.keyCode == SWT.DEL) { |
| keyEvent.character = SWT.DEL; |
| } else { |
| keyEvent.character = (char)charCode; |
| } |
| keyEvent.stateMask = (alt ? SWT.ALT : 0) | (ctrl ? SWT.CTRL : 0) | (shift ? SWT.SHIFT : 0) | (meta ? SWT.COMMAND : 0); |
| |
| boolean doit; |
| if (keyEvent.type == SWT.KeyDown) { |
| doit = sendKeyEvent(keyEvent); |
| } else { /* SWT.KeyUp */ |
| browser.notifyListeners(keyEvent.type, keyEvent); |
| doit = keyEvent.doit; |
| } |
| if (browser.isDisposed()) { |
| Cocoa.objc_msgSend(evt, Cocoa.S_preventDefault); |
| return; |
| } |
| |
| /* |
| * Bug in WebKit. As a result of using HIWebViewCreate on OSX versions < 10.5 (Leopard), attempting |
| * to traverse out of WebKit backwards (Shift+Tab) leaves it in a strange state where WebKit no |
| * longer has focus but still receives keys. The Carbon-based WebKit examples have the same |
| * problem. The workaround is to only allow forward Tab traversals in the Browser on OSX < 10.5. |
| */ |
| if (doit && OS.VERSION < 0x1050 && keyEvent.keyCode == SWT.TAB && (keyEvent.stateMask & SWT.SHIFT) != 0) { |
| doit = false; |
| } |
| if (!doit) { |
| Cocoa.objc_msgSend(evt, Cocoa.S_preventDefault); |
| } else { |
| if (!hasNewFocusElement && keyEvent.keyCode == SWT.TAB && DOMEVENT_KEYUP.equals(typeString)) { |
| hasNewFocusElement = false; |
| } |
| } |
| return; |
| } |
| |
| /* mouse event */ |
| |
| /* |
| * 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 = Cocoa.objc_msgSend(evt, Cocoa.S_screenX); |
| int screenY = Cocoa.objc_msgSend(evt, Cocoa.S_screenY); |
| Point position = new Point(screenX, screenY); |
| position = browser.getDisplay().map(null, browser, position); |
| |
| int detail = Cocoa.objc_msgSend(evt, Cocoa.S_detail); |
| 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 (typeString)) { |
| mouseEvent.type = SWT.MouseDown; |
| int button = Cocoa.objc_msgSend(evt, Cocoa.S_button); |
| mouseEvent.button = button + 1; |
| mouseEvent.count = detail; |
| } else if (DOMEVENT_MOUSEUP.equals (typeString)) { |
| mouseEvent.type = SWT.MouseUp; |
| int button = Cocoa.objc_msgSend(evt, Cocoa.S_button); |
| 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 (typeString)) { |
| /* |
| * Feature 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; |
| } else if (DOMEVENT_MOUSEWHEEL.equals (typeString)) { |
| mouseEvent.type = SWT.MouseWheel; |
| int delta = Cocoa.objc_msgSend(evt, Cocoa.S_wheelDelta); |
| mouseEvent.count = delta / 120; |
| } |
| |
| browser.notifyListeners (mouseEvent.type, mouseEvent); |
| if (browser.isDisposed()) return; |
| if (detail == 2 && DOMEVENT_MOUSEDOWN.equals (typeString)) { |
| int button = Cocoa.objc_msgSend(evt, Cocoa.S_button); |
| 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 (int value) { |
| if (Cocoa.objc_msgSend (value, Cocoa.S_isKindOfClass, Cocoa.C_NSString) != 0) { |
| int length = Cocoa.objc_msgSend (value, Cocoa.S_length); |
| char[] buffer = new char[length]; |
| Cocoa.objc_msgSend (value, Cocoa.S_getCharacters_, buffer); |
| return new String (buffer); |
| } |
| if (Cocoa.objc_msgSend (value, Cocoa.S_isKindOfClass, Cocoa.C_NSNumber) != 0) { |
| int ptr = Cocoa.objc_msgSend (value, Cocoa.S_objCType); |
| byte[] type = new byte[1]; |
| OS.memmove (type, ptr, 1); |
| if (type[0] == 'c' || type[0] == 'B') { |
| int result = Cocoa.objc_msgSend (value, Cocoa.S_boolValue); |
| return new Boolean (result != 0); |
| } |
| if ("islqISLQfd".indexOf (type[0]) != -1) { //$NON-NLS-1$ |
| double result = Cocoa.objc_msgSend_fpret (value, Cocoa.S_doubleValue); |
| return new Double (result); |
| } |
| } |
| if (Cocoa.objc_msgSend (value, Cocoa.S_isKindOfClass, Cocoa.C_WebScriptObject) != 0) { |
| int str = createNSString ("length"); //$NON-NLS-1$ |
| int numberValue = Cocoa.objc_msgSend (value, Cocoa.S_valueForKey, str); |
| OS.CFRelease (str); |
| int length = Cocoa.objc_msgSend (numberValue, Cocoa.S_intValue); |
| Object[] arguments = new Object[length]; |
| for (int i = 0; i < length; i++) { |
| int current = Cocoa.objc_msgSend (value, Cocoa.S_webScriptValueAtIndex, i); |
| if (current != 0) { |
| arguments[i] = convertToJava (current); |
| } |
| } |
| return arguments; |
| } |
| if (Cocoa.objc_msgSend (value, Cocoa.S_isKindOfClass, Cocoa.C_WebUndefined) != 0) { |
| return null; |
| } |
| |
| SWT.error (SWT.ERROR_INVALID_ARGUMENT); |
| return null; |
| } |
| |
| int convertToJS (Object value) { |
| if (value == null) { |
| return Cocoa.objc_msgSend (Cocoa.C_WebUndefined, Cocoa.S_undefined); |
| } |
| if (value instanceof String) { |
| return createNSString((String)value); |
| } |
| if (value instanceof Boolean) { |
| int booleanValue = ((Boolean)value).booleanValue () ? 1 : 0; |
| return Cocoa.objc_msgSend (Cocoa.C_NSNumber, Cocoa.S_numberWithBool, booleanValue); |
| } |
| if (value instanceof Number) { |
| double doubleValue = ((Number)value).doubleValue (); |
| return Cocoa.objc_msgSend (Cocoa.C_NSNumber, Cocoa.S_numberWithDouble, doubleValue); |
| } |
| if (value instanceof Object[]) { |
| Object[] arrayValue = (Object[])value; |
| int length = arrayValue.length; |
| int array = Cocoa.objc_msgSend (Cocoa.C_NSMutableArray, Cocoa.S_arrayWithCapacity, length); |
| for (int i = 0; i < length; i++) { |
| Object currentObject = arrayValue[i]; |
| int jsObject = convertToJS (currentObject); |
| Cocoa.objc_msgSend (array, Cocoa.S_addObject, jsObject); |
| } |
| return array; |
| } |
| SWT.error (SWT.ERROR_INVALID_RETURN_VALUE); |
| return 0; |
| } |
| |
| long /*int*/ callJava (long /*int*/ index, long /*int*/ token, long /*int*/ args, long /*int*/ arg1) { |
| Object returnValue = null; |
| if (Cocoa.objc_msgSend (index, Cocoa.S_isKindOfClass, Cocoa.C_NSNumber) != 0) { |
| int functionIndex = Cocoa.objc_msgSend (index, Cocoa.S_intValue); |
| if (Cocoa.objc_msgSend (token, Cocoa.S_isKindOfClass, Cocoa.C_NSString) != 0) { |
| int length = Cocoa.objc_msgSend (token, Cocoa.S_length); |
| char[] buffer = new char[length]; |
| Cocoa.objc_msgSend (token, Cocoa.S_getCharacters_, buffer); |
| String tokenString = new String (buffer); |
| Object key = new Integer (functionIndex); |
| BrowserFunction function = (BrowserFunction)functions.get (key); |
| if (function != null && tokenString.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) { |
| return convertToJS (WebBrowser.CreateErrorString (e.getLocalizedMessage ())); |
| } |
| } |
| } |