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