X-Git-Url: https://git.josue.xyz/?p=VSoRC%2F.git;a=blobdiff_plain;f=node_modules%2Fnode-pty%2Fdeps%2Fwinpty%2Fsrc%2Fagent%2FConsoleFont.cc;fp=node_modules%2Fnode-pty%2Fdeps%2Fwinpty%2Fsrc%2Fagent%2FConsoleFont.cc;h=0000000000000000000000000000000000000000;hp=aa1f7876d3807ddb631b449419a7b8bc7b708399;hb=5e96dd57ddd883604e87f62bdddcb111c63a6e1a;hpb=acb5f682a2b75b972710cabd81658f63071324b0 diff --git a/node_modules/node-pty/deps/winpty/src/agent/ConsoleFont.cc b/node_modules/node-pty/deps/winpty/src/agent/ConsoleFont.cc deleted file mode 100644 index aa1f787..0000000 --- a/node_modules/node-pty/deps/winpty/src/agent/ConsoleFont.cc +++ /dev/null @@ -1,698 +0,0 @@ -// Copyright (c) 2015 Ryan Prichard -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "ConsoleFont.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "../shared/DebugClient.h" -#include "../shared/OsModule.h" -#include "../shared/StringUtil.h" -#include "../shared/WindowsVersion.h" -#include "../shared/WinptyAssert.h" -#include "../shared/winpty_snprintf.h" - -namespace { - -#define COUNT_OF(x) (sizeof(x) / sizeof((x)[0])) - -// See https://en.wikipedia.org/wiki/List_of_CJK_fonts -const wchar_t kLucidaConsole[] = L"Lucida Console"; -const wchar_t kMSGothic[] = { 0xff2d, 0xff33, 0x0020, 0x30b4, 0x30b7, 0x30c3, 0x30af, 0 }; // 932, Japanese -const wchar_t kNSimSun[] = { 0x65b0, 0x5b8b, 0x4f53, 0 }; // 936, Chinese Simplified -const wchar_t kGulimChe[] = { 0xad74, 0xb9bc, 0xccb4, 0 }; // 949, Korean -const wchar_t kMingLight[] = { 0x7d30, 0x660e, 0x9ad4, 0 }; // 950, Chinese Traditional - -struct FontSize { - short size; - int width; -}; - -struct Font { - const wchar_t *faceName; - unsigned int family; - short size; -}; - -// Ideographs in East Asian languages take two columns rather than one. -// In the console screen buffer, a "full-width" character will occupy two -// cells of the buffer, the first with attribute 0x100 and the second with -// attribute 0x200. -// -// Windows does not correctly identify code points as double-width in all -// configurations. It depends heavily on the code page, the font facename, -// and (somehow) even the font size. In the 437 code page (MS-DOS), for -// example, no codepoints are interpreted as double-width. When the console -// is in an East Asian code page (932, 936, 949, or 950), then sometimes -// selecting a "Western" facename like "Lucida Console" or "Consolas" doesn't -// register, or if the font *can* be chosen, then the console doesn't handle -// double-width correctly. I tested the double-width handling by writing -// several code points with WriteConsole and checking whether one or two cells -// were filled. -// -// In the Japanese code page (932), Microsoft's default font is MS Gothic. -// MS Gothic double-width handling seems to be broken with console versions -// prior to Windows 10 (including Windows 10's legacy mode), and it's -// especially broken in Windows 8 and 8.1. -// -// Test by running: misc/Utf16Echo A2 A3 2014 3044 30FC 4000 -// -// The first three codepoints are always rendered as half-width with the -// Windows Japanese fonts. (Of these, the first two must be half-width, -// but U+2014 could be either.) The last three are rendered as full-width, -// and they are East_Asian_Width=Wide. -// -// Windows 7 fails by modeling all codepoints as full-width with font -// sizes 22 and above. -// -// Windows 8 gets U+00A2, U+00A3, U+2014, U+30FC, and U+4000 wrong, but -// using a point size not listed in the console properties dialog -// (e.g. "9") is less wrong: -// -// | code point | -// font | 00A2 00A3 2014 3044 30FC 4000 | cell size -// ------------+---------------------------------+---------- -// 8 | F F F F H H | 4x8 -// 9 | F F F F F F | 5x9 -// 16 | F F F F H H | 8x16 -// raster 6x13 | H H H F F H(*) | 6x13 -// -// (*) The Raster Font renders U+4000 as a white box (i.e. an unsupported -// character). -// - -// See: -// - misc/Font-Report-June2016 directory for per-size details -// - misc/font-notes.txt -// - misc/Utf16Echo.cc, misc/FontSurvey.cc, misc/SetFont.cc, misc/GetFont.cc - -const FontSize kLucidaFontSizes[] = { - { 5, 3 }, - { 6, 4 }, - { 8, 5 }, - { 10, 6 }, - { 12, 7 }, - { 14, 8 }, - { 16, 10 }, - { 18, 11 }, - { 20, 12 }, - { 36, 22 }, - { 48, 29 }, - { 60, 36 }, - { 72, 43 }, -}; - -// Japanese. Used on Vista and Windows 7. -const FontSize k932GothicVista[] = { - { 6, 3 }, - { 8, 4 }, - { 10, 5 }, - { 12, 6 }, - { 13, 7 }, - { 15, 8 }, - { 17, 9 }, - { 19, 10 }, - { 21, 11 }, - // All larger fonts are more broken w.r.t. full-size East Asian characters. -}; - -// Japanese. Used on Windows 8, 8.1, and the legacy 10 console. -const FontSize k932GothicWin8[] = { - // All of these characters are broken w.r.t. full-size East Asian - // characters, but they're equally broken. - { 5, 3 }, - { 7, 4 }, - { 9, 5 }, - { 11, 6 }, - { 13, 7 }, - { 15, 8 }, - { 17, 9 }, - { 20, 10 }, - { 22, 11 }, - { 24, 12 }, - // include extra-large fonts for small terminals - { 36, 18 }, - { 48, 24 }, - { 60, 30 }, - { 72, 36 }, -}; - -// Japanese. Used on the new Windows 10 console. -const FontSize k932GothicWin10[] = { - { 6, 3 }, - { 8, 4 }, - { 10, 5 }, - { 12, 6 }, - { 14, 7 }, - { 16, 8 }, - { 18, 9 }, - { 20, 10 }, - { 22, 11 }, - { 24, 12 }, - // include extra-large fonts for small terminals - { 36, 18 }, - { 48, 24 }, - { 60, 30 }, - { 72, 36 }, -}; - -// Chinese Simplified. -const FontSize k936SimSun[] = { - { 6, 3 }, - { 8, 4 }, - { 10, 5 }, - { 12, 6 }, - { 14, 7 }, - { 16, 8 }, - { 18, 9 }, - { 20, 10 }, - { 22, 11 }, - { 24, 12 }, - // include extra-large fonts for small terminals - { 36, 18 }, - { 48, 24 }, - { 60, 30 }, - { 72, 36 }, -}; - -// Korean. -const FontSize k949GulimChe[] = { - { 6, 3 }, - { 8, 4 }, - { 10, 5 }, - { 12, 6 }, - { 14, 7 }, - { 16, 8 }, - { 18, 9 }, - { 20, 10 }, - { 22, 11 }, - { 24, 12 }, - // include extra-large fonts for small terminals - { 36, 18 }, - { 48, 24 }, - { 60, 30 }, - { 72, 36 }, -}; - -// Chinese Traditional. -const FontSize k950MingLight[] = { - { 6, 3 }, - { 8, 4 }, - { 10, 5 }, - { 12, 6 }, - { 14, 7 }, - { 16, 8 }, - { 18, 9 }, - { 20, 10 }, - { 22, 11 }, - { 24, 12 }, - // include extra-large fonts for small terminals - { 36, 18 }, - { 48, 24 }, - { 60, 30 }, - { 72, 36 }, -}; - -// Some of these types and functions are missing from the MinGW headers. -// Others are undocumented. - -struct AGENT_CONSOLE_FONT_INFO { - DWORD nFont; - COORD dwFontSize; -}; - -struct AGENT_CONSOLE_FONT_INFOEX { - ULONG cbSize; - DWORD nFont; - COORD dwFontSize; - UINT FontFamily; - UINT FontWeight; - WCHAR FaceName[LF_FACESIZE]; -}; - -// undocumented XP API -typedef BOOL WINAPI SetConsoleFont_t( - HANDLE hOutput, - DWORD dwFontIndex); - -// undocumented XP API -typedef DWORD WINAPI GetNumberOfConsoleFonts_t(); - -// XP and up -typedef BOOL WINAPI GetCurrentConsoleFont_t( - HANDLE hOutput, - BOOL bMaximumWindow, - AGENT_CONSOLE_FONT_INFO *lpConsoleCurrentFont); - -// XP and up -typedef COORD WINAPI GetConsoleFontSize_t( - HANDLE hConsoleOutput, - DWORD nFont); - -// Vista and up -typedef BOOL WINAPI GetCurrentConsoleFontEx_t( - HANDLE hConsoleOutput, - BOOL bMaximumWindow, - AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx); - -// Vista and up -typedef BOOL WINAPI SetCurrentConsoleFontEx_t( - HANDLE hConsoleOutput, - BOOL bMaximumWindow, - AGENT_CONSOLE_FONT_INFOEX *lpConsoleCurrentFontEx); - -#define GET_MODULE_PROC(mod, funcName) \ - m_##funcName = reinterpret_cast((mod).proc(#funcName)); \ - -#define DEFINE_ACCESSOR(funcName) \ - funcName##_t &funcName() const { \ - ASSERT(valid()); \ - return *m_##funcName; \ - } - -class XPFontAPI { -public: - XPFontAPI() : m_kernel32(L"kernel32.dll") { - GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFont); - GET_MODULE_PROC(m_kernel32, GetConsoleFontSize); - } - - bool valid() const { - return m_GetCurrentConsoleFont != NULL && - m_GetConsoleFontSize != NULL; - } - - DEFINE_ACCESSOR(GetCurrentConsoleFont) - DEFINE_ACCESSOR(GetConsoleFontSize) - -private: - OsModule m_kernel32; - GetCurrentConsoleFont_t *m_GetCurrentConsoleFont; - GetConsoleFontSize_t *m_GetConsoleFontSize; -}; - -class UndocumentedXPFontAPI : public XPFontAPI { -public: - UndocumentedXPFontAPI() : m_kernel32(L"kernel32.dll") { - GET_MODULE_PROC(m_kernel32, SetConsoleFont); - GET_MODULE_PROC(m_kernel32, GetNumberOfConsoleFonts); - } - - bool valid() const { - return this->XPFontAPI::valid() && - m_SetConsoleFont != NULL && - m_GetNumberOfConsoleFonts != NULL; - } - - DEFINE_ACCESSOR(SetConsoleFont) - DEFINE_ACCESSOR(GetNumberOfConsoleFonts) - -private: - OsModule m_kernel32; - SetConsoleFont_t *m_SetConsoleFont; - GetNumberOfConsoleFonts_t *m_GetNumberOfConsoleFonts; -}; - -class VistaFontAPI : public XPFontAPI { -public: - VistaFontAPI() : m_kernel32(L"kernel32.dll") { - GET_MODULE_PROC(m_kernel32, GetCurrentConsoleFontEx); - GET_MODULE_PROC(m_kernel32, SetCurrentConsoleFontEx); - } - - bool valid() const { - return this->XPFontAPI::valid() && - m_GetCurrentConsoleFontEx != NULL && - m_SetCurrentConsoleFontEx != NULL; - } - - DEFINE_ACCESSOR(GetCurrentConsoleFontEx) - DEFINE_ACCESSOR(SetCurrentConsoleFontEx) - -private: - OsModule m_kernel32; - GetCurrentConsoleFontEx_t *m_GetCurrentConsoleFontEx; - SetCurrentConsoleFontEx_t *m_SetCurrentConsoleFontEx; -}; - -static std::vector > readFontTable( - XPFontAPI &api, HANDLE conout, DWORD maxCount) { - std::vector > ret; - for (DWORD i = 0; i < maxCount; ++i) { - COORD size = api.GetConsoleFontSize()(conout, i); - if (size.X == 0 && size.Y == 0) { - break; - } - ret.push_back(std::make_pair(i, size)); - } - return ret; -} - -static void dumpFontTable(HANDLE conout, const char *prefix) { - const int kMaxCount = 1000; - if (!isTracingEnabled()) { - return; - } - XPFontAPI api; - if (!api.valid()) { - trace("dumpFontTable: cannot dump font table -- missing APIs"); - return; - } - std::vector > table = - readFontTable(api, conout, kMaxCount); - std::string line; - char tmp[128]; - size_t first = 0; - while (first < table.size()) { - size_t last = std::min(table.size() - 1, first + 10 - 1); - winpty_snprintf(tmp, "%sfonts %02u-%02u:", - prefix, static_cast(first), static_cast(last)); - line = tmp; - for (size_t i = first; i <= last; ++i) { - if (i % 10 == 5) { - line += " - "; - } - winpty_snprintf(tmp, " %2dx%-2d", - table[i].second.X, table[i].second.Y); - line += tmp; - } - trace("%s", line.c_str()); - first = last + 1; - } - if (table.size() == kMaxCount) { - trace("%sfonts: ... stopped reading at %d fonts ...", - prefix, kMaxCount); - } -} - -static std::string stringToCodePoints(const std::wstring &str) { - std::string ret = "("; - for (size_t i = 0; i < str.size(); ++i) { - char tmp[32]; - winpty_snprintf(tmp, "%X", str[i]); - if (ret.size() > 1) { - ret.push_back(' '); - } - ret += tmp; - } - ret.push_back(')'); - return ret; -} - -static void dumpFontInfoEx( - const AGENT_CONSOLE_FONT_INFOEX &infoex, - const char *prefix) { - if (!isTracingEnabled()) { - return; - } - std::wstring faceName(infoex.FaceName, - winpty_wcsnlen(infoex.FaceName, COUNT_OF(infoex.FaceName))); - trace("%snFont=%u dwFontSize=(%d,%d) " - "FontFamily=0x%x FontWeight=%u FaceName=%s %s", - prefix, - static_cast(infoex.nFont), - infoex.dwFontSize.X, infoex.dwFontSize.Y, - infoex.FontFamily, infoex.FontWeight, utf8FromWide(faceName).c_str(), - stringToCodePoints(faceName).c_str()); -} - -static void dumpVistaFont(VistaFontAPI &api, HANDLE conout, const char *prefix) { - if (!isTracingEnabled()) { - return; - } - AGENT_CONSOLE_FONT_INFOEX infoex = {0}; - infoex.cbSize = sizeof(infoex); - if (!api.GetCurrentConsoleFontEx()(conout, FALSE, &infoex)) { - trace("GetCurrentConsoleFontEx call failed"); - return; - } - dumpFontInfoEx(infoex, prefix); -} - -static void dumpXPFont(XPFontAPI &api, HANDLE conout, const char *prefix) { - if (!isTracingEnabled()) { - return; - } - AGENT_CONSOLE_FONT_INFO info = {0}; - if (!api.GetCurrentConsoleFont()(conout, FALSE, &info)) { - trace("GetCurrentConsoleFont call failed"); - return; - } - trace("%snFont=%u dwFontSize=(%d,%d)", - prefix, - static_cast(info.nFont), - info.dwFontSize.X, info.dwFontSize.Y); -} - -static bool setFontVista( - VistaFontAPI &api, - HANDLE conout, - const Font &font) { - AGENT_CONSOLE_FONT_INFOEX infoex = {}; - infoex.cbSize = sizeof(AGENT_CONSOLE_FONT_INFOEX); - infoex.dwFontSize.Y = font.size; - infoex.FontFamily = font.family; - infoex.FontWeight = 400; - winpty_wcsncpy_nul(infoex.FaceName, font.faceName); - dumpFontInfoEx(infoex, "setFontVista: setting font to: "); - if (!api.SetCurrentConsoleFontEx()(conout, FALSE, &infoex)) { - trace("setFontVista: SetCurrentConsoleFontEx call failed"); - return false; - } - memset(&infoex, 0, sizeof(infoex)); - infoex.cbSize = sizeof(infoex); - if (!api.GetCurrentConsoleFontEx()(conout, FALSE, &infoex)) { - trace("setFontVista: GetCurrentConsoleFontEx call failed"); - return false; - } - if (wcsncmp(infoex.FaceName, font.faceName, - COUNT_OF(infoex.FaceName)) != 0) { - trace("setFontVista: face name was not set"); - dumpFontInfoEx(infoex, "setFontVista: post-call font: "); - return false; - } - // We'd like to verify that the new font size is correct, but we can't - // predict what it will be, even though we just set it to `pxSize` through - // an apprently symmetric interface. For the Chinese and Korean fonts, the - // new `infoex.dwFontSize.Y` value can be slightly larger than the height - // we specified. - return true; -} - -static Font selectSmallFont(int codePage, int columns, bool isNewW10) { - // Iterate over a set of font sizes according to the code page, and select - // one. - - const wchar_t *faceName = nullptr; - unsigned int fontFamily = 0; - const FontSize *table = nullptr; - size_t tableSize = 0; - - switch (codePage) { - case 932: // Japanese - faceName = kMSGothic; - fontFamily = 0x36; - if (isNewW10) { - table = k932GothicWin10; - tableSize = COUNT_OF(k932GothicWin10); - } else if (isAtLeastWindows8()) { - table = k932GothicWin8; - tableSize = COUNT_OF(k932GothicWin8); - } else { - table = k932GothicVista; - tableSize = COUNT_OF(k932GothicVista); - } - break; - case 936: // Chinese Simplified - faceName = kNSimSun; - fontFamily = 0x36; - table = k936SimSun; - tableSize = COUNT_OF(k936SimSun); - break; - case 949: // Korean - faceName = kGulimChe; - fontFamily = 0x36; - table = k949GulimChe; - tableSize = COUNT_OF(k949GulimChe); - break; - case 950: // Chinese Traditional - faceName = kMingLight; - fontFamily = 0x36; - table = k950MingLight; - tableSize = COUNT_OF(k950MingLight); - break; - default: - faceName = kLucidaConsole; - fontFamily = 0x36; - table = kLucidaFontSizes; - tableSize = COUNT_OF(kLucidaFontSizes); - break; - } - - size_t bestIndex = static_cast(-1); - std::tuple bestScore = std::make_tuple(-1, -1); - - // We might want to pick the smallest possible font, because we don't know - // how large the monitor is (and the monitor size can change). We might - // want to pick a larger font to accommodate console programs that resize - // the console on their own, like DOS edit.com, which tends to resize the - // console to 80 columns. - - for (size_t i = 0; i < tableSize; ++i) { - const int width = table[i].width * columns; - - // In general, we'd like to pick a font size where cutting the number - // of columns in half doesn't immediately violate the minimum width - // constraint. (e.g. To run DOS edit.com, a user might resize their - // terminal to ~100 columns so it's big enough to show the 80 columns - // post-resize.) To achieve this, give priority to fonts that allow - // this halving. We don't want to encourage *very* large fonts, - // though, so disable the effect as the number of columns scales from - // 80 to 40. - const int halfColumns = std::min(columns, std::max(40, columns / 2)); - const int halfWidth = table[i].width * halfColumns; - - std::tuple thisScore = std::make_tuple(-1, -1); - if (width >= 160 && halfWidth >= 160) { - // Both sizes are good. Prefer the smaller fonts. - thisScore = std::make_tuple(2, -width); - } else if (width >= 160) { - // Prefer the smaller fonts. - thisScore = std::make_tuple(1, -width); - } else { - // Otherwise, prefer the largest font in our table. - thisScore = std::make_tuple(0, width); - } - if (thisScore > bestScore) { - bestIndex = i; - bestScore = thisScore; - } - } - - ASSERT(bestIndex != static_cast(-1)); - return Font { faceName, fontFamily, table[bestIndex].size }; -} - -static void setSmallFontVista(VistaFontAPI &api, HANDLE conout, - int columns, bool isNewW10) { - int codePage = GetConsoleOutputCP(); - const auto font = selectSmallFont(codePage, columns, isNewW10); - if (setFontVista(api, conout, font)) { - trace("setSmallFontVista: success"); - return; - } - if (codePage == 932 || codePage == 936 || - codePage == 949 || codePage == 950) { - trace("setSmallFontVista: falling back to default codepage font instead"); - const auto fontFB = selectSmallFont(0, columns, isNewW10); - if (setFontVista(api, conout, fontFB)) { - trace("setSmallFontVista: fallback was successful"); - return; - } - } - trace("setSmallFontVista: failure"); -} - -struct FontSizeComparator { - bool operator()(const std::pair &obj1, - const std::pair &obj2) const { - int score1 = obj1.second.X + obj1.second.Y; - int score2 = obj2.second.X + obj2.second.Y; - return score1 < score2; - } -}; - -static void setSmallFontXP(UndocumentedXPFontAPI &api, HANDLE conout) { - // Read the console font table and sort it from smallest to largest. - const DWORD fontCount = api.GetNumberOfConsoleFonts()(); - trace("setSmallFontXP: number of console fonts: %u", - static_cast(fontCount)); - std::vector > table = - readFontTable(api, conout, fontCount); - std::sort(table.begin(), table.end(), FontSizeComparator()); - for (size_t i = 0; i < table.size(); ++i) { - // Skip especially narrow fonts to permit narrower terminals. - if (table[i].second.X < 4) { - continue; - } - trace("setSmallFontXP: setting font to %u", - static_cast(table[i].first)); - if (!api.SetConsoleFont()(conout, table[i].first)) { - trace("setSmallFontXP: SetConsoleFont call failed"); - continue; - } - AGENT_CONSOLE_FONT_INFO info; - if (!api.GetCurrentConsoleFont()(conout, FALSE, &info)) { - trace("setSmallFontXP: GetCurrentConsoleFont call failed"); - return; - } - if (info.nFont != table[i].first) { - trace("setSmallFontXP: font was not set"); - dumpXPFont(api, conout, "setSmallFontXP: post-call font: "); - continue; - } - trace("setSmallFontXP: success"); - return; - } - trace("setSmallFontXP: failure"); -} - -} // anonymous namespace - -// A Windows console window can never be larger than the desktop window. To -// maximize the possible size of the console in rows*cols, try to configure -// the console with a small font. Unfortunately, we cannot make the font *too* -// small, because there is also a minimum window size in pixels. -void setSmallFont(HANDLE conout, int columns, bool isNewW10) { - trace("setSmallFont: attempting to set a small font for %d columns " - "(CP=%u OutputCP=%u)", - columns, - static_cast(GetConsoleCP()), - static_cast(GetConsoleOutputCP())); - VistaFontAPI vista; - if (vista.valid()) { - dumpVistaFont(vista, conout, "previous font: "); - dumpFontTable(conout, "previous font table: "); - setSmallFontVista(vista, conout, columns, isNewW10); - dumpVistaFont(vista, conout, "new font: "); - dumpFontTable(conout, "new font table: "); - return; - } - UndocumentedXPFontAPI xp; - if (xp.valid()) { - dumpXPFont(xp, conout, "previous font: "); - dumpFontTable(conout, "previous font table: "); - setSmallFontXP(xp, conout); - dumpXPFont(xp, conout, "new font: "); - dumpFontTable(conout, "new font table: "); - return; - } - trace("setSmallFont: neither Vista nor XP APIs detected -- giving up"); - dumpFontTable(conout, "font table: "); -}