]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/browser/WebFrameLoadDelegate.java
8fb1426fb7cd4432d9480bd2c8409b63e6b22efb
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / browser / WebFrameLoadDelegate.java
1 /*******************************************************************************
2  * Copyright (c) 2010, 2017 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.swt.browser;
15
16
17 import java.net.*;
18 import java.nio.charset.*;
19
20 import org.eclipse.swt.*;
21 import org.eclipse.swt.events.*;
22 import org.eclipse.swt.graphics.*;
23 import org.eclipse.swt.internal.*;
24 import org.eclipse.swt.internal.ole.win32.*;
25 import org.eclipse.swt.internal.webkit.*;
26 import org.eclipse.swt.internal.win32.*;
27 import org.eclipse.swt.layout.*;
28 import org.eclipse.swt.widgets.*;
29
30 class WebFrameLoadDelegate {
31         COMObject iWebFrameLoadDelegate;
32         int refCount = 0;
33
34         Browser browser;
35         String html;
36         String url;
37
38         static final String OBJECTNAME_EXTERNAL = "external"; //$NON-NLS-1$
39
40 WebFrameLoadDelegate (Browser browser) {
41         createCOMInterfaces ();
42         this.browser = browser;
43 }
44
45 void addEventHandlers (boolean top) {
46         if (top) {
47                 StringBuilder buffer = new StringBuilder ("window.SWTkeyhandler = function SWTkeyhandler(e) {"); //$NON-NLS-1$
48                 buffer.append ("try {e.returnValue = HandleWebKitEvent(e.type, e.keyCode, e.charCode, e.altKey, e.ctrlKey, e.shiftKey, e.metaKey);} catch (e) {}};"); //$NON-NLS-1$
49                 buffer.append ("document.addEventListener('keydown', SWTkeyhandler, true);"); //$NON-NLS-1$
50                 buffer.append ("document.addEventListener('keypress', SWTkeyhandler, true);"); //$NON-NLS-1$
51                 buffer.append ("document.addEventListener('keyup', SWTkeyhandler, true);"); //$NON-NLS-1$
52                 browser.execute (buffer.toString ());
53
54                 buffer = new StringBuilder ("window.SWTmousehandler = function SWTmousehandler(e) {"); //$NON-NLS-1$
55                 buffer.append ("try {e.returnValue = HandleWebKitEvent(e.type, e.screenX, e.screenY, e.detail, e.button + 1, e.altKey, e.ctrlKey, e.shiftKey, e.metaKey, e.relatedTarget != null);} catch (e) {}};"); //$NON-NLS-1$
56                 buffer.append ("document.addEventListener('mousedown', SWTmousehandler, true);"); //$NON-NLS-1$
57                 buffer.append ("document.addEventListener('mouseup', SWTmousehandler, true);"); //$NON-NLS-1$
58                 buffer.append ("document.addEventListener('mousemove', SWTmousehandler, true);"); //$NON-NLS-1$
59                 buffer.append ("document.addEventListener('mousewheel', SWTmousehandler, true);"); //$NON-NLS-1$
60                 buffer.append ("document.addEventListener('dragstart', SWTmousehandler, true);"); //$NON-NLS-1$
61                 buffer.append ("document.addEventListener('mouseover', SWTmousehandler, true);"); //$NON-NLS-1$
62                 buffer.append ("document.addEventListener('mouseout', SWTmousehandler, true);"); //$NON-NLS-1$
63
64                 browser.execute (buffer.toString ());
65         } else {
66                 StringBuilder buffer = new StringBuilder ("for (var i = 0; i < frames.length; i++) {"); //$NON-NLS-1$
67                 buffer.append ("frames[i].document.addEventListener('keydown', window.SWTkeyhandler, true);"); //$NON-NLS-1$
68                 buffer.append ("frames[i].document.addEventListener('keypress', window.SWTkeyhandler, true);"); //$NON-NLS-1$
69                 buffer.append ("frames[i].document.addEventListener('keyup', window.SWTkeyhandler, true);"); //$NON-NLS-1$
70                 buffer.append ("frames[i].document.addEventListener('mousedown', window.SWTmousehandler, true);"); //$NON-NLS-1$
71                 buffer.append ("frames[i].document.addEventListener('mouseup', window.SWTmousehandler, true);"); //$NON-NLS-1$
72                 buffer.append ("frames[i].document.addEventListener('mousemove', window.SWTmousehandler, true);"); //$NON-NLS-1$
73                 buffer.append ("frames[i].document.addEventListener('mouseover', window.SWTmousehandler, true);"); //$NON-NLS-1$
74                 buffer.append ("frames[i].document.addEventListener('mouseout', window.SWTmousehandler, true);"); //$NON-NLS-1$
75                 buffer.append ("frames[i].document.addEventListener('mousewheel', window.SWTmousehandler, true);"); //$NON-NLS-1$
76                 buffer.append ("frames[i].document.addEventListener('dragstart', window.SWTmousehandler, true);"); //$NON-NLS-1$
77                 buffer.append ('}');
78                 browser.execute (buffer.toString ());
79         }
80 }
81
82 int AddRef () {
83         refCount++;
84         return refCount;
85 }
86
87 void createCOMInterfaces () {
88         iWebFrameLoadDelegate = new COMObject (new int[] {2, 0, 0, 2, 2, 3, 2, 3, 3, 2, 3, 2, 5, 2, 2, 3, 4}) {
89                 @Override
90                 public long method0 (long[] args) {return QueryInterface (args[0], args[1]);}
91                 @Override
92                 public long method1 (long[] args) {return AddRef ();}
93                 @Override
94                 public long method2 (long[] args) {return Release ();}
95                 @Override
96                 public long method3 (long[] args) {return didStartProvisionalLoadForFrame (args[0], args[1]);}
97                 @Override
98                 public long method4 (long[] args) {return COM.E_NOTIMPL;}
99                 @Override
100                 public long method5 (long[] args) {return didFailProvisionalLoadWithError (args[0], args[1], args[2]);}
101                 @Override
102                 public long method6 (long[] args) {return didCommitLoadForFrame (args[0], args[1]);}
103                 @Override
104                 public long method7 (long[] args) {return didReceiveTitle (args[0], args[1], args[2]);}
105                 @Override
106                 public long method8 (long[] args) {return COM.E_NOTIMPL;}
107                 @Override
108                 public long method9 (long[] args) {return didFinishLoadForFrame (args[0], args[1]);}
109                 @Override
110                 public long method10 (long[] args){return COM.E_NOTIMPL;}
111                 @Override
112                 public long method11 (long[] args){return didChangeLocationWithinPageForFrame (args[0], args[1]);}
113                 @Override
114                 public long method12 (long[] args){return COM.S_OK;}
115                 @Override
116                 public long method13 (long[] args){return COM.E_NOTIMPL;}
117                 @Override
118                 public long method14 (long[] args){return COM.S_OK;}
119                 @Override
120                 public long method15 (long[] args){return COM.S_OK;}
121                 @Override
122                 public long method16 (long[] args){return didClearWindowObject (args[0], args[1], args[2], args[3]);}
123         };
124
125         /* Callbacks that take double parameters require custom callbacks that instead pass pointers to the doubles. */
126         long ppVtable = iWebFrameLoadDelegate.ppVtable;
127         long[] pVtable = new long[1];
128         OS.MoveMemory (pVtable, ppVtable, C.PTR_SIZEOF);
129         long[] funcs = new long[17];
130         OS.MoveMemory (funcs, pVtable[0], C.PTR_SIZEOF * funcs.length);
131         funcs[12] = WebKit_win32.willPerformClientRedirectToURL_CALLBACK (funcs[12]);
132         OS.MoveMemory (pVtable[0], funcs, C.PTR_SIZEOF * funcs.length);
133 }
134
135 int didChangeLocationWithinPageForFrame (long webView, long frame) {
136         IWebFrame iwebframe = new IWebFrame (frame);
137         long[] result = new long[1];
138         int hr = iwebframe.dataSource (result);
139         if (hr != COM.S_OK || result[0] == 0) {
140                 return COM.S_OK;
141         }
142         IWebDataSource dataSource = new IWebDataSource (result[0]);
143         result[0] = 0;
144         hr = dataSource.request (result);
145         dataSource.Release ();
146         if (hr != COM.S_OK || result[0] == 0) {
147                 return COM.S_OK;
148         }
149         IWebURLRequest request = new IWebURLRequest (result[0]);
150         result[0] = 0;
151         hr = request.URL (result);
152         request.Release ();
153         if (hr != COM.S_OK || result[0] == 0) {
154                 return COM.S_OK;
155         }
156         String url2 = WebKit.extractBSTR (result[0]);
157         COM.SysFreeString (result[0]);
158         if (url2.length() == 0) return COM.S_OK;
159         /*
160          * If the URI indicates that the page is being rendered from memory
161          * (via setText()) then set it to about:blank to be consistent with IE.
162          */
163         if (url2.equals (WebKit.URI_FILEROOT)) {
164                 url2 = WebKit.ABOUT_BLANK;
165         } else {
166                 int length = WebKit.URI_FILEROOT.length ();
167                 if (url2.startsWith (WebKit.URI_FILEROOT) && url2.charAt (length) == '#') {
168                         url2 = WebKit.ABOUT_BLANK + url2.substring (length);
169                 }
170         }
171         final Display display = browser.getDisplay ();
172         result[0] = 0;
173         IWebView iWebView = new IWebView (webView);
174         hr = iWebView.mainFrame (result);
175         boolean top = false;
176         if (hr == COM.S_OK && result[0] != 0) {
177                 top = frame == result[0];
178                 new IWebFrame (result[0]).Release ();
179         }
180         if (top) {
181                 StatusTextEvent statusText = new StatusTextEvent (browser);
182                 statusText.display = display;
183                 statusText.widget = browser;
184                 statusText.text = url2;
185                 StatusTextListener[] statusTextListeners = browser.webBrowser.statusTextListeners;
186                 for (int i = 0; i < statusTextListeners.length; i++) {
187                         statusTextListeners[i].changed (statusText);
188                 }
189         }
190
191         LocationEvent location = new LocationEvent (browser);
192         location.display = display;
193         location.widget = browser;
194         location.location = url2;
195         location.top = top;
196         LocationListener[] locationListeners = browser.webBrowser.locationListeners;
197         for (int i = 0; i < locationListeners.length; i++) {
198                 locationListeners[i].changed (location);
199         }
200         return COM.S_OK;
201 }
202
203 int didClearWindowObject (long webView, long context, long windowScriptObject, long frame) {
204         WebKit_win32.JSGlobalContextRetain (context);
205         long globalObject = WebKit_win32.JSContextGetGlobalObject (context);
206         long privateData = ((WebKit)browser.webBrowser).webViewData;
207         long externalObject = WebKit_win32.JSObjectMake (context, WebKit.ExternalClass, privateData);
208         byte[] bytes = (OBJECTNAME_EXTERNAL + '\0').getBytes (StandardCharsets.UTF_8);
209         long name = WebKit_win32.JSStringCreateWithUTF8CString (bytes);
210         WebKit_win32.JSObjectSetProperty (context, globalObject, name, externalObject, 0, null);
211         WebKit_win32.JSStringRelease (name);
212
213         for (BrowserFunction current : browser.webBrowser.functions.values()) {
214                 browser.execute (current.functionString);
215         }
216
217         IWebView iwebView = new IWebView (webView);
218         long[] mainFrame = new long[1];
219         iwebView.mainFrame (mainFrame);
220         boolean top = mainFrame[0] == frame;
221         new IWebFrame (mainFrame[0]).Release ();
222         addEventHandlers (top);
223         return COM.S_OK;
224 }
225
226 int didCommitLoadForFrame (long webview, long frame) {
227         IWebFrame iWebFrame = new IWebFrame (frame);
228         long[] result = new long[1];
229         int hr = iWebFrame.dataSource (result);
230         if (hr != COM.S_OK || result[0] == 0) {
231                 return COM.S_OK;
232         }
233         IWebDataSource dataSource = new IWebDataSource (result[0]);
234         result[0] = 0;
235         hr = dataSource.request (result);
236         dataSource.Release ();
237         if (hr != COM.S_OK || result[0] == 0) {
238                 return COM.S_OK;
239         }
240         IWebMutableURLRequest request = new IWebMutableURLRequest (result[0]);
241         result[0] = 0;
242         hr = request.URL (result);
243         request.Release ();
244         if (hr != COM.S_OK || result[0] == 0) {
245                 return COM.S_OK;
246         }
247         String url2 = WebKit.extractBSTR (result[0]);
248         COM.SysFreeString (result[0]);
249         if (url2.length () == 0) return COM.S_OK;
250         /*
251          * If the URI indicates that the page is being rendered from memory
252          * (via setText()) then set it to about:blank to be consistent with IE.
253          */
254         if (url2.equals (WebKit.URI_FILEROOT)) {
255                 url2 = WebKit.ABOUT_BLANK;
256         } else {
257                 int length = WebKit.URI_FILEROOT.length ();
258                 if (url2.startsWith (WebKit.URI_FILEROOT) && url2.charAt (length) == '#') {
259                         url2 = WebKit.ABOUT_BLANK + url2.substring (length);
260                 }
261         }
262         Display display = browser.getDisplay ();
263         result[0] = 0;
264         IWebView iwebView = new IWebView (webview);
265         hr = iwebView.mainFrame (result);
266         boolean top = false;
267         if (hr == COM.S_OK && result[0] != 0) {
268                 top = frame == result[0];
269                 new IWebFrame (result[0]).Release ();
270         }
271         if (top) {
272                 /* reset resource status variables */
273                 this.url = url2;
274
275                 /*
276                 * Each invocation of setText() causes webView_didCommitLoadForFrame to be invoked
277                 * twice, once for the initial navigate to about:blank, and once for the auto-navigate
278                 * to about:blank that WebKit does when loadHTMLString is invoked.  If this is the
279                 * first webView_didCommitLoadForFrame callback received for a setText() invocation
280                 * then do not send any events or re-install registered BrowserFunctions.
281                 */
282                 if (url2.startsWith (WebKit.ABOUT_BLANK) && html != null) return COM.S_OK;
283
284                 /* re-install registered functions */
285                 for (BrowserFunction function : browser.webBrowser.functions.values()) {
286                         browser.webBrowser.execute (function.functionString);
287                 }
288
289                 ProgressEvent progress = new ProgressEvent (browser);
290                 progress.display = display;
291                 progress.widget = browser;
292                 progress.current = 1;
293                 progress.total = WebKit.MAX_PROGRESS;
294                 ProgressListener[] progressListeners = browser.webBrowser.progressListeners;
295                 for (int i = 0; i < progressListeners.length; i++) {
296                         progressListeners[i].changed (progress);
297                 }
298                 if (browser.isDisposed ()) return COM.S_OK;
299
300                 StatusTextEvent statusText = new StatusTextEvent (browser);
301                 statusText.display = display;
302                 statusText.widget = browser;
303                 statusText.text = url2;
304                 StatusTextListener[] statusTextListeners = browser.webBrowser.statusTextListeners;
305                 for (int i = 0; i < statusTextListeners.length; i++) {
306                         statusTextListeners[i].changed (statusText);
307                 }
308                 if (browser.isDisposed ()) return COM.S_OK;
309         }
310         LocationEvent location = new LocationEvent (browser);
311         location.display = display;
312         location.widget = browser;
313         location.location = url2;
314         location.top = top;
315         LocationListener[] locationListeners = browser.webBrowser.locationListeners;
316         for (int i = 0; i < locationListeners.length; i++) {
317                 locationListeners[i].changed (location);
318         }
319         return COM.S_OK;
320 }
321
322 int didFailProvisionalLoadWithError (long webView, long error, long frame) {
323         IWebError iweberror = new IWebError (error);
324         int[] errorCode = new int[1];
325         int hr = iweberror.code (errorCode);
326         if (WebKit_win32.WebURLErrorBadURL < errorCode[0]) return COM.S_OK;
327
328         String failingURLString = null;
329         long[] failingURL = new long[1];
330         hr = iweberror.failingURL (failingURL);
331         if (hr == COM.S_OK && failingURL[0] != 0) {
332                 failingURLString = WebKit.extractBSTR (failingURL[0]);
333                 COM.SysFreeString (failingURL[0]);
334         }
335         if (failingURLString != null && WebKit_win32.WebURLErrorServerCertificateNotYetValid <= errorCode[0] && errorCode[0] <= WebKit_win32.WebURLErrorSecureConnectionFailed) {
336                 /* handle invalid certificate error */
337                 long[] result = new long[1];
338                 hr = iweberror.localizedDescription (result);
339                 if (hr != COM.S_OK || result[0] == 0) {
340                         return COM.S_OK;
341                 }
342                 String description = WebKit.extractBSTR (result[0]);
343                 COM.SysFreeString (result[0]);
344
345                 result[0] = 0;
346                 hr = iweberror.QueryInterface (WebKit_win32.IID_IWebErrorPrivate, result);
347                 if (hr != COM.S_OK || result[0] == 0) {
348                         return COM.S_OK;
349                 }
350
351                 IWebErrorPrivate webErrorPrivate = new IWebErrorPrivate (result[0]);
352                 result[0] = 0;
353                 long[] certificate = new long[1];
354                 hr = webErrorPrivate.sslPeerCertificate (certificate);
355                 webErrorPrivate.Release ();
356                 if (hr != COM.S_OK || certificate[0] == 0) {
357                         return COM.S_OK;
358                 }
359                 if (showCertificateDialog (webView, failingURLString, description, certificate[0])) {
360                         IWebFrame iWebFrame = new IWebFrame (frame);
361                         hr = WebKit_win32.WebKitCreateInstance (WebKit_win32.CLSID_WebMutableURLRequest, 0, WebKit_win32.IID_IWebMutableURLRequest, result);
362                         if (hr != COM.S_OK || result[0] == 0) {
363                                 certificate[0] = 0;
364                                 return COM.S_OK;
365                         }
366                         IWebMutableURLRequest request = new IWebMutableURLRequest (result[0]);
367                         request.setURL (failingURL[0]);
368                         request.setAllowsAnyHTTPSCertificate ();
369                         iWebFrame.loadRequest (request.getAddress ());
370                         request.Release ();
371                 }
372                 certificate[0] = 0;
373                 return COM.S_OK;
374         }
375
376         /* handle other types of errors */
377         long[] result = new long[1];
378         hr = iweberror.localizedDescription (result);
379         if (hr != COM.S_OK || result[0] == 0) {
380                 return COM.S_OK;
381         }
382         String description = WebKit.extractBSTR (result[0]);
383         COM.SysFreeString (result[0]);
384         if (!browser.isDisposed ()) {
385                 String message = failingURLString != null ? failingURLString + "\n\n" : ""; //$NON-NLS-1$ //$NON-NLS-2$
386                 message += Compatibility.getMessage ("SWT_Page_Load_Failed", new Object[] {description}); //$NON-NLS-1$
387                 MessageBox messageBox = new MessageBox (browser.getShell (), SWT.OK | SWT.ICON_ERROR);
388                 messageBox.setMessage (message);
389                 messageBox.open ();
390         }
391         return COM.S_OK;
392 }
393
394 int didFinishLoadForFrame (long webview, long frame) {
395         IWebView iWebView = new IWebView (webview);
396         long[] iWebFrame = new long[1];
397         int hr = iWebView.mainFrame (iWebFrame);
398         if (hr != COM.S_OK || iWebFrame[0] == 0) {
399                 return COM.S_OK;
400         }
401         boolean top = frame == iWebFrame[0];
402         new IWebFrame (iWebFrame[0]).Release();
403         if (!top) return COM.S_OK;
404
405         /*
406          * If html is not null then there is html from a previous setText() call
407          * waiting to be set into the about:blank page once it has completed loading.
408          */
409         if (html != null) {
410                 if (getUrl ().startsWith (WebKit.ABOUT_BLANK)) {
411                         ((WebKit)browser.webBrowser).loadingText = true;
412                         long string = WebKit.createBSTR (html);
413                         long URLString;
414                         if (((WebKit)browser.webBrowser).untrustedText) {
415                                 URLString = WebKit.createBSTR (WebKit.ABOUT_BLANK);
416                         } else {
417                                 URLString = WebKit.createBSTR (WebKit.URI_FILEROOT);
418                         }
419                         IWebFrame mainFrame = new IWebFrame (frame);
420                         mainFrame.loadHTMLString (string, URLString);
421                         html = null;
422                 }
423         }
424
425         /*
426         * The loadHTMLString() invocation above will trigger a second didFinishLoadForFrame
427         * callback when it is completed.  If text was just set into the browser then wait for this
428         * second callback to come before sending the title or completed events.
429         */
430         if (!((WebKit)browser.webBrowser).loadingText) {
431                 if (browser.isDisposed ()) return COM.S_OK;
432                 /*
433                 * To be consistent with other platforms a title event should be fired when a
434                 * page has completed loading.  A page with a <title> tag will do this
435                 * automatically when the didReceiveTitle callback is received.  However a page
436                 * without a <title> tag will not do this by default, so fire the event
437                 * here with the page's url as the title.
438                 */
439                 Display display = browser.getDisplay ();
440                 IWebFrame mainFrame = new IWebFrame (frame);
441                 long[] result = new long[1];
442                 hr = mainFrame.dataSource (result);
443                 if (hr != COM.S_OK || result[0] == 0) {
444                         return COM.S_OK;
445                 }
446                 IWebDataSource dataSource = new IWebDataSource (result[0]);
447                 result[0] = 0;
448                 hr = dataSource.pageTitle (result);
449                 dataSource.Release ();
450                 if (hr != COM.S_OK) {
451                         return COM.S_OK;
452                 }
453                 String title = null;
454                 if (result[0] != 0) {
455                         title = WebKit.extractBSTR (result[0]);
456                         COM.SysFreeString (result[0]);
457                 }
458                 if (title == null || title.length () == 0) {    /* page has no title */
459                         TitleEvent newEvent = new TitleEvent (browser);
460                         newEvent.display = display;
461                         newEvent.widget = browser;
462                         newEvent.title = getUrl ();
463                         TitleListener[] titleListeners = browser.webBrowser.titleListeners;
464                         for (int i = 0; i < titleListeners.length; i++) {
465                                 titleListeners[i].changed (newEvent);
466                         }
467                         if (browser.isDisposed ()) return COM.S_OK;
468                 }
469
470                 ProgressEvent progress = new ProgressEvent (browser);
471                 progress.display = display;
472                 progress.widget = browser;
473                 progress.current = WebKit.MAX_PROGRESS;
474                 progress.total = WebKit.MAX_PROGRESS;
475                 ProgressListener[] progressListeners = browser.webBrowser.progressListeners;
476                 for (int i = 0; i < progressListeners.length; i++) {
477                         progressListeners[i].completed (progress);
478                 }
479                 if (browser.isDisposed ()) return COM.S_OK;
480         }
481         ((WebKit)browser.webBrowser).loadingText = false;
482         return COM.S_OK;
483 }
484
485 int didReceiveTitle (long webView, long title, long frame) {
486         long[] mainFrame = new long[1];
487         IWebView iWebView = new IWebView (webView);
488         int hr = iWebView.mainFrame (mainFrame);
489         if (hr != COM.S_OK || frame == 0) {
490                 return COM.S_OK;
491         }
492         if (frame == mainFrame[0]) {
493                 String newTitle = WebKit.extractBSTR (title);
494                 TitleEvent newEvent = new TitleEvent (browser);
495                 newEvent.display = browser.getDisplay ();
496                 newEvent.widget = browser;
497                 newEvent.title = newTitle;
498                 TitleListener[] titleListeners = browser.webBrowser.titleListeners;
499                 for (int i = 0; i < titleListeners.length; i++) {
500                         titleListeners[i].changed (newEvent);
501                 }
502         }
503         new IWebFrame (mainFrame[0]).Release ();
504         return COM.S_OK;
505 }
506
507 int didStartProvisionalLoadForFrame (long webView, long frame) {
508         return COM.S_OK;
509 }
510
511 void disposeCOMInterfaces () {
512         if (iWebFrameLoadDelegate != null) {
513                 iWebFrameLoadDelegate.dispose ();
514                 iWebFrameLoadDelegate = null;
515         }
516 }
517
518 long getAddress () {
519         return iWebFrameLoadDelegate.getAddress ();
520 }
521
522 String getUrl () {
523         /* WebKit auto-navigates to about:blank at startup */
524         if (url == null || url.length () == 0) return WebKit.ABOUT_BLANK;
525         return url;
526 }
527
528 int QueryInterface (long riid, long ppvObject) {
529         if (riid == 0 || ppvObject == 0) return COM.E_INVALIDARG;
530         GUID guid = new GUID ();
531         COM.MoveMemory (guid, riid, GUID.sizeof);
532
533         if (COM.IsEqualGUID (guid, COM.IIDIUnknown)) {
534                 OS.MoveMemory (ppvObject, new long[] {iWebFrameLoadDelegate.getAddress ()}, C.PTR_SIZEOF);
535                 new IUnknown (iWebFrameLoadDelegate.getAddress ()).AddRef ();
536                 return COM.S_OK;
537         }
538         if (COM.IsEqualGUID (guid, WebKit_win32.IID_IWebFrameLoadDelegate)) {
539                 OS.MoveMemory (ppvObject, new long[] {iWebFrameLoadDelegate.getAddress ()}, C.PTR_SIZEOF);
540                 new IUnknown (iWebFrameLoadDelegate.getAddress ()).AddRef ();
541                 return COM.S_OK;
542         }
543
544         OS.MoveMemory (ppvObject, new long[] {0}, C.PTR_SIZEOF);
545         return COM.E_NOINTERFACE;
546 }
547
548 int Release () {
549         refCount--;
550         if (refCount == 0) {
551                 disposeCOMInterfaces ();
552         }
553         return refCount;
554 }
555
556 boolean showCertificateDialog (long webView, final String failingUrlString, final String description, final long certificate) {
557         Shell parent = browser.getShell ();
558         final Shell shell = new Shell (parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM);
559         shell.setText (Compatibility.getMessage ("SWT_InvalidCert_Title")); //$NON-NLS-1$
560         shell.setLayout (new GridLayout ());
561         Label label = new Label (shell, SWT.WRAP);
562         String host = null;
563         try {
564                 host = new URL (failingUrlString).getHost ();
565         } catch (MalformedURLException e) {
566                 /* show the url instead */
567                 host = failingUrlString;
568         }
569         StringBuilder message = new StringBuilder ("\n"); //$NON-NLS-1$
570         message.append (Compatibility.getMessage ("SWT_InvalidCert_Message", new String[] {host})); //$NON-NLS-1$
571         message.append ("\n\n"); //$NON-NLS-1$
572         message.append (Compatibility.getMessage (description));
573         message.append ("\n"); //$NON-NLS-1$
574         message.append (Compatibility.getMessage ("SWT_InvalidCert_Connect")); //$NON-NLS-1$
575         message.append ("\n"); //$NON-NLS-1$
576         label.setText(message.toString ());
577
578         GridData data = new GridData ();
579         Monitor monitor = browser.getMonitor ();
580         int maxWidth = monitor.getBounds ().width * 2 / 3;
581         int width = label.computeSize (SWT.DEFAULT, SWT.DEFAULT).x;
582         data.widthHint = Math.min (width, maxWidth);
583         data.horizontalAlignment = GridData.FILL;
584         data.grabExcessHorizontalSpace = true;
585         label.setLayoutData (data);
586
587         final boolean[] result = new boolean[1];
588         final Button[] buttons = new Button[3];
589         Listener listener = event -> {
590                 if (event.widget == buttons[2]) {
591                         showCertificate (shell, certificate);
592                 } else {
593                         result[0] = event.widget == buttons[0];
594                         shell.close();
595                 }
596         };
597
598         Composite composite = new Composite (shell, SWT.NONE);
599         data = new GridData ();
600         data.horizontalAlignment = GridData.END;
601         composite.setLayoutData (data);
602         composite.setLayout (new GridLayout (3, true));
603         buttons[0] = new Button (composite, SWT.PUSH);
604         buttons[0].setText (SWT.getMessage("SWT_Continue")); //$NON-NLS-1$
605         buttons[0].setLayoutData (new GridData (GridData.FILL_HORIZONTAL));
606         buttons[0].addListener (SWT.Selection, listener);
607         buttons[1] = new Button (composite, SWT.PUSH);
608         buttons[1].setText (SWT.getMessage("SWT_Cancel")); //$NON-NLS-1$
609         buttons[1].setLayoutData (new GridData (GridData.FILL_HORIZONTAL));
610         buttons[1].addListener (SWT.Selection, listener);
611         buttons[2] = new Button (composite, SWT.PUSH);
612         buttons[2].setText (SWT.getMessage("SWT_ViewCertificate")); //$NON-NLS-1$
613         buttons[2].setLayoutData (new GridData (GridData.FILL_HORIZONTAL));
614         buttons[2].addListener (SWT.Selection, listener);
615
616         shell.setDefaultButton (buttons[0]);
617         shell.pack ();
618
619         Rectangle parentSize = parent.getBounds ();
620         Rectangle shellSize = shell.getBounds ();
621         int x = parent.getLocation ().x + (parentSize.width - shellSize.width) / 2;
622         int y = parent.getLocation ().y + (parentSize.height - shellSize.height) / 2;
623         shell.setLocation (x, y);
624         shell.open ();
625         Display display = browser.getDisplay ();
626         while (!shell.isDisposed ()) {
627                 if (!display.readAndDispatch ()) display.sleep ();
628         }
629         return result[0];
630 }
631
632 void showCertificate (Shell parent, long certificate) {
633         CERT_CONTEXT context = new CERT_CONTEXT ();
634         OS.MoveMemory (context, certificate, CERT_CONTEXT.sizeof);
635         CERT_INFO info = new CERT_INFO ();
636         OS.MoveMemory (info, context.pCertInfo, CERT_INFO.sizeof);
637
638         int length = OS.CertNameToStr (OS.X509_ASN_ENCODING, info.Issuer, OS.CERT_SIMPLE_NAME_STR, null, 0);
639         char [] buffer = new char [length];
640         OS.CertNameToStr (OS.X509_ASN_ENCODING, info.Issuer, OS.CERT_SIMPLE_NAME_STR, buffer, length);
641         String issuer = new String (buffer, 0, length - 1);
642
643         length = OS.CertNameToStr (OS.X509_ASN_ENCODING, info.Subject, OS.CERT_SIMPLE_NAME_STR, null, 0);
644         buffer = new char [length];
645         OS.CertNameToStr (OS.X509_ASN_ENCODING, info.Subject, OS.CERT_SIMPLE_NAME_STR, buffer, length);
646         String subject = new String (buffer, 0, length - 1);
647
648         final String SEPARATOR_DATE = "/"; //$NON-NLS-1$
649         final String SEPARATOR_TIME = ":"; //$NON-NLS-1$
650         SYSTEMTIME systemTime = new SYSTEMTIME ();
651         OS.FileTimeToSystemTime (info.NotBefore, systemTime);
652         String validFrom = systemTime.wDay + SEPARATOR_DATE + systemTime.wMonth + SEPARATOR_DATE + systemTime.wYear;
653         String validFromTime = systemTime.wHour + SEPARATOR_TIME + systemTime.wMinute + SEPARATOR_TIME + systemTime.wSecond;
654
655         systemTime = new SYSTEMTIME ();
656         OS.FileTimeToSystemTime (info.NotAfter, systemTime);
657         String validTo = systemTime.wDay + SEPARATOR_DATE + systemTime.wMonth + SEPARATOR_DATE + systemTime.wYear;
658         String validToTime = systemTime.wHour + SEPARATOR_TIME + systemTime.wMinute + SEPARATOR_TIME + systemTime.wSecond;
659
660         length = info.SerialNumber.cbData;
661         byte[] serialNumber = new byte[length];
662         OS.MoveMemory (serialNumber, info.SerialNumber.pbData, length);
663         String hexSerialNumber = new String ();
664         for (int i = length - 1; i >= 0; i--) {
665                 int number = 0xFF & serialNumber[i];
666                 String hex = Integer.toHexString (number);
667                 if (hex.length () == 1) hexSerialNumber += "0"; //$NON-NLS-1$
668                 hexSerialNumber += hex + " "; //$NON-NLS-1$
669         }
670
671         final Shell dialog = new Shell (parent, SWT.APPLICATION_MODAL | SWT.DIALOG_TRIM);
672         dialog.setText (SWT.getMessage ("SWT_Certificate")); //$NON-NLS-1$
673         dialog.setLayout (new GridLayout (1, false));
674
675         TabFolder tabFolder = new TabFolder (dialog, SWT.NONE);
676         tabFolder.setLayoutData (new GridData (SWT.FILL, SWT.FILL, true, true, 1, 1));
677         tabFolder.setLayout (new FillLayout ());
678
679         TabItem general = new TabItem (tabFolder, SWT.NONE);
680         general.setText (SWT.getMessage ("SWT_General")); //$NON-NLS-1$
681         Composite composite = new Composite (tabFolder, SWT.BORDER);
682         composite.setLayout (new GridLayout (1, false));
683         Label issuedTo = new Label (composite, SWT.NONE);
684         issuedTo.setLayoutData (new GridData (SWT.BEGINNING, SWT.CENTER, false, false));
685         issuedTo.setText (Compatibility.getMessage ("SWT_IssuedTo", new Object[] {subject})); //$NON-NLS-1$
686         Label issuedBy = new Label (composite, SWT.NONE);
687         issuedBy.setLayoutData (new GridData (SWT.BEGINNING, SWT.CENTER, false, false));
688         issuedBy.setText (Compatibility.getMessage ("SWT_IssuedFrom", new Object[] {issuer}));  //$NON-NLS-1$
689         Label valid = new Label (composite, SWT.NONE);
690         valid.setLayoutData (new GridData (SWT.BEGINNING, SWT.CENTER, false, false));
691         valid.setText (Compatibility.getMessage ("SWT_ValidFromTo", new Object[] {validFrom, validTo})); //$NON-NLS-1$
692         general.setControl (composite);
693
694         TabItem details = new TabItem (tabFolder, SWT.NONE);
695         details.setText (SWT.getMessage ("SWT_Details")); //$NON-NLS-1$
696         Table table = new Table (tabFolder, SWT.SINGLE | SWT.BORDER| SWT.FULL_SELECTION);
697         table.setHeaderVisible (true);
698         TableColumn tableColumn = new TableColumn (table, SWT.LEAD);
699         tableColumn.setText (SWT.getMessage ("SWT_Field")); //$NON-NLS-1$
700         tableColumn = new TableColumn (table, SWT.NONE);
701         tableColumn.setText (SWT.getMessage ("SWT_Value")); //$NON-NLS-1$
702         TableItem tableItem = new TableItem(table, SWT.NONE);
703         String version = "V" + String.valueOf (info.dwVersion + 1); //$NON-NLS-1$
704         tableItem.setText (new String[]{SWT.getMessage ("SWT_Version"), version}); //$NON-NLS-1$
705         tableItem = new TableItem (table, SWT.NONE);
706         tableItem.setText (new String[] {SWT.getMessage ("SWT_SerialNumber"), hexSerialNumber}); //$NON-NLS-1$
707         tableItem = new TableItem (table, SWT.NONE);
708         tableItem.setText (new String[] {SWT.getMessage ("SWT_Issuer"), issuer}); //$NON-NLS-1$
709
710         tableItem = new TableItem (table, SWT.NONE);
711         StringBuilder stringBuilder2 = new StringBuilder ();
712         stringBuilder2.append (validFrom);
713         stringBuilder2.append (", "); //$NON-NLS-1$
714         stringBuilder2.append (validFromTime);
715         stringBuilder2.append (" GMT"); //$NON-NLS-1$
716         tableItem.setText (new String[] {SWT.getMessage ("SWT_ValidFrom"), stringBuilder2.toString ()}); //$NON-NLS-1$
717
718         tableItem = new TableItem (table, SWT.NONE);
719         StringBuilder stringBuilder = new StringBuilder ();
720         stringBuilder.append (validTo);
721         stringBuilder.append (", "); //$NON-NLS-1$
722         stringBuilder.append (validToTime);
723         stringBuilder.append (" GMT"); //$NON-NLS-1$
724         tableItem.setText (new String[] {SWT.getMessage ("SWT_ValidTo"), stringBuilder.toString ()}); //$NON-NLS-1$
725
726         tableItem = new TableItem (table, SWT.NONE);
727         tableItem.setText (new String[] {SWT.getMessage ("SWT_Subject"), subject}); //$NON-NLS-1$
728         for (int i = 0; i < table.getColumnCount (); i++) {
729                 table.getColumn (i).pack ();
730         }
731         details.setControl (table);
732
733         Button ok = new Button (dialog, SWT.PUSH);
734         GridData layoutData = new GridData (SWT.END, SWT.CENTER, false, false);
735         layoutData.widthHint = 75;
736         ok.setLayoutData (layoutData);
737         ok.setText (SWT.getMessage ("SWT_OK")); //$NON-NLS-1$
738         ok.addSelectionListener (new SelectionAdapter() {
739                 @Override
740                 public void widgetSelected (SelectionEvent e) {
741                         dialog.dispose ();
742                 }
743         });
744
745         dialog.setDefaultButton (ok);
746         dialog.pack ();
747         Rectangle parentSize = parent.getBounds ();
748         Rectangle dialogSize = dialog.getBounds ();
749         int x = parent.getLocation ().x + (parentSize.width - dialogSize.width) / 2;
750         int y = parent.getLocation ().y + (parentSize.height - dialogSize.height) / 2;
751         dialog.setLocation (x, y);
752         dialog.open ();
753         Display display = browser.getDisplay ();
754         while (!dialog.isDisposed ()) {
755                 if (!display.readAndDispatch ()) display.sleep ();
756         }
757
758 }
759
760 }