WinLauncher fails to download files.
[WebKit-https.git] / Tools / WinLauncher / Common.cpp
1 /*
2  * Copyright (C) 2006, 2008, 2013-2015 Apple Inc.  All rights reserved.
3  * Copyright (C) 2009, 2011 Brent Fulgham.  All rights reserved.
4  * Copyright (C) 2009, 2010, 2011 Appcelerator, Inc. All rights reserved.
5  * Copyright (C) 2013 Alex Christensen. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
27  */
28
29 #include "AccessibilityDelegate.h"
30 #include "DOMDefaultImpl.h"
31 #include "PrintWebUIDelegate.h"
32 #include "ResourceLoadDelegate.h"
33 #include "WebDownloadDelegate.h"
34 #include "WinLauncher.h"
35 #include "WinLauncherReplace.h"
36 #include <WebKit/WebKitCOMAPI.h>
37 #include <wtf/ExportMacros.h>
38 #include <wtf/Platform.h>
39 #include <wtf/text/CString.h>
40 #include <wtf/text/WTFString.h>
41
42 #if USE(CF)
43 #include <CoreFoundation/CFRunLoop.h>
44 #include <WebKit/CFDictionaryPropertyBag.h>
45 #endif
46
47 #include <cassert>
48 #include <comip.h>
49 #include <commctrl.h>
50 #include <commdlg.h>
51 #include <comutil.h>
52 #include <dbghelp.h>
53 #include <memory>
54 #include <objbase.h>
55 #include <shellapi.h>
56 #include <shlobj.h>
57 #include <shlwapi.h>
58 #include <string>
59 #include <vector>
60 #include <wininet.h>
61
62 #define MAX_LOADSTRING 100
63 #define URLBAR_HEIGHT  24
64 #define CONTROLBUTTON_WIDTH 24
65
66 static const int maxHistorySize = 10;
67
68 typedef _com_ptr_t<_com_IIID<IWebFrame, &__uuidof(IWebFrame)>> IWebFramePtr;
69 typedef _com_ptr_t<_com_IIID<IWebMutableURLRequest, &__uuidof(IWebMutableURLRequest)>> IWebMutableURLRequestPtr;
70
71 // Global Variables:
72 HINSTANCE hInst;
73 HWND hMainWnd;
74 HWND hURLBarWnd;
75 HWND hBackButtonWnd;
76 HWND hForwardButtonWnd;
77 HWND hCacheWnd;
78 WNDPROC DefEditProc = nullptr;
79 WNDPROC DefButtonProc = nullptr;
80 WNDPROC DefWebKitProc = nullptr;
81 HWND gViewWindow = 0;
82 WinLauncher* gWinLauncher = nullptr;
83 TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
84 TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
85
86 // Support moving the transparent window
87 POINT s_windowPosition = { 100, 100 };
88 SIZE s_windowSize = { 800, 400 };
89
90 // Forward declarations of functions included in this code module:
91 ATOM MyRegisterClass(HINSTANCE hInstance);
92 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
93 INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
94 INT_PTR CALLBACK CustomUserAgent(HWND, UINT, WPARAM, LPARAM);
95 LRESULT CALLBACK EditProc(HWND, UINT, WPARAM, LPARAM);
96 LRESULT CALLBACK BackButtonProc(HWND, UINT, WPARAM, LPARAM);
97 LRESULT CALLBACK ForwardButtonProc(HWND, UINT, WPARAM, LPARAM);
98 LRESULT CALLBACK ReloadButtonProc(HWND, UINT, WPARAM, LPARAM);
99 INT_PTR CALLBACK Caches(HWND, UINT, WPARAM, LPARAM);
100
101 static void loadURL(BSTR urlBStr);
102 static void updateStatistics(HWND hDlg);
103
104 static void resizeSubViews()
105 {
106     if (gWinLauncher->usesLayeredWebView() || !gViewWindow)
107         return;
108
109     RECT rcClient;
110     GetClientRect(hMainWnd, &rcClient);
111     MoveWindow(hBackButtonWnd, 0, 0, CONTROLBUTTON_WIDTH, URLBAR_HEIGHT, TRUE);
112     MoveWindow(hForwardButtonWnd, CONTROLBUTTON_WIDTH, 0, CONTROLBUTTON_WIDTH, URLBAR_HEIGHT, TRUE);
113     MoveWindow(hURLBarWnd, CONTROLBUTTON_WIDTH * 2, 0, rcClient.right, URLBAR_HEIGHT, TRUE);
114     MoveWindow(gViewWindow, 0, URLBAR_HEIGHT, rcClient.right, rcClient.bottom - URLBAR_HEIGHT, TRUE);
115 }
116
117 static void subclassForLayeredWindow()
118 {
119     hMainWnd = gViewWindow;
120 #if defined _M_AMD64 || defined _WIN64
121     DefWebKitProc = reinterpret_cast<WNDPROC>(::GetWindowLongPtr(hMainWnd, GWLP_WNDPROC));
122     ::SetWindowLongPtr(hMainWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WndProc));
123 #else
124     DefWebKitProc = reinterpret_cast<WNDPROC>(::GetWindowLong(hMainWnd, GWL_WNDPROC));
125     ::SetWindowLong(hMainWnd, GWL_WNDPROC, reinterpret_cast<LONG_PTR>(WndProc));
126 #endif
127 }
128
129 static void computeFullDesktopFrame()
130 {
131     RECT desktop;
132     if (!::SystemParametersInfo(SPI_GETWORKAREA, 0, static_cast<void*>(&desktop), 0))
133         return;
134
135     s_windowPosition.x = 0;
136     s_windowPosition.y = 0;
137     s_windowSize.cx = desktop.right - desktop.left;
138     s_windowSize.cy = desktop.bottom - desktop.top;
139 }
140
141 BOOL WINAPI DllMain(HINSTANCE dllInstance, DWORD reason, LPVOID)
142 {
143     if (reason == DLL_PROCESS_ATTACH) {
144 #if defined(_M_X64) || defined(__x86_64__)
145         // The VS2013 runtime has a bug where it mis-detects AVX-capable processors
146         // if the feature has been disabled in firmware. This causes us to crash
147         // in some of the math functions. For now, we disable those optimizations
148         // because Microsoft is not going to fix the problem in VS2013.
149         // FIXME: http://webkit.org/b/141449: Remove this workaround when we switch to VS2015+.
150         _set_FMA3_enable(0);
151 #endif
152         hInst = dllInstance;
153     }
154
155     return TRUE;
156 }
157
158 static bool getAppDataFolder(_bstr_t& directory)
159 {
160     wchar_t appDataDirectory[MAX_PATH];
161     if (FAILED(SHGetFolderPathW(0, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, appDataDirectory)))
162         return false;
163
164     wchar_t executablePath[MAX_PATH];
165     if (!::GetModuleFileNameW(0, executablePath, MAX_PATH))
166         return false;
167
168     ::PathRemoveExtensionW(executablePath);
169
170     directory = _bstr_t(appDataDirectory) + L"\\" + ::PathFindFileNameW(executablePath);
171
172     return true;
173 }
174
175 static bool setCacheFolder()
176 {
177     IWebCachePtr webCache = gWinLauncher->webCache();
178     if (!webCache)
179         return false;
180
181     _bstr_t appDataFolder;
182     if (!getAppDataFolder(appDataFolder))
183         return false;
184
185     appDataFolder += L"\\cache";
186     webCache->setCacheFolder(appDataFolder);
187
188     return true;
189 }
190
191 void createCrashReport(EXCEPTION_POINTERS* exceptionPointers)
192 {
193     _bstr_t directory;
194
195     if (!getAppDataFolder(directory))
196         return;
197
198     if (::SHCreateDirectoryEx(0, directory, 0) != ERROR_SUCCESS
199         && ::GetLastError() != ERROR_FILE_EXISTS
200         && ::GetLastError() != ERROR_ALREADY_EXISTS)
201         return;
202
203     std::wstring fileName = directory + L"\\CrashReport.dmp";
204     HANDLE miniDumpFile = ::CreateFile(fileName.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
205
206     if (miniDumpFile && miniDumpFile != INVALID_HANDLE_VALUE) {
207
208         MINIDUMP_EXCEPTION_INFORMATION mdei;
209         mdei.ThreadId = ::GetCurrentThreadId();
210         mdei.ExceptionPointers  = exceptionPointers;
211         mdei.ClientPointers = 0;
212
213 #ifdef _DEBUG
214         MINIDUMP_TYPE dumpType = MiniDumpWithFullMemory;
215 #else
216         MINIDUMP_TYPE dumpType = MiniDumpNormal;
217 #endif
218
219         ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), miniDumpFile, dumpType, &mdei, 0, 0);
220         ::CloseHandle(miniDumpFile);
221         processCrashReport(fileName.c_str());
222     }
223 }
224
225 static BOOL CALLBACK AbortProc(HDC hDC, int Error)
226 {
227     MSG msg;
228     while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
229         ::TranslateMessage(&msg);
230         ::DispatchMessage(&msg);
231     }
232
233     return TRUE;
234 }
235
236 static HDC getPrinterDC()
237 {
238     PRINTDLG pdlg;
239     memset(&pdlg, 0, sizeof(PRINTDLG));
240     pdlg.lStructSize = sizeof(PRINTDLG);
241     pdlg.Flags = PD_PRINTSETUP | PD_RETURNDC;
242
243     ::PrintDlg(&pdlg);
244
245     return pdlg.hDC;
246 }
247
248 static void initDocStruct(DOCINFO* di, TCHAR* docname)
249 {
250     memset(di, 0, sizeof(DOCINFO));
251     di->cbSize = sizeof(DOCINFO);
252     di->lpszDocName = docname;
253 }
254
255 typedef _com_ptr_t<_com_IIID<IWebFramePrivate, &__uuidof(IWebFramePrivate)>> IWebFramePrivatePtr;
256
257 void PrintView(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
258 {
259     HDC printDC = getPrinterDC();
260     if (!printDC) {
261         ::MessageBoxW(0, L"Error creating printing DC", L"Error", MB_APPLMODAL | MB_OK);
262         return;
263     }
264
265     if (::SetAbortProc(printDC, AbortProc) == SP_ERROR) {
266         ::MessageBoxW(0, L"Error setting up AbortProc", L"Error", MB_APPLMODAL | MB_OK);
267         return;
268     }
269
270     IWebFramePtr frame = gWinLauncher->mainFrame();
271     if (!frame)
272         return;
273
274     IWebFramePrivatePtr framePrivate;
275     if (FAILED(frame->QueryInterface(&framePrivate.GetInterfacePtr())))
276         return;
277
278     framePrivate->setInPrintingMode(TRUE, printDC);
279
280     UINT pageCount = 0;
281     framePrivate->getPrintedPageCount(printDC, &pageCount);
282
283     DOCINFO di;
284     initDocStruct(&di, L"WebKit Doc");
285     ::StartDoc(printDC, &di);
286
287     // FIXME: Need CoreGraphics implementation
288     void* graphicsContext = 0;
289     for (size_t page = 1; page <= pageCount; ++page) {
290         ::StartPage(printDC);
291         framePrivate->spoolPages(printDC, page, page, graphicsContext);
292         ::EndPage(printDC);
293     }
294
295     framePrivate->setInPrintingMode(FALSE, printDC);
296
297     ::EndDoc(printDC);
298     ::DeleteDC(printDC);
299 }
300
301 static void ToggleMenuFlag(HWND hWnd, UINT menuID)
302 {
303     HMENU menu = ::GetMenu(hWnd);
304
305     MENUITEMINFO info;
306     ::memset(&info, 0x00, sizeof(info));
307     info.cbSize = sizeof(info);
308     info.fMask = MIIM_STATE;
309
310     if (!::GetMenuItemInfo(menu, menuID, FALSE, &info))
311         return;
312
313     BOOL newState = !(info.fState & MFS_CHECKED);
314     info.fState = (newState) ? MFS_CHECKED : MFS_UNCHECKED;
315
316     ::SetMenuItemInfo(menu, menuID, FALSE, &info);
317 }
318
319 static bool menuItemIsChecked(const MENUITEMINFO& info)
320 {
321     return info.fState & MFS_CHECKED;
322 }
323
324 static void turnOffOtherUserAgents(HMENU menu)
325 {
326     MENUITEMINFO info;
327     ::memset(&info, 0x00, sizeof(info));
328     info.cbSize = sizeof(info);
329     info.fMask = MIIM_STATE;
330
331     // Must unset the other menu items:
332     for (UINT menuToClear = IDM_UA_DEFAULT; menuToClear <= IDM_UA_OTHER; ++menuToClear) {
333         if (!::GetMenuItemInfo(menu, menuToClear, FALSE, &info))
334             continue;
335         if (!menuItemIsChecked(info))
336             continue;
337
338         info.fState = MFS_UNCHECKED;
339         ::SetMenuItemInfo(menu, menuToClear, FALSE, &info);
340     }
341 }
342
343 static void ToggleMenuItem(HWND hWnd, UINT menuID)
344 {
345     HMENU menu = ::GetMenu(hWnd);
346
347     MENUITEMINFO info;
348     ::memset(&info, 0x00, sizeof(info));
349     info.cbSize = sizeof(info);
350     info.fMask = MIIM_STATE;
351
352     if (!::GetMenuItemInfo(menu, menuID, FALSE, &info))
353         return;
354
355     BOOL newState = !menuItemIsChecked(info);
356
357     if (!gWinLauncher->standardPreferences() || !gWinLauncher->privatePreferences())
358         return;
359
360     switch (menuID) {
361     case IDM_AVFOUNDATION:
362         gWinLauncher->standardPreferences()->setAVFoundationEnabled(newState);
363         break;
364     case IDM_ACC_COMPOSITING:
365         gWinLauncher->privatePreferences()->setAcceleratedCompositingEnabled(newState);
366         break;
367     case IDM_WK_FULLSCREEN:
368         gWinLauncher->privatePreferences()->setFullScreenEnabled(newState);
369         break;
370     case IDM_COMPOSITING_BORDERS:
371         gWinLauncher->privatePreferences()->setShowDebugBorders(newState);
372         gWinLauncher->privatePreferences()->setShowRepaintCounter(newState);
373         break;
374     case IDM_DISABLE_IMAGES:
375         gWinLauncher->standardPreferences()->setLoadsImagesAutomatically(!newState);
376         break;
377     case IDM_DISABLE_STYLES:
378         gWinLauncher->privatePreferences()->setAuthorAndUserStylesEnabled(!newState);
379         break;
380     case IDM_DISABLE_JAVASCRIPT:
381         gWinLauncher->standardPreferences()->setJavaScriptEnabled(!newState);
382         break;
383     case IDM_DISABLE_LOCAL_FILE_RESTRICTIONS:
384         gWinLauncher->privatePreferences()->setAllowUniversalAccessFromFileURLs(newState);
385         gWinLauncher->privatePreferences()->setAllowFileAccessFromFileURLs(newState);
386         break;
387     case IDM_UA_DEFAULT:
388     case IDM_UA_SAFARI_8_0:
389     case IDM_UA_SAFARI_IOS_8_IPHONE:
390     case IDM_UA_SAFARI_IOS_8_IPAD:
391     case IDM_UA_IE_11:
392     case IDM_UA_CHROME_MAC:
393     case IDM_UA_CHROME_WIN:
394     case IDM_UA_FIREFOX_MAC:
395     case IDM_UA_FIREFOX_WIN:
396         gWinLauncher->setUserAgent(menuID);
397         turnOffOtherUserAgents(menu);
398         break;
399     case IDM_UA_OTHER:
400         // The actual user agent string will be set by the custom user agent dialog
401         turnOffOtherUserAgents(menu);
402         break;
403     }
404
405     info.fState = (newState) ? MFS_CHECKED : MFS_UNCHECKED;
406
407     ::SetMenuItemInfo(menu, menuID, FALSE, &info);
408 }
409
410 static const int dragBarHeight = 30;
411
412 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
413 {
414     WNDPROC parentProc = (gWinLauncher) ? (gWinLauncher->usesLayeredWebView() ? DefWebKitProc : DefWindowProc) : DefWindowProc;
415
416     switch (message) {
417     case WM_NCHITTEST:
418         if (gWinLauncher && gWinLauncher->usesLayeredWebView()) {
419             RECT window;
420             ::GetWindowRect(hWnd, &window);
421             // For testing our transparent window, we need a region to use as a handle for
422             // dragging. The right way to do this would be to query the web view to see what's
423             // under the mouse. However, for testing purposes we just use an arbitrary
424             // 30 pixel band at the top of the view as an arbitrary gripping location.
425             //
426             // When we are within this bad, return HT_CAPTION to tell Windows we want to
427             // treat this region as if it were the title bar on a normal window.
428             int y = HIWORD(lParam);
429
430             if ((y > window.top) && (y < window.top + dragBarHeight))
431                 return HTCAPTION;
432         }
433         return CallWindowProc(parentProc, hWnd, message, wParam, lParam);
434     case WM_COMMAND: {
435         int wmId = LOWORD(wParam);
436         int wmEvent = HIWORD(wParam);
437         if (wmId >= IDM_HISTORY_LINK0 && wmId <= IDM_HISTORY_LINK9) {
438             if (gWinLauncher)
439                 gWinLauncher->navigateToHistory(hWnd, wmId);
440             break;
441         }
442         // Parse the menu selections:
443         switch (wmId) {
444         case IDM_ABOUT:
445             DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
446             break;
447         case IDM_EXIT:
448             DestroyWindow(hWnd);
449             break;
450         case IDM_PRINT:
451             PrintView(hWnd, message, wParam, lParam);
452             break;
453         case IDM_WEB_INSPECTOR:
454             if (gWinLauncher)
455                 gWinLauncher->launchInspector();
456             break;
457         case IDM_CACHES:
458             if (!::IsWindow(hCacheWnd)) {
459                 hCacheWnd = CreateDialog(hInst, MAKEINTRESOURCE(IDD_CACHES), hWnd, Caches);
460                 ::ShowWindow(hCacheWnd, SW_SHOW);
461             }
462             break;
463         case IDM_HISTORY_BACKWARD:
464         case IDM_HISTORY_FORWARD:
465             if (gWinLauncher)
466                 gWinLauncher->navigateForwardOrBackward(hWnd, wmId);
467             break;
468         case IDM_AVFOUNDATION:
469         case IDM_ACC_COMPOSITING:
470         case IDM_WK_FULLSCREEN:
471         case IDM_COMPOSITING_BORDERS:
472         case IDM_DISABLE_IMAGES:
473         case IDM_DISABLE_STYLES:
474         case IDM_DISABLE_JAVASCRIPT:
475         case IDM_DISABLE_LOCAL_FILE_RESTRICTIONS:
476         case IDM_UA_DEFAULT:
477         case IDM_UA_SAFARI_8_0:
478         case IDM_UA_SAFARI_IOS_8_IPHONE:
479         case IDM_UA_SAFARI_IOS_8_IPAD:
480         case IDM_UA_IE_11:
481         case IDM_UA_CHROME_MAC:
482         case IDM_UA_CHROME_WIN:
483         case IDM_UA_FIREFOX_MAC:
484         case IDM_UA_FIREFOX_WIN:
485             ToggleMenuItem(hWnd, wmId);
486             break;
487         case IDM_UA_OTHER:
488             if (wmEvent)
489                 ToggleMenuItem(hWnd, wmId);
490             else
491                 DialogBox(hInst, MAKEINTRESOURCE(IDD_USER_AGENT), hWnd, CustomUserAgent);
492             break;
493         case IDM_ACTUAL_SIZE:
494             if (gWinLauncher)
495                 gWinLauncher->resetZoom();
496             break;
497         case IDM_ZOOM_IN:
498             if (gWinLauncher)
499                 gWinLauncher->zoomIn();
500             break;
501         case IDM_ZOOM_OUT:
502             if (gWinLauncher)
503                 gWinLauncher->zoomOut();
504             break;
505         default:
506             return CallWindowProc(parentProc, hWnd, message, wParam, lParam);
507         }
508         }
509         break;
510     case WM_DESTROY:
511 #if USE(CF)
512         CFRunLoopStop(CFRunLoopGetMain());
513 #endif
514         PostQuitMessage(0);
515         break;
516     case WM_SIZE:
517         if (!gWinLauncher || !gWinLauncher->hasWebView() || gWinLauncher->usesLayeredWebView())
518             return CallWindowProc(parentProc, hWnd, message, wParam, lParam);
519
520         resizeSubViews();
521         break;
522     default:
523         return CallWindowProc(parentProc, hWnd, message, wParam, lParam);
524     }
525
526     return 0;
527 }
528
529 LRESULT CALLBACK EditProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
530 {
531     switch (message) {
532     case WM_CHAR:
533         if (wParam == 13) { // Enter Key
534             wchar_t strPtr[INTERNET_MAX_URL_LENGTH];
535             *((LPWORD)strPtr) = INTERNET_MAX_URL_LENGTH; 
536             int strLen = SendMessage(hDlg, EM_GETLINE, 0, (LPARAM)strPtr);
537
538             strPtr[strLen] = 0;
539             _bstr_t bstr(strPtr);
540             loadURL(bstr.GetBSTR());
541
542             return 0;
543         } 
544     default:
545         return CallWindowProc(DefEditProc, hDlg, message, wParam, lParam);
546     }
547 }
548
549 LRESULT CALLBACK BackButtonProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
550 {
551     switch (message) {
552     case WM_LBUTTONUP:
553         gWinLauncher->goBack();
554     default:
555         return CallWindowProc(DefButtonProc, hDlg, message, wParam, lParam);
556     }
557 }
558
559 LRESULT CALLBACK ForwardButtonProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
560 {
561     switch (message) {
562     case WM_LBUTTONUP:
563         gWinLauncher->goForward();
564     default:
565         return CallWindowProc(DefButtonProc, hDlg, message, wParam, lParam);
566     }
567 }
568
569 // Message handler for about box.
570 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
571 {
572     UNREFERENCED_PARAMETER(lParam);
573     switch (message) {
574     case WM_INITDIALOG:
575         return (INT_PTR)TRUE;
576
577     case WM_COMMAND:
578         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
579             EndDialog(hDlg, LOWORD(wParam));
580             return (INT_PTR)TRUE;
581         }
582         break;
583     }
584     return (INT_PTR)FALSE;
585 }
586
587 INT_PTR CALLBACK Caches(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
588 {
589     UNREFERENCED_PARAMETER(lParam);
590     switch (message) {
591     case WM_INITDIALOG:
592         ::SetTimer(hDlg, IDT_UPDATE_STATS, 1000, nullptr);
593         return (INT_PTR)TRUE;
594
595     case WM_COMMAND:
596         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
597             ::KillTimer(hDlg, IDT_UPDATE_STATS);
598             ::DestroyWindow(hDlg);
599             hCacheWnd = 0;
600             return (INT_PTR)TRUE;
601         }
602         break;
603
604     case IDT_UPDATE_STATS:
605         ::InvalidateRect(hDlg, nullptr, FALSE);
606         return (INT_PTR)TRUE;
607
608     case WM_PAINT:
609         updateStatistics(hDlg);
610         break;
611     }
612
613     return (INT_PTR)FALSE;
614 }
615
616 INT_PTR CALLBACK CustomUserAgent(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
617 {
618     UNREFERENCED_PARAMETER(lParam);
619     switch (message) {
620     case WM_INITDIALOG: {
621         HWND edit = ::GetDlgItem(hDlg, IDC_USER_AGENT_INPUT);
622         _bstr_t userAgent;
623         if (gWinLauncher)
624             userAgent = gWinLauncher->userAgent();
625
626         ::SetWindowText(edit, static_cast<LPCTSTR>(userAgent));
627         return (INT_PTR)TRUE;
628     }
629
630     case WM_COMMAND:
631         if (LOWORD(wParam) == IDOK) {
632             HWND edit = ::GetDlgItem(hDlg, IDC_USER_AGENT_INPUT);
633
634             TCHAR buffer[1024];
635             int strLen = ::GetWindowText(edit, buffer, 1024);
636             buffer[strLen] = 0;
637
638             _bstr_t bstr(buffer);
639             if (bstr.length()) {
640                 gWinLauncher->setUserAgent(bstr);
641                 ::PostMessage(hMainWnd, static_cast<UINT>(WM_COMMAND), MAKELPARAM(IDM_UA_OTHER, 1), 0);
642             }
643         }
644
645         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
646             ::EndDialog(hDlg, LOWORD(wParam));
647             return (INT_PTR)TRUE;
648         }
649         break;
650     }
651     return (INT_PTR)FALSE;
652 }
653
654 static void loadURL(BSTR passedURL)
655 {
656     if (FAILED(gWinLauncher->loadURL(passedURL)))
657         return;
658
659     SetFocus(gViewWindow);
660 }
661
662 static void setWindowText(HWND dialog, UINT field, _bstr_t value)
663 {
664     ::SetDlgItemText(dialog, field, value);
665 }
666
667 static void setWindowText(HWND dialog, UINT field, UINT value)
668 {
669     String valueStr = WTF::String::number(value);
670
671     setWindowText(dialog, field, _bstr_t(valueStr.utf8().data()));
672 }
673
674 typedef _com_ptr_t<_com_IIID<IPropertyBag, &__uuidof(IPropertyBag)>> IPropertyBagPtr;
675
676 static void setWindowText(HWND dialog, UINT field, IPropertyBagPtr statistics, const _bstr_t& key)
677 {
678     _variant_t var;
679     V_VT(&var) = VT_UI8;
680     if (FAILED(statistics->Read(key, &var.GetVARIANT(), nullptr)))
681         return;
682
683     unsigned long long value = V_UI8(&var);
684     String valueStr = WTF::String::number(value);
685
686     setWindowText(dialog, field, _bstr_t(valueStr.utf8().data()));
687 }
688
689 static void setWindowText(HWND dialog, UINT field, CFDictionaryRef dictionary, CFStringRef key, UINT& total)
690 {
691     CFNumberRef countNum = static_cast<CFNumberRef>(CFDictionaryGetValue(dictionary, key));
692     if (!countNum)
693         return;
694
695     int count = 0;
696     CFNumberGetValue(countNum, kCFNumberIntType, &count);
697
698     setWindowText(dialog, field, static_cast<UINT>(count));
699     total += count;
700 }
701
702 static void updateStatistics(HWND dialog)
703 {
704     if (!gWinLauncher)
705         return;
706
707     IWebCoreStatisticsPtr webCoreStatistics = gWinLauncher->statistics();
708     if (!webCoreStatistics)
709         return;
710
711     IPropertyBagPtr statistics;
712     HRESULT hr = webCoreStatistics->memoryStatistics(&statistics.GetInterfacePtr());
713     if (FAILED(hr))
714         return;
715
716     // FastMalloc.
717     setWindowText(dialog, IDC_RESERVED_VM, statistics, "FastMallocReservedVMBytes");
718     setWindowText(dialog, IDC_COMMITTED_VM, statistics, "FastMallocCommittedVMBytes");
719     setWindowText(dialog, IDC_FREE_LIST_BYTES, statistics, "FastMallocFreeListBytes");
720
721     // WebCore Cache.
722 #if USE(CF)
723     IWebCachePtr webCache = gWinLauncher->webCache();
724
725     int dictCount = 6;
726     IPropertyBag* cacheDict[6] = { 0 };
727     if (FAILED(webCache->statistics(&dictCount, cacheDict)))
728         return;
729
730     COMPtr<CFDictionaryPropertyBag> counts, sizes, liveSizes, decodedSizes, purgableSizes;
731     counts.adoptRef(reinterpret_cast<CFDictionaryPropertyBag*>(cacheDict[0]));
732     sizes.adoptRef(reinterpret_cast<CFDictionaryPropertyBag*>(cacheDict[1]));
733     liveSizes.adoptRef(reinterpret_cast<CFDictionaryPropertyBag*>(cacheDict[2]));
734     decodedSizes.adoptRef(reinterpret_cast<CFDictionaryPropertyBag*>(cacheDict[3]));
735     purgableSizes.adoptRef(reinterpret_cast<CFDictionaryPropertyBag*>(cacheDict[4]));
736
737     static CFStringRef imagesKey = CFSTR("images");
738     static CFStringRef stylesheetsKey = CFSTR("style sheets");
739     static CFStringRef xslKey = CFSTR("xsl");
740     static CFStringRef scriptsKey = CFSTR("scripts");
741
742     if (counts) {
743         UINT totalObjects = 0;
744         setWindowText(dialog, IDC_IMAGES_OBJECT_COUNT, counts->dictionary(), imagesKey, totalObjects);
745         setWindowText(dialog, IDC_CSS_OBJECT_COUNT, counts->dictionary(), stylesheetsKey, totalObjects);
746         setWindowText(dialog, IDC_XSL_OBJECT_COUNT, counts->dictionary(), xslKey, totalObjects);
747         setWindowText(dialog, IDC_JSC_OBJECT_COUNT, counts->dictionary(), scriptsKey, totalObjects);
748         setWindowText(dialog, IDC_TOTAL_OBJECT_COUNT, totalObjects);
749     }
750
751     if (sizes) {
752         UINT totalBytes = 0;
753         setWindowText(dialog, IDC_IMAGES_BYTES, sizes->dictionary(), imagesKey, totalBytes);
754         setWindowText(dialog, IDC_CSS_BYTES, sizes->dictionary(), stylesheetsKey, totalBytes);
755         setWindowText(dialog, IDC_XSL_BYTES, sizes->dictionary(), xslKey, totalBytes);
756         setWindowText(dialog, IDC_JSC_BYTES, sizes->dictionary(), scriptsKey, totalBytes);
757         setWindowText(dialog, IDC_TOTAL_BYTES, totalBytes);
758     }
759
760     if (liveSizes) {
761         UINT totalLiveBytes = 0;
762         setWindowText(dialog, IDC_IMAGES_LIVE_COUNT, liveSizes->dictionary(), imagesKey, totalLiveBytes);
763         setWindowText(dialog, IDC_CSS_LIVE_COUNT, liveSizes->dictionary(), stylesheetsKey, totalLiveBytes);
764         setWindowText(dialog, IDC_XSL_LIVE_COUNT, liveSizes->dictionary(), xslKey, totalLiveBytes);
765         setWindowText(dialog, IDC_JSC_LIVE_COUNT, liveSizes->dictionary(), scriptsKey, totalLiveBytes);
766         setWindowText(dialog, IDC_TOTAL_LIVE_COUNT, totalLiveBytes);
767     }
768
769     if (decodedSizes) {
770         UINT totalDecoded = 0;
771         setWindowText(dialog, IDC_IMAGES_DECODED_COUNT, decodedSizes->dictionary(), imagesKey, totalDecoded);
772         setWindowText(dialog, IDC_CSS_DECODED_COUNT, decodedSizes->dictionary(), stylesheetsKey, totalDecoded);
773         setWindowText(dialog, IDC_XSL_DECODED_COUNT, decodedSizes->dictionary(), xslKey, totalDecoded);
774         setWindowText(dialog, IDC_JSC_DECODED_COUNT, decodedSizes->dictionary(), scriptsKey, totalDecoded);
775         setWindowText(dialog, IDC_TOTAL_DECODED, totalDecoded);
776     }
777
778     if (purgableSizes) {
779         UINT totalPurgable = 0;
780         setWindowText(dialog, IDC_IMAGES_PURGEABLE_COUNT, purgableSizes->dictionary(), imagesKey, totalPurgable);
781         setWindowText(dialog, IDC_CSS_PURGEABLE_COUNT, purgableSizes->dictionary(), stylesheetsKey, totalPurgable);
782         setWindowText(dialog, IDC_XSL_PURGEABLE_COUNT, purgableSizes->dictionary(), xslKey, totalPurgable);
783         setWindowText(dialog, IDC_JSC_PURGEABLE_COUNT, purgableSizes->dictionary(), scriptsKey, totalPurgable);
784         setWindowText(dialog, IDC_TOTAL_PURGEABLE, totalPurgable);
785     }
786 #endif
787
788     // JavaScript Heap.
789     setWindowText(dialog, IDC_JSC_HEAP_SIZE, statistics, "JavaScriptHeapSize");
790     setWindowText(dialog, IDC_JSC_HEAP_FREE, statistics, "JavaScriptFreeSize");
791
792     UINT count;
793     if (SUCCEEDED(webCoreStatistics->javaScriptObjectsCount(&count)))
794         setWindowText(dialog, IDC_TOTAL_JSC_HEAP_OBJECTS, count);
795     if (SUCCEEDED(webCoreStatistics->javaScriptGlobalObjectsCount(&count)))
796         setWindowText(dialog, IDC_GLOBAL_JSC_HEAP_OBJECTS, count);
797     if (SUCCEEDED(webCoreStatistics->javaScriptProtectedObjectsCount(&count)))
798         setWindowText(dialog, IDC_PROTECTED_JSC_HEAP_OBJECTS, count);
799
800     // Font and Glyph Caches.
801     if (SUCCEEDED(webCoreStatistics->cachedFontDataCount(&count)))
802         setWindowText(dialog, IDC_TOTAL_FONT_OBJECTS, count);
803     if (SUCCEEDED(webCoreStatistics->cachedFontDataInactiveCount(&count)))
804         setWindowText(dialog, IDC_INACTIVE_FONT_OBJECTS, count);
805     if (SUCCEEDED(webCoreStatistics->glyphPageCount(&count)))
806         setWindowText(dialog, IDC_GLYPH_PAGES, count);
807
808     // Site Icon Database.
809     if (SUCCEEDED(webCoreStatistics->iconPageURLMappingCount(&count)))
810         setWindowText(dialog, IDC_PAGE_URL_MAPPINGS, count);
811     if (SUCCEEDED(webCoreStatistics->iconRetainedPageURLCount(&count)))
812         setWindowText(dialog, IDC_RETAINED_PAGE_URLS, count);
813     if (SUCCEEDED(webCoreStatistics->iconRecordCount(&count)))
814         setWindowText(dialog, IDC_SITE_ICON_RECORDS, count);
815     if (SUCCEEDED(webCoreStatistics->iconsWithDataCount(&count)))
816         setWindowText(dialog, IDC_SITE_ICONS_WITH_DATA, count);
817 }
818
819 static void parseCommandLine(bool& usesLayeredWebView, bool& useFullDesktop, bool& pageLoadTesting, _bstr_t& requestedURL)
820 {
821     usesLayeredWebView = false;
822     useFullDesktop = false;
823     pageLoadTesting = false;
824
825     int argc = 0;
826     WCHAR** argv = CommandLineToArgvW(GetCommandLineW(), &argc);
827     for (int i = 1; i < argc; ++i) {
828         if (!wcsicmp(argv[i], L"--transparent"))
829             usesLayeredWebView = true;
830         else if (!wcsicmp(argv[i], L"--desktop"))
831             useFullDesktop = true;
832         else if (!requestedURL)
833             requestedURL = argv[i];
834         else if (!wcsicmp(argv[i], L"--performance"))
835             pageLoadTesting = true;
836     }
837 }
838
839 extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpstrCmdLine, int nCmdShow)
840 {
841     return wWinMain(hInstance, hPrevInstance, lpstrCmdLine, nCmdShow);
842 }