| Left: | ||
| Right: |
| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
| 3 * Copyright (C) 2006-2015 Eyeo GmbH | 3 * Copyright (C) 2006-2015 Eyeo GmbH |
| 4 * | 4 * |
| 5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
| 6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
| 7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
| 8 * | 8 * |
| 9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 #include "../shared/Version.h" | 32 #include "../shared/Version.h" |
| 33 #include <thread> | 33 #include <thread> |
| 34 #include <array> | 34 #include <array> |
| 35 | 35 |
| 36 #ifdef DEBUG_HIDE_EL | 36 #ifdef DEBUG_HIDE_EL |
| 37 DWORD profileTime = 0; | 37 DWORD profileTime = 0; |
| 38 #endif | 38 #endif |
| 39 | 39 |
| 40 extern CComModule _Module; | 40 extern CComModule _Module; |
| 41 | 41 |
| 42 typedef HANDLE (WINAPI *OPENTHEMEDATA)(HWND, LPCWSTR); | 42 namespace |
| 43 typedef HRESULT (WINAPI *DRAWTHEMEBACKGROUND)(HANDLE, HDC, INT, INT, LPRECT, LPR ECT); | 43 { |
| 44 typedef HRESULT (WINAPI *CLOSETHEMEDATA)(HANDLE); | 44 typedef HANDLE (WINAPI *OPENTHEMEDATA)(HWND, LPCWSTR); |
| 45 typedef HRESULT (WINAPI *DRAWTHEMEBACKGROUND)(HANDLE, HDC, INT, INT, LPRECT, L PRECT); | |
| 46 typedef HRESULT (WINAPI *CLOSETHEMEDATA)(HANDLE); | |
| 47 | |
| 48 CLOSETHEMEDATA pfnClose = NULL; | |
| 49 DRAWTHEMEBACKGROUND pfnDrawThemeBackground = NULL; | |
| 50 OPENTHEMEDATA pfnOpenThemeData = NULL; | |
| 51 } | |
| 45 | 52 |
| 46 HICON CPluginClass::s_hIcons[ICON_MAX] = { NULL, NULL, NULL }; | 53 HICON CPluginClass::s_hIcons[ICON_MAX] = { NULL, NULL, NULL }; |
| 47 DWORD CPluginClass::s_hIconTypes[ICON_MAX] = { IDI_ICON_DISABLED, IDI_ICON_ENABL ED, IDI_ICON_DEACTIVATED }; | 54 DWORD CPluginClass::s_hIconTypes[ICON_MAX] = { IDI_ICON_DISABLED, IDI_ICON_ENABL ED, IDI_ICON_DEACTIVATED }; |
| 48 uint32_t iconHeight = 32; | 55 uint32_t iconHeight = 32; |
| 49 uint32_t iconWidth = 32; | 56 uint32_t iconWidth = 32; |
| 50 | 57 |
| 51 CPluginMimeFilterClient* CPluginClass::s_mimeFilter = NULL; | 58 CPluginMimeFilterClient* CPluginClass::s_mimeFilter = NULL; |
| 52 | |
| 53 CLOSETHEMEDATA pfnClose = NULL; | |
| 54 DRAWTHEMEBACKGROUND pfnDrawThemeBackground = NULL; | |
| 55 OPENTHEMEDATA pfnOpenThemeData = NULL; | |
| 56 | |
| 57 ATOM CPluginClass::s_atomPaneClass = NULL; | 59 ATOM CPluginClass::s_atomPaneClass = NULL; |
| 58 HINSTANCE CPluginClass::s_hUxtheme = NULL; | |
| 59 std::set<CPluginClass*> CPluginClass::s_instances; | 60 std::set<CPluginClass*> CPluginClass::s_instances; |
| 60 std::map<DWORD, CPluginClass*> CPluginClass::s_threadInstances; | 61 std::map<DWORD, CPluginClass*> CPluginClass::s_threadInstances; |
| 61 | |
| 62 CComAutoCriticalSection CPluginClass::s_criticalSectionLocal; | 62 CComAutoCriticalSection CPluginClass::s_criticalSectionLocal; |
| 63 CComAutoCriticalSection CPluginClass::s_criticalSectionWindow; | 63 CComAutoCriticalSection CPluginClass::s_criticalSectionWindow; |
| 64 CComQIPtr<IWebBrowser2> CPluginClass::s_asyncWebBrowser2; | |
| 65 CPluginClass::DetachedInitializerType CPluginClass::di; | |
| 64 | 66 |
| 65 CComQIPtr<IWebBrowser2> CPluginClass::s_asyncWebBrowser2; | |
| 66 | 67 |
| 67 /* | 68 /* |
| 68 * Without namespace declaration, the identifier "Rectangle" is ambiguous | 69 * Without namespace declaration, the identifier "Rectangle" is ambiguous |
| 69 * See http://msdn.microsoft.com/en-us/library/windows/desktop/dd162898(v=vs.85) .aspx | 70 * See http://msdn.microsoft.com/en-us/library/windows/desktop/dd162898(v=vs.85) .aspx |
| 70 */ | 71 */ |
| 71 namespace AdblockPlus | 72 namespace AdblockPlus |
| 72 { | 73 { |
| 73 /** | 74 /** |
| 74 * Replacement for ATL type CRect. | 75 * Replacement for ATL type CRect. |
| 75 */ | 76 */ |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 96 // _CrtDumpMemoryLeaks(); | 97 // _CrtDumpMemoryLeaks(); |
| 97 | 98 |
| 98 m_isAdvised = false; | 99 m_isAdvised = false; |
| 99 m_hTabWnd = NULL; | 100 m_hTabWnd = NULL; |
| 100 m_hStatusBarWnd = NULL; | 101 m_hStatusBarWnd = NULL; |
| 101 m_hPaneWnd = NULL; | 102 m_hPaneWnd = NULL; |
| 102 m_nPaneWidth = 0; | 103 m_nPaneWidth = 0; |
| 103 m_pWndProcStatus = NULL; | 104 m_pWndProcStatus = NULL; |
| 104 m_hTheme = NULL; | 105 m_hTheme = NULL; |
| 105 m_isInitializedOk = false; | 106 m_isInitializedOk = false; |
| 106 | |
| 107 | |
| 108 m_tab = new CPluginTab(this); | 107 m_tab = new CPluginTab(this); |
| 109 | |
| 110 Dictionary::Create(GetBrowserLanguage()); | 108 Dictionary::Create(GetBrowserLanguage()); |
| 109 di.SpawnInitializer(); | |
| 111 } | 110 } |
| 112 | 111 |
| 113 CPluginClass::~CPluginClass() | 112 CPluginClass::~CPluginClass() |
| 114 { | 113 { |
| 115 delete m_tab; | 114 delete m_tab; |
| 116 } | 115 } |
| 117 | 116 |
| 117 /* | |
| 118 * Because this initialization function does not throw, neither can EnsureInitia lized(). | |
| 119 */ | |
| 120 void CPluginClass::Initializer() // noexcept | |
| 121 { | |
| 122 try | |
| 123 { | |
| 124 /* | |
| 125 * Initializes these static, anonymous-namespace variables | |
| 126 * - pfnClose | |
| 127 * - pfnDrawThemeBackground | |
| 128 * - pfnOpenThemeData | |
| 129 */ | |
| 130 HINSTANCE UxthemeModule = ::GetModuleHandle(L"uxtheme.dll"); | |
| 131 if (!UxthemeModule) | |
| 132 { | |
| 133 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_UXT HEME, "CPluginClass::Initializer - GetModuleHandle(uxtheme.dll)"); | |
| 134 } | |
| 135 else | |
| 136 { | |
| 137 pfnClose = (CLOSETHEMEDATA)::GetProcAddress(UxthemeModule, "CloseThemeData "); | |
| 138 if (!pfnClose) | |
| 139 { | |
| 140 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_U XTHEME_CLOSE, "CPluginClass::Initializer - GetProcAddress(CloseThemeData)"); | |
| 141 } | |
| 142 pfnDrawThemeBackground = (DRAWTHEMEBACKGROUND)::GetProcAddress(UxthemeModu le, "DrawThemeBackground"); | |
| 143 if (!pfnDrawThemeBackground) | |
| 144 { | |
| 145 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_U XTHEME_DRAW_BACKGROUND, "CPluginClass::Initializer - GetProcAddress(DrawThemeBac kground)"); | |
| 146 } | |
| 147 pfnOpenThemeData = (OPENTHEMEDATA)::GetProcAddress(UxthemeModule, "OpenThe meData"); | |
| 148 if (!pfnOpenThemeData) | |
| 149 { | |
| 150 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_U XTHEME_OPEN, "CPluginClass::Initializer - GetProcAddress(pfnOpenThemeData)"); | |
| 151 } | |
| 152 } | |
| 153 } | |
| 154 catch (...) | |
| 155 { | |
| 156 // Suppress all exceptions | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 | |
| 118 HWND CPluginClass::GetBrowserHWND() const | 161 HWND CPluginClass::GetBrowserHWND() const |
| 119 { | 162 { |
| 120 if (!m_webBrowser2) | 163 if (!m_webBrowser2) |
| 121 { | 164 { |
| 122 DEBUG_ERROR_LOG(0, 0, 0, "CPluginClass::GetBrowserHWND - Reached with m_webB rowser2 == nullptr"); | 165 DEBUG_ERROR_LOG(0, 0, 0, "CPluginClass::GetBrowserHWND - Reached with m_webB rowser2 == nullptr"); |
| 123 return nullptr; | 166 return nullptr; |
| 124 } | 167 } |
| 125 SHANDLE_PTR hBrowserWndHandle = 0; | 168 SHANDLE_PTR hBrowserWndHandle = 0; |
| 126 HRESULT hr = m_webBrowser2->get_HWND(&hBrowserWndHandle); | 169 HRESULT hr = m_webBrowser2->get_HWND(&hBrowserWndHandle); |
| 127 if (FAILED(hr)) | 170 if (FAILED(hr)) |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 168 } | 211 } |
| 169 return url; | 212 return url; |
| 170 } | 213 } |
| 171 | 214 |
| 172 DWORD WINAPI CPluginClass::StartInitObject(LPVOID thisPtr) | 215 DWORD WINAPI CPluginClass::StartInitObject(LPVOID thisPtr) |
| 173 { | 216 { |
| 174 if (thisPtr == NULL) | 217 if (thisPtr == NULL) |
| 175 return 0; | 218 return 0; |
| 176 if (!((CPluginClass*)thisPtr)->InitObject()) | 219 if (!((CPluginClass*)thisPtr)->InitObject()) |
| 177 { | 220 { |
| 178 ((CPluginClass*)thisPtr)->Unadvise(); | 221 ((CPluginClass*)thisPtr)->Unadvise(); |
|
Eric
2015/12/14 18:46:02
This statement is the motivation to clean up detac
| |
| 179 } | 222 } |
| 180 | 223 |
| 181 return 0; | 224 return 0; |
| 182 } | 225 } |
| 183 | 226 |
| 184 /* | 227 /* |
| 185 * IE calls this when it creates a new browser window or tab, immediately after it also | 228 * IE calls this when it creates a new browser window or tab, immediately after it also |
| 186 * creates the object. The argument 'unknownSite' in is the OLE "site" of the ob ject, | 229 * creates the object. The argument 'unknownSite' in is the OLE "site" of the ob ject, |
| 187 * which is an IWebBrowser2 interface associated with the window/tab. | 230 * which is an IWebBrowser2 interface associated with the window/tab. |
| 188 * | 231 * |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 230 try | 273 try |
| 231 { | 274 { |
| 232 DEBUG_GENERAL("Loaded as BHO"); | 275 DEBUG_GENERAL("Loaded as BHO"); |
| 233 HRESULT hr = DispEventAdvise(m_webBrowser2); | 276 HRESULT hr = DispEventAdvise(m_webBrowser2); |
| 234 if (SUCCEEDED(hr)) | 277 if (SUCCEEDED(hr)) |
| 235 { | 278 { |
| 236 m_isAdvised = true; | 279 m_isAdvised = true; |
| 237 try | 280 try |
| 238 { | 281 { |
| 239 std::thread startInitObjectThread(StartInitObject, this); | 282 std::thread startInitObjectThread(StartInitObject, this); |
| 240 startInitObjectThread.detach(); // TODO: but actually we should wait for the thread in the dtr. | 283 startInitObjectThread.detach(); // TODO: but actually we should wait for the thread in the dtr. |
|
Eric
2015/12/14 18:46:01
This comment is sort-of-right; at least it express
| |
| 241 } | 284 } |
| 242 catch (const std::system_error& ex) | 285 catch (const std::system_error& ex) |
| 243 { | 286 { |
| 244 DEBUG_SYSTEM_EXCEPTION(ex, PLUGIN_ERROR_THREAD, PLUGIN_ERROR_MAIN_TH READ_CREATE_PROCESS, | 287 DEBUG_SYSTEM_EXCEPTION(ex, PLUGIN_ERROR_THREAD, PLUGIN_ERROR_MAIN_TH READ_CREATE_PROCESS, |
| 245 "Class::Thread - Failed to create StartInitObject thread"); | 288 "Class::Thread - Failed to create StartInitObject thread"); |
| 246 } | 289 } |
| 247 } | 290 } |
| 248 else | 291 else |
| 249 { | 292 { |
| 250 DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_ADVIC E, "Class::SetSite - Advise"); | 293 DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_SET_SITE, PLUGIN_ERROR_SET_SITE_ADVIC E, "Class::SetSite - Advise"); |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 589 bool CPluginClass::InitObject() | 632 bool CPluginClass::InitObject() |
| 590 { | 633 { |
| 591 DEBUG_GENERAL("InitObject - begin"); | 634 DEBUG_GENERAL("InitObject - begin"); |
| 592 CPluginSettings* settings = CPluginSettings::GetInstance(); | 635 CPluginSettings* settings = CPluginSettings::GetInstance(); |
| 593 | 636 |
| 594 if (!settings->GetPluginEnabled()) | 637 if (!settings->GetPluginEnabled()) |
| 595 { | 638 { |
| 596 s_mimeFilter->Unregister(); | 639 s_mimeFilter->Unregister(); |
| 597 } | 640 } |
| 598 | 641 |
| 599 // Load theme module | |
| 600 s_criticalSectionLocal.Lock(); | |
| 601 { | |
| 602 if (!s_hUxtheme) | |
| 603 { | |
| 604 s_hUxtheme = ::GetModuleHandle(L"uxtheme.dll"); | |
| 605 if (s_hUxtheme) | |
| 606 { | |
| 607 pfnClose = (CLOSETHEMEDATA)::GetProcAddress(s_hUxtheme, "CloseThemeData" ); | |
| 608 if (!pfnClose) | |
| 609 { | |
| 610 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET _UXTHEME_CLOSE, "Class::InitObject - GetProcAddress(CloseThemeData)"); | |
| 611 } | |
| 612 | |
| 613 pfnDrawThemeBackground = (DRAWTHEMEBACKGROUND)::GetProcAddress(s_hUxthem e, "DrawThemeBackground"); | |
| 614 if (!pfnDrawThemeBackground) | |
| 615 { | |
| 616 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET _UXTHEME_DRAW_BACKGROUND, "Class::InitObject - GetProcAddress(DrawThemeBackgroun d)"); | |
| 617 } | |
| 618 | |
| 619 pfnOpenThemeData = (OPENTHEMEDATA)::GetProcAddress(s_hUxtheme, "OpenThem eData"); | |
| 620 if (!pfnOpenThemeData) | |
| 621 { | |
| 622 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET _UXTHEME_OPEN, "Class::InitObject - GetProcAddress(pfnOpenThemeData)"); | |
| 623 } | |
| 624 } | |
| 625 else | |
| 626 { | |
| 627 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_UI, PLUGIN_ERROR_UI_GET_U XTHEME, "Class::InitObject - GetModuleHandle(uxtheme.dll)"); | |
| 628 } | |
| 629 } | |
| 630 } | |
| 631 s_criticalSectionLocal.Unlock(); | |
| 632 | |
| 633 // Register pane class | 642 // Register pane class |
| 634 if (!GetAtomPaneClass()) | 643 if (!GetAtomPaneClass()) |
| 635 { | 644 { |
| 636 WNDCLASSEX wcex; | 645 WNDCLASSEX wcex; |
| 637 | 646 |
| 638 wcex.cbSize = sizeof(wcex); | 647 wcex.cbSize = sizeof(wcex); |
| 639 wcex.style = 0; | 648 wcex.style = 0; |
| 640 wcex.lpfnWndProc = (WNDPROC)PaneWindowProc; | 649 wcex.lpfnWndProc = (WNDPROC)PaneWindowProc; |
| 641 wcex.cbClsExtra = 0; | 650 wcex.cbClsExtra = 0; |
| 642 wcex.cbWndExtra = 0; | 651 wcex.cbWndExtra = 0; |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 895 { | 904 { |
| 896 vFlags.intVal = navOpenInNewWindow; | 905 vFlags.intVal = navOpenInNewWindow; |
| 897 hr = GetAsyncBrowser()->Navigate(navigatePath, &vFlags, NULL, NULL, NULL); | 906 hr = GetAsyncBrowser()->Navigate(navigatePath, &vFlags, NULL, NULL, NULL); |
| 898 } | 907 } |
| 899 | 908 |
| 900 if (FAILED(hr)) | 909 if (FAILED(hr)) |
| 901 { | 910 { |
| 902 DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_NAVIGATION, PLUGIN_ERROR_NAVIGATION_WELCOME , "Navigation::Welcome page failed") | 911 DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_NAVIGATION, PLUGIN_ERROR_NAVIGATION_WELCOME , "Navigation::Welcome page failed") |
| 903 } | 912 } |
| 904 } | 913 } |
| 905 void CPluginClass::CloseTheme() | 914 |
| 915 void CPluginClass::UpdateTheme() | |
| 906 { | 916 { |
| 917 EnsureInitialized(); // pfnClose, pfnOpenThemeData | |
| 907 if (m_hTheme) | 918 if (m_hTheme) |
| 908 { | 919 { |
| 909 if (pfnClose) | 920 if (pfnClose) |
| 910 { | 921 { |
| 911 pfnClose(m_hTheme); | 922 pfnClose(m_hTheme); |
| 912 } | 923 } |
| 913 | |
| 914 m_hTheme = NULL; | 924 m_hTheme = NULL; |
| 915 } | 925 } |
| 926 if (pfnOpenThemeData) | |
| 927 { | |
| 928 m_hTheme = pfnOpenThemeData(m_hPaneWnd, L"STATUS"); | |
| 929 } | |
| 916 } | 930 } |
| 917 | 931 |
| 918 void CPluginClass::UpdateTheme() | |
| 919 { | |
| 920 CloseTheme(); | |
| 921 | |
| 922 if (pfnOpenThemeData) | |
| 923 { | |
| 924 m_hTheme = pfnOpenThemeData(m_hPaneWnd, L"STATUS"); | |
| 925 if (!m_hTheme) | |
| 926 { | |
| 927 } | |
| 928 } | |
| 929 } | |
| 930 | |
| 931 | 932 |
| 932 CPluginClass* CPluginClass::FindInstance(HWND hStatusBarWnd) | 933 CPluginClass* CPluginClass::FindInstance(HWND hStatusBarWnd) |
| 933 { | 934 { |
| 934 CPluginClass* result = nullptr; | 935 CPluginClass* result = nullptr; |
| 935 | 936 |
| 936 s_criticalSectionLocal.Lock(); | 937 s_criticalSectionLocal.Lock(); |
| 937 { | 938 { |
| 938 for (auto instance : s_instances) | 939 for (auto instance : s_instances) |
| 939 { | 940 { |
| 940 if (instance->m_hStatusBarWnd == hStatusBarWnd) | 941 if (instance->m_hStatusBarWnd == hStatusBarWnd) |
| (...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1406 | 1407 |
| 1407 nDrawEdge = 3; | 1408 nDrawEdge = 3; |
| 1408 rcClient.left += 3; | 1409 rcClient.left += 3; |
| 1409 | 1410 |
| 1410 ::DrawEdge(hDC, &rcClient, BDR_SUNKENOUTER, BF_RECT); | 1411 ::DrawEdge(hDC, &rcClient, BDR_SUNKENOUTER, BF_RECT); |
| 1411 } | 1412 } |
| 1412 // Themed background drawing | 1413 // Themed background drawing |
| 1413 else | 1414 else |
| 1414 { | 1415 { |
| 1415 // Draw background | 1416 // Draw background |
| 1417 EnsureInitialized(); // pfnDrawThemeBackground | |
| 1416 if (pfnDrawThemeBackground) | 1418 if (pfnDrawThemeBackground) |
| 1417 { | 1419 { |
| 1418 AdblockPlus::Rectangle rc = rcClient; | 1420 AdblockPlus::Rectangle rc = rcClient; |
| 1419 rc.right -= 2; | 1421 rc.right -= 2; |
| 1420 pfnDrawThemeBackground(pClass->m_hTheme, hDC, 0, 0, &rc, NULL); | 1422 pfnDrawThemeBackground(pClass->m_hTheme, hDC, 0, 0, &rc, NULL); |
| 1421 } | 1423 } |
| 1422 | 1424 |
| 1423 // Copy separator picture to left side | 1425 // Copy separator picture to left side |
| 1424 int nHeight = rcClient.Height(); | 1426 int nHeight = rcClient.Height(); |
| 1425 int nWidth = rcClient.Width() - 2; | 1427 int nWidth = rcClient.Width() - 2; |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1633 s_criticalSectionLocal.Unlock(); | 1635 s_criticalSectionLocal.Unlock(); |
| 1634 | 1636 |
| 1635 return icon; | 1637 return icon; |
| 1636 } | 1638 } |
| 1637 | 1639 |
| 1638 ATOM CPluginClass::GetAtomPaneClass() | 1640 ATOM CPluginClass::GetAtomPaneClass() |
| 1639 { | 1641 { |
| 1640 return s_atomPaneClass; | 1642 return s_atomPaneClass; |
| 1641 } | 1643 } |
| 1642 | 1644 |
| OLD | NEW |