Compare commits

...

2 commits

Author SHA1 Message Date
Leonard Hecker ebbc14c113 wip 2021-10-11 17:10:31 +02:00
Leonard Hecker 70eeea68e4 wip 2021-10-11 02:15:21 +02:00
46 changed files with 4915 additions and 747 deletions

View file

@ -117,7 +117,6 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
## dynamic_bitset
@ -148,7 +147,6 @@ 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.
```
## \{fmt\}
@ -215,10 +213,8 @@ 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.
```
## boost
**Source**: [https://github.com/boostorg/boost](https://github.com/boostorg/boost)
@ -249,7 +245,36 @@ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
```
## robin-hood-hashing
**Source**: [https://github.com/martinus/robin-hood-hashing](https://github.com/martinus/robin-hood-hashing)
### License
```
MIT License
Copyright (c) 2018-2021 Martin Ankerl
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.
```
## ConEmu

View file

@ -400,6 +400,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsTerminal.UIA.Tests",
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "api-ms-win-core-synch-l1-2-0", "src\api-ms-win-core-synch-l1-2-0\api-ms-win-core-synch-l1-2-0.vcxproj", "{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RendererAtlas", "src\renderer\atlas\atlas.vcxproj", "{8222900C-8B6C-452A-91AC-BE95DB04B95F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
AuditMode|Any CPU = AuditMode|Any CPU
@ -3339,6 +3341,46 @@ Global
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x64.Build.0 = Release|x64
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x86.ActiveCfg = Release|Win32
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x86.Build.0 = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|ARM.ActiveCfg = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|x64.ActiveCfg = AuditMode|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|x64.Build.0 = AuditMode|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|x86.ActiveCfg = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.AuditMode|x86.Build.0 = AuditMode|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|Any CPU.ActiveCfg = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM.ActiveCfg = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM64.ActiveCfg = Debug|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|ARM64.Build.0 = Debug|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x64.ActiveCfg = Debug|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x64.Build.0 = Debug|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x86.ActiveCfg = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Debug|x86.Build.0 = Debug|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|ARM.ActiveCfg = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|ARM64.Build.0 = Fuzzing|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|DotNet_x64Test.ActiveCfg = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|DotNet_x86Test.ActiveCfg = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|x64.Build.0 = Fuzzing|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Fuzzing|x86.Build.0 = Fuzzing|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|Any CPU.ActiveCfg = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM.ActiveCfg = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM64.ActiveCfg = Release|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|ARM64.Build.0 = Release|ARM64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x64.ActiveCfg = Release|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x64.Build.0 = Release|x64
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x86.ActiveCfg = Release|Win32
{8222900C-8B6C-452A-91AC-BE95DB04B95F}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -3438,6 +3480,9 @@ Global
{C323DAEE-B307-4C7B-ACE5-7293CBEFCB5B} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
{F19DACD5-0C6E-40DC-B6E4-767A3200542C} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5} = {89CDCC5C-9F53-4054-97A4-639D99F169CD}
{8222900C-8B6C-452A-91AC-BE95DB04B95F} = {05500DEF-2294-41E3-AF9A-24E580B82836}
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB}
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD} = {E8F24881-5E37-4362-B191-A3BA0ED7F4EB}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3140B1B7-C8EE-43D1-A772-D82A7061A271}

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018-2021 Martin Ankerl
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.

View file

@ -0,0 +1,9 @@
### Notes for Future Maintainers
The provenance information (where it came from and which commit) is stored in the file `cgmanifest.json` in the same directory as this readme.
Please update the provenance information in that file when ingesting an updated version of the dependent library.
That provenance file is automatically read and inventoried by Microsoft systems to ensure compliance with appropiate governance standards.
## Updates
Get updates from here: https://github.com/martinus/robin-hood-hashing

View file

@ -0,0 +1,14 @@
{
"Registrations": [
{
"component": {
"type": "git",
"git": {
"repositoryUrl": "https://github.com/martinus/robin-hood-hashing",
"commitHash": "24b3f50f9532153edc23b29ae277dcccfd75a462"
}
}
}
],
"Version": 1
}

File diff suppressed because it is too large Load diff

View file

@ -12,17 +12,27 @@
void CharRowCellReference::operator=(const std::wstring_view chars)
{
THROW_HR_IF(E_INVALIDARG, chars.empty());
auto& dbcsAttr = _cellData().DbcsAttr();
if (chars.size() == 1)
{
if (dbcsAttr.IsGlyphStored())
{
auto& storage = _parent.GetUnicodeStorage();
const auto key = _parent.GetStorageKey(_index);
storage.Erase(key);
}
_cellData().Char() = chars.front();
_cellData().DbcsAttr().SetGlyphStored(false);
dbcsAttr.SetGlyphStored(false);
}
else
{
auto& storage = _parent.GetUnicodeStorage();
const auto key = _parent.GetStorageKey(_index);
storage.StoreGlyph(key, { chars.cbegin(), chars.cend() });
_cellData().DbcsAttr().SetGlyphStored(true);
storage.StoreGlyph(key, chars);
dbcsAttr.SetGlyphStored(true);
}
}
@ -107,30 +117,3 @@ CharRowCellReference::const_iterator CharRowCellReference::end() const
}
}
#pragma warning(pop)
bool operator==(const CharRowCellReference& ref, const std::vector<wchar_t>& glyph)
{
const DbcsAttribute& dbcsAttr = ref._cellData().DbcsAttr();
if (glyph.size() == 1 && dbcsAttr.IsGlyphStored())
{
return false;
}
else if (glyph.size() > 1 && !dbcsAttr.IsGlyphStored())
{
return false;
}
else if (glyph.size() == 1 && !dbcsAttr.IsGlyphStored())
{
return ref._cellData().Char() == glyph.front();
}
else
{
const auto& chars = ref._parent.GetUnicodeStorage().GetText(ref._parent.GetStorageKey(ref._index));
return chars == glyph;
}
}
bool operator==(const std::vector<wchar_t>& glyph, const CharRowCellReference& ref)
{
return ref == glyph;
}

View file

@ -44,9 +44,6 @@ public:
const_iterator begin() const;
const_iterator end() const;
friend bool operator==(const CharRowCellReference& ref, const std::vector<wchar_t>& glyph);
friend bool operator==(const std::vector<wchar_t>& glyph, const CharRowCellReference& ref);
private:
// what char row the object belongs to
CharRow& _parent;
@ -58,6 +55,3 @@ private:
std::wstring_view _glyphData() const;
};
bool operator==(const CharRowCellReference& ref, const std::vector<wchar_t>& glyph);
bool operator==(const std::vector<wchar_t>& glyph, const CharRowCellReference& ref);

View file

@ -4,11 +4,6 @@
#include "precomp.h"
#include "UnicodeStorage.hpp"
UnicodeStorage::UnicodeStorage() noexcept :
_map{}
{
}
// Routine Description:
// - fetches the text associated with key
// Arguments:
@ -16,26 +11,30 @@ UnicodeStorage::UnicodeStorage() noexcept :
// Return Value:
// - the glyph data associated with key
// Note: will throw exception if key is not stored yet
const UnicodeStorage::mapped_type& UnicodeStorage::GetText(const key_type key) const
std::wstring_view UnicodeStorage::GetText(const COORD key) const
{
return _map.at(key);
return { _map.at(key).data(), 2 };
}
// Routine Description:
// - stores glyph data associated with key.
// - stores a surrogate pair associated with key.
// Arguments:
// - key - the key into the storage
// - glyph - the glyph data to store
void UnicodeStorage::StoreGlyph(const key_type key, const mapped_type& glyph)
void UnicodeStorage::StoreGlyph(const COORD key, const std::wstring_view& glyph)
{
_map.insert_or_assign(key, glyph);
// If you crash here it means that Windows Terminal has started supporting more of unicode.
// At the time of writing it only supports surrogate pairs at most.
// Replace the _map value type with std::wstring or something (at the cost of reduced performance).
assert(glyph.size() == 2);
memcpy(_map[key].data(), glyph.data(), 2 * sizeof(wchar_t));
}
// Routine Description:
// - erases key and its associated data from the storage
// Arguments:
// - key - the key to remove
void UnicodeStorage::Erase(const key_type key) noexcept
void UnicodeStorage::Erase(const COORD key) noexcept
{
_map.erase(key);
}
@ -50,7 +49,8 @@ void UnicodeStorage::Erase(const key_type key) noexcept
void UnicodeStorage::Remap(const std::unordered_map<SHORT, SHORT>& rowMap, const std::optional<SHORT> width)
{
// Make a temporary map to hold all the new row positioning
std::unordered_map<key_type, mapped_type> newMap;
decltype(_map) newMap;
newMap.reserve(_map.size());
// Walk through every stored item.
for (const auto& pair : _map)
@ -94,5 +94,5 @@ void UnicodeStorage::Remap(const std::unordered_map<SHORT, SHORT>& rowMap, const
}
// Swap into the stored map, free the temporary when we exit.
_map.swap(newMap);
_map = std::move(newMap);
}

View file

@ -14,29 +14,16 @@ Author(s):
#pragma once
#include <vector>
#include <unordered_map>
#include <climits>
// std::unordered_map needs help to know how to hash a COORD
namespace std
{
template<>
struct hash<COORD>
{
// Routine Description:
// - hashes a coord. coord will be hashed by storing the x and y values consecutively in the lower
// bits of a size_t.
// Arguments:
// - coord - the coord to hash
// Return Value:
// - the hashed coord
constexpr size_t operator()(const COORD& coord) const noexcept
// We take COORD by value not just because it neatly fits into a register...
// Reading unaligned pointers doesn't work
size_t operator()(COORD coord) const noexcept
{
size_t retVal = coord.Y;
const size_t xCoord = coord.X;
retVal |= xCoord << (sizeof(coord.Y) * CHAR_BIT);
return retVal;
return std::hash<uint32_t>{}(til::bit_cast<uint32_t>(coord));
}
};
}
@ -44,21 +31,13 @@ namespace std
class UnicodeStorage final
{
public:
using key_type = typename COORD;
using mapped_type = typename std::vector<wchar_t>;
UnicodeStorage() noexcept;
const mapped_type& GetText(const key_type key) const;
void StoreGlyph(const key_type key, const mapped_type& glyph);
void Erase(const key_type key) noexcept;
std::wstring_view GetText(const COORD key) const;
void StoreGlyph(const COORD key, const std::wstring_view& glyph);
void Erase(const COORD key) noexcept;
void Remap(const std::unordered_map<SHORT, SHORT>& rowMap, const std::optional<SHORT> width);
private:
std::unordered_map<key_type, mapped_type> _map;
std::unordered_map<COORD, std::array<wchar_t, 2>> _map;
#ifdef UNIT_TESTING
friend class UnicodeStorageTests;

View file

@ -19,8 +19,8 @@ class UnicodeStorageTests
{
UnicodeStorage storage;
const COORD coord{ 1, 3 };
const std::vector<wchar_t> newMoon{ 0xD83C, 0xDF11 };
const std::vector<wchar_t> fullMoon{ 0xD83C, 0xDF15 };
const std::wstring newMoon{ L"\uD83C\uDF11" };
const std::wstring fullMoon{ L"\uD83C\uDF15" };
// store initial glyph
storage.StoreGlyph(coord, newMoon);
@ -28,7 +28,7 @@ class UnicodeStorageTests
// verify it was stored
auto findIt = storage._map.find(coord);
VERIFY_ARE_NOT_EQUAL(findIt, storage._map.end());
const std::vector<wchar_t>& newMoonGlyph = findIt->second;
const auto& newMoonGlyph = findIt->second;
VERIFY_ARE_EQUAL(newMoonGlyph.size(), newMoon.size());
for (size_t i = 0; i < newMoon.size(); ++i)
{
@ -41,7 +41,7 @@ class UnicodeStorageTests
// verify the glyph was overwritten
findIt = storage._map.find(coord);
VERIFY_ARE_NOT_EQUAL(findIt, storage._map.end());
const std::vector<wchar_t>& fullMoonGlyph = findIt->second;
const auto& fullMoonGlyph = findIt->second;
VERIFY_ARE_EQUAL(fullMoonGlyph.size(), fullMoon.size());
for (size_t i = 0; i < fullMoon.size(); ++i)
{

View file

@ -112,7 +112,7 @@
<SDLCheck>true</SDLCheck>
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)\src\inc;$(SolutionDir)\dep;$(SolutionDir)\dep\Console;$(SolutionDir)\dep\gsl\include;$(SolutionDir)\dep\wil\include;$(SolutionDir)\dep\Win32K;$(SolutionDir)\oss\boost\boost_1_73_0;$(SolutionDir)\oss\chromium;$(SolutionDir)\oss\dynamic_bitset;$(SolutionDir)\oss\fmt\include;$(SolutionDir)\oss\interval_tree;$(SolutionDir)\oss\libpopcnt;$(SolutionDir)\oss\pcg\include;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>$(SolutionDir)\src\inc;$(SolutionDir)\dep;$(SolutionDir)\dep\Console;$(SolutionDir)\dep\gsl\include;$(SolutionDir)\dep\wil\include;$(SolutionDir)\dep\Win32K;$(SolutionDir)\oss\boost\boost_1_73_0;$(SolutionDir)\oss\chromium;$(SolutionDir)\oss\dynamic_bitset;$(SolutionDir)\oss\fmt\include;$(SolutionDir)\oss\interval_tree;$(SolutionDir)\oss\libpopcnt;$(SolutionDir)\oss\pcg\include;$(SolutionDir)\oss\robin-hood-hashing;%(AdditionalIncludeDirectories);</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<RuntimeTypeInfo>false</RuntimeTypeInfo>

View file

@ -46,6 +46,9 @@
<ProjectReference Include="..\..\renderer\dx\lib\dx.vcxproj">
<Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project>
</ProjectReference>
<ProjectReference Include="..\..\renderer\atlas\atlas.vcxproj">
<Project>{8222900C-8B6C-452A-91AC-BE95DB04B95F}</Project>
</ProjectReference>
<ProjectReference Include="..\..\renderer\gdi\lib\gdi.vcxproj">
<Project>{1c959542-bac2-4e55-9a6d-13251914cbb9}</Project>
</ProjectReference>

View file

@ -274,8 +274,7 @@ void ApiRoutines::GetNumberOfConsoleMouseButtonsImpl(ULONG& buttons) noexcept
const FontInfo& fontInfo = activeScreenInfo.GetCurrentFont();
consoleFontInfoEx.FontFamily = fontInfo.GetFamily();
consoleFontInfoEx.FontWeight = fontInfo.GetWeight();
RETURN_IF_FAILED(fontInfo.FillLegacyNameBuffer(gsl::make_span(consoleFontInfoEx.FaceName)));
fontInfo.FillLegacyNameBuffer(consoleFontInfoEx.FaceName);
return S_OK;
}

View file

@ -22,10 +22,7 @@ Revision History:
#include "ConsoleArguments.hpp"
#include "ApiRoutines.h"
#include "../renderer/inc/IRenderData.hpp"
#include "../renderer/inc/IRenderEngine.hpp"
#include "../renderer/inc/IRenderer.hpp"
#include "../renderer/inc/IFontDefaultList.hpp"
#include "../renderer/base/Renderer.hpp"
#include "../server/DeviceComm.h"
#include "../server/ConDrvDeviceComm.h"
@ -62,7 +59,7 @@ public:
std::vector<wchar_t> WordDelimiters;
Microsoft::Console::Render::IRenderer* pRender;
Microsoft::Console::Render::Renderer* pRender;
Microsoft::Console::Render::IFontDefaultList* pFontDefaultList;

View file

@ -58,7 +58,7 @@ Settings::Settings() :
_fInterceptCopyPaste(0),
_DefaultForeground(INVALID_COLOR),
_DefaultBackground(INVALID_COLOR),
_fUseDx(false),
_fUseDx(0),
_fCopyColor(false)
{
_dwScreenBufferSize.X = 80;
@ -816,7 +816,7 @@ void Settings::SetTerminalScrolling(const bool terminalScrollingEnabled) noexcep
// - This is based on user preference and velocity hold back state.
// Return Value:
// - True means use DirectX renderer. False means use GDI renderer.
bool Settings::GetUseDx() const noexcept
DWORD Settings::GetUseDx() const noexcept
{
return _fUseDx;
}

View file

@ -186,7 +186,7 @@ public:
bool IsTerminalScrolling() const noexcept;
void SetTerminalScrolling(const bool terminalScrollingEnabled) noexcept;
bool GetUseDx() const noexcept;
DWORD GetUseDx() const noexcept;
bool GetCopyColor() const noexcept;
private:
@ -230,7 +230,7 @@ private:
bool _fAutoReturnOnNewline;
bool _fRenderGridWorldwide;
bool _fScreenReversed;
bool _fUseDx;
DWORD _fUseDx;
bool _fCopyColor;
std::array<COLORREF, XTERM_COLOR_TABLE_SIZE> _colorTable;

View file

@ -771,8 +771,9 @@ PWSTR TranslateConsoleTitle(_In_ PCWSTR pwszConsoleTitle, const BOOL fUnexpand,
// Set up the renderer to be used to calculate the width of a glyph,
// should we be unable to figure out its width another way.
auto pfn = std::bind(&Renderer::IsGlyphWideByFont, static_cast<Renderer*>(g.pRender), std::placeholders::_1);
SetGlyphWidthFallback(pfn);
SetGlyphWidthFallback([renderer = g.pRender](const std::wstring_view& glyph) -> bool {
return renderer->IsGlyphWideByFont(glyph);
});
}
catch (...)
{

View file

@ -62,7 +62,7 @@ class CodepointWidthDetectorTests
}
}
static bool FallbackMethod(const std::wstring_view glyph)
static bool FallbackMethod(const std::wstring_view& glyph)
{
if (glyph.size() < 1)
{

View file

@ -53,6 +53,15 @@
namespace til // Terminal Implementation Library. Also: "Today I Learned"
{
template<class To, class From, std::enable_if_t<std::conjunction_v<std::bool_constant<sizeof(To) == sizeof(From)>, std::is_trivially_copyable<To>, std::is_trivially_copyable<From>>, int> = 0>
[[nodiscard]] constexpr To bit_cast(const From& _Val) noexcept
{
#ifdef __cpp_lib_bit_cast
#warning "Replace til::bit_cast and __builtin_bit_cast with std::bit_cast"
#endif
return __builtin_bit_cast(To, _Val);
}
template<typename T>
void manage_vector(std::vector<T>& vector, typename std::vector<T>::size_type requestedSize, float shrinkThreshold)
{

60
src/inc/til/pair.h Normal file
View file

@ -0,0 +1,60 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
namespace til // Terminal Implementation Library. Also: "Today I Learned"
{
// pair is a simple clone of std::pair, with one difference:
// copy and move constructors and operators are explicitly defaulted.
// This allows pair to be std::is_trivially_copyable, if both T and S are.
// --> pair can be used with memcpy(), unlike std::pair.
template<typename T, typename S>
struct pair
{
using first_type = T;
using second_type = S;
pair() = default;
pair(const pair&) = default;
pair& operator=(const pair&) = default;
pair(pair&&) = default;
pair& operator=(pair&&) = default;
constexpr pair(const T& first, const S& second) noexcept(std::is_nothrow_copy_constructible_v<T>&& std::is_nothrow_copy_constructible_v<S>) :
first(first), second(second)
{
}
constexpr pair(T&& first, S&& second) noexcept(std::is_nothrow_constructible_v<T>&& std::is_nothrow_constructible_v<S>) :
first(std::forward<T>(first)), second(std::forward<S>(second))
{
}
constexpr void swap(pair& other) noexcept(std::is_nothrow_swappable_v<T>&& std::is_nothrow_swappable_v<S>)
{
if (this != std::addressof(other))
{
std::swap(first, other.first);
std::swap(second, other.second);
}
}
first_type first{};
second_type second{};
};
template<typename T, typename S>
[[nodiscard]] constexpr bool operator==(const pair<T, S>& lhs, const pair<T, S>& rhs)
{
return lhs.first == rhs.first && lhs.second == rhs.second;
}
template<typename T, typename S>
[[nodiscard]] constexpr bool operator!=(const pair<T, S>& lhs, const pair<T, S>& rhs)
{
return !(lhs == rhs);
}
};

View file

@ -9,17 +9,14 @@
#include "window.hpp"
#include "windowio.hpp"
#include "windowdpiapi.hpp"
#include "windowmetrics.hpp"
#include "WindowMetrics.hpp"
#include "../../inc/conint.h"
#include "../../host/globals.h"
#include "../../host/dbcs.h"
#include "../../host/getset.h"
#include "../../host/misc.h"
#include "../../host/_output.h"
#include "../../host/output.h"
#include "../../host/renderData.hpp"
#include "../../host/scrolling.hpp"
#include "../../host/srvinit.h"
#include "../../host/stream.h"
@ -30,6 +27,7 @@
#include "../../renderer/gdi/gdirenderer.hpp"
#if TIL_FEATURE_CONHOSTDXENGINE_ENABLED
#include "../../renderer/atlas/AtlasEngine.h"
#include "../../renderer/dx/DxRenderer.hpp"
#endif
@ -209,16 +207,18 @@ void Window::_UpdateSystemMetrics() const
// Ensure we have appropriate system metrics before we start constructing the window.
_UpdateSystemMetrics();
const bool useDx = pSettings->GetUseDx();
const auto useDx = pSettings->GetUseDx();
GdiEngine* pGdiEngine = nullptr;
#if TIL_FEATURE_CONHOSTDXENGINE_ENABLED
[[maybe_unused]] DxEngine* pDxEngine = nullptr;
DxEngine* pDxEngine = nullptr;
AtlasEngine* pAtlasEngine = nullptr;
#endif
try
{
#if TIL_FEATURE_CONHOSTDXENGINE_ENABLED
if (useDx)
switch (useDx)
{
#if TIL_FEATURE_CONHOSTDXENGINE_ENABLED
case 1:
pDxEngine = new DxEngine();
// TODO: MSFT:21255595 make this less gross
// Manually set the Dx Engine to Hwnd mode. When we're trying to
@ -227,12 +227,16 @@ void Window::_UpdateSystemMetrics() const
// math in the hwnd mode, not the Composition mode.
THROW_IF_FAILED(pDxEngine->SetHwnd(nullptr));
g.pRender->AddRenderEngine(pDxEngine);
}
else
break;
case 2:
pAtlasEngine = new AtlasEngine();
g.pRender->AddRenderEngine(pAtlasEngine);
break;
#endif
{
default:
pGdiEngine = new GdiEngine();
g.pRender->AddRenderEngine(pGdiEngine);
break;
}
}
catch (...)
@ -242,10 +246,6 @@ void Window::_UpdateSystemMetrics() const
if (NT_SUCCESS(status))
{
SCREEN_INFORMATION& siAttached = GetScreenInfo();
siAttached.RefreshFontWithRenderer();
// Save reference to settings
_pSettings = pSettings;
@ -324,7 +324,7 @@ void Window::_UpdateSystemMetrics() const
_hWnd = hWnd;
#if TIL_FEATURE_CONHOSTDXENGINE_ENABLED
if (useDx)
if (pDxEngine)
{
status = NTSTATUS_FROM_WIN32(HRESULT_CODE((pDxEngine->SetHwnd(hWnd))));
@ -333,6 +333,10 @@ void Window::_UpdateSystemMetrics() const
status = NTSTATUS_FROM_WIN32(HRESULT_CODE((pDxEngine->Enable())));
}
}
else if (pAtlasEngine)
{
status = NTSTATUS_FROM_WIN32(HRESULT_CODE((pAtlasEngine->SetHwnd(hWnd))));
}
else
#endif
{
@ -362,6 +366,7 @@ void Window::_UpdateSystemMetrics() const
// Post a window size update so that the new console window will size itself correctly once it's up and
// running. This works around chicken & egg cases involving window size calculations having to do with font
// sizes, DPI, and non-primary monitors (see MSFT #2367234).
SCREEN_INFORMATION& siAttached = GetScreenInfo();
siAttached.PostUpdateWindowSize();
// Locate window theming modules and try to set the dark mode.

View file

@ -63,7 +63,7 @@ const RegistrySerialization::_RegPropertyMap RegistrySerialization::s_PropertyMa
{ _RegPropertyType::Dword, CONSOLE_REGISTRY_DEFAULTFOREGROUND, SET_FIELD_AND_SIZE(_DefaultForeground) },
{ _RegPropertyType::Dword, CONSOLE_REGISTRY_DEFAULTBACKGROUND, SET_FIELD_AND_SIZE(_DefaultBackground) },
{ _RegPropertyType::Boolean, CONSOLE_REGISTRY_TERMINALSCROLLING, SET_FIELD_AND_SIZE(_TerminalScrolling) },
{ _RegPropertyType::Boolean, CONSOLE_REGISTRY_USEDX, SET_FIELD_AND_SIZE(_fUseDx) },
{ _RegPropertyType::Dword, CONSOLE_REGISTRY_USEDX, SET_FIELD_AND_SIZE(_fUseDx) },
{ _RegPropertyType::Boolean, CONSOLE_REGISTRY_COPYCOLOR, SET_FIELD_AND_SIZE(_fCopyColor) }
};
@ -251,7 +251,8 @@ NTSTATUS RegistrySerialization::s_OpenKey(_In_opt_ HKEY const hKey, _In_ PCWSTR
[[nodiscard]]
NTSTATUS RegistrySerialization::s_DeleteValue(const HKEY hKey, _In_ PCWSTR const pwszValueName)
{
return NTSTATUS_FROM_WIN32(RegDeleteKeyValueW(hKey, nullptr, pwszValueName));
const auto result = RegDeleteKeyValueW(hKey, nullptr, pwszValueName);
return result == ERROR_FILE_NOT_FOUND ? S_OK : NTSTATUS_FROM_WIN32(result);
}
// Routine Description:

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,344 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include <d2d1.h>
#include <d3d11_1.h>
#include <dwrite.h>
#include <dxgi.h>
#include <robin_hood.h>
#include <til/pair.h>
#include "../../renderer/inc/IRenderEngine.hpp"
namespace Microsoft::Console::Render
{
class AtlasEngine final : public IRenderEngine
{
public:
explicit AtlasEngine();
AtlasEngine(const AtlasEngine&) = delete;
AtlasEngine& operator=(const AtlasEngine&) = delete;
// IRenderEngine
[[nodiscard]] HRESULT StartPaint() noexcept override;
[[nodiscard]] HRESULT EndPaint() noexcept override;
[[nodiscard]] bool RequiresContinuousRedraw() noexcept override;
void WaitUntilCanRender() noexcept override;
[[nodiscard]] HRESULT Present() noexcept override;
[[nodiscard]] HRESULT PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT ScrollFrame() noexcept override;
[[nodiscard]] HRESULT Invalidate(const SMALL_RECT* const psrRegion) noexcept override;
[[nodiscard]] HRESULT InvalidateCursor(const SMALL_RECT* const psrRegion) noexcept override;
[[nodiscard]] HRESULT InvalidateSystem(const RECT* const prcDirtyClient) noexcept override;
[[nodiscard]] HRESULT InvalidateSelection(const std::vector<SMALL_RECT>& rectangles) noexcept override;
[[nodiscard]] HRESULT InvalidateScroll(const COORD* const pcoordDelta) noexcept override;
[[nodiscard]] HRESULT InvalidateAll() noexcept override;
[[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT InvalidateTitle(const std::wstring_view proposedTitle) noexcept override;
[[nodiscard]] HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept override;
[[nodiscard]] HRESULT ResetLineTransform() noexcept override;
[[nodiscard]] HRESULT PrepareLineTransform(const LineRendition lineRendition, const size_t targetRow, const size_t viewportLeft) noexcept override;
[[nodiscard]] HRESULT PaintBackground() noexcept override;
[[nodiscard]] HRESULT PaintBufferLine(gsl::span<const Cluster> const clusters, const COORD coord, const bool fTrimLeft, const bool lineWrapped) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(const GridLineSet lines, const COLORREF color, const size_t cchLine, const COORD coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintSelection(const SMALL_RECT rect) noexcept override;
[[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) noexcept override;
[[nodiscard]] HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes, const gsl::not_null<IRenderData*> pData, const bool usingSoftFont, const bool isSettingDefaultBrushes) noexcept override;
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo) noexcept override;
[[nodiscard]] HRESULT UpdateSoftFont(const gsl::span<const uint16_t> bitPattern, const SIZE cellSize, const size_t centeringHint) noexcept override;
[[nodiscard]] HRESULT UpdateDpi(const int iDpi) noexcept override;
[[nodiscard]] HRESULT UpdateViewport(const SMALL_RECT srNewViewport) noexcept override;
[[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo, const int iDpi) noexcept override;
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override;
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override;
[[nodiscard]] HRESULT UpdateTitle(const std::wstring_view newTitle) noexcept override;
// Just for compatibility with DxEngine, but can be removed at some point.
HRESULT Enable()
{
return S_OK;
}
// DxRenderer - getter
[[nodiscard]] bool GetRetroTerminalEffect() const noexcept;
[[nodiscard]] float GetScaling() const noexcept;
[[nodiscard]] HANDLE GetSwapChainHandle();
[[nodiscard]] Types::Viewport GetViewportInCharacters(const Types::Viewport& viewInPixels) const noexcept;
[[nodiscard]] Types::Viewport GetViewportInPixels(const Types::Viewport& viewInCharacters) const noexcept;
// DxRenderer - setter
void SetAntialiasingMode(const D2D1_TEXT_ANTIALIAS_MODE antialiasingMode) noexcept;
void SetCallback(std::function<void()> pfn);
void SetDefaultTextBackgroundOpacity(const float opacity) noexcept;
void SetForceFullRepaintRendering(bool enable) noexcept;
[[nodiscard]] HRESULT SetHwnd(const HWND hwnd) noexcept;
void SetPixelShaderPath(std::wstring_view value) noexcept;
void SetRetroTerminalEffect(bool enable) noexcept;
void SetSelectionBackground(const COLORREF color, const float alpha = 0.5f) noexcept;
void SetSoftwareRendering(bool enable) noexcept;
void SetWarningCallback(std::function<void(const HRESULT)> pfn);
[[nodiscard]] HRESULT SetWindowSize(const SIZE pixels) noexcept;
void ToggleShaderEffects();
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& pfiFontInfoDesired, FontInfo& fiFontInfo, const std::unordered_map<std::wstring_view, uint32_t>& features, const std::unordered_map<std::wstring_view, float>& axes) noexcept;
void UpdateHyperlinkHoveredId(const uint16_t hoveredId) noexcept;
// Some helper classes for the implementation.
// public because I don't want to sprinkle the code with friends.
public:
template<typename T>
struct aligned_buffer
{
constexpr aligned_buffer() noexcept = default;
explicit aligned_buffer(size_t size, size_t alignment) :
_data{ THROW_IF_NULL_ALLOC(static_cast<T*>(_aligned_malloc(size * sizeof(T), alignment))) },
_size{ size }
{
}
~aligned_buffer()
{
_aligned_free(_data);
}
aligned_buffer(aligned_buffer&& other) noexcept :
_data{ std::exchange(other._data, nullptr) },
_size{ std::exchange(other._size, 0) }
{
}
aligned_buffer& operator=(aligned_buffer&& other) noexcept
{
_aligned_free(_data);
_data = std::exchange(other._data, nullptr);
_size = std::exchange(other._size, 0);
return *this;
}
T* data()
{
return _data;
}
size_t size()
{
return _size;
}
private:
T* _data = nullptr;
size_t _size = 0;
};
template<typename T>
struct vec2
{
T x{};
T y{};
bool operator==(const vec2& other) const noexcept
{
return memcmp(this, &other, sizeof(vec2)) == 0;
}
bool operator!=(const vec2& other) const noexcept
{
return memcmp(this, &other, sizeof(vec2)) != 0;
}
vec2 operator*(const vec2& other) const noexcept
{
return { static_cast<T>(x * other.x), static_cast<T>(y * other.y) };
}
vec2 operator/(const vec2& other) const noexcept
{
return { static_cast<T>(x / other.x), static_cast<T>(y / other.y) };
}
template<typename U = T>
U area() const noexcept
{
return static_cast<U>(x) * static_cast<U>(y);
}
};
template<typename T>
struct vec4
{
T x{};
T y{};
T z{};
T w{};
};
using u8 = uint8_t;
using u16 = uint16_t;
using u16x2 = vec2<u16>;
using u32 = uint32_t;
using u32x2 = vec2<u32>;
using f32 = float;
using f32x2 = vec2<f32>;
using f32x4 = vec4<f32>;
union glyph_entry
{
uint32_t value;
struct
{
uint32_t codepoint : 20;
uint32_t wide : 1;
uint32_t bold : 1;
uint32_t italic : 1;
};
constexpr bool operator==(const glyph_entry& other) const noexcept
{
return value == other.value;
}
};
struct glyph_entry_hasher
{
constexpr size_t operator()(glyph_entry entry) const noexcept
{
uint64_t x = entry.value;
x ^= x >> 33;
x *= UINT64_C(0xff51afd7ed558ccd);
x ^= x >> 33;
return static_cast<size_t>(x);
}
};
private:
// D3D constant buffers sizes must be a multiple of 16 bytes.
struct alignas(16) const_buffer
{
f32x4 viewport;
u32x2 cellSize;
u32 cellCountX;
u32 backgroundColor;
u32 selectionColor;
#pragma warning(suppress : 4324) // structure was padded due to alignment specifier
};
struct cell
{
union
{
u32 glyphIndex;
u16x2 glyphIndex16;
};
u32 flags;
u32x2 color;
};
enum class invalidation_flags : u8
{
none = 0,
device = 1 << 0,
size = 1 << 1,
font = 1 << 2,
cbuffer = 1 << 3,
title = 1 << 4,
};
friend constexpr invalidation_flags operator~(invalidation_flags v) noexcept { return static_cast<invalidation_flags>(~static_cast<u8>(v)); }
friend constexpr invalidation_flags operator|(invalidation_flags lhs, invalidation_flags rhs) noexcept { return static_cast<invalidation_flags>(static_cast<u8>(lhs) | static_cast<u8>(rhs)); }
friend constexpr invalidation_flags operator&(invalidation_flags lhs, invalidation_flags rhs) noexcept { return static_cast<invalidation_flags>(static_cast<u8>(lhs) & static_cast<u8>(rhs)); }
friend constexpr void operator|=(invalidation_flags& lhs, invalidation_flags rhs) noexcept { lhs = lhs | rhs; }
friend constexpr void operator&=(invalidation_flags& lhs, invalidation_flags rhs) noexcept { lhs = lhs & rhs; }
// resource handling
[[nodiscard]] HRESULT _handleException(const wil::ResultException& exception) noexcept;
__declspec(noinline) void _createResources();
__declspec(noinline) void _recreateSizeDependentResources();
__declspec(noinline) void _recreateFontDependentResources();
void _setShaderResources() const;
void _updateConstantBuffer() const;
// text handling
IDWriteTextFormat* _getTextFormat(bool bold, bool italic) const noexcept { return _r.textFormats[italic][bold].get(); }
wil::com_ptr<IDWriteTextFormat> _createTextFormat(const wchar_t* fontFamilyName, DWRITE_FONT_WEIGHT fontWeight, DWRITE_FONT_STYLE fontStyle, float fontSize, const wchar_t* localeName) const;
u16x2 _allocateAtlasCell() noexcept;
void _drawGlyph(const til::pair<glyph_entry, std::array<u16x2, 2>>& pair) const;
void _drawCursor() const;
void _copyScratchpadCell(uint32_t scratchpadIndex, u16x2 target, uint32_t copyFlags = 0) const;
template<typename T1, typename T2>
cell* _getCell(T1 x, T2 y) noexcept
{
return _r.cells.data() + static_cast<size_t>(_api.cellCount.x) * y + x;
}
struct static_resources
{
wil::com_ptr<ID2D1Factory> d2dFactory;
wil::com_ptr<IDWriteFactory> dwriteFactory;
bool isWindows10OrGreater = true;
} _sr;
struct resources
{
// D3D resources
wil::com_ptr<ID3D11Device> device;
wil::com_ptr<ID3D11DeviceContext1> deviceContext;
wil::com_ptr<IDXGISwapChain1> swapChain;
wil::unique_handle swapChainHandle;
wil::unique_handle frameLatencyWaitableObject;
wil::com_ptr<ID3D11RenderTargetView> renderTargetView;
wil::com_ptr<ID3D11VertexShader> vertexShader;
wil::com_ptr<ID3D11PixelShader> pixelShader;
wil::com_ptr<ID3D11Buffer> constantBuffer;
wil::com_ptr<ID3D11Buffer> cellBuffer;
wil::com_ptr<ID3D11ShaderResourceView> cellView;
// D2D resources
wil::com_ptr<ID3D11Texture2D> glyphBuffer;
wil::com_ptr<ID3D11ShaderResourceView> glyphView;
wil::com_ptr<ID3D11Texture2D> glyphScratchpad;
wil::com_ptr<ID2D1RenderTarget> d2dRenderTarget;
wil::com_ptr<ID2D1Brush> brush;
wil::com_ptr<IDWriteTextFormat> textFormats[2][2];
// Resources dependent on _api.sizeInPixel
aligned_buffer<cell> cells;
// Resources dependent on _api.cellSize
robin_hood::unordered_flat_map<glyph_entry, std::array<u16x2, 2>, glyph_entry_hasher> glyphs;
std::vector<til::pair<glyph_entry, std::array<u16x2, 2>>> glyphQueue;
u16x2 atlasSizeInPixel;
u16x2 atlasPosition;
} _r;
struct api_state
{
f32x2 cellSizeDIP; // invalidation_flags::font
u16x2 cellSize; // invalidation_flags::size
u16x2 cellCount; // caches `sizeInPixel / cellSize`
u16x2 sizeInPixel; // invalidation_flags::size
std::wstring fontName; // invalidation_flags::font|size
u16 fontSize = 0; // invalidation_flags::font|size
u16 fontWeight = DWRITE_FONT_WEIGHT_NORMAL; // invalidation_flags::font
u16 dpi = USER_DEFAULT_SCREEN_DPI; // invalidation_flags::font|size
u16 antialiasingMode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; // invalidation_flags::font
std::function<void()> swapChainChangedCallback;
HWND hwnd = nullptr;
} _api;
struct render_api_state
{
til::rectangle dirtyArea;
u32x2 currentColor{};
glyph_entry attributes{};
u32 backgroundColor = ~u32(0);
u32 selectionColor = 0x7fffffff;
} _rapi;
invalidation_flags _invalidations = invalidation_flags::device;
};
}

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{8222900C-8B6C-452A-91AC-BE95DB04B95F}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>atlas</RootNamespace>
<ProjectName>RendererAtlas</ProjectName>
<TargetName>ConRenderAtlas</TargetName>
<ConfigurationType>StaticLibrary</ConfigurationType>
</PropertyGroup>
<Import Project="$(SolutionDir)src\common.build.pre.props" />
<ItemGroup>
<ClCompile Include="pch.cpp">
<PrecompiledHeader>Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="AtlasEngine.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
<ClInclude Include="AtlasEngine.h" />
</ItemGroup>
<ItemGroup>
<FxCompile Include="shader_ps.hlsl">
<ShaderType>Pixel</ShaderType>
<ShaderModel>4.1</ShaderModel>
<VariableName>shader_ps</VariableName>
<ObjectFileOutput />
<HeaderFileOutput>$(OutDir)$(ProjectName)\%(Filename).h</HeaderFileOutput>
<TreatWarningAsError>true</TreatWarningAsError>
<AdditionalOptions Condition="'$(Configuration)'=='Release'">/Qstrip_debug /Qstrip_reflect %(AdditionalOptions)</AdditionalOptions>
</FxCompile>
<FxCompile Include="shader_vs.hlsl">
<ShaderType>Vertex</ShaderType>
<ShaderModel>4.1</ShaderModel>
<VariableName>shader_vs</VariableName>
<ObjectFileOutput />
<HeaderFileOutput>$(OutDir)$(ProjectName)\%(Filename).h</HeaderFileOutput>
<TreatWarningAsError>true</TreatWarningAsError>
<AdditionalOptions Condition="'$(Configuration)'=='Release'">/Qstrip_debug /Qstrip_reflect %(AdditionalOptions)</AdditionalOptions>
</FxCompile>
</ItemGroup>
<Import Project="$(SolutionDir)src\common.build.post.props" />
<ItemDefinitionGroup>
<ClCompile>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<AdditionalIncludeDirectories>$(OutDir)$(ProjectName)\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
</Project>

View file

@ -0,0 +1,4 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"

50
src/renderer/atlas/pch.h Normal file
View file

@ -0,0 +1,50 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <array>
#include <iomanip>
#include <optional>
#include <sstream>
#include <string_view>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <d2d1.h>
#include <d3d11_1.h>
#include <dwrite.h>
#include <dxgi1_3.h>
#include <dxgidebug.h>
#include <VersionHelpers.h>
#include <gsl/pointers>
#include <gsl/span>
#include <gsl/gsl_util>
#include <wil/com.h>
#include <wil/result_macros.h>
#include <wil/stl.h>
#include <wil/win32_helpers.h>
#include <robin_hood.h>
// Dynamic Bitset (optional dependency on LibPopCnt for perf at bit counting)
// Variable-size compressed-storage header-only bit flag storage library.
#pragma warning(push)
#pragma warning(disable : 4702) // unreachable code
#include <dynamic_bitset.hpp>
#pragma warning(pop)
// Chromium Numerics (safe math)
#pragma warning(push)
#pragma warning(disable : 4100) // '...': unreferenced formal parameter
#pragma warning(disable : 26812) // The enum type '...' is unscoped. Prefer 'enum class' over 'enum' (Enum.3).
#include <base/numerics/safe_math.h>
#pragma warning(pop)
#include "til.h"
#include <til/pair.h>

View file

@ -0,0 +1,75 @@
// According to Nvidia's "Understanding Structured Buffer Performance" guide
// one should aim for structures with sizes divisible by 128 bits (16 bytes).
// This prevents elements from spanning cache lines.
struct Cell
{
uint glyphPos;
uint flags;
uint2 color;
};
cbuffer ConstantBuffer : register(b0)
{
float4 viewport;
uint2 cellSize;
uint cellCountX;
uint backgroundColor;
uint selectionColor;
};
StructuredBuffer<Cell> cells : register(t0);
Texture2D<float4> glyphs : register(t1);
float4 decodeRGB(uint i)
{
uint r = i & 0xff;
uint g = (i >> 8) & 0xff;
uint b = (i >> 16) & 0xff;
uint a = i >> 24;
return float4(r, g, b, a) / 255.0;
}
uint2 decodeU16x2(uint i)
{
return uint2(i & 0xffff, i >> 16);
}
float insideRect(float2 pos, float4 boundaries)
{
float2 v = step(boundaries.xy, pos) - step(boundaries.zw, pos);
return v.x * v.y;
}
float4 main(float4 pos: SV_Position): SV_Target
{
if (!insideRect(pos.xy, viewport))
{
return decodeRGB(backgroundColor);
}
uint2 cellIndex = pos.xy / cellSize;
uint2 cellPos = pos.xy % cellSize;
Cell cell = cells[cellIndex.y * cellCountX + cellIndex.x];
uint2 glyphPos = decodeU16x2(cell.glyphPos);
uint2 pixelPos = glyphPos + cellPos;
float4 alpha = glyphs[pixelPos];
float3 color = lerp(
decodeRGB(cell.color.y).rgb,
decodeRGB(cell.color.x).rgb,
alpha.rgb
);
if (cell.flags & 1)
{
color = abs(glyphs[cellPos].rgb - color);
}
if (cell.flags & 2)
{
float4 sc = decodeRGB(selectionColor);
color = lerp(color, sc.rgb, sc.a);
}
return float4(color, 1);
}

View file

@ -0,0 +1,12 @@
float4 main(uint id : SV_VERTEXID) : SV_POSITION
{
// The algorithm below is a fast way to generate a full screen triangle,
// published by Bill Bilodeau "Vertex Shader Tricks" at GDC14.
// It covers the entire viewport and is faster for the GPU than a quad/rectangle.
return float4(
float(id / 2) * 4.0 - 1.0,
float(id % 2) * 4.0 - 1.0,
0.0,
1.0
);
}

View file

@ -61,7 +61,7 @@ unsigned int FontInfoBase::GetWeight() const
return _weight;
}
const std::wstring_view FontInfoBase::GetFaceName() const noexcept
const std::wstring& FontInfoBase::GetFaceName() const noexcept
{
return _faceName;
}

View file

@ -74,5 +74,6 @@ HRESULT RenderEngineBase::PrepareLineTransform(const LineRendition /*lineRenditi
// - Blocks until the engine is able to render without blocking.
void RenderEngineBase::WaitUntilCanRender() noexcept
{
// do nothing by default
// Throttle the render loop a bit by default.
Sleep(8);
}

View file

@ -213,12 +213,6 @@ DWORD WINAPI RenderThread::_ThreadProc()
LOG_IF_FAILED(_pRenderer->PaintFrame());
SetEvent(_hPaintCompletedEvent);
// extra check before we sleep since it's a "long" activity, relatively speaking.
if (_fKeepRunning)
{
Sleep(s_FrameLimitMilliseconds);
}
}
return S_OK;

View file

@ -37,8 +37,6 @@ namespace Microsoft::Console::Render
static DWORD WINAPI s_ThreadProc(_In_ LPVOID lpParameter);
DWORD WINAPI _ThreadProc();
static DWORD const s_FrameLimitMilliseconds = 8;
HANDLE _hThread;
HANDLE _hEvent;

View file

@ -1498,18 +1498,13 @@ CATCH_RETURN()
// - See https://docs.microsoft.com/en-us/windows/uwp/gaming/reduce-latency-with-dxgi-1-3-swap-chains.
void DxEngine::WaitUntilCanRender() noexcept
{
if (!_swapChainFrameLatencyWaitableObject)
{
return;
}
// DxEngine isn't really performant and can easily hold the console lock for 20ms per (full) frame.
// Sleeping 8ms per frame thus increases throughput of the concurrently running VtEngine.
Sleep(8);
const auto ret = WaitForSingleObjectEx(
_swapChainFrameLatencyWaitableObject.get(),
1000, // 1 second timeout (shouldn't ever occur)
true);
if (ret != WAIT_OBJECT_0)
if (_swapChainFrameLatencyWaitableObject)
{
LOG_WIN32_MSG(ret, "Waiting for swap chain frame latency waitable object returned error or timeout.");
WaitForSingleObjectEx(_swapChainFrameLatencyWaitableObject.get(), 1000, true);
}
}

View file

@ -38,7 +38,7 @@ public:
unsigned char GetFamily() const;
unsigned int GetWeight() const;
const std::wstring_view GetFaceName() const noexcept;
const std::wstring& GetFaceName() const noexcept;
unsigned int GetCodePage() const;
HRESULT FillLegacyNameBuffer(gsl::span<wchar_t> buffer) const;

View file

@ -44,27 +44,15 @@ namespace Microsoft::Console::Render
};
using GridLineSet = til::enumset<GridLines>;
virtual ~IRenderEngine() = 0;
virtual ~IRenderEngine() {}
protected:
IRenderEngine() = default;
IRenderEngine(const IRenderEngine&) = default;
IRenderEngine(IRenderEngine&&) = default;
IRenderEngine& operator=(const IRenderEngine&) = default;
IRenderEngine& operator=(IRenderEngine&&) = default;
public:
[[nodiscard]] virtual HRESULT StartPaint() noexcept = 0;
[[nodiscard]] virtual HRESULT EndPaint() noexcept = 0;
[[nodiscard]] virtual bool RequiresContinuousRedraw() noexcept = 0;
virtual void WaitUntilCanRender() noexcept = 0;
[[nodiscard]] virtual HRESULT Present() noexcept = 0;
[[nodiscard]] virtual HRESULT PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept = 0;
[[nodiscard]] virtual HRESULT ScrollFrame() noexcept = 0;
[[nodiscard]] virtual HRESULT Invalidate(const SMALL_RECT* const psrRegion) noexcept = 0;
[[nodiscard]] virtual HRESULT InvalidateCursor(const SMALL_RECT* const psrRegion) noexcept = 0;
[[nodiscard]] virtual HRESULT InvalidateSystem(const RECT* const prcDirtyClient) noexcept = 0;
@ -72,50 +60,24 @@ namespace Microsoft::Console::Render
[[nodiscard]] virtual HRESULT InvalidateScroll(const COORD* const pcoordDelta) noexcept = 0;
[[nodiscard]] virtual HRESULT InvalidateAll() noexcept = 0;
[[nodiscard]] virtual HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept = 0;
[[nodiscard]] virtual HRESULT InvalidateTitle(const std::wstring_view proposedTitle) noexcept = 0;
[[nodiscard]] virtual HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept = 0;
[[nodiscard]] virtual HRESULT ResetLineTransform() noexcept = 0;
[[nodiscard]] virtual HRESULT PrepareLineTransform(const LineRendition lineRendition,
const size_t targetRow,
const size_t viewportLeft) noexcept = 0;
[[nodiscard]] virtual HRESULT PrepareLineTransform(const LineRendition lineRendition, const size_t targetRow, const size_t viewportLeft) noexcept = 0;
[[nodiscard]] virtual HRESULT PaintBackground() noexcept = 0;
[[nodiscard]] virtual HRESULT PaintBufferLine(gsl::span<const Cluster> const clusters,
const COORD coord,
const bool fTrimLeft,
const bool lineWrapped) noexcept = 0;
[[nodiscard]] virtual HRESULT PaintBufferGridLines(const GridLineSet lines,
const COLORREF color,
const size_t cchLine,
const COORD coordTarget) noexcept = 0;
[[nodiscard]] virtual HRESULT PaintBufferLine(gsl::span<const Cluster> const clusters, const COORD coord, const bool fTrimLeft, const bool lineWrapped) noexcept = 0;
[[nodiscard]] virtual HRESULT PaintBufferGridLines(const GridLineSet lines, const COLORREF color, const size_t cchLine, const COORD coordTarget) noexcept = 0;
[[nodiscard]] virtual HRESULT PaintSelection(const SMALL_RECT rect) noexcept = 0;
[[nodiscard]] virtual HRESULT PaintCursor(const CursorOptions& options) noexcept = 0;
[[nodiscard]] virtual HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes,
const gsl::not_null<IRenderData*> pData,
const bool usingSoftFont,
const bool isSettingDefaultBrushes) noexcept = 0;
[[nodiscard]] virtual HRESULT UpdateFont(const FontInfoDesired& FontInfoDesired,
_Out_ FontInfo& FontInfo) noexcept = 0;
[[nodiscard]] virtual HRESULT UpdateSoftFont(const gsl::span<const uint16_t> bitPattern,
const SIZE cellSize,
const size_t centeringHint) noexcept = 0;
[[nodiscard]] virtual HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes, const gsl::not_null<IRenderData*> pData, const bool usingSoftFont, const bool isSettingDefaultBrushes) noexcept = 0;
[[nodiscard]] virtual HRESULT UpdateFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo) noexcept = 0;
[[nodiscard]] virtual HRESULT UpdateSoftFont(const gsl::span<const uint16_t> bitPattern, const SIZE cellSize, const size_t centeringHint) noexcept = 0;
[[nodiscard]] virtual HRESULT UpdateDpi(const int iDpi) noexcept = 0;
[[nodiscard]] virtual HRESULT UpdateViewport(const SMALL_RECT srNewViewport) noexcept = 0;
[[nodiscard]] virtual HRESULT GetProposedFont(const FontInfoDesired& FontInfoDesired,
_Out_ FontInfo& FontInfo,
const int iDpi) noexcept = 0;
[[nodiscard]] virtual HRESULT GetProposedFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo, const int iDpi) noexcept = 0;
[[nodiscard]] virtual HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept = 0;
[[nodiscard]] virtual HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept = 0;
[[nodiscard]] virtual HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept = 0;
[[nodiscard]] virtual HRESULT UpdateTitle(const std::wstring_view newTitle) noexcept = 0;
};
inline Microsoft::Console::Render::IRenderEngine::~IRenderEngine() {}
}

View file

@ -261,6 +261,13 @@ CATCH_RETURN();
return S_OK;
}
// RenderEngineBase defines a WaitUntilCanRender() that sleeps for 8ms to throttle rendering.
// But UiaEngine is never the only the engine running. Overriding this function prevents
// us from sleeping 16ms per frame, when the other engine also sleeps for 8ms.
void UiaEngine::WaitUntilCanRender() noexcept
{
}
// Routine Description:
// - Used to perform longer running presentation steps outside the lock so the
// other threads can continue.

View file

@ -33,15 +33,13 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT Enable() noexcept;
[[nodiscard]] HRESULT Disable() noexcept;
// IRenderEngine Members
// IRenderEngine Members
[[nodiscard]] HRESULT StartPaint() noexcept override;
[[nodiscard]] HRESULT EndPaint() noexcept override;
void WaitUntilCanRender() noexcept override;
[[nodiscard]] HRESULT Present() noexcept override;
[[nodiscard]] HRESULT PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT ScrollFrame() noexcept override;
[[nodiscard]] HRESULT Invalidate(const SMALL_RECT* const psrRegion) noexcept override;
[[nodiscard]] HRESULT InvalidateCursor(const SMALL_RECT* const psrRegion) noexcept override;
[[nodiscard]] HRESULT InvalidateSystem(const RECT* const prcDirtyClient) noexcept override;
@ -49,27 +47,16 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT InvalidateScroll(const COORD* const pcoordDelta) noexcept override;
[[nodiscard]] HRESULT InvalidateAll() noexcept override;
[[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT PaintBackground() noexcept override;
[[nodiscard]] HRESULT PaintBufferLine(gsl::span<const Cluster> const clusters,
COORD const coord,
bool const fTrimLeft,
const bool lineWrapped) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(GridLineSet const lines, COLORREF const color, size_t const cchLine, COORD const coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintBufferLine(gsl::span<const Cluster> const clusters, const COORD coord, const bool fTrimLeft, const bool lineWrapped) noexcept override;
[[nodiscard]] HRESULT PaintBufferGridLines(const GridLineSet lines, const COLORREF color, const size_t cchLine, const COORD coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintSelection(const SMALL_RECT rect) noexcept override;
[[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) noexcept override;
[[nodiscard]] HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes,
const gsl::not_null<IRenderData*> pData,
const bool usingSoftFont,
const bool isSettingDefaultBrushes) noexcept override;
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo) noexcept override;
[[nodiscard]] HRESULT UpdateDpi(int const iDpi) noexcept override;
[[nodiscard]] HRESULT UpdateDrawingBrushes(const TextAttribute& textAttributes, const gsl::not_null<IRenderData*> pData, const bool usingSoftFont, const bool isSettingDefaultBrushes) noexcept override;
[[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo) noexcept override;
[[nodiscard]] HRESULT UpdateDpi(const int iDpi) noexcept override;
[[nodiscard]] HRESULT UpdateViewport(const SMALL_RECT srNewViewport) noexcept override;
[[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override;
[[nodiscard]] HRESULT GetProposedFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo, const int iDpi) noexcept override;
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) noexcept override;
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept override;

View file

@ -4,374 +4,378 @@
#include "precomp.h"
#include "inc/CodepointWidthDetector.hpp"
namespace
#pragma warning(disable : 4463)
struct UnicodeRangeBasic
{
// used to store range data in CodepointWidthDetector's internal map
struct UnicodeRange final
{
unsigned int lowerBound;
unsigned int upperBound;
CodepointWidth width;
};
uint16_t upperBound;
// lowerBound = it->upperBound - it->boundWidth
// Code points can be up to 2^16, however no range in our table exceeds 2^15.
// This is why we store the "width" between the lower and upper boundary instead.
uint16_t boundWidth : 15;
uint16_t isAmbiguous : 1;
};
static bool operator<(const UnicodeRange& range, const unsigned int searchTerm) noexcept
{
return range.upperBound < searchTerm;
}
struct UnicodeRangeSurrogate
{
uint32_t upperBound;
// This fields is identical to the one in UnicodeRangeBasic.
// Technically we could store the absolute code point value here,
// but it doesn't make any practical performance difference.
uint32_t boundWidth : 31;
uint32_t isAmbiguous : 1;
};
// Generated by Generate-CodepointWidthsFromUCD.ps1 -Pack:True -Full:False -NoOverrides:False
// on 10/25/2020 7:32:04 AM (UTC) from Unicode 13.0.0.
// 321205 (0x4E6B5) codepoints covered.
// 240 (0xF0) codepoints overridden.
// Override path: .\src\types\unicode_width_overrides.xml
static constexpr std::array<UnicodeRange, 295> s_wideAndAmbiguousTable{
UnicodeRange{ 0xa1, 0xa1, CodepointWidth::Ambiguous },
UnicodeRange{ 0xa4, 0xa4, CodepointWidth::Ambiguous },
UnicodeRange{ 0xa7, 0xa8, CodepointWidth::Ambiguous },
UnicodeRange{ 0xaa, 0xaa, CodepointWidth::Ambiguous },
UnicodeRange{ 0xad, 0xae, CodepointWidth::Ambiguous },
UnicodeRange{ 0xb0, 0xb4, CodepointWidth::Ambiguous },
UnicodeRange{ 0xb6, 0xba, CodepointWidth::Ambiguous },
UnicodeRange{ 0xbc, 0xbf, CodepointWidth::Ambiguous },
UnicodeRange{ 0xc6, 0xc6, CodepointWidth::Ambiguous },
UnicodeRange{ 0xd0, 0xd0, CodepointWidth::Ambiguous },
UnicodeRange{ 0xd7, 0xd8, CodepointWidth::Ambiguous },
UnicodeRange{ 0xde, 0xe1, CodepointWidth::Ambiguous },
UnicodeRange{ 0xe6, 0xe6, CodepointWidth::Ambiguous },
UnicodeRange{ 0xe8, 0xea, CodepointWidth::Ambiguous },
UnicodeRange{ 0xec, 0xed, CodepointWidth::Ambiguous },
UnicodeRange{ 0xf0, 0xf0, CodepointWidth::Ambiguous },
UnicodeRange{ 0xf2, 0xf3, CodepointWidth::Ambiguous },
UnicodeRange{ 0xf7, 0xfa, CodepointWidth::Ambiguous },
UnicodeRange{ 0xfc, 0xfc, CodepointWidth::Ambiguous },
UnicodeRange{ 0xfe, 0xfe, CodepointWidth::Ambiguous },
UnicodeRange{ 0x101, 0x101, CodepointWidth::Ambiguous },
UnicodeRange{ 0x111, 0x111, CodepointWidth::Ambiguous },
UnicodeRange{ 0x113, 0x113, CodepointWidth::Ambiguous },
UnicodeRange{ 0x11b, 0x11b, CodepointWidth::Ambiguous },
UnicodeRange{ 0x126, 0x127, CodepointWidth::Ambiguous },
UnicodeRange{ 0x12b, 0x12b, CodepointWidth::Ambiguous },
UnicodeRange{ 0x131, 0x133, CodepointWidth::Ambiguous },
UnicodeRange{ 0x138, 0x138, CodepointWidth::Ambiguous },
UnicodeRange{ 0x13f, 0x142, CodepointWidth::Ambiguous },
UnicodeRange{ 0x144, 0x144, CodepointWidth::Ambiguous },
UnicodeRange{ 0x148, 0x14b, CodepointWidth::Ambiguous },
UnicodeRange{ 0x14d, 0x14d, CodepointWidth::Ambiguous },
UnicodeRange{ 0x152, 0x153, CodepointWidth::Ambiguous },
UnicodeRange{ 0x166, 0x167, CodepointWidth::Ambiguous },
UnicodeRange{ 0x16b, 0x16b, CodepointWidth::Ambiguous },
UnicodeRange{ 0x1ce, 0x1ce, CodepointWidth::Ambiguous },
UnicodeRange{ 0x1d0, 0x1d0, CodepointWidth::Ambiguous },
UnicodeRange{ 0x1d2, 0x1d2, CodepointWidth::Ambiguous },
UnicodeRange{ 0x1d4, 0x1d4, CodepointWidth::Ambiguous },
UnicodeRange{ 0x1d6, 0x1d6, CodepointWidth::Ambiguous },
UnicodeRange{ 0x1d8, 0x1d8, CodepointWidth::Ambiguous },
UnicodeRange{ 0x1da, 0x1da, CodepointWidth::Ambiguous },
UnicodeRange{ 0x1dc, 0x1dc, CodepointWidth::Ambiguous },
UnicodeRange{ 0x251, 0x251, CodepointWidth::Ambiguous },
UnicodeRange{ 0x261, 0x261, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2c4, 0x2c4, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2c7, 0x2c7, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2c9, 0x2cb, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2cd, 0x2cd, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2d0, 0x2d0, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2d8, 0x2db, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2dd, 0x2dd, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2df, 0x2df, CodepointWidth::Ambiguous },
UnicodeRange{ 0x300, 0x36f, CodepointWidth::Ambiguous },
UnicodeRange{ 0x391, 0x3a1, CodepointWidth::Ambiguous },
UnicodeRange{ 0x3a3, 0x3a9, CodepointWidth::Ambiguous },
UnicodeRange{ 0x3b1, 0x3c1, CodepointWidth::Ambiguous },
UnicodeRange{ 0x3c3, 0x3c9, CodepointWidth::Ambiguous },
UnicodeRange{ 0x401, 0x401, CodepointWidth::Ambiguous },
UnicodeRange{ 0x410, 0x44f, CodepointWidth::Ambiguous },
UnicodeRange{ 0x451, 0x451, CodepointWidth::Ambiguous },
UnicodeRange{ 0x1100, 0x115f, CodepointWidth::Wide },
UnicodeRange{ 0x2010, 0x2010, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2013, 0x2016, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2018, 0x2019, CodepointWidth::Ambiguous },
UnicodeRange{ 0x201c, 0x201d, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2020, 0x2022, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2024, 0x2027, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2030, 0x2030, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2032, 0x2033, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2035, 0x2035, CodepointWidth::Ambiguous },
UnicodeRange{ 0x203b, 0x203b, CodepointWidth::Ambiguous },
UnicodeRange{ 0x203e, 0x203e, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2074, 0x2074, CodepointWidth::Ambiguous },
UnicodeRange{ 0x207f, 0x207f, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2081, 0x2084, CodepointWidth::Ambiguous },
UnicodeRange{ 0x20ac, 0x20ac, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2103, 0x2103, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2105, 0x2105, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2109, 0x2109, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2113, 0x2113, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2116, 0x2116, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2121, 0x2122, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2126, 0x2126, CodepointWidth::Ambiguous },
UnicodeRange{ 0x212b, 0x212b, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2153, 0x2154, CodepointWidth::Ambiguous },
UnicodeRange{ 0x215b, 0x215e, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2160, 0x216b, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2170, 0x2179, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2189, 0x2189, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2190, 0x2199, CodepointWidth::Ambiguous },
UnicodeRange{ 0x21b8, 0x21b9, CodepointWidth::Ambiguous },
UnicodeRange{ 0x21d2, 0x21d2, CodepointWidth::Ambiguous },
UnicodeRange{ 0x21d4, 0x21d4, CodepointWidth::Ambiguous },
UnicodeRange{ 0x21e7, 0x21e7, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2200, 0x2200, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2202, 0x2203, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2207, 0x2208, CodepointWidth::Ambiguous },
UnicodeRange{ 0x220b, 0x220b, CodepointWidth::Ambiguous },
UnicodeRange{ 0x220f, 0x220f, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2211, 0x2211, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2215, 0x2215, CodepointWidth::Ambiguous },
UnicodeRange{ 0x221a, 0x221a, CodepointWidth::Ambiguous },
UnicodeRange{ 0x221d, 0x2220, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2223, 0x2223, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2225, 0x2225, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2227, 0x222c, CodepointWidth::Ambiguous },
UnicodeRange{ 0x222e, 0x222e, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2234, 0x2237, CodepointWidth::Ambiguous },
UnicodeRange{ 0x223c, 0x223d, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2248, 0x2248, CodepointWidth::Ambiguous },
UnicodeRange{ 0x224c, 0x224c, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2252, 0x2252, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2260, 0x2261, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2264, 0x2267, CodepointWidth::Ambiguous },
UnicodeRange{ 0x226a, 0x226b, CodepointWidth::Ambiguous },
UnicodeRange{ 0x226e, 0x226f, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2282, 0x2283, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2286, 0x2287, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2295, 0x2295, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2299, 0x2299, CodepointWidth::Ambiguous },
UnicodeRange{ 0x22a5, 0x22a5, CodepointWidth::Ambiguous },
UnicodeRange{ 0x22bf, 0x22bf, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2312, 0x2312, CodepointWidth::Ambiguous },
UnicodeRange{ 0x231a, 0x231b, CodepointWidth::Wide },
UnicodeRange{ 0x2329, 0x232a, CodepointWidth::Wide },
UnicodeRange{ 0x23e9, 0x23ec, CodepointWidth::Wide },
UnicodeRange{ 0x23f0, 0x23f0, CodepointWidth::Wide },
UnicodeRange{ 0x23f3, 0x23f3, CodepointWidth::Wide },
UnicodeRange{ 0x2460, 0x24e9, CodepointWidth::Ambiguous },
UnicodeRange{ 0x24eb, 0x24ff, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2500, 0x259f, CodepointWidth::Narrow }, // box-drawing and block elements require 1-cell alignment
UnicodeRange{ 0x25a0, 0x25a1, CodepointWidth::Ambiguous },
UnicodeRange{ 0x25a3, 0x25a9, CodepointWidth::Ambiguous },
UnicodeRange{ 0x25b2, 0x25b3, CodepointWidth::Ambiguous },
UnicodeRange{ 0x25b6, 0x25b7, CodepointWidth::Ambiguous },
UnicodeRange{ 0x25bc, 0x25bd, CodepointWidth::Ambiguous },
UnicodeRange{ 0x25c0, 0x25c1, CodepointWidth::Ambiguous },
UnicodeRange{ 0x25c6, 0x25c8, CodepointWidth::Ambiguous },
UnicodeRange{ 0x25cb, 0x25cb, CodepointWidth::Ambiguous },
UnicodeRange{ 0x25ce, 0x25d1, CodepointWidth::Ambiguous },
UnicodeRange{ 0x25e2, 0x25e5, CodepointWidth::Ambiguous },
UnicodeRange{ 0x25ef, 0x25ef, CodepointWidth::Ambiguous },
UnicodeRange{ 0x25fd, 0x25fe, CodepointWidth::Wide },
UnicodeRange{ 0x2605, 0x2606, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2609, 0x2609, CodepointWidth::Ambiguous },
UnicodeRange{ 0x260e, 0x260f, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2614, 0x2615, CodepointWidth::Wide },
UnicodeRange{ 0x261c, 0x261c, CodepointWidth::Ambiguous },
UnicodeRange{ 0x261e, 0x261e, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2640, 0x2640, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2642, 0x2642, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2648, 0x2653, CodepointWidth::Wide },
UnicodeRange{ 0x2660, 0x2661, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2663, 0x2665, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2667, 0x266a, CodepointWidth::Ambiguous },
UnicodeRange{ 0x266c, 0x266d, CodepointWidth::Ambiguous },
UnicodeRange{ 0x266f, 0x266f, CodepointWidth::Ambiguous },
UnicodeRange{ 0x267f, 0x267f, CodepointWidth::Wide },
UnicodeRange{ 0x2693, 0x2693, CodepointWidth::Wide },
UnicodeRange{ 0x269e, 0x269f, CodepointWidth::Ambiguous },
UnicodeRange{ 0x26a1, 0x26a1, CodepointWidth::Wide },
UnicodeRange{ 0x26aa, 0x26ab, CodepointWidth::Wide },
UnicodeRange{ 0x26bd, 0x26be, CodepointWidth::Wide },
UnicodeRange{ 0x26bf, 0x26bf, CodepointWidth::Ambiguous },
UnicodeRange{ 0x26c4, 0x26c5, CodepointWidth::Wide },
UnicodeRange{ 0x26c6, 0x26cd, CodepointWidth::Ambiguous },
UnicodeRange{ 0x26ce, 0x26ce, CodepointWidth::Wide },
UnicodeRange{ 0x26cf, 0x26d3, CodepointWidth::Ambiguous },
UnicodeRange{ 0x26d4, 0x26d4, CodepointWidth::Wide },
UnicodeRange{ 0x26d5, 0x26e1, CodepointWidth::Ambiguous },
UnicodeRange{ 0x26e3, 0x26e3, CodepointWidth::Ambiguous },
UnicodeRange{ 0x26e8, 0x26e9, CodepointWidth::Ambiguous },
UnicodeRange{ 0x26ea, 0x26ea, CodepointWidth::Wide },
UnicodeRange{ 0x26eb, 0x26f1, CodepointWidth::Ambiguous },
UnicodeRange{ 0x26f2, 0x26f3, CodepointWidth::Wide },
UnicodeRange{ 0x26f4, 0x26f4, CodepointWidth::Ambiguous },
UnicodeRange{ 0x26f5, 0x26f5, CodepointWidth::Wide },
UnicodeRange{ 0x26f6, 0x26f9, CodepointWidth::Ambiguous },
UnicodeRange{ 0x26fa, 0x26fa, CodepointWidth::Wide },
UnicodeRange{ 0x26fb, 0x26fc, CodepointWidth::Ambiguous },
UnicodeRange{ 0x26fd, 0x26fd, CodepointWidth::Wide },
UnicodeRange{ 0x26fe, 0x26ff, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2705, 0x2705, CodepointWidth::Wide },
UnicodeRange{ 0x270a, 0x270b, CodepointWidth::Wide },
UnicodeRange{ 0x2728, 0x2728, CodepointWidth::Wide },
UnicodeRange{ 0x273d, 0x273d, CodepointWidth::Ambiguous },
UnicodeRange{ 0x274c, 0x274c, CodepointWidth::Wide },
UnicodeRange{ 0x274e, 0x274e, CodepointWidth::Wide },
UnicodeRange{ 0x2753, 0x2755, CodepointWidth::Wide },
UnicodeRange{ 0x2757, 0x2757, CodepointWidth::Wide },
UnicodeRange{ 0x2776, 0x277f, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2795, 0x2797, CodepointWidth::Wide },
UnicodeRange{ 0x27b0, 0x27b0, CodepointWidth::Wide },
UnicodeRange{ 0x27bf, 0x27bf, CodepointWidth::Wide },
UnicodeRange{ 0x2b1b, 0x2b1c, CodepointWidth::Wide },
UnicodeRange{ 0x2b50, 0x2b50, CodepointWidth::Wide },
UnicodeRange{ 0x2b55, 0x2b55, CodepointWidth::Wide },
UnicodeRange{ 0x2b56, 0x2b59, CodepointWidth::Ambiguous },
UnicodeRange{ 0x2e80, 0x2e99, CodepointWidth::Wide },
UnicodeRange{ 0x2e9b, 0x2ef3, CodepointWidth::Wide },
UnicodeRange{ 0x2f00, 0x2fd5, CodepointWidth::Wide },
UnicodeRange{ 0x2ff0, 0x2ffb, CodepointWidth::Wide },
UnicodeRange{ 0x3000, 0x303e, CodepointWidth::Wide },
UnicodeRange{ 0x3041, 0x3096, CodepointWidth::Wide },
UnicodeRange{ 0x3099, 0x30ff, CodepointWidth::Wide },
UnicodeRange{ 0x3105, 0x312f, CodepointWidth::Wide },
UnicodeRange{ 0x3131, 0x318e, CodepointWidth::Wide },
UnicodeRange{ 0x3190, 0x31e3, CodepointWidth::Wide },
UnicodeRange{ 0x31f0, 0x321e, CodepointWidth::Wide },
UnicodeRange{ 0x3220, 0x3247, CodepointWidth::Wide },
UnicodeRange{ 0x3248, 0x324f, CodepointWidth::Ambiguous },
UnicodeRange{ 0x3250, 0x4dbf, CodepointWidth::Wide },
UnicodeRange{ 0x4dc0, 0x4dff, CodepointWidth::Narrow }, // hexagrams are historically narrow
UnicodeRange{ 0x4e00, 0xa48c, CodepointWidth::Wide },
UnicodeRange{ 0xa490, 0xa4c6, CodepointWidth::Wide },
UnicodeRange{ 0xa960, 0xa97c, CodepointWidth::Wide },
UnicodeRange{ 0xac00, 0xd7a3, CodepointWidth::Wide },
UnicodeRange{ 0xe000, 0xf8ff, CodepointWidth::Ambiguous },
UnicodeRange{ 0xf900, 0xfaff, CodepointWidth::Wide },
UnicodeRange{ 0xfe00, 0xfe0f, CodepointWidth::Ambiguous },
UnicodeRange{ 0xfe10, 0xfe19, CodepointWidth::Wide },
UnicodeRange{ 0xfe20, 0xfe2f, CodepointWidth::Narrow }, // narrow combining ligatures (split into left/right halves, which take 2 columns together)
UnicodeRange{ 0xfe30, 0xfe52, CodepointWidth::Wide },
UnicodeRange{ 0xfe54, 0xfe66, CodepointWidth::Wide },
UnicodeRange{ 0xfe68, 0xfe6b, CodepointWidth::Wide },
UnicodeRange{ 0xff01, 0xff60, CodepointWidth::Wide },
UnicodeRange{ 0xffe0, 0xffe6, CodepointWidth::Wide },
UnicodeRange{ 0xfffd, 0xfffd, CodepointWidth::Ambiguous },
UnicodeRange{ 0x16fe0, 0x16fe4, CodepointWidth::Wide },
UnicodeRange{ 0x16ff0, 0x16ff1, CodepointWidth::Wide },
UnicodeRange{ 0x17000, 0x187f7, CodepointWidth::Wide },
UnicodeRange{ 0x18800, 0x18cd5, CodepointWidth::Wide },
UnicodeRange{ 0x18d00, 0x18d08, CodepointWidth::Wide },
UnicodeRange{ 0x1b000, 0x1b11e, CodepointWidth::Wide },
UnicodeRange{ 0x1b150, 0x1b152, CodepointWidth::Wide },
UnicodeRange{ 0x1b164, 0x1b167, CodepointWidth::Wide },
UnicodeRange{ 0x1b170, 0x1b2fb, CodepointWidth::Wide },
UnicodeRange{ 0x1f004, 0x1f004, CodepointWidth::Wide },
UnicodeRange{ 0x1f0cf, 0x1f0cf, CodepointWidth::Wide },
UnicodeRange{ 0x1f100, 0x1f10a, CodepointWidth::Ambiguous },
UnicodeRange{ 0x1f110, 0x1f12d, CodepointWidth::Ambiguous },
UnicodeRange{ 0x1f130, 0x1f169, CodepointWidth::Ambiguous },
UnicodeRange{ 0x1f170, 0x1f18d, CodepointWidth::Ambiguous },
UnicodeRange{ 0x1f18e, 0x1f18e, CodepointWidth::Wide },
UnicodeRange{ 0x1f18f, 0x1f190, CodepointWidth::Ambiguous },
UnicodeRange{ 0x1f191, 0x1f19a, CodepointWidth::Wide },
UnicodeRange{ 0x1f19b, 0x1f1ac, CodepointWidth::Ambiguous },
UnicodeRange{ 0x1f1e6, 0x1f202, CodepointWidth::Wide },
UnicodeRange{ 0x1f210, 0x1f23b, CodepointWidth::Wide },
UnicodeRange{ 0x1f240, 0x1f248, CodepointWidth::Wide },
UnicodeRange{ 0x1f250, 0x1f251, CodepointWidth::Wide },
UnicodeRange{ 0x1f260, 0x1f265, CodepointWidth::Wide },
UnicodeRange{ 0x1f300, 0x1f320, CodepointWidth::Wide },
UnicodeRange{ 0x1f32d, 0x1f335, CodepointWidth::Wide },
UnicodeRange{ 0x1f337, 0x1f37c, CodepointWidth::Wide },
UnicodeRange{ 0x1f37e, 0x1f393, CodepointWidth::Wide },
UnicodeRange{ 0x1f3a0, 0x1f3ca, CodepointWidth::Wide },
UnicodeRange{ 0x1f3cf, 0x1f3d3, CodepointWidth::Wide },
UnicodeRange{ 0x1f3e0, 0x1f3f0, CodepointWidth::Wide },
UnicodeRange{ 0x1f3f4, 0x1f3f4, CodepointWidth::Wide },
UnicodeRange{ 0x1f3f8, 0x1f43e, CodepointWidth::Wide },
UnicodeRange{ 0x1f440, 0x1f440, CodepointWidth::Wide },
UnicodeRange{ 0x1f442, 0x1f4fc, CodepointWidth::Wide },
UnicodeRange{ 0x1f4ff, 0x1f53d, CodepointWidth::Wide },
UnicodeRange{ 0x1f54b, 0x1f54e, CodepointWidth::Wide },
UnicodeRange{ 0x1f550, 0x1f567, CodepointWidth::Wide },
UnicodeRange{ 0x1f57a, 0x1f57a, CodepointWidth::Wide },
UnicodeRange{ 0x1f595, 0x1f596, CodepointWidth::Wide },
UnicodeRange{ 0x1f5a4, 0x1f5a4, CodepointWidth::Wide },
UnicodeRange{ 0x1f5fb, 0x1f64f, CodepointWidth::Wide },
UnicodeRange{ 0x1f680, 0x1f6c5, CodepointWidth::Wide },
UnicodeRange{ 0x1f6cc, 0x1f6cc, CodepointWidth::Wide },
UnicodeRange{ 0x1f6d0, 0x1f6d2, CodepointWidth::Wide },
UnicodeRange{ 0x1f6d5, 0x1f6d7, CodepointWidth::Wide },
UnicodeRange{ 0x1f6eb, 0x1f6ec, CodepointWidth::Wide },
UnicodeRange{ 0x1f6f4, 0x1f6fc, CodepointWidth::Wide },
UnicodeRange{ 0x1f7e0, 0x1f7eb, CodepointWidth::Wide },
UnicodeRange{ 0x1f90c, 0x1f93a, CodepointWidth::Wide },
UnicodeRange{ 0x1f93c, 0x1f945, CodepointWidth::Wide },
UnicodeRange{ 0x1f947, 0x1f978, CodepointWidth::Wide },
UnicodeRange{ 0x1f97a, 0x1f9cb, CodepointWidth::Wide },
UnicodeRange{ 0x1f9cd, 0x1f9ff, CodepointWidth::Wide },
UnicodeRange{ 0x1fa70, 0x1fa74, CodepointWidth::Wide },
UnicodeRange{ 0x1fa78, 0x1fa7a, CodepointWidth::Wide },
UnicodeRange{ 0x1fa80, 0x1fa86, CodepointWidth::Wide },
UnicodeRange{ 0x1fa90, 0x1faa8, CodepointWidth::Wide },
UnicodeRange{ 0x1fab0, 0x1fab6, CodepointWidth::Wide },
UnicodeRange{ 0x1fac0, 0x1fac2, CodepointWidth::Wide },
UnicodeRange{ 0x1fad0, 0x1fad6, CodepointWidth::Wide },
UnicodeRange{ 0x20000, 0x2fffd, CodepointWidth::Wide },
UnicodeRange{ 0x30000, 0x3fffd, CodepointWidth::Wide },
UnicodeRange{ 0xe0100, 0xe01ef, CodepointWidth::Ambiguous },
UnicodeRange{ 0xf0000, 0xffffd, CodepointWidth::Ambiguous },
UnicodeRange{ 0x100000, 0x10fffd, CodepointWidth::Ambiguous },
};
constexpr bool operator<(const UnicodeRangeBasic& range, const uint16_t searchTerm) noexcept
{
return range.upperBound < searchTerm;
}
// Routine Description:
// - Constructs an instance of the CodepointWidthDetector class
CodepointWidthDetector::CodepointWidthDetector() noexcept :
_fallbackCache{},
_pfnFallbackMethod{}
constexpr bool operator<(const UnicodeRangeSurrogate& range, const uint32_t searchTerm) noexcept
{
return range.upperBound < searchTerm;
}
// The following two tables are generated by:
// * Downloading ucd.nounihan.flat.xml from https://www.unicode.org/Public/UCD/latest/ucdxml
// * Running .\tools\Generate-CodepointWidthsFromUCD.ps1 -Pack -OverridePath .\src\types\unicode_width_overrides.xml ucd.nounihan.flat.xml
// Generated by Generate-CodepointWidthsFromUCD.ps1 -Pack:$True -Full:$False -NoOverrides:$False
// on 10.10.2021 22:40:05 (UTC) from Unicode 14.0.0.
// 321259 (0x4E6EB) codepoints covered.
// 240 (0xF0) codepoints overridden.
// Override path: .\src\types\unicode_width_overrides.xml
static constexpr std::array<UnicodeRangeBasic, 226> tableBasic{ {
UnicodeRangeBasic{ 0xa1, 0x0, 1 },
UnicodeRangeBasic{ 0xa4, 0x0, 1 },
UnicodeRangeBasic{ 0xa8, 0x1, 1 },
UnicodeRangeBasic{ 0xaa, 0x0, 1 },
UnicodeRangeBasic{ 0xae, 0x1, 1 },
UnicodeRangeBasic{ 0xb4, 0x4, 1 },
UnicodeRangeBasic{ 0xba, 0x4, 1 },
UnicodeRangeBasic{ 0xbf, 0x3, 1 },
UnicodeRangeBasic{ 0xc6, 0x0, 1 },
UnicodeRangeBasic{ 0xd0, 0x0, 1 },
UnicodeRangeBasic{ 0xd8, 0x1, 1 },
UnicodeRangeBasic{ 0xe1, 0x3, 1 },
UnicodeRangeBasic{ 0xe6, 0x0, 1 },
UnicodeRangeBasic{ 0xea, 0x2, 1 },
UnicodeRangeBasic{ 0xed, 0x1, 1 },
UnicodeRangeBasic{ 0xf0, 0x0, 1 },
UnicodeRangeBasic{ 0xf3, 0x1, 1 },
UnicodeRangeBasic{ 0xfa, 0x3, 1 },
UnicodeRangeBasic{ 0xfc, 0x0, 1 },
UnicodeRangeBasic{ 0xfe, 0x0, 1 },
UnicodeRangeBasic{ 0x101, 0x0, 1 },
UnicodeRangeBasic{ 0x111, 0x0, 1 },
UnicodeRangeBasic{ 0x113, 0x0, 1 },
UnicodeRangeBasic{ 0x11b, 0x0, 1 },
UnicodeRangeBasic{ 0x127, 0x1, 1 },
UnicodeRangeBasic{ 0x12b, 0x0, 1 },
UnicodeRangeBasic{ 0x133, 0x2, 1 },
UnicodeRangeBasic{ 0x138, 0x0, 1 },
UnicodeRangeBasic{ 0x142, 0x3, 1 },
UnicodeRangeBasic{ 0x144, 0x0, 1 },
UnicodeRangeBasic{ 0x14b, 0x3, 1 },
UnicodeRangeBasic{ 0x14d, 0x0, 1 },
UnicodeRangeBasic{ 0x153, 0x1, 1 },
UnicodeRangeBasic{ 0x167, 0x1, 1 },
UnicodeRangeBasic{ 0x16b, 0x0, 1 },
UnicodeRangeBasic{ 0x1ce, 0x0, 1 },
UnicodeRangeBasic{ 0x1d0, 0x0, 1 },
UnicodeRangeBasic{ 0x1d2, 0x0, 1 },
UnicodeRangeBasic{ 0x1d4, 0x0, 1 },
UnicodeRangeBasic{ 0x1d6, 0x0, 1 },
UnicodeRangeBasic{ 0x1d8, 0x0, 1 },
UnicodeRangeBasic{ 0x1da, 0x0, 1 },
UnicodeRangeBasic{ 0x1dc, 0x0, 1 },
UnicodeRangeBasic{ 0x251, 0x0, 1 },
UnicodeRangeBasic{ 0x261, 0x0, 1 },
UnicodeRangeBasic{ 0x2c4, 0x0, 1 },
UnicodeRangeBasic{ 0x2c7, 0x0, 1 },
UnicodeRangeBasic{ 0x2cb, 0x2, 1 },
UnicodeRangeBasic{ 0x2cd, 0x0, 1 },
UnicodeRangeBasic{ 0x2d0, 0x0, 1 },
UnicodeRangeBasic{ 0x2db, 0x3, 1 },
UnicodeRangeBasic{ 0x2dd, 0x0, 1 },
UnicodeRangeBasic{ 0x2df, 0x0, 1 },
UnicodeRangeBasic{ 0x36f, 0x6f, 1 },
UnicodeRangeBasic{ 0x3a1, 0x10, 1 },
UnicodeRangeBasic{ 0x3a9, 0x6, 1 },
UnicodeRangeBasic{ 0x3c1, 0x10, 1 },
UnicodeRangeBasic{ 0x3c9, 0x6, 1 },
UnicodeRangeBasic{ 0x401, 0x0, 1 },
UnicodeRangeBasic{ 0x44f, 0x3f, 1 },
UnicodeRangeBasic{ 0x451, 0x0, 1 },
UnicodeRangeBasic{ 0x115f, 0x5f, 0 },
UnicodeRangeBasic{ 0x2010, 0x0, 1 },
UnicodeRangeBasic{ 0x2016, 0x3, 1 },
UnicodeRangeBasic{ 0x2019, 0x1, 1 },
UnicodeRangeBasic{ 0x201d, 0x1, 1 },
UnicodeRangeBasic{ 0x2022, 0x2, 1 },
UnicodeRangeBasic{ 0x2027, 0x3, 1 },
UnicodeRangeBasic{ 0x2030, 0x0, 1 },
UnicodeRangeBasic{ 0x2033, 0x1, 1 },
UnicodeRangeBasic{ 0x2035, 0x0, 1 },
UnicodeRangeBasic{ 0x203b, 0x0, 1 },
UnicodeRangeBasic{ 0x203e, 0x0, 1 },
UnicodeRangeBasic{ 0x2074, 0x0, 1 },
UnicodeRangeBasic{ 0x207f, 0x0, 1 },
UnicodeRangeBasic{ 0x2084, 0x3, 1 },
UnicodeRangeBasic{ 0x20ac, 0x0, 1 },
UnicodeRangeBasic{ 0x2103, 0x0, 1 },
UnicodeRangeBasic{ 0x2105, 0x0, 1 },
UnicodeRangeBasic{ 0x2109, 0x0, 1 },
UnicodeRangeBasic{ 0x2113, 0x0, 1 },
UnicodeRangeBasic{ 0x2116, 0x0, 1 },
UnicodeRangeBasic{ 0x2122, 0x1, 1 },
UnicodeRangeBasic{ 0x2126, 0x0, 1 },
UnicodeRangeBasic{ 0x212b, 0x0, 1 },
UnicodeRangeBasic{ 0x2154, 0x1, 1 },
UnicodeRangeBasic{ 0x215e, 0x3, 1 },
UnicodeRangeBasic{ 0x216b, 0xb, 1 },
UnicodeRangeBasic{ 0x2179, 0x9, 1 },
UnicodeRangeBasic{ 0x2189, 0x0, 1 },
UnicodeRangeBasic{ 0x2199, 0x9, 1 },
UnicodeRangeBasic{ 0x21b9, 0x1, 1 },
UnicodeRangeBasic{ 0x21d2, 0x0, 1 },
UnicodeRangeBasic{ 0x21d4, 0x0, 1 },
UnicodeRangeBasic{ 0x21e7, 0x0, 1 },
UnicodeRangeBasic{ 0x2200, 0x0, 1 },
UnicodeRangeBasic{ 0x2203, 0x1, 1 },
UnicodeRangeBasic{ 0x2208, 0x1, 1 },
UnicodeRangeBasic{ 0x220b, 0x0, 1 },
UnicodeRangeBasic{ 0x220f, 0x0, 1 },
UnicodeRangeBasic{ 0x2211, 0x0, 1 },
UnicodeRangeBasic{ 0x2215, 0x0, 1 },
UnicodeRangeBasic{ 0x221a, 0x0, 1 },
UnicodeRangeBasic{ 0x2220, 0x3, 1 },
UnicodeRangeBasic{ 0x2223, 0x0, 1 },
UnicodeRangeBasic{ 0x2225, 0x0, 1 },
UnicodeRangeBasic{ 0x222c, 0x5, 1 },
UnicodeRangeBasic{ 0x222e, 0x0, 1 },
UnicodeRangeBasic{ 0x2237, 0x3, 1 },
UnicodeRangeBasic{ 0x223d, 0x1, 1 },
UnicodeRangeBasic{ 0x2248, 0x0, 1 },
UnicodeRangeBasic{ 0x224c, 0x0, 1 },
UnicodeRangeBasic{ 0x2252, 0x0, 1 },
UnicodeRangeBasic{ 0x2261, 0x1, 1 },
UnicodeRangeBasic{ 0x2267, 0x3, 1 },
UnicodeRangeBasic{ 0x226b, 0x1, 1 },
UnicodeRangeBasic{ 0x226f, 0x1, 1 },
UnicodeRangeBasic{ 0x2283, 0x1, 1 },
UnicodeRangeBasic{ 0x2287, 0x1, 1 },
UnicodeRangeBasic{ 0x2295, 0x0, 1 },
UnicodeRangeBasic{ 0x2299, 0x0, 1 },
UnicodeRangeBasic{ 0x22a5, 0x0, 1 },
UnicodeRangeBasic{ 0x22bf, 0x0, 1 },
UnicodeRangeBasic{ 0x2312, 0x0, 1 },
UnicodeRangeBasic{ 0x231b, 0x1, 0 },
UnicodeRangeBasic{ 0x232a, 0x1, 0 },
UnicodeRangeBasic{ 0x23ec, 0x3, 0 },
UnicodeRangeBasic{ 0x23f0, 0x0, 0 },
UnicodeRangeBasic{ 0x23f3, 0x0, 0 },
UnicodeRangeBasic{ 0x24e9, 0x89, 1 },
UnicodeRangeBasic{ 0x24ff, 0x14, 1 },
UnicodeRangeBasic{ 0x25a1, 0x1, 1 },
UnicodeRangeBasic{ 0x25a9, 0x6, 1 },
UnicodeRangeBasic{ 0x25b3, 0x1, 1 },
UnicodeRangeBasic{ 0x25b7, 0x1, 1 },
UnicodeRangeBasic{ 0x25bd, 0x1, 1 },
UnicodeRangeBasic{ 0x25c1, 0x1, 1 },
UnicodeRangeBasic{ 0x25c8, 0x2, 1 },
UnicodeRangeBasic{ 0x25cb, 0x0, 1 },
UnicodeRangeBasic{ 0x25d1, 0x3, 1 },
UnicodeRangeBasic{ 0x25e5, 0x3, 1 },
UnicodeRangeBasic{ 0x25ef, 0x0, 1 },
UnicodeRangeBasic{ 0x25fe, 0x1, 0 },
UnicodeRangeBasic{ 0x2606, 0x1, 1 },
UnicodeRangeBasic{ 0x2609, 0x0, 1 },
UnicodeRangeBasic{ 0x260f, 0x1, 1 },
UnicodeRangeBasic{ 0x2615, 0x1, 0 },
UnicodeRangeBasic{ 0x261c, 0x0, 1 },
UnicodeRangeBasic{ 0x261e, 0x0, 1 },
UnicodeRangeBasic{ 0x2640, 0x0, 1 },
UnicodeRangeBasic{ 0x2642, 0x0, 1 },
UnicodeRangeBasic{ 0x2653, 0xb, 0 },
UnicodeRangeBasic{ 0x2661, 0x1, 1 },
UnicodeRangeBasic{ 0x2665, 0x2, 1 },
UnicodeRangeBasic{ 0x266a, 0x3, 1 },
UnicodeRangeBasic{ 0x266d, 0x1, 1 },
UnicodeRangeBasic{ 0x266f, 0x0, 1 },
UnicodeRangeBasic{ 0x267f, 0x0, 0 },
UnicodeRangeBasic{ 0x2693, 0x0, 0 },
UnicodeRangeBasic{ 0x269f, 0x1, 1 },
UnicodeRangeBasic{ 0x26a1, 0x0, 0 },
UnicodeRangeBasic{ 0x26ab, 0x1, 0 },
UnicodeRangeBasic{ 0x26be, 0x1, 0 },
UnicodeRangeBasic{ 0x26bf, 0x0, 1 },
UnicodeRangeBasic{ 0x26c5, 0x1, 0 },
UnicodeRangeBasic{ 0x26cd, 0x7, 1 },
UnicodeRangeBasic{ 0x26ce, 0x0, 0 },
UnicodeRangeBasic{ 0x26d3, 0x4, 1 },
UnicodeRangeBasic{ 0x26d4, 0x0, 0 },
UnicodeRangeBasic{ 0x26e1, 0xc, 1 },
UnicodeRangeBasic{ 0x26e3, 0x0, 1 },
UnicodeRangeBasic{ 0x26e9, 0x1, 1 },
UnicodeRangeBasic{ 0x26ea, 0x0, 0 },
UnicodeRangeBasic{ 0x26f1, 0x6, 1 },
UnicodeRangeBasic{ 0x26f3, 0x1, 0 },
UnicodeRangeBasic{ 0x26f4, 0x0, 1 },
UnicodeRangeBasic{ 0x26f5, 0x0, 0 },
UnicodeRangeBasic{ 0x26f9, 0x3, 1 },
UnicodeRangeBasic{ 0x26fa, 0x0, 0 },
UnicodeRangeBasic{ 0x26fc, 0x1, 1 },
UnicodeRangeBasic{ 0x26fd, 0x0, 0 },
UnicodeRangeBasic{ 0x26ff, 0x1, 1 },
UnicodeRangeBasic{ 0x2705, 0x0, 0 },
UnicodeRangeBasic{ 0x270b, 0x1, 0 },
UnicodeRangeBasic{ 0x2728, 0x0, 0 },
UnicodeRangeBasic{ 0x273d, 0x0, 1 },
UnicodeRangeBasic{ 0x274c, 0x0, 0 },
UnicodeRangeBasic{ 0x274e, 0x0, 0 },
UnicodeRangeBasic{ 0x2755, 0x2, 0 },
UnicodeRangeBasic{ 0x2757, 0x0, 0 },
UnicodeRangeBasic{ 0x277f, 0x9, 1 },
UnicodeRangeBasic{ 0x2797, 0x2, 0 },
UnicodeRangeBasic{ 0x27b0, 0x0, 0 },
UnicodeRangeBasic{ 0x27bf, 0x0, 0 },
UnicodeRangeBasic{ 0x2b1c, 0x1, 0 },
UnicodeRangeBasic{ 0x2b50, 0x0, 0 },
UnicodeRangeBasic{ 0x2b55, 0x0, 0 },
UnicodeRangeBasic{ 0x2b59, 0x3, 1 },
UnicodeRangeBasic{ 0x2e99, 0x19, 0 },
UnicodeRangeBasic{ 0x2ef3, 0x58, 0 },
UnicodeRangeBasic{ 0x2fd5, 0xd5, 0 },
UnicodeRangeBasic{ 0x2ffb, 0xb, 0 },
UnicodeRangeBasic{ 0x303e, 0x3e, 0 },
UnicodeRangeBasic{ 0x3096, 0x55, 0 },
UnicodeRangeBasic{ 0x30ff, 0x66, 0 },
UnicodeRangeBasic{ 0x312f, 0x2a, 0 },
UnicodeRangeBasic{ 0x318e, 0x5d, 0 },
UnicodeRangeBasic{ 0x31e3, 0x53, 0 },
UnicodeRangeBasic{ 0x321e, 0x2e, 0 },
UnicodeRangeBasic{ 0x3247, 0x27, 0 },
UnicodeRangeBasic{ 0x324f, 0x7, 1 },
UnicodeRangeBasic{ 0x4dbf, 0x1b6f, 0 },
UnicodeRangeBasic{ 0xa48c, 0x568c, 0 },
UnicodeRangeBasic{ 0xa4c6, 0x36, 0 },
UnicodeRangeBasic{ 0xa97c, 0x1c, 0 },
UnicodeRangeBasic{ 0xd7a3, 0x2ba3, 0 },
UnicodeRangeBasic{ 0xf8ff, 0x18ff, 1 },
UnicodeRangeBasic{ 0xfaff, 0x1ff, 0 },
UnicodeRangeBasic{ 0xfe0f, 0xf, 1 },
UnicodeRangeBasic{ 0xfe19, 0x9, 0 },
UnicodeRangeBasic{ 0xfe52, 0x22, 0 },
UnicodeRangeBasic{ 0xfe66, 0x12, 0 },
UnicodeRangeBasic{ 0xfe6b, 0x3, 0 },
UnicodeRangeBasic{ 0xff60, 0x5f, 0 },
UnicodeRangeBasic{ 0xffe6, 0x6, 0 },
UnicodeRangeBasic{ 0xfffd, 0x0, 1 },
} };
static constexpr std::array<UnicodeRangeSurrogate, 71> tableSurrogates{ {
UnicodeRangeSurrogate{ 0x16fe4, 0x4, 0 },
UnicodeRangeSurrogate{ 0x16ff1, 0x1, 0 },
UnicodeRangeSurrogate{ 0x187f7, 0x17f7, 0 },
UnicodeRangeSurrogate{ 0x18cd5, 0x4d5, 0 },
UnicodeRangeSurrogate{ 0x18d08, 0x8, 0 },
UnicodeRangeSurrogate{ 0x1aff3, 0x3, 0 },
UnicodeRangeSurrogate{ 0x1affb, 0x6, 0 },
UnicodeRangeSurrogate{ 0x1affe, 0x1, 0 },
UnicodeRangeSurrogate{ 0x1b122, 0x122, 0 },
UnicodeRangeSurrogate{ 0x1b152, 0x2, 0 },
UnicodeRangeSurrogate{ 0x1b167, 0x3, 0 },
UnicodeRangeSurrogate{ 0x1b2fb, 0x18b, 0 },
UnicodeRangeSurrogate{ 0x1f004, 0x0, 0 },
UnicodeRangeSurrogate{ 0x1f0cf, 0x0, 0 },
UnicodeRangeSurrogate{ 0x1f10a, 0xa, 1 },
UnicodeRangeSurrogate{ 0x1f12d, 0x1d, 1 },
UnicodeRangeSurrogate{ 0x1f169, 0x39, 1 },
UnicodeRangeSurrogate{ 0x1f18d, 0x1d, 1 },
UnicodeRangeSurrogate{ 0x1f18e, 0x0, 0 },
UnicodeRangeSurrogate{ 0x1f190, 0x1, 1 },
UnicodeRangeSurrogate{ 0x1f19a, 0x9, 0 },
UnicodeRangeSurrogate{ 0x1f1ac, 0x11, 1 },
UnicodeRangeSurrogate{ 0x1f202, 0x1c, 0 },
UnicodeRangeSurrogate{ 0x1f23b, 0x2b, 0 },
UnicodeRangeSurrogate{ 0x1f248, 0x8, 0 },
UnicodeRangeSurrogate{ 0x1f251, 0x1, 0 },
UnicodeRangeSurrogate{ 0x1f265, 0x5, 0 },
UnicodeRangeSurrogate{ 0x1f320, 0x20, 0 },
UnicodeRangeSurrogate{ 0x1f335, 0x8, 0 },
UnicodeRangeSurrogate{ 0x1f37c, 0x45, 0 },
UnicodeRangeSurrogate{ 0x1f393, 0x15, 0 },
UnicodeRangeSurrogate{ 0x1f3ca, 0x2a, 0 },
UnicodeRangeSurrogate{ 0x1f3d3, 0x4, 0 },
UnicodeRangeSurrogate{ 0x1f3f0, 0x10, 0 },
UnicodeRangeSurrogate{ 0x1f3f4, 0x0, 0 },
UnicodeRangeSurrogate{ 0x1f43e, 0x46, 0 },
UnicodeRangeSurrogate{ 0x1f440, 0x0, 0 },
UnicodeRangeSurrogate{ 0x1f4fc, 0xba, 0 },
UnicodeRangeSurrogate{ 0x1f53d, 0x3e, 0 },
UnicodeRangeSurrogate{ 0x1f54e, 0x3, 0 },
UnicodeRangeSurrogate{ 0x1f567, 0x17, 0 },
UnicodeRangeSurrogate{ 0x1f57a, 0x0, 0 },
UnicodeRangeSurrogate{ 0x1f596, 0x1, 0 },
UnicodeRangeSurrogate{ 0x1f5a4, 0x0, 0 },
UnicodeRangeSurrogate{ 0x1f64f, 0x54, 0 },
UnicodeRangeSurrogate{ 0x1f6c5, 0x45, 0 },
UnicodeRangeSurrogate{ 0x1f6cc, 0x0, 0 },
UnicodeRangeSurrogate{ 0x1f6d2, 0x2, 0 },
UnicodeRangeSurrogate{ 0x1f6d7, 0x2, 0 },
UnicodeRangeSurrogate{ 0x1f6df, 0x2, 0 },
UnicodeRangeSurrogate{ 0x1f6ec, 0x1, 0 },
UnicodeRangeSurrogate{ 0x1f6fc, 0x8, 0 },
UnicodeRangeSurrogate{ 0x1f7eb, 0xb, 0 },
UnicodeRangeSurrogate{ 0x1f7f0, 0x0, 0 },
UnicodeRangeSurrogate{ 0x1f93a, 0x2e, 0 },
UnicodeRangeSurrogate{ 0x1f945, 0x9, 0 },
UnicodeRangeSurrogate{ 0x1f9ff, 0xb8, 0 },
UnicodeRangeSurrogate{ 0x1fa74, 0x4, 0 },
UnicodeRangeSurrogate{ 0x1fa7c, 0x4, 0 },
UnicodeRangeSurrogate{ 0x1fa86, 0x6, 0 },
UnicodeRangeSurrogate{ 0x1faac, 0x1c, 0 },
UnicodeRangeSurrogate{ 0x1faba, 0xa, 0 },
UnicodeRangeSurrogate{ 0x1fac5, 0x5, 0 },
UnicodeRangeSurrogate{ 0x1fad9, 0x9, 0 },
UnicodeRangeSurrogate{ 0x1fae7, 0x7, 0 },
UnicodeRangeSurrogate{ 0x1faf6, 0x6, 0 },
UnicodeRangeSurrogate{ 0x2fffd, 0xfffd, 0 },
UnicodeRangeSurrogate{ 0x3fffd, 0xfffd, 0 },
UnicodeRangeSurrogate{ 0xe01ef, 0xef, 1 },
UnicodeRangeSurrogate{ 0xffffd, 0xfffd, 1 },
UnicodeRangeSurrogate{ 0x10fffd, 0xfffd, 1 },
} };
// Routine Description:
// - returns the width type of codepoint as fast as we can by using quick lookup table and fallback cache.
// Arguments:
// - glyph - the utf16 encoded codepoint to search for
// Return Value:
// - the width type of the codepoint
CodepointWidth CodepointWidthDetector::GetWidth(const std::wstring_view glyph) const
CodepointWidth CodepointWidthDetector::GetWidth(const std::wstring_view& glyph) const noexcept
{
THROW_HR_IF(E_INVALIDARG, glyph.empty());
if (glyph.size() == 1)
switch (glyph.size())
{
// We first attempt to look at our custom quick lookup table of char width preferences.
const auto width = GetQuickCharWidth(glyph.front());
// If it's invalid, the quick width had no opinion, so go to the lookup table.
if (width == CodepointWidth::Invalid)
{
return _lookupGlyphWidthWithCache(glyph);
}
// If it's ambiguous, the quick width wanted us to ask the font directly, try that if we can.
// If not, go to the lookup table.
else if (width == CodepointWidth::Ambiguous)
{
if (_pfnFallbackMethod)
{
return _checkFallbackViaCache(glyph) ? CodepointWidth::Wide : CodepointWidth::Ambiguous;
}
else
{
return _lookupGlyphWidthWithCache(glyph);
}
}
// Otherwise, return Width as it is.
else
{
return width;
}
case 0:
return CodepointWidth::Ambiguous;
case 1:
{
const uint16_t codepoint = til::at(glyph, 0);
// ASCII code points below 0x80 are fairly common.
// We shouldn't have to call _getCodepointWidth for that.
// In fact those code points aren't even in tableBasic.
return codepoint < 0x80 ? CodepointWidth::Narrow : _getCodepointWidth(tableBasic, codepoint, glyph);
}
else
case 2:
{
return _lookupGlyphWidthWithCache(glyph);
uint32_t codepoint = (til::at(glyph, 0) & 0x3FF) << 10;
codepoint |= til::at(glyph, 1) & 0x3FF;
codepoint += 0x10000;
return _getCodepointWidth(tableSurrogates, codepoint, glyph);
}
default:
return CodepointWidth::Wide;
}
}
@ -383,13 +387,7 @@ CodepointWidth CodepointWidthDetector::GetWidth(const std::wstring_view glyph) c
// - true if wch is wide
bool CodepointWidthDetector::IsWide(const wchar_t wch) const noexcept
{
try
{
return IsWide({ &wch, 1 });
}
CATCH_LOG();
return true;
return wch < 0x80 ? false : IsWide({ &wch, 1 });
}
// Routine Description:
@ -398,75 +396,11 @@ bool CodepointWidthDetector::IsWide(const wchar_t wch) const noexcept
// - glyph - the utf16 encoded codepoint to check width of
// Return Value:
// - true if codepoint is wide
bool CodepointWidthDetector::IsWide(const std::wstring_view glyph) const
bool CodepointWidthDetector::IsWide(const std::wstring_view& glyph) const noexcept
{
return GetWidth(glyph) == CodepointWidth::Wide;
}
// Routine Description:
// - returns the width type of codepoint by searching the map generated from the unicode spec
// Arguments:
// - glyph - the utf16 encoded codepoint to search for
// Return Value:
// - the width type of the codepoint
CodepointWidth CodepointWidthDetector::_lookupGlyphWidth(const std::wstring_view glyph) const
{
if (glyph.empty())
{
return CodepointWidth::Invalid;
}
const auto codepoint = _extractCodepoint(glyph);
const auto it = std::lower_bound(s_wideAndAmbiguousTable.begin(), s_wideAndAmbiguousTable.end(), codepoint);
// For characters that are not _in_ the table, lower_bound will return the nearest item that is.
// We must check its bounds to make sure that our hit was a true hit.
if (it != s_wideAndAmbiguousTable.end() && codepoint >= it->lowerBound && codepoint <= it->upperBound)
{
return it->width;
}
return CodepointWidth::Narrow;
}
// Routine Description:
// - returns the width type of codepoint using fallback methods.
// Arguments:
// - glyph - the utf16 encoded codepoint to check width of
// Return Value:
// - the width type of the codepoint
CodepointWidth CodepointWidthDetector::_lookupGlyphWidthWithCache(const std::wstring_view glyph) const noexcept
{
try
{
// Use our generated table to try to lookup the width based on the Unicode standard.
const CodepointWidth width = _lookupGlyphWidth(glyph);
// If it's ambiguous, then ask the font if we can.
if (width == CodepointWidth::Ambiguous)
{
if (_pfnFallbackMethod)
{
return _checkFallbackViaCache(glyph) ? CodepointWidth::Wide : CodepointWidth::Ambiguous;
}
else
{
return CodepointWidth::Ambiguous;
}
}
// If it's not ambiguous, it should say wide or narrow.
else
{
return width;
}
}
CATCH_LOG();
// If we got this far, we couldn't figure it out.
// It's better to be too wide than too narrow.
return CodepointWidth::Wide;
}
// Routine Description:
// - Checks the fallback function but caches the results until the font changes
// because the lookup function is usually very expensive and will return the same results
@ -474,47 +408,29 @@ CodepointWidth CodepointWidthDetector::_lookupGlyphWidthWithCache(const std::wst
// Arguments:
// - glyph - the utf16 encoded codepoint to check width of
// - true if codepoint is wide or false if it is narrow
bool CodepointWidthDetector::_checkFallbackViaCache(const std::wstring_view glyph) const
CodepointWidth CodepointWidthDetector::_checkFallbackViaCache(uint32_t codepoint, const std::wstring_view& glyph) const noexcept
try
{
const std::wstring findMe{ glyph };
if (!_pfnFallbackMethod)
{
return CodepointWidth::Narrow;
}
// TODO: Cache needs to be emptied when font changes.
const auto it = _fallbackCache.find(findMe);
if (it == _fallbackCache.end())
{
auto result = _pfnFallbackMethod(glyph);
_fallbackCache.insert_or_assign(findMe, result);
return result;
}
else
const auto it = _fallbackCache.find(codepoint);
if (it != _fallbackCache.end())
{
return it->second;
}
}
// Routine Description:
// - extract unicode codepoint from utf16 encoding
// Arguments:
// - glyph - the utf16 encoded codepoint convert
// Return Value:
// - the codepoint being stored
unsigned int CodepointWidthDetector::_extractCodepoint(const std::wstring_view glyph) noexcept
const auto result = _pfnFallbackMethod(glyph) ? CodepointWidth::Wide : CodepointWidth::Narrow;
_fallbackCache.insert_or_assign(codepoint, result);
return result;
}
catch (...)
{
if (glyph.size() == 1)
{
return static_cast<unsigned int>(glyph.front());
}
else
{
const unsigned int mask = 0x3FF;
// leading bits, shifted over to make space for trailing bits
unsigned int codepoint = (glyph.at(0) & mask) << 10;
// trailing bits
codepoint |= (glyph.at(1) & mask);
// 0x10000 is subtracted from the codepoint to encode a surrogate pair, add it back
codepoint += 0x10000;
return codepoint;
}
LOG_CAUGHT_EXCEPTION();
return CodepointWidth::Narrow;
}
// Method Description:
@ -527,9 +443,9 @@ unsigned int CodepointWidthDetector::_extractCodepoint(const std::wstring_view g
// - pfnFallback - the function to use as the fallback method.
// Return Value:
// - <none>
void CodepointWidthDetector::SetFallbackMethod(std::function<bool(const std::wstring_view)> pfnFallback)
void CodepointWidthDetector::SetFallbackMethod(std::function<bool(const std::wstring_view&)> pfnFallback) noexcept
{
_pfnFallbackMethod = pfnFallback;
_pfnFallbackMethod = std::move(pfnFallback);
}
// Method Description:
@ -542,5 +458,6 @@ void CodepointWidthDetector::SetFallbackMethod(std::function<bool(const std::wst
// - <none>
void CodepointWidthDetector::NotifyFontChanged() const noexcept
{
#pragma warning(suppress : 26447) // The function is declared 'noexcept' but calls function 'clear()' which may throw exceptions (f.6).
_fallbackCache.clear();
}

View file

@ -12,7 +12,7 @@ static CodepointWidthDetector widthDetector;
// Function Description:
// - determines if the glyph represented by the string of characters should be
// wide or not. See CodepointWidthDetector::IsWide
bool IsGlyphFullWidth(const std::wstring_view glyph)
bool IsGlyphFullWidth(const std::wstring_view& glyph) noexcept
{
return widthDetector.IsWide(glyph);
}
@ -35,7 +35,7 @@ bool IsGlyphFullWidth(const wchar_t wch) noexcept
// - pfnFallback - the function to use as the fallback method.
// Return Value:
// - <none>
void SetGlyphWidthFallback(std::function<bool(const std::wstring_view)> pfnFallback)
void SetGlyphWidthFallback(std::function<bool(const std::wstring_view&)> pfnFallback)
{
widthDetector.SetFallbackMethod(pfnFallback);
}

View file

@ -130,49 +130,7 @@
return cchTarget;
}
// Routine Description:
// - naively determines the width of a UCS2 encoded wchar
// Arguments:
// - wch - the wchar_t to measure
// Return Value:
// - CodepointWidth indicating width of wch
// Notes:
// 04-08-92 ShunK Created.
// Jul-27-1992 KazuM Added Screen Information and Code Page Information.
// Jan-29-1992 V-Hirots Substruct Screen Information.
// Oct-06-1996 KazuM Not use RtlUnicodeToMultiByteSize and WideCharToMultiByte
// Because 950 (Chinese Traditional) only defined 13500 chars,
// and unicode defined almost 18000 chars.
// So there are almost 4000 chars can not be mapped to big5 code.
// Apr-30-2015 MiNiksa Corrected unknown character code assumption. Max Width in Text Metric
// is not reliable for calculating half/full width. Must use current
// display font data (cached) instead.
// May-23-2017 migrie Forced Box-Drawing Characters (x2500-x257F) to narrow.
// Jan-16-2018 migrie Separated core lookup from asking the renderer the width
// May-01-2019 MiNiksa Forced lookup-via-renderer for retroactively recategorized emoji
// that used to be narrow but now might be wide. (approx x2194-x2b55, not inclusive)
// Also forced block characters segment (x2580-x259F) to narrow
// Oct-25-2020 DuHowett Replaced the entire table with a set of overrides that get built into
// CodepointWidthDetector (unicode_width_overrides.xml)
CodepointWidth GetQuickCharWidth(const wchar_t wch) noexcept
wchar_t Utf16ToUcs2(const std::wstring_view charData) noexcept
{
if (0x20 <= wch && wch <= 0x7e)
{
/* ASCII */
return CodepointWidth::Narrow;
}
return CodepointWidth::Invalid;
}
wchar_t Utf16ToUcs2(const std::wstring_view charData)
{
THROW_HR_IF(E_INVALIDARG, charData.empty());
if (charData.size() > 1)
{
return UNICODE_REPLACEMENT;
}
else
{
return charData.front();
}
return charData.size() == 1 ? til::at(charData, 0) : UNICODE_REPLACEMENT;
}

View file

@ -14,26 +14,22 @@ Author:
#pragma once
#include "convert.hpp"
#include <functional>
static_assert(sizeof(unsigned int) == sizeof(wchar_t) * 2,
"UnicodeRange expects to be able to store a unicode codepoint in an unsigned int");
// use to measure the width of a codepoint
class CodepointWidthDetector final
{
public:
CodepointWidthDetector() noexcept;
CodepointWidthDetector() noexcept = default;
CodepointWidthDetector(const CodepointWidthDetector&) = delete;
CodepointWidthDetector(CodepointWidthDetector&&) = delete;
~CodepointWidthDetector() = default;
CodepointWidthDetector& operator=(const CodepointWidthDetector&) = delete;
CodepointWidthDetector& operator=(CodepointWidthDetector&&) = delete;
CodepointWidth GetWidth(const std::wstring_view glyph) const;
bool IsWide(const std::wstring_view glyph) const;
CodepointWidth GetWidth(const std::wstring_view& glyph) const noexcept;
bool IsWide(const std::wstring_view& glyph) const noexcept;
bool IsWide(const wchar_t wch) const noexcept;
void SetFallbackMethod(std::function<bool(const std::wstring_view)> pfnFallback);
void SetFallbackMethod(std::function<bool(const std::wstring_view&)> pfnFallback) noexcept;
void NotifyFontChanged() const noexcept;
#ifdef UNIT_TESTING
@ -41,11 +37,22 @@ public:
#endif
private:
CodepointWidth _lookupGlyphWidth(const std::wstring_view glyph) const;
CodepointWidth _lookupGlyphWidthWithCache(const std::wstring_view glyph) const noexcept;
bool _checkFallbackViaCache(const std::wstring_view glyph) const;
static unsigned int _extractCodepoint(const std::wstring_view glyph) noexcept;
template<typename T, typename U>
CodepointWidth _getCodepointWidth(const T& table, U codepoint, const std::wstring_view& glyph) const noexcept
{
#pragma warning(suppress : 26447) // The function is declared 'noexcept' but calls function 'lower_bound<...>()' which may throw exceptions (f.6).
const auto it = std::lower_bound(table.begin(), table.end(), codepoint);
mutable std::unordered_map<std::wstring, bool> _fallbackCache;
std::function<bool(std::wstring_view)> _pfnFallbackMethod;
// (it->upperBound - it->boundWidth) is equal to the lowerBound of the code point range.
if (it != table.end() && codepoint >= (it->upperBound - it->boundWidth)) {
return it->isAmbiguous ? _checkFallbackViaCache(codepoint, glyph) : CodepointWidth::Wide;
}
return CodepointWidth::Narrow;
}
CodepointWidth _checkFallbackViaCache(uint32_t codepoint, const std::wstring_view& glyph) const noexcept;
mutable std::unordered_map<uint32_t, CodepointWidth> _fallbackCache;
std::function<bool(const std::wstring_view&)> _pfnFallbackMethod;
};

View file

@ -12,7 +12,7 @@ Abstract:
#include <functional>
#include <string_view>
bool IsGlyphFullWidth(const std::wstring_view glyph);
bool IsGlyphFullWidth(const std::wstring_view& glyph) noexcept;
bool IsGlyphFullWidth(const wchar_t wch) noexcept;
void SetGlyphWidthFallback(std::function<bool(std::wstring_view)> pfnFallback);
void SetGlyphWidthFallback(std::function<bool(const std::wstring_view&)> pfnFallback);
void NotifyGlyphWidthFontChanged() noexcept;

View file

@ -34,6 +34,4 @@ enum class CodepointWidth : BYTE
[[nodiscard]] size_t GetALengthFromW(const UINT codepage,
const std::wstring_view source);
CodepointWidth GetQuickCharWidth(const wchar_t wch) noexcept;
wchar_t Utf16ToUcs2(const std::wstring_view charData);
wchar_t Utf16ToUcs2(const std::wstring_view charData) noexcept;

View file

@ -166,7 +166,10 @@ Class UnicodeRangeList : System.Collections.Generic.List[Object] {
ReplaceUnicodeRange([UnicodeRange]$newRange) {
$subset = [System.Collections.Generic.List[Object]]::New(3)
$subset.Add($newRange)
if ($newRange.Width -ne [CodepointWidth]::Narrow) {
$subset.Add($newRange)
}
$i = $this._FindInsertionPoint($newRange.Start)
@ -260,21 +263,26 @@ If (-not $NoOverrides) {
}
}
# Emit Code
" // Generated by {0} -Pack:{1} -Full:{2} -NoOverrides:{3}" -f $MyInvocation.MyCommand.Name, $Pack, $Full, $NoOverrides
" // on {0} (UTC) from {1}." -f (Get-Date -AsUTC), $InputObject.ucd.description
" // {0} (0x{0:X}) codepoints covered." -f $c
If (-not $NoOverrides) {
" // {0} (0x{0:X}) codepoints overridden." -f $overrideCount
" // Override path: {0}" -f $OverridePath
}
" static constexpr std::array<UnicodeRange, {0}> s_wideAndAmbiguousTable{{" -f $ranges.Count
ForEach($_ in $ranges) {
$comment = ""
if ($null -ne $_.Comment) {
# We only vend comments when we aren't packing tightly
$comment = " // {0}" -f $_.Comment
function Emit-Table([string] $type, [string] $name, [UnicodeRange[]] $ranges) {
"static constexpr std::array<$type, $($ranges.Count)> $name{ {"
foreach ($_ in $ranges) {
$comment = ""
if ($_.Comment) {
# We only vend comments when we aren't packing tightly
$comment = " // $($_.Comment)"
}
" $type{{ 0x{0:x}, 0x{1:x}, {2} }},$comment" -f $_.End, ($_.End - $_.Start), ($_.Width -eq [CodepointWidth]::Ambiguous ? 1 : 0)
}
" UnicodeRange{{ 0x{0:x}, 0x{1:x}, CodepointWidth::{2} }},{3}" -f $_.Start, $_.End, $_.Width, $comment
"} };"
}
" };"
# Emit Code
"// Generated by {0} -Pack:`${1} -Full:`${2} -NoOverrides:`${3}" -f $MyInvocation.MyCommand.Name, $Pack, $Full, $NoOverrides
"// on {0} (UTC) from {1}." -f (Get-Date -AsUTC), $InputObject.ucd.description
"// {0} (0x{0:X}) codepoints covered." -f $c
If (-not $NoOverrides) {
"// {0} (0x{0:X}) codepoints overridden." -f $overrideCount
"// Override path: {0}" -f $OverridePath
}
Emit-Table "UnicodeRangeBasic" "tableBasic" ($ranges | Where-Object { $_.End -lt 0x10000 })
Emit-Table "UnicodeRangeSurrogate" "tableSurrogates" ($ranges | Where-Object { $_.End -ge 0x10000 })