1b71a76b28fe43d0ea474c44eee48466d5595757
[WebKit-https.git] / Tools / MiniBrowser / win / 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 "MiniBrowser.h"
35 #include "MiniBrowserReplace.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 #ifndef WM_DPICHANGED
69 #define WM_DPICHANGED 0x02E0
70 #endif
71
72 typedef _com_ptr_t<_com_IIID<IWebFrame, &__uuidof(IWebFrame)>> IWebFramePtr;
73 typedef _com_ptr_t<_com_IIID<IWebMutableURLRequest, &__uuidof(IWebMutableURLRequest)>> IWebMutableURLRequestPtr;
74
75 // Global Variables:
76 HINSTANCE hInst;
77 HWND hMainWnd;
78 HWND hURLBarWnd;
79 HGDIOBJ hURLFont;
80 HWND hBackButtonWnd;
81 HWND hForwardButtonWnd;
82 HWND hCacheWnd;
83 WNDPROC DefEditProc = nullptr;
84 WNDPROC DefButtonProc = nullptr;
85 WNDPROC DefWebKitProc = nullptr;
86 HWND gViewWindow = 0;
87 MiniBrowser* gMiniBrowser = nullptr;
88 TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
89 TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
90
91 // Support moving the transparent window
92 POINT s_windowPosition = { 100, 100 };
93 SIZE s_windowSize = { 500, 200 };
94
95 // Forward declarations of functions included in this code module:
96 ATOM MyRegisterClass(HINSTANCE hInstance);
97 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
98 INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
99 INT_PTR CALLBACK CustomUserAgent(HWND, UINT, WPARAM, LPARAM);
100 LRESULT CALLBACK EditProc(HWND, UINT, WPARAM, LPARAM);
101 LRESULT CALLBACK BackButtonProc(HWND, UINT, WPARAM, LPARAM);
102 LRESULT CALLBACK ForwardButtonProc(HWND, UINT, WPARAM, LPARAM);
103 LRESULT CALLBACK ReloadButtonProc(HWND, UINT, WPARAM, LPARAM);
104 INT_PTR CALLBACK Caches(HWND, UINT, WPARAM, LPARAM);
105 INT_PTR CALLBACK AuthDialogProc(HWND, UINT, WPARAM, LPARAM);
106
107 static void loadURL(BSTR urlBStr);
108 static void updateStatistics(HWND hDlg);
109
110 namespace WebCore {
111 float deviceScaleFactorForWindow(HWND);
112 }
113
114 static void resizeSubViews()
115 {
116     if (gMiniBrowser->usesLayeredWebView() || !gViewWindow)
117         return;
118
119     float scaleFactor = WebCore::deviceScaleFactorForWindow(gViewWindow);
120
121     RECT rcClient;
122     GetClientRect(hMainWnd, &rcClient);
123
124     int height = scaleFactor * URLBAR_HEIGHT;
125     int width = scaleFactor * CONTROLBUTTON_WIDTH;
126
127     MoveWindow(hBackButtonWnd, 0, 0, width, height, TRUE);
128     MoveWindow(hForwardButtonWnd, width, 0, width, height, TRUE);
129     MoveWindow(hURLBarWnd, width * 2, 0, rcClient.right, height, TRUE);
130     MoveWindow(gViewWindow, 0, height, rcClient.right, rcClient.bottom - height, TRUE);
131
132     ::SendMessage(hURLBarWnd, static_cast<UINT>(WM_SETFONT), reinterpret_cast<WPARAM>(gMiniBrowser->urlBarFont()), TRUE);
133 }
134
135 static void subclassForLayeredWindow()
136 {
137     hMainWnd = gViewWindow;
138 #if defined _M_AMD64 || defined _WIN64
139     DefWebKitProc = reinterpret_cast<WNDPROC>(::GetWindowLongPtr(hMainWnd, GWLP_WNDPROC));
140     ::SetWindowLongPtr(hMainWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WndProc));
141 #else
142     DefWebKitProc = reinterpret_cast<WNDPROC>(::GetWindowLong(hMainWnd, GWL_WNDPROC));
143     ::SetWindowLong(hMainWnd, GWL_WNDPROC, reinterpret_cast<LONG_PTR>(WndProc));
144 #endif
145 }
146
147 static void computeFullDesktopFrame()
148 {
149     RECT desktop;
150     if (!::SystemParametersInfo(SPI_GETWORKAREA, 0, static_cast<void*>(&desktop), 0))
151         return;
152
153     float scaleFactor = WebCore::deviceScaleFactorForWindow(nullptr);
154
155     s_windowPosition.x = 0;
156     s_windowPosition.y = 0;
157     s_windowSize.cx = scaleFactor * (desktop.right - desktop.left);
158     s_windowSize.cy = scaleFactor * (desktop.bottom - desktop.top);
159 }
160
161 BOOL WINAPI DllMain(HINSTANCE dllInstance, DWORD reason, LPVOID)
162 {
163     if (reason == DLL_PROCESS_ATTACH)
164         hInst = dllInstance;
165
166     return TRUE;
167 }
168
169 static bool getAppDataFolder(_bstr_t& directory)
170 {
171     wchar_t appDataDirectory[MAX_PATH];
172     if (FAILED(SHGetFolderPathW(0, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, appDataDirectory)))
173         return false;
174
175     wchar_t executablePath[MAX_PATH];
176     if (!::GetModuleFileNameW(0, executablePath, MAX_PATH))
177         return false;
178
179     ::PathRemoveExtensionW(executablePath);
180
181     directory = _bstr_t(appDataDirectory) + L"\\" + ::PathFindFileNameW(executablePath);
182
183     return true;
184 }
185
186 static bool setCacheFolder()
187 {
188     IWebCachePtr webCache = gMiniBrowser->webCache();
189     if (!webCache)
190         return false;
191
192     _bstr_t appDataFolder;
193     if (!getAppDataFolder(appDataFolder))
194         return false;
195
196     appDataFolder += L"\\cache";
197     webCache->setCacheFolder(appDataFolder);
198
199     return true;
200 }
201
202 void createCrashReport(EXCEPTION_POINTERS* exceptionPointers)
203 {
204     _bstr_t directory;
205
206     if (!getAppDataFolder(directory))
207         return;
208
209     if (::SHCreateDirectoryEx(0, directory, 0) != ERROR_SUCCESS
210         && ::GetLastError() != ERROR_FILE_EXISTS
211         && ::GetLastError() != ERROR_ALREADY_EXISTS)
212         return;
213
214     std::wstring fileName = std::wstring(static_cast<const wchar_t*>(directory)) + L"\\CrashReport.dmp";
215     HANDLE miniDumpFile = ::CreateFile(fileName.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
216
217     if (miniDumpFile && miniDumpFile != INVALID_HANDLE_VALUE) {
218
219         MINIDUMP_EXCEPTION_INFORMATION mdei;
220         mdei.ThreadId = ::GetCurrentThreadId();
221         mdei.ExceptionPointers  = exceptionPointers;
222         mdei.ClientPointers = 0;
223
224 #ifdef _DEBUG
225         MINIDUMP_TYPE dumpType = MiniDumpWithFullMemory;
226 #else
227         MINIDUMP_TYPE dumpType = MiniDumpNormal;
228 #endif
229
230         ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), miniDumpFile, dumpType, &mdei, 0, 0);
231         ::CloseHandle(miniDumpFile);
232         processCrashReport(fileName.c_str());
233     }
234 }
235
236 static BOOL CALLBACK AbortProc(HDC hDC, int Error)
237 {
238     MSG msg;
239     while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
240         ::TranslateMessage(&msg);
241         ::DispatchMessage(&msg);
242     }
243
244     return TRUE;
245 }
246
247 static HDC getPrinterDC()
248 {
249     PRINTDLG pdlg;
250     memset(&pdlg, 0, sizeof(PRINTDLG));
251     pdlg.lStructSize = sizeof(PRINTDLG);
252     pdlg.Flags = PD_PRINTSETUP | PD_RETURNDC;
253
254     ::PrintDlg(&pdlg);
255
256     return pdlg.hDC;
257 }
258
259 static void initDocStruct(DOCINFO* di, TCHAR* docname)
260 {
261     memset(di, 0, sizeof(DOCINFO));
262     di->cbSize = sizeof(DOCINFO);
263     di->lpszDocName = docname;
264 }
265
266 typedef _com_ptr_t<_com_IIID<IWebFramePrivate, &__uuidof(IWebFramePrivate)>> IWebFramePrivatePtr;
267
268 void PrintView(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
269 {
270     HDC printDC = getPrinterDC();
271     if (!printDC) {
272         ::MessageBoxW(0, L"Error creating printing DC", L"Error", MB_APPLMODAL | MB_OK);
273         return;
274     }
275
276     if (::SetAbortProc(printDC, AbortProc) == SP_ERROR) {
277         ::MessageBoxW(0, L"Error setting up AbortProc", L"Error", MB_APPLMODAL | MB_OK);
278         return;
279     }
280
281     IWebFramePtr frame = gMiniBrowser->mainFrame();
282     if (!frame)
283         return;
284
285     IWebFramePrivatePtr framePrivate;
286     if (FAILED(frame->QueryInterface(&framePrivate.GetInterfacePtr())))
287         return;
288
289     framePrivate->setInPrintingMode(TRUE, printDC);
290
291     UINT pageCount = 0;
292     framePrivate->getPrintedPageCount(printDC, &pageCount);
293
294     DOCINFO di;
295     initDocStruct(&di, L"WebKit Doc");
296     ::StartDoc(printDC, &di);
297
298     // FIXME: Need CoreGraphics implementation
299     void* graphicsContext = 0;
300     for (size_t page = 1; page <= pageCount; ++page) {
301         ::StartPage(printDC);
302         framePrivate->spoolPages(printDC, page, page, graphicsContext);
303         ::EndPage(printDC);
304     }
305
306     framePrivate->setInPrintingMode(FALSE, printDC);
307
308     ::EndDoc(printDC);
309     ::DeleteDC(printDC);
310 }
311
312 static void ToggleMenuFlag(HWND hWnd, UINT menuID)
313 {
314     HMENU menu = ::GetMenu(hWnd);
315
316     MENUITEMINFO info;
317     ::memset(&info, 0x00, sizeof(info));
318     info.cbSize = sizeof(info);
319     info.fMask = MIIM_STATE;
320
321     if (!::GetMenuItemInfo(menu, menuID, FALSE, &info))
322         return;
323
324     BOOL newState = !(info.fState & MFS_CHECKED);
325     info.fState = (newState) ? MFS_CHECKED : MFS_UNCHECKED;
326
327     ::SetMenuItemInfo(menu, menuID, FALSE, &info);
328 }
329
330 static bool menuItemIsChecked(const MENUITEMINFO& info)
331 {
332     return info.fState & MFS_CHECKED;
333 }
334
335 static void turnOffOtherUserAgents(HMENU menu)
336 {
337     MENUITEMINFO info;
338     ::memset(&info, 0x00, sizeof(info));
339     info.cbSize = sizeof(info);
340     info.fMask = MIIM_STATE;
341
342     // Must unset the other menu items:
343     for (UINT menuToClear = IDM_UA_DEFAULT; menuToClear <= IDM_UA_OTHER; ++menuToClear) {
344         if (!::GetMenuItemInfo(menu, menuToClear, FALSE, &info))
345             continue;
346         if (!menuItemIsChecked(info))
347             continue;
348
349         info.fState = MFS_UNCHECKED;
350         ::SetMenuItemInfo(menu, menuToClear, FALSE, &info);
351     }
352 }
353
354 static bool ToggleMenuItem(HWND hWnd, UINT menuID)
355 {
356     if (!gMiniBrowser)
357         return false;
358
359     HMENU menu = ::GetMenu(hWnd);
360
361     MENUITEMINFO info;
362     ::memset(&info, 0x00, sizeof(info));
363     info.cbSize = sizeof(info);
364     info.fMask = MIIM_STATE;
365
366     if (!::GetMenuItemInfo(menu, menuID, FALSE, &info))
367         return false;
368
369     BOOL newState = !menuItemIsChecked(info);
370
371     if (!gMiniBrowser->standardPreferences() || !gMiniBrowser->privatePreferences())
372         return false;
373
374     switch (menuID) {
375     case IDM_AVFOUNDATION:
376         gMiniBrowser->standardPreferences()->setAVFoundationEnabled(newState);
377         break;
378     case IDM_ACC_COMPOSITING:
379         gMiniBrowser->privatePreferences()->setAcceleratedCompositingEnabled(newState);
380         break;
381     case IDM_WK_FULLSCREEN:
382         gMiniBrowser->privatePreferences()->setFullScreenEnabled(newState);
383         break;
384     case IDM_COMPOSITING_BORDERS:
385         gMiniBrowser->privatePreferences()->setShowDebugBorders(newState);
386         gMiniBrowser->privatePreferences()->setShowRepaintCounter(newState);
387         break;
388     case IDM_DEBUG_INFO_LAYER:
389         gMiniBrowser->privatePreferences()->setShowTiledScrollingIndicator(newState);
390         break;
391     case IDM_INVERT_COLORS:
392         gMiniBrowser->privatePreferences()->setShouldInvertColors(newState);
393         break;
394     case IDM_DISABLE_IMAGES:
395         gMiniBrowser->standardPreferences()->setLoadsImagesAutomatically(!newState);
396         break;
397     case IDM_DISABLE_STYLES:
398         gMiniBrowser->privatePreferences()->setAuthorAndUserStylesEnabled(!newState);
399         break;
400     case IDM_DISABLE_JAVASCRIPT:
401         gMiniBrowser->standardPreferences()->setJavaScriptEnabled(!newState);
402         break;
403     case IDM_DISABLE_LOCAL_FILE_RESTRICTIONS:
404         gMiniBrowser->privatePreferences()->setAllowUniversalAccessFromFileURLs(newState);
405         gMiniBrowser->privatePreferences()->setAllowFileAccessFromFileURLs(newState);
406         break;
407     case IDM_UA_DEFAULT:
408     case IDM_UA_SAFARI_8_0:
409     case IDM_UA_SAFARI_IOS_8_IPHONE:
410     case IDM_UA_SAFARI_IOS_8_IPAD:
411     case IDM_UA_IE_11:
412     case IDM_UA_CHROME_MAC:
413     case IDM_UA_CHROME_WIN:
414     case IDM_UA_FIREFOX_MAC:
415     case IDM_UA_FIREFOX_WIN:
416         gMiniBrowser->setUserAgent(menuID);
417         turnOffOtherUserAgents(menu);
418         break;
419     case IDM_UA_OTHER:
420         // The actual user agent string will be set by the custom user agent dialog
421         turnOffOtherUserAgents(menu);
422         break;
423     default:
424         return false;
425     }
426
427     info.fState = (newState) ? MFS_CHECKED : MFS_UNCHECKED;
428
429     ::SetMenuItemInfo(menu, menuID, FALSE, &info);
430
431     return true;
432 }
433
434 static const int dragBarHeight = 30;
435
436 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
437 {
438     WNDPROC parentProc = (gMiniBrowser) ? (gMiniBrowser->usesLayeredWebView() ? DefWebKitProc : DefWindowProc) : DefWindowProc;
439
440     switch (message) {
441     case WM_NCHITTEST:
442         if (gMiniBrowser && gMiniBrowser->usesLayeredWebView()) {
443             RECT window;
444             ::GetWindowRect(hWnd, &window);
445             // For testing our transparent window, we need a region to use as a handle for
446             // dragging. The right way to do this would be to query the web view to see what's
447             // under the mouse. However, for testing purposes we just use an arbitrary
448             // 30 logical pixel band at the top of the view as an arbitrary gripping location.
449             //
450             // When we are within this bad, return HT_CAPTION to tell Windows we want to
451             // treat this region as if it were the title bar on a normal window.
452             int y = HIWORD(lParam);
453             float scaledDragBarHeightFactor = dragBarHeight * gMiniBrowser->deviceScaleFactor();
454             if ((y > window.top) && (y < window.top + scaledDragBarHeightFactor))
455                 return HTCAPTION;
456         }
457         return CallWindowProc(parentProc, hWnd, message, wParam, lParam);
458     case WM_COMMAND: {
459         int wmId = LOWORD(wParam);
460         int wmEvent = HIWORD(wParam);
461         if (wmId >= IDM_HISTORY_LINK0 && wmId <= IDM_HISTORY_LINK9) {
462             if (gMiniBrowser)
463                 gMiniBrowser->navigateToHistory(hWnd, wmId);
464             break;
465         }
466         // Parse the menu selections:
467         switch (wmId) {
468         case IDM_ABOUT:
469             DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
470             break;
471         case IDM_EXIT:
472             DestroyWindow(hWnd);
473             break;
474         case IDM_PRINT:
475             PrintView(hWnd, message, wParam, lParam);
476             break;
477         case IDM_WEB_INSPECTOR:
478             if (gMiniBrowser)
479                 gMiniBrowser->launchInspector();
480             break;
481         case IDM_CACHES:
482             if (!::IsWindow(hCacheWnd)) {
483                 hCacheWnd = CreateDialog(hInst, MAKEINTRESOURCE(IDD_CACHES), hWnd, Caches);
484                 ::ShowWindow(hCacheWnd, SW_SHOW);
485             }
486             break;
487         case IDM_HISTORY_BACKWARD:
488         case IDM_HISTORY_FORWARD:
489             if (gMiniBrowser)
490                 gMiniBrowser->navigateForwardOrBackward(hWnd, wmId);
491             break;
492         case IDM_UA_OTHER:
493             if (wmEvent)
494                 ToggleMenuItem(hWnd, wmId);
495             else
496                 DialogBox(hInst, MAKEINTRESOURCE(IDD_USER_AGENT), hWnd, CustomUserAgent);
497             break;
498         case IDM_ACTUAL_SIZE:
499             if (gMiniBrowser)
500                 gMiniBrowser->resetZoom();
501             break;
502         case IDM_ZOOM_IN:
503             if (gMiniBrowser)
504                 gMiniBrowser->zoomIn();
505             break;
506         case IDM_ZOOM_OUT:
507             if (gMiniBrowser)
508                 gMiniBrowser->zoomOut();
509             break;
510         case IDM_SHOW_LAYER_TREE:
511             if (gMiniBrowser)
512                 gMiniBrowser->showLayerTree();
513             break;
514         default:
515             if (!ToggleMenuItem(hWnd, wmId))
516                 return CallWindowProc(parentProc, hWnd, message, wParam, lParam);
517         }
518         }
519         break;
520     case WM_DESTROY:
521 #if USE(CF)
522         CFRunLoopStop(CFRunLoopGetMain());
523 #endif
524         PostQuitMessage(0);
525         break;
526     case WM_SIZE:
527         if (!gMiniBrowser || !gMiniBrowser->hasWebView() || gMiniBrowser->usesLayeredWebView())
528             return CallWindowProc(parentProc, hWnd, message, wParam, lParam);
529
530         resizeSubViews();
531         break;
532     case WM_DPICHANGED:
533         if (gMiniBrowser)
534             gMiniBrowser->updateDeviceScaleFactor();
535         return CallWindowProc(parentProc, hWnd, message, wParam, lParam);
536     default:
537         return CallWindowProc(parentProc, hWnd, message, wParam, lParam);
538     }
539
540     return 0;
541 }
542
543 LRESULT CALLBACK EditProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
544 {
545     switch (message) {
546     case WM_CHAR:
547         if (wParam == 13) { // Enter Key
548             wchar_t strPtr[INTERNET_MAX_URL_LENGTH];
549             *((LPWORD)strPtr) = INTERNET_MAX_URL_LENGTH; 
550             int strLen = SendMessage(hDlg, EM_GETLINE, 0, (LPARAM)strPtr);
551
552             strPtr[strLen] = 0;
553             _bstr_t bstr(strPtr);
554             loadURL(bstr.GetBSTR());
555
556             return 0;
557         } 
558     default:
559         return CallWindowProc(DefEditProc, hDlg, message, wParam, lParam);
560     }
561 }
562
563 LRESULT CALLBACK BackButtonProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
564 {
565     switch (message) {
566     case WM_LBUTTONUP:
567         gMiniBrowser->goBack();
568     default:
569         return CallWindowProc(DefButtonProc, hDlg, message, wParam, lParam);
570     }
571 }
572
573 LRESULT CALLBACK ForwardButtonProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
574 {
575     switch (message) {
576     case WM_LBUTTONUP:
577         gMiniBrowser->goForward();
578     default:
579         return CallWindowProc(DefButtonProc, hDlg, message, wParam, lParam);
580     }
581 }
582
583 // Message handler for about box.
584 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
585 {
586     UNREFERENCED_PARAMETER(lParam);
587     switch (message) {
588     case WM_INITDIALOG:
589         return (INT_PTR)TRUE;
590
591     case WM_COMMAND:
592         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
593             EndDialog(hDlg, LOWORD(wParam));
594             return (INT_PTR)TRUE;
595         }
596         break;
597     }
598     return (INT_PTR)FALSE;
599 }
600
601 INT_PTR CALLBACK Caches(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
602 {
603     UNREFERENCED_PARAMETER(lParam);
604     switch (message) {
605     case WM_INITDIALOG:
606         ::SetTimer(hDlg, IDT_UPDATE_STATS, 1000, nullptr);
607         return (INT_PTR)TRUE;
608
609     case WM_COMMAND:
610         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
611             ::KillTimer(hDlg, IDT_UPDATE_STATS);
612             ::DestroyWindow(hDlg);
613             hCacheWnd = 0;
614             return (INT_PTR)TRUE;
615         }
616         break;
617
618     case IDT_UPDATE_STATS:
619         ::InvalidateRect(hDlg, nullptr, FALSE);
620         return (INT_PTR)TRUE;
621
622     case WM_PAINT:
623         updateStatistics(hDlg);
624         break;
625     }
626
627     return (INT_PTR)FALSE;
628 }
629
630 INT_PTR CALLBACK CustomUserAgent(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
631 {
632     UNREFERENCED_PARAMETER(lParam);
633     switch (message) {
634     case WM_INITDIALOG: {
635         HWND edit = ::GetDlgItem(hDlg, IDC_USER_AGENT_INPUT);
636         _bstr_t userAgent;
637         if (gMiniBrowser)
638             userAgent = gMiniBrowser->userAgent();
639
640         ::SetWindowText(edit, static_cast<LPCTSTR>(userAgent));
641         return (INT_PTR)TRUE;
642     }
643
644     case WM_COMMAND:
645         if (LOWORD(wParam) == IDOK) {
646             HWND edit = ::GetDlgItem(hDlg, IDC_USER_AGENT_INPUT);
647
648             TCHAR buffer[1024];
649             int strLen = ::GetWindowText(edit, buffer, 1024);
650             buffer[strLen] = 0;
651
652             _bstr_t bstr(buffer);
653             if (bstr.length()) {
654                 gMiniBrowser->setUserAgent(bstr);
655                 ::PostMessage(hMainWnd, static_cast<UINT>(WM_COMMAND), MAKELPARAM(IDM_UA_OTHER, 1), 0);
656             }
657         }
658
659         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
660             ::EndDialog(hDlg, LOWORD(wParam));
661             return (INT_PTR)TRUE;
662         }
663         break;
664     }
665     return (INT_PTR)FALSE;
666 }
667
668 HRESULT DisplayAuthDialog(std::wstring& username, std::wstring& password)
669 {
670     auto result = DialogBox(hInst, MAKEINTRESOURCE(IDD_AUTH), hMainWnd, AuthDialogProc);
671     if (!result)
672         return E_FAIL;
673
674     auto pair = reinterpret_cast<std::pair<std::wstring, std::wstring>*>(result);
675     username = pair->first;
676     password = pair->second;
677     delete pair;
678
679     return S_OK;
680 }
681
682 INT_PTR CALLBACK AuthDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
683 {
684     switch (message) {
685     case WM_INITDIALOG: {
686         HWND edit = ::GetDlgItem(hDlg, IDC_AUTH_USER);
687         ::SetWindowText(edit, static_cast<LPCTSTR>(L""));
688         
689         edit = ::GetDlgItem(hDlg, IDC_AUTH_PASSWORD);
690         ::SetWindowText(edit, static_cast<LPCTSTR>(L""));
691         return (INT_PTR)TRUE;
692     }
693
694     case WM_COMMAND:
695         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
696             INT_PTR result { };
697
698             if (LOWORD(wParam) == IDOK) {
699                 TCHAR user[256];
700                 int strLen = ::GetWindowText(::GetDlgItem(hDlg, IDC_AUTH_USER), user, 256);
701                 user[strLen] = 0;
702
703                 TCHAR pass[256];
704                 strLen = ::GetWindowText(::GetDlgItem(hDlg, IDC_AUTH_PASSWORD), pass, 256);
705                 pass[strLen] = 0;
706
707                 result = reinterpret_cast<INT_PTR>(new std::pair<std::wstring, std::wstring>(user, pass));
708             }
709
710             ::EndDialog(hDlg, result);
711             return (INT_PTR)TRUE;
712         }
713         break;
714     }
715     return (INT_PTR)FALSE;
716 }
717
718 static void loadURL(BSTR passedURL)
719 {
720     if (FAILED(gMiniBrowser->loadURL(passedURL)))
721         return;
722
723     SetFocus(gViewWindow);
724 }
725
726 static void setWindowText(HWND dialog, UINT field, _bstr_t value)
727 {
728     ::SetDlgItemText(dialog, field, value);
729 }
730
731 static void setWindowText(HWND dialog, UINT field, UINT value)
732 {
733     String valueStr = WTF::String::number(value);
734
735     setWindowText(dialog, field, _bstr_t(valueStr.utf8().data()));
736 }
737
738 typedef _com_ptr_t<_com_IIID<IPropertyBag, &__uuidof(IPropertyBag)>> IPropertyBagPtr;
739
740 static void setWindowText(HWND dialog, UINT field, IPropertyBagPtr statistics, const _bstr_t& key)
741 {
742     _variant_t var;
743     V_VT(&var) = VT_UI8;
744     if (FAILED(statistics->Read(key, &var.GetVARIANT(), nullptr)))
745         return;
746
747     unsigned long long value = V_UI8(&var);
748     String valueStr = WTF::String::number(value);
749
750     setWindowText(dialog, field, _bstr_t(valueStr.utf8().data()));
751 }
752
753 static void setWindowText(HWND dialog, UINT field, CFDictionaryRef dictionary, CFStringRef key, UINT& total)
754 {
755     CFNumberRef countNum = static_cast<CFNumberRef>(CFDictionaryGetValue(dictionary, key));
756     if (!countNum)
757         return;
758
759     int count = 0;
760     CFNumberGetValue(countNum, kCFNumberIntType, &count);
761
762     setWindowText(dialog, field, static_cast<UINT>(count));
763     total += count;
764 }
765
766 static void updateStatistics(HWND dialog)
767 {
768     if (!gMiniBrowser)
769         return;
770
771     IWebCoreStatisticsPtr webCoreStatistics = gMiniBrowser->statistics();
772     if (!webCoreStatistics)
773         return;
774
775     IPropertyBagPtr statistics;
776     HRESULT hr = webCoreStatistics->memoryStatistics(&statistics.GetInterfacePtr());
777     if (FAILED(hr))
778         return;
779
780     // FastMalloc.
781     setWindowText(dialog, IDC_RESERVED_VM, statistics, "FastMallocReservedVMBytes");
782     setWindowText(dialog, IDC_COMMITTED_VM, statistics, "FastMallocCommittedVMBytes");
783     setWindowText(dialog, IDC_FREE_LIST_BYTES, statistics, "FastMallocFreeListBytes");
784
785     // WebCore Cache.
786 #if USE(CF)
787     IWebCachePtr webCache = gMiniBrowser->webCache();
788
789     int dictCount = 6;
790     IPropertyBag* cacheDict[6] = { 0 };
791     if (FAILED(webCache->statistics(&dictCount, cacheDict)))
792         return;
793
794     COMPtr<CFDictionaryPropertyBag> counts, sizes, liveSizes, decodedSizes, purgableSizes;
795     counts.adoptRef(reinterpret_cast<CFDictionaryPropertyBag*>(cacheDict[0]));
796     sizes.adoptRef(reinterpret_cast<CFDictionaryPropertyBag*>(cacheDict[1]));
797     liveSizes.adoptRef(reinterpret_cast<CFDictionaryPropertyBag*>(cacheDict[2]));
798     decodedSizes.adoptRef(reinterpret_cast<CFDictionaryPropertyBag*>(cacheDict[3]));
799     purgableSizes.adoptRef(reinterpret_cast<CFDictionaryPropertyBag*>(cacheDict[4]));
800
801     static CFStringRef imagesKey = CFSTR("images");
802     static CFStringRef stylesheetsKey = CFSTR("style sheets");
803     static CFStringRef xslKey = CFSTR("xsl");
804     static CFStringRef scriptsKey = CFSTR("scripts");
805
806     if (counts) {
807         UINT totalObjects = 0;
808         setWindowText(dialog, IDC_IMAGES_OBJECT_COUNT, counts->dictionary(), imagesKey, totalObjects);
809         setWindowText(dialog, IDC_CSS_OBJECT_COUNT, counts->dictionary(), stylesheetsKey, totalObjects);
810         setWindowText(dialog, IDC_XSL_OBJECT_COUNT, counts->dictionary(), xslKey, totalObjects);
811         setWindowText(dialog, IDC_JSC_OBJECT_COUNT, counts->dictionary(), scriptsKey, totalObjects);
812         setWindowText(dialog, IDC_TOTAL_OBJECT_COUNT, totalObjects);
813     }
814
815     if (sizes) {
816         UINT totalBytes = 0;
817         setWindowText(dialog, IDC_IMAGES_BYTES, sizes->dictionary(), imagesKey, totalBytes);
818         setWindowText(dialog, IDC_CSS_BYTES, sizes->dictionary(), stylesheetsKey, totalBytes);
819         setWindowText(dialog, IDC_XSL_BYTES, sizes->dictionary(), xslKey, totalBytes);
820         setWindowText(dialog, IDC_JSC_BYTES, sizes->dictionary(), scriptsKey, totalBytes);
821         setWindowText(dialog, IDC_TOTAL_BYTES, totalBytes);
822     }
823
824     if (liveSizes) {
825         UINT totalLiveBytes = 0;
826         setWindowText(dialog, IDC_IMAGES_LIVE_COUNT, liveSizes->dictionary(), imagesKey, totalLiveBytes);
827         setWindowText(dialog, IDC_CSS_LIVE_COUNT, liveSizes->dictionary(), stylesheetsKey, totalLiveBytes);
828         setWindowText(dialog, IDC_XSL_LIVE_COUNT, liveSizes->dictionary(), xslKey, totalLiveBytes);
829         setWindowText(dialog, IDC_JSC_LIVE_COUNT, liveSizes->dictionary(), scriptsKey, totalLiveBytes);
830         setWindowText(dialog, IDC_TOTAL_LIVE_COUNT, totalLiveBytes);
831     }
832
833     if (decodedSizes) {
834         UINT totalDecoded = 0;
835         setWindowText(dialog, IDC_IMAGES_DECODED_COUNT, decodedSizes->dictionary(), imagesKey, totalDecoded);
836         setWindowText(dialog, IDC_CSS_DECODED_COUNT, decodedSizes->dictionary(), stylesheetsKey, totalDecoded);
837         setWindowText(dialog, IDC_XSL_DECODED_COUNT, decodedSizes->dictionary(), xslKey, totalDecoded);
838         setWindowText(dialog, IDC_JSC_DECODED_COUNT, decodedSizes->dictionary(), scriptsKey, totalDecoded);
839         setWindowText(dialog, IDC_TOTAL_DECODED, totalDecoded);
840     }
841
842     if (purgableSizes) {
843         UINT totalPurgable = 0;
844         setWindowText(dialog, IDC_IMAGES_PURGEABLE_COUNT, purgableSizes->dictionary(), imagesKey, totalPurgable);
845         setWindowText(dialog, IDC_CSS_PURGEABLE_COUNT, purgableSizes->dictionary(), stylesheetsKey, totalPurgable);
846         setWindowText(dialog, IDC_XSL_PURGEABLE_COUNT, purgableSizes->dictionary(), xslKey, totalPurgable);
847         setWindowText(dialog, IDC_JSC_PURGEABLE_COUNT, purgableSizes->dictionary(), scriptsKey, totalPurgable);
848         setWindowText(dialog, IDC_TOTAL_PURGEABLE, totalPurgable);
849     }
850 #endif
851
852     // JavaScript Heap.
853     setWindowText(dialog, IDC_JSC_HEAP_SIZE, statistics, "JavaScriptHeapSize");
854     setWindowText(dialog, IDC_JSC_HEAP_FREE, statistics, "JavaScriptFreeSize");
855
856     UINT count;
857     if (SUCCEEDED(webCoreStatistics->javaScriptObjectsCount(&count)))
858         setWindowText(dialog, IDC_TOTAL_JSC_HEAP_OBJECTS, count);
859     if (SUCCEEDED(webCoreStatistics->javaScriptGlobalObjectsCount(&count)))
860         setWindowText(dialog, IDC_GLOBAL_JSC_HEAP_OBJECTS, count);
861     if (SUCCEEDED(webCoreStatistics->javaScriptProtectedObjectsCount(&count)))
862         setWindowText(dialog, IDC_PROTECTED_JSC_HEAP_OBJECTS, count);
863
864     // Font and Glyph Caches.
865     if (SUCCEEDED(webCoreStatistics->cachedFontDataCount(&count)))
866         setWindowText(dialog, IDC_TOTAL_FONT_OBJECTS, count);
867     if (SUCCEEDED(webCoreStatistics->cachedFontDataInactiveCount(&count)))
868         setWindowText(dialog, IDC_INACTIVE_FONT_OBJECTS, count);
869     if (SUCCEEDED(webCoreStatistics->glyphPageCount(&count)))
870         setWindowText(dialog, IDC_GLYPH_PAGES, count);
871
872     // Site Icon Database.
873     if (SUCCEEDED(webCoreStatistics->iconPageURLMappingCount(&count)))
874         setWindowText(dialog, IDC_PAGE_URL_MAPPINGS, count);
875     if (SUCCEEDED(webCoreStatistics->iconRetainedPageURLCount(&count)))
876         setWindowText(dialog, IDC_RETAINED_PAGE_URLS, count);
877     if (SUCCEEDED(webCoreStatistics->iconRecordCount(&count)))
878         setWindowText(dialog, IDC_SITE_ICON_RECORDS, count);
879     if (SUCCEEDED(webCoreStatistics->iconsWithDataCount(&count)))
880         setWindowText(dialog, IDC_SITE_ICONS_WITH_DATA, count);
881 }
882
883 static void parseCommandLine(bool& usesLayeredWebView, bool& useFullDesktop, bool& pageLoadTesting, _bstr_t& requestedURL)
884 {
885     usesLayeredWebView = false;
886     useFullDesktop = false;
887     pageLoadTesting = false;
888
889     int argc = 0;
890     WCHAR** argv = CommandLineToArgvW(GetCommandLineW(), &argc);
891     for (int i = 1; i < argc; ++i) {
892         if (!wcsicmp(argv[i], L"--transparent"))
893             usesLayeredWebView = true;
894         else if (!wcsicmp(argv[i], L"--desktop"))
895             useFullDesktop = true;
896         else if (!wcsicmp(argv[i], L"--performance"))
897             pageLoadTesting = true;
898         else if (!wcsicmp(argv[i], L"--highDPI"))
899             continue; // ignore
900         else if (!requestedURL)
901             requestedURL = argv[i];
902     }
903 }
904
905 extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpstrCmdLine, int nCmdShow)
906 {
907     return wWinMain(hInstance, hPrevInstance, lpstrCmdLine, nCmdShow);
908 }