Compare commits

...

1 commit

Author SHA1 Message Date
Leonard Hecker 9cb4fc4373 wip 2021-10-10 20:31:03 +02:00
99 changed files with 5826 additions and 1139 deletions

View file

@ -9,6 +9,7 @@ BUILDBRANCH
BUILDMSG BUILDMSG
BUILDNUMBER BUILDNUMBER
BYPOSITION BYPOSITION
calloc
charconv charconv
CLASSNOTAVAILABLE CLASSNOTAVAILABLE
cmdletbinding cmdletbinding
@ -25,6 +26,8 @@ DERR
dlldata dlldata
DONTADDTORECENT DONTADDTORECENT
DWORDLONG DWORDLONG
dxgidebug
dxguid
enumset enumset
environstrings environstrings
EXPCMDFLAGS EXPCMDFLAGS
@ -66,8 +69,8 @@ IObject
iosfwd iosfwd
IPackage IPackage
IPeasant IPeasant
isspace
ISetup ISetup
isspace
IStorage IStorage
istream istream
IStringable IStringable
@ -82,12 +85,12 @@ llu
localtime localtime
lround lround
LSHIFT LSHIFT
memicmp
MENUCOMMAND MENUCOMMAND
MENUDATA MENUDATA
MENUINFO MENUINFO
memicmp
mptt
mov mov
mptt
msappx msappx
MULTIPLEUSE MULTIPLEUSE
NCHITTEST NCHITTEST

View file

@ -3,6 +3,7 @@ austdi
Ballmer Ballmer
bhoj bhoj
Bhojwani Bhojwani
Bilodeau
carlos carlos
dhowett dhowett
Diviness Diviness
@ -25,8 +26,8 @@ jerrysh
Kaiyu Kaiyu
kimwalisch kimwalisch
KMehrain KMehrain
KODELIFE
Kodelife Kodelife
KODELIFE
Kourosh Kourosh
kowalczyk kowalczyk
leonmsft leonmsft
@ -73,8 +74,8 @@ Wirt
Wojciech Wojciech
zadjii zadjii
Zamor Zamor
Zamora
zamora zamora
Zamora
Zoey Zoey
zorio zorio
Zverovich Zverovich

View file

@ -312,6 +312,7 @@ commdlg
COMMITID COMMITID
compat compat
componentization componentization
COMPOSITIONSURFACE
conapi conapi
conareainfo conareainfo
conattrs conattrs
@ -426,6 +427,8 @@ cstring
cstyle cstyle
csv csv
CSwitch CSwitch
csx
csy
CTerminal CTerminal
CText CText
ctime ctime
@ -847,6 +850,7 @@ GAUSSIAN
gci gci
gcx gcx
gcy gcy
GDC
gdi gdi
gdip gdip
gdirenderer gdirenderer
@ -1344,6 +1348,7 @@ LPWINDOWPOS
lpwpos lpwpos
lpwstr lpwstr
LRESULT LRESULT
lroundf
lru lru
lsb lsb
lsconfig lsconfig
@ -1445,6 +1450,7 @@ MOUSEMOVE
mousewheel mousewheel
movemask movemask
MOVESTART MOVESTART
movsb
msb msb
msbuild msbuild
mscorlib mscorlib
@ -1623,6 +1629,7 @@ NVIDIA
NVR NVR
OACR OACR
oauth oauth
obin
objbase objbase
ocf ocf
ocolor ocolor
@ -1746,6 +1753,7 @@ pdx
peb peb
PEMAGIC PEMAGIC
PENDTASKMSG PENDTASKMSG
Pentium
pfa pfa
PFACENODE PFACENODE
pfed pfed
@ -1910,6 +1918,7 @@ pythonw
qos qos
QRSTU QRSTU
qsort qsort
Qstrip
queryable queryable
QUESTIONMARK QUESTIONMARK
quickedit quickedit
@ -1917,6 +1926,7 @@ QWER
qzmp qzmp
RAII RAII
RALT RALT
rapi
rasterbar rasterbar
rasterfont rasterfont
rasterization rasterization
@ -2199,7 +2209,6 @@ somefile
SOURCEBRANCH SOURCEBRANCH
sourced sourced
SOURCESDIRECTORY SOURCESDIRECTORY
SPACEBAR
spammy spammy
spand spand
sprintf sprintf
@ -2309,6 +2318,7 @@ taskbar
tbar tbar
TBase TBase
tbc tbc
TBDR
tbi tbi
Tbl Tbl
TBM TBM
@ -2421,6 +2431,7 @@ Trd
TREX TREX
triaged triaged
triaging triaging
TRIANGLELIST
TRIANGLESTRIP TRIANGLESTRIP
TRIMZEROHEADINGS TRIMZEROHEADINGS
truetype truetype
@ -2498,12 +2509,13 @@ unittesting
universaltest universaltest
unk unk
unknwn unknwn
Unmap
unmark unmark
UNORM UNORM
unparseable unparseable
unpause unpause
Unregister
unregistering unregistering
unscoped
untests untests
untextured untextured
untimes untimes
@ -2568,6 +2580,7 @@ vectorized
VERCTRL VERCTRL
versioning versioning
VERTBAR VERTBAR
VERTEXID
VFT VFT
vga vga
vgaoem vgaoem
@ -2575,6 +2588,7 @@ viewkind
viewports viewports
Virt Virt
VIRTTERM VIRTTERM
virtualalloc
Virtualizing Virtualizing
vkey vkey
VKKEYSCAN VKKEYSCAN
@ -2851,6 +2865,7 @@ YDPI
yIcon yIcon
yml yml
YOffset YOffset
yolo
YPosition YPosition
YSize YSize
YSubstantial YSubstantial

View file

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16 # Visual Studio Version 17
VisualStudioVersion = 16.0.29001.49 VisualStudioVersion = 17.0.31410.414
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Terminal", "Terminal", "{59840756-302F-44DF-AA47-441A9D673202}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Terminal", "Terminal", "{59840756-302F-44DF-AA47-441A9D673202}"
EndProject EndProject
@ -131,6 +131,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Scratch", "src\tools\scratc
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InteractivityWin32", "src\interactivity\win32\lib\win32.LIB.vcxproj", "{06EC74CB-9A12-429C-B551-8532EC964726}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InteractivityWin32", "src\interactivity\win32\lib\win32.LIB.vcxproj", "{06EC74CB-9A12-429C-B551-8532EC964726}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
{8222900C-8B6C-452A-91AC-BE95DB04B95F} = {8222900C-8B6C-452A-91AC-BE95DB04B95F}
{1C959542-BAC2-4E55-9A6D-13251914CBB9} = {1C959542-BAC2-4E55-9A6D-13251914CBB9} {1C959542-BAC2-4E55-9A6D-13251914CBB9} = {1C959542-BAC2-4E55-9A6D-13251914CBB9}
{990F2657-8580-4828-943F-5DD657D11842} = {990F2657-8580-4828-943F-5DD657D11842} {990F2657-8580-4828-943F-5DD657D11842} = {990F2657-8580-4828-943F-5DD657D11842}
{AF0A096A-8B3A-4949-81EF-7DF8F0FEE91F} = {AF0A096A-8B3A-4949-81EF-7DF8F0FEE91F} {AF0A096A-8B3A-4949-81EF-7DF8F0FEE91F} = {AF0A096A-8B3A-4949-81EF-7DF8F0FEE91F}
@ -400,6 +401,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsTerminal.UIA.Tests",
EndProject 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}" 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 EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RendererAtlas", "src\renderer\atlas\atlas.vcxproj", "{8222900C-8B6C-452A-91AC-BE95DB04B95F}"
EndProject
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "HostPackage", "src\host\HostPackage\HostPackage.wapproj", "{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenConsoleShellExt", "src\host\ShellExtension\OpenConsoleShellExt.vcxproj", "{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
AuditMode|Any CPU = AuditMode|Any CPU AuditMode|Any CPU = AuditMode|Any CPU
@ -3339,6 +3346,170 @@ Global
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x64.Build.0 = Release|x64 {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.ActiveCfg = Release|Win32
{9CF74355-F018-4C19-81AD-9DC6B7F2C6F5}.Release|x86.Build.0 = 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
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|Any CPU.ActiveCfg = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|Any CPU.Build.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|Any CPU.Deploy.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|ARM.ActiveCfg = Debug|ARM
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|ARM.Build.0 = Debug|ARM
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|ARM.Deploy.0 = Debug|ARM
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|ARM64.ActiveCfg = Debug|ARM64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|ARM64.Build.0 = Debug|ARM64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|ARM64.Deploy.0 = Debug|ARM64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|DotNet_x64Test.ActiveCfg = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|DotNet_x64Test.Build.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|DotNet_x64Test.Deploy.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|DotNet_x86Test.ActiveCfg = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|DotNet_x86Test.Build.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|DotNet_x86Test.Deploy.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|x64.ActiveCfg = Debug|x64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|x64.Build.0 = Debug|x64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|x64.Deploy.0 = Debug|x64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|x86.ActiveCfg = Debug|x86
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|x86.Build.0 = Debug|x86
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.AuditMode|x86.Deploy.0 = Debug|x86
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|ARM.ActiveCfg = Debug|ARM
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|ARM.Build.0 = Debug|ARM
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|ARM.Deploy.0 = Debug|ARM
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|ARM64.ActiveCfg = Debug|ARM64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|ARM64.Build.0 = Debug|ARM64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|ARM64.Deploy.0 = Debug|ARM64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|DotNet_x64Test.ActiveCfg = Debug|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|DotNet_x64Test.Build.0 = Debug|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|DotNet_x64Test.Deploy.0 = Debug|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|DotNet_x86Test.ActiveCfg = Debug|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|DotNet_x86Test.Build.0 = Debug|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|DotNet_x86Test.Deploy.0 = Debug|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|x64.ActiveCfg = Debug|x64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|x64.Build.0 = Debug|x64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|x64.Deploy.0 = Debug|x64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|x86.ActiveCfg = Debug|x86
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|x86.Build.0 = Debug|x86
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Debug|x86.Deploy.0 = Debug|x86
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|Any CPU.ActiveCfg = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|Any CPU.Build.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|Any CPU.Deploy.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|ARM.ActiveCfg = Debug|ARM
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|ARM.Build.0 = Debug|ARM
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|ARM.Deploy.0 = Debug|ARM
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|ARM64.ActiveCfg = Debug|ARM64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|ARM64.Build.0 = Debug|ARM64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|ARM64.Deploy.0 = Debug|ARM64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|DotNet_x64Test.ActiveCfg = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|DotNet_x64Test.Build.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|DotNet_x64Test.Deploy.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|DotNet_x86Test.ActiveCfg = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|DotNet_x86Test.Build.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|DotNet_x86Test.Deploy.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|x64.ActiveCfg = Debug|x64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|x64.Build.0 = Debug|x64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|x64.Deploy.0 = Debug|x64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|x86.ActiveCfg = Debug|x86
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|x86.Build.0 = Debug|x86
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Fuzzing|x86.Deploy.0 = Debug|x86
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|Any CPU.Build.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|Any CPU.Deploy.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|ARM.ActiveCfg = Release|ARM
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|ARM.Build.0 = Release|ARM
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|ARM.Deploy.0 = Release|ARM
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|ARM64.ActiveCfg = Release|ARM64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|ARM64.Build.0 = Release|ARM64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|ARM64.Deploy.0 = Release|ARM64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|DotNet_x64Test.ActiveCfg = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|DotNet_x64Test.Build.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|DotNet_x64Test.Deploy.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|DotNet_x86Test.ActiveCfg = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|DotNet_x86Test.Build.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|DotNet_x86Test.Deploy.0 = Release|Any CPU
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|x64.ActiveCfg = Release|x64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|x64.Build.0 = Release|x64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|x64.Deploy.0 = Release|x64
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|x86.ActiveCfg = Release|x86
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|x86.Build.0 = Release|x86
{44D35904-4DC6-4EEC-86F2-6E3E341C95BE}.Release|x86.Deploy.0 = Release|x86
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.AuditMode|Any CPU.ActiveCfg = AuditMode|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.AuditMode|ARM.ActiveCfg = AuditMode|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.AuditMode|ARM64.ActiveCfg = AuditMode|ARM64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.AuditMode|ARM64.Build.0 = AuditMode|ARM64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.AuditMode|DotNet_x64Test.ActiveCfg = AuditMode|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.AuditMode|DotNet_x86Test.ActiveCfg = AuditMode|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.AuditMode|x64.ActiveCfg = AuditMode|x64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.AuditMode|x64.Build.0 = AuditMode|x64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.AuditMode|x86.ActiveCfg = AuditMode|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.AuditMode|x86.Build.0 = AuditMode|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Debug|Any CPU.ActiveCfg = Debug|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Debug|ARM.ActiveCfg = Debug|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Debug|ARM64.ActiveCfg = Debug|ARM64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Debug|ARM64.Build.0 = Debug|ARM64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Debug|DotNet_x64Test.ActiveCfg = Debug|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Debug|DotNet_x86Test.ActiveCfg = Debug|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Debug|x64.ActiveCfg = Debug|x64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Debug|x64.Build.0 = Debug|x64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Debug|x86.ActiveCfg = Debug|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Debug|x86.Build.0 = Debug|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Fuzzing|Any CPU.ActiveCfg = Fuzzing|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Fuzzing|ARM.ActiveCfg = Fuzzing|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Fuzzing|ARM64.ActiveCfg = Fuzzing|ARM64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Fuzzing|ARM64.Build.0 = Fuzzing|ARM64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Fuzzing|DotNet_x64Test.ActiveCfg = Fuzzing|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Fuzzing|DotNet_x86Test.ActiveCfg = Fuzzing|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Fuzzing|x64.ActiveCfg = Fuzzing|x64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Fuzzing|x64.Build.0 = Fuzzing|x64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Fuzzing|x86.ActiveCfg = Fuzzing|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Fuzzing|x86.Build.0 = Fuzzing|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Release|Any CPU.ActiveCfg = Release|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Release|ARM.ActiveCfg = Release|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Release|ARM64.ActiveCfg = Release|ARM64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Release|ARM64.Build.0 = Release|ARM64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Release|DotNet_x64Test.ActiveCfg = Release|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Release|DotNet_x86Test.ActiveCfg = Release|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Release|x64.ActiveCfg = Release|x64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Release|x64.Build.0 = Release|x64
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Release|x86.ActiveCfg = Release|Win32
{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}.Release|x86.Build.0 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -3438,6 +3609,9 @@ Global
{C323DAEE-B307-4C7B-ACE5-7293CBEFCB5B} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E} {C323DAEE-B307-4C7B-ACE5-7293CBEFCB5B} = {BDB237B6-1D1D-400F-84CC-40A58FA59C8E}
{F19DACD5-0C6E-40DC-B6E4-767A3200542C} = {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} {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 EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3140B1B7-C8EE-43D1-A772-D82A7061A271} 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

@ -17,8 +17,8 @@
// Note: will through if unable to allocate char/attribute buffers // Note: will through if unable to allocate char/attribute buffers
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 26447) // small_vector's constructor says it can throw but it should not given how we use it. This suppresses this error for the AuditMode build. #pragma warning(disable : 26447) // small_vector's constructor says it can throw but it should not given how we use it. This suppresses this error for the AuditMode build.
CharRow::CharRow(size_t rowWidth, ROW* const pParent) noexcept : CharRow::CharRow(CharRowCell* buffer, size_t rowWidth, ROW* const pParent) noexcept :
_data(rowWidth, value_type()), _data(buffer, rowWidth),
_pParent{ FAIL_FAST_IF_NULL(pParent) } _pParent{ FAIL_FAST_IF_NULL(pParent) }
{ {
} }
@ -53,38 +53,9 @@ void CharRow::Reset() noexcept
// - resizes the width of the CharRowBase // - resizes the width of the CharRowBase
// Arguments: // Arguments:
// - newSize - the new width of the character and attributes rows // - newSize - the new width of the character and attributes rows
// Return Value: void CharRow::Resize(CharRowCell* buffer, const size_t newSize) noexcept
// - S_OK on success, otherwise relevant error code
[[nodiscard]] HRESULT CharRow::Resize(const size_t newSize) noexcept
{ {
try _data = { buffer, newSize };
{
const value_type insertVals;
_data.resize(newSize, insertVals);
}
CATCH_RETURN();
return S_OK;
}
typename CharRow::iterator CharRow::begin() noexcept
{
return _data.begin();
}
typename CharRow::const_iterator CharRow::cbegin() const noexcept
{
return _data.cbegin();
}
typename CharRow::iterator CharRow::end() noexcept
{
return _data.end();
}
typename CharRow::const_iterator CharRow::cend() const noexcept
{
return _data.cend();
} }
// Routine Description: // Routine Description:
@ -95,12 +66,16 @@ typename CharRow::const_iterator CharRow::cend() const noexcept
// - The calculated left boundary of the internal string. // - The calculated left boundary of the internal string.
size_t CharRow::MeasureLeft() const noexcept size_t CharRow::MeasureLeft() const noexcept
{ {
const_iterator it = _data.cbegin(); const auto beg = _data.begin();
while (it != _data.cend() && it->IsSpace()) const auto end = _data.end();
auto it = beg;
while (it != end && it->IsSpace())
{ {
++it; ++it;
} }
return it - _data.cbegin();
return it - beg;
} }
// Routine Description: // Routine Description:
@ -111,17 +86,21 @@ size_t CharRow::MeasureLeft() const noexcept
// - The calculated right boundary of the internal string. // - The calculated right boundary of the internal string.
size_t CharRow::MeasureRight() const size_t CharRow::MeasureRight() const
{ {
const_reverse_iterator it = _data.crbegin(); const auto beg = _data.rbegin();
while (it != _data.crend() && it->IsSpace()) const auto end = _data.rend();
auto it = beg;
while (it != end && it->IsSpace())
{ {
++it; ++it;
} }
return _data.crend() - it;
return end - it;
} }
void CharRow::ClearCell(const size_t column) void CharRow::ClearCell(const size_t column)
{ {
_data.at(column).Reset(); _data[column].Reset();
} }
// Routine Description: // Routine Description:
@ -132,7 +111,7 @@ void CharRow::ClearCell(const size_t column)
// - True if there is valid text in this row. False otherwise. // - True if there is valid text in this row. False otherwise.
bool CharRow::ContainsText() const noexcept bool CharRow::ContainsText() const noexcept
{ {
for (const value_type& cell : _data) for (const auto& cell : _data)
{ {
if (!cell.IsSpace()) if (!cell.IsSpace())
{ {
@ -151,7 +130,7 @@ bool CharRow::ContainsText() const noexcept
// Note: will throw exception if column is out of bounds // Note: will throw exception if column is out of bounds
const DbcsAttribute& CharRow::DbcsAttrAt(const size_t column) const const DbcsAttribute& CharRow::DbcsAttrAt(const size_t column) const
{ {
return _data.at(column).DbcsAttr(); return _data[column].DbcsAttr();
} }
// Routine Description: // Routine Description:
@ -163,7 +142,7 @@ const DbcsAttribute& CharRow::DbcsAttrAt(const size_t column) const
// Note: will throw exception if column is out of bounds // Note: will throw exception if column is out of bounds
DbcsAttribute& CharRow::DbcsAttrAt(const size_t column) DbcsAttribute& CharRow::DbcsAttrAt(const size_t column)
{ {
return _data.at(column).DbcsAttr(); return _data[column].DbcsAttr();
} }
// Routine Description: // Routine Description:
@ -175,7 +154,7 @@ DbcsAttribute& CharRow::DbcsAttrAt(const size_t column)
// Note: will throw exception if column is out of bounds // Note: will throw exception if column is out of bounds
void CharRow::ClearGlyph(const size_t column) void CharRow::ClearGlyph(const size_t column)
{ {
_data.at(column).EraseChars(); _data[column].EraseChars();
} }
// Routine Description: // Routine Description:

View file

@ -49,15 +49,12 @@ class CharRow final
public: public:
using glyph_type = typename wchar_t; using glyph_type = typename wchar_t;
using value_type = typename CharRowCell; using value_type = typename CharRowCell;
using iterator = typename boost::container::small_vector_base<value_type>::iterator;
using const_iterator = typename boost::container::small_vector_base<value_type>::const_iterator;
using const_reverse_iterator = typename boost::container::small_vector_base<value_type>::const_reverse_iterator;
using reference = typename CharRowCellReference; using reference = typename CharRowCellReference;
CharRow(size_t rowWidth, ROW* const pParent) noexcept; CharRow(CharRowCell* buffer, size_t rowWidth, ROW* const pParent) noexcept;
size_t size() const noexcept; size_t size() const noexcept;
[[nodiscard]] HRESULT Resize(const size_t newSize) noexcept; void Resize(CharRowCell* buffer, const size_t newSize) noexcept;
size_t MeasureLeft() const noexcept; size_t MeasureLeft() const noexcept;
size_t MeasureRight() const; size_t MeasureRight() const;
bool ContainsText() const noexcept; bool ContainsText() const noexcept;
@ -71,14 +68,46 @@ public:
const reference GlyphAt(const size_t column) const; const reference GlyphAt(const size_t column) const;
reference GlyphAt(const size_t column); reference GlyphAt(const size_t column);
// iterators auto begin() noexcept
iterator begin() noexcept; {
const_iterator cbegin() const noexcept; // gsl::span uses strict bounds checking even in Release mode.
const_iterator begin() const noexcept { return cbegin(); } // While this can be useful, not even our STL is that strict.
// --> Reduce iteration overhead in Release by returning pointers.
#ifdef NDEBUG
return _data.data();
#else
return _data.begin();
#endif
}
iterator end() noexcept; auto begin() const noexcept
const_iterator cend() const noexcept; {
const_iterator end() const noexcept { return cend(); } #ifdef NDEBUG
return _data.data();
#else
return _data.begin();
#endif
}
auto end() noexcept
{
#ifdef NDEBUG
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
return _data.data() + _data.size();
#else
return _data.end();
#endif
}
auto end() const noexcept
{
#ifdef NDEBUG
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
return _data.data() + _data.size();
#else
return _data.end();
#endif
}
UnicodeStorage& GetUnicodeStorage() noexcept; UnicodeStorage& GetUnicodeStorage() noexcept;
const UnicodeStorage& GetUnicodeStorage() const noexcept; const UnicodeStorage& GetUnicodeStorage() const noexcept;
@ -96,20 +125,21 @@ private:
protected: protected:
// storage for glyph data and dbcs attributes // storage for glyph data and dbcs attributes
boost::container::small_vector<value_type, 120> _data; gsl::span<CharRowCell> _data;
// ROW that this CharRow belongs to // ROW that this CharRow belongs to
ROW* _pParent; ROW* _pParent;
}; };
template<typename InputIt1, typename InputIt2> template<typename InputIt1, typename InputIt2, typename OutputIt>
void OverwriteColumns(InputIt1 startChars, InputIt1 endChars, InputIt2 startAttrs, CharRow::iterator outIt) void OverwriteColumns(InputIt1 startChars, InputIt1 endChars, InputIt2 startAttrs, OutputIt outIt)
{ {
std::transform(startChars, std::transform(
endChars, startChars,
startAttrs, endChars,
outIt, startAttrs,
[](const wchar_t wch, const DbcsAttribute attr) { outIt,
return CharRow::value_type{ wch, attr }; [](const wchar_t wch, const DbcsAttribute attr) {
}); return CharRow::value_type{ wch, attr };
});
} }

View file

@ -33,7 +33,7 @@ void CharRowCell::Reset() noexcept
// - true if cell contains a space glyph, false otherwise // - true if cell contains a space glyph, false otherwise
bool CharRowCell::IsSpace() const noexcept bool CharRowCell::IsSpace() const noexcept
{ {
return !_attr.IsGlyphStored() && _wch == UNICODE_SPACE; return !_attr.IsGlyphStored() && (_wch == 0 || _wch == UNICODE_SPACE);
} }
// Routine Description: // Routine Description:

View file

@ -50,7 +50,7 @@ public:
friend constexpr bool operator==(const CharRowCell& a, const CharRowCell& b) noexcept; friend constexpr bool operator==(const CharRowCell& a, const CharRowCell& b) noexcept;
private: private:
wchar_t _wch{ UNICODE_SPACE }; wchar_t _wch{};
DbcsAttribute _attr{}; DbcsAttribute _attr{};
}; };

View file

@ -5,6 +5,13 @@
#include "UnicodeStorage.hpp" #include "UnicodeStorage.hpp"
#include "CharRow.hpp" #include "CharRow.hpp"
CharRowCellReference::CharRowCellReference(CharRow& parent, const size_t index) :
_parent{ parent },
_index{ index }
{
Expects(index < parent.size());
}
// Routine Description: // Routine Description:
// - assignment operator. will store extended glyph data in a separate storage location // - assignment operator. will store extended glyph data in a separate storage location
// Arguments: // Arguments:
@ -41,7 +48,7 @@ CharRowCellReference::operator std::wstring_view() const
// - ref to the CharRowCell // - ref to the CharRowCell
CharRowCell& CharRowCellReference::_cellData() CharRowCell& CharRowCellReference::_cellData()
{ {
return _parent._data.at(_index); return til::at(_parent._data, _index);
} }
// Routine Description: // Routine Description:
@ -50,7 +57,7 @@ CharRowCell& CharRowCellReference::_cellData()
// - ref to the CharRowCell // - ref to the CharRowCell
const CharRowCell& CharRowCellReference::_cellData() const const CharRowCell& CharRowCellReference::_cellData() const
{ {
return _parent._data.at(_index); return til::at(_parent._data, _index);
} }
// Routine Description: // Routine Description:

View file

@ -25,11 +25,7 @@ class CharRowCellReference final
public: public:
using const_iterator = const wchar_t*; using const_iterator = const wchar_t*;
CharRowCellReference(CharRow& parent, const size_t index) noexcept : CharRowCellReference(CharRow& parent, const size_t index);
_parent{ parent },
_index{ index }
{
}
~CharRowCellReference() = default; ~CharRowCellReference() = default;
CharRowCellReference(const CharRowCellReference&) noexcept = default; CharRowCellReference(const CharRowCellReference&) noexcept = default;

View file

@ -81,7 +81,7 @@ OutputCellIterator::OutputCellIterator(const CHAR_INFO& charInfo, const size_t f
// - This is an iterator over a range of text only. No color data will be modified as the text is inserted. // - This is an iterator over a range of text only. No color data will be modified as the text is inserted.
// Arguments: // Arguments:
// - utf16Text - UTF-16 text range // - utf16Text - UTF-16 text range
OutputCellIterator::OutputCellIterator(const std::wstring_view utf16Text) : OutputCellIterator::OutputCellIterator(const std::wstring_view utf16Text) noexcept :
_mode(Mode::LooseTextOnly), _mode(Mode::LooseTextOnly),
_currentView(s_GenerateView(utf16Text)), _currentView(s_GenerateView(utf16Text)),
_run(utf16Text), _run(utf16Text),
@ -97,7 +97,7 @@ OutputCellIterator::OutputCellIterator(const std::wstring_view utf16Text) :
// Arguments: // Arguments:
// - utf16Text - UTF-16 text range // - utf16Text - UTF-16 text range
// - attribute - Color to apply over the entire range // - attribute - Color to apply over the entire range
OutputCellIterator::OutputCellIterator(const std::wstring_view utf16Text, const TextAttribute attribute) : OutputCellIterator::OutputCellIterator(const std::wstring_view utf16Text, const TextAttribute attribute) noexcept :
_mode(Mode::Loose), _mode(Mode::Loose),
_currentView(s_GenerateView(utf16Text, attribute)), _currentView(s_GenerateView(utf16Text, attribute)),
_run(utf16Text), _run(utf16Text),
@ -362,7 +362,7 @@ bool OutputCellIterator::_TryMoveTrailing() noexcept
// - view - View representing characters corresponding to a single glyph // - view - View representing characters corresponding to a single glyph
// Return Value: // Return Value:
// - Object representing the view into this cell // - Object representing the view into this cell
OutputCellView OutputCellIterator::s_GenerateView(const std::wstring_view view) OutputCellView OutputCellIterator::s_GenerateView(const std::wstring_view view) noexcept
{ {
return s_GenerateView(view, InvalidTextAttribute, TextAttributeBehavior::Current); return s_GenerateView(view, InvalidTextAttribute, TextAttributeBehavior::Current);
} }
@ -377,8 +377,7 @@ OutputCellView OutputCellIterator::s_GenerateView(const std::wstring_view view)
// - attr - Color attributes to apply to the text // - attr - Color attributes to apply to the text
// Return Value: // Return Value:
// - Object representing the view into this cell // - Object representing the view into this cell
OutputCellView OutputCellIterator::s_GenerateView(const std::wstring_view view, OutputCellView OutputCellIterator::s_GenerateView(const std::wstring_view view, const TextAttribute attr) noexcept
const TextAttribute attr)
{ {
return s_GenerateView(view, attr, TextAttributeBehavior::Stored); return s_GenerateView(view, attr, TextAttributeBehavior::Stored);
} }
@ -394,9 +393,7 @@ OutputCellView OutputCellIterator::s_GenerateView(const std::wstring_view view,
// - behavior - Behavior of the given text attribute (used when writing) // - behavior - Behavior of the given text attribute (used when writing)
// Return Value: // Return Value:
// - Object representing the view into this cell // - Object representing the view into this cell
OutputCellView OutputCellIterator::s_GenerateView(const std::wstring_view view, OutputCellView OutputCellIterator::s_GenerateView(const std::wstring_view view, const TextAttribute attr, const TextAttributeBehavior behavior) noexcept
const TextAttribute attr,
const TextAttributeBehavior behavior)
{ {
const auto glyph = Utf16Parser::ParseNext(view); const auto glyph = Utf16Parser::ParseNext(view);
DbcsAttribute dbcsAttr; DbcsAttribute dbcsAttr;

View file

@ -37,8 +37,8 @@ public:
OutputCellIterator(const TextAttribute& attr, const size_t fillLimit = 0) noexcept; OutputCellIterator(const TextAttribute& attr, const size_t fillLimit = 0) noexcept;
OutputCellIterator(const wchar_t& wch, const TextAttribute& attr, const size_t fillLimit = 0) noexcept; OutputCellIterator(const wchar_t& wch, const TextAttribute& attr, const size_t fillLimit = 0) noexcept;
OutputCellIterator(const CHAR_INFO& charInfo, const size_t fillLimit = 0) noexcept; OutputCellIterator(const CHAR_INFO& charInfo, const size_t fillLimit = 0) noexcept;
OutputCellIterator(const std::wstring_view utf16Text); OutputCellIterator(const std::wstring_view utf16Text) noexcept;
OutputCellIterator(const std::wstring_view utf16Text, const TextAttribute attribute); OutputCellIterator(const std::wstring_view utf16Text, const TextAttribute attribute) noexcept;
OutputCellIterator(const gsl::span<const WORD> legacyAttributes) noexcept; OutputCellIterator(const gsl::span<const WORD> legacyAttributes) noexcept;
OutputCellIterator(const gsl::span<const CHAR_INFO> charInfos) noexcept; OutputCellIterator(const gsl::span<const CHAR_INFO> charInfos) noexcept;
OutputCellIterator(const gsl::span<const OutputCell> cells); OutputCellIterator(const gsl::span<const OutputCell> cells);
@ -100,14 +100,9 @@ private:
bool _TryMoveTrailing() noexcept; bool _TryMoveTrailing() noexcept;
static OutputCellView s_GenerateView(const std::wstring_view view); static OutputCellView s_GenerateView(const std::wstring_view view) noexcept;
static OutputCellView s_GenerateView(const std::wstring_view view, const TextAttribute attr) noexcept;
static OutputCellView s_GenerateView(const std::wstring_view view, static OutputCellView s_GenerateView(const std::wstring_view view, const TextAttribute attr, const TextAttributeBehavior behavior) noexcept;
const TextAttribute attr);
static OutputCellView s_GenerateView(const std::wstring_view view,
const TextAttribute attr,
const TextAttributeBehavior behavior);
static OutputCellView s_GenerateView(const wchar_t& wch) noexcept; static OutputCellView s_GenerateView(const wchar_t& wch) noexcept;
static OutputCellView s_GenerateViewLegacyAttr(const WORD& legacyAttr) noexcept; static OutputCellView s_GenerateViewLegacyAttr(const WORD& legacyAttr) noexcept;

View file

@ -31,7 +31,17 @@ OutputCellView::OutputCellView(const std::wstring_view view,
// TODO: GH 2681 - remove this suppression by reconciling the probably bad design of the iterators that leads to this being required. // TODO: GH 2681 - remove this suppression by reconciling the probably bad design of the iterators that leads to this being required.
[[gsl::suppress(26445)]] const std::wstring_view& OutputCellView::Chars() const noexcept [[gsl::suppress(26445)]] const std::wstring_view& OutputCellView::Chars() const noexcept
{ {
return _view; static constexpr std::wstring_view emptyBufferCell{ L"\0", 1 };
static constexpr std::wstring_view spaceBufferCell{ L" ", 1 };
// The buffer uses virtual memory and rows might not be initialized yet.
// To us they'll appear as if they contain \0, but we don't want to pass that to the renderer.
if (_view != emptyBufferCell)
{
return _view;
}
return spaceBufferCell;
} }
// Routine Description: // Routine Description:

View file

@ -16,10 +16,9 @@
// - pParent - the text buffer that this row belongs to // - pParent - the text buffer that this row belongs to
// Return Value: // Return Value:
// - constructed object // - constructed object
ROW::ROW(const SHORT rowId, const unsigned short rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent) : ROW::ROW(const SHORT rowId, CharRowCell* buffer, const unsigned short rowWidth, const TextAttribute& fillAttribute, TextBuffer* const pParent) :
_id{ rowId }, _id{ rowId },
_rowWidth{ rowWidth }, _charRow{ buffer, rowWidth, this },
_charRow{ rowWidth, this },
_attrRow{ rowWidth, fillAttribute }, _attrRow{ rowWidth, fillAttribute },
_lineRendition{ LineRendition::SingleWidth }, _lineRendition{ LineRendition::SingleWidth },
_wrapForced{ false }, _wrapForced{ false },
@ -34,7 +33,7 @@ ROW::ROW(const SHORT rowId, const unsigned short rowWidth, const TextAttribute f
// - Attr - The default attribute (color) to fill // - Attr - The default attribute (color) to fill
// Return Value: // Return Value:
// - <none> // - <none>
bool ROW::Reset(const TextAttribute Attr) bool ROW::Reset(const TextAttribute& Attr)
{ {
_lineRendition = LineRendition::SingleWidth; _lineRendition = LineRendition::SingleWidth;
_wrapForced = false; _wrapForced = false;
@ -52,26 +51,6 @@ bool ROW::Reset(const TextAttribute Attr)
return true; return true;
} }
// Routine Description:
// - resizes ROW to new width
// Arguments:
// - width - the new width, in cells
// Return Value:
// - S_OK if successful, otherwise relevant error
[[nodiscard]] HRESULT ROW::Resize(const unsigned short width)
{
RETURN_IF_FAILED(_charRow.Resize(width));
try
{
_attrRow.Resize(width);
}
CATCH_RETURN();
_rowWidth = width;
return S_OK;
}
// Routine Description: // Routine Description:
// - clears char data in column in row // - clears char data in column in row
// Arguments: // Arguments:

View file

@ -32,9 +32,9 @@ class TextBuffer;
class ROW final class ROW final
{ {
public: public:
ROW(const SHORT rowId, const unsigned short rowWidth, const TextAttribute fillAttribute, TextBuffer* const pParent); ROW(const SHORT rowId, CharRowCell* buffer, const unsigned short rowWidth, const TextAttribute& fillAttribute, TextBuffer* const pParent);
size_t size() const noexcept { return _rowWidth; } size_t size() const noexcept { return _charRow.size(); }
void SetWrapForced(const bool wrap) noexcept { _wrapForced = wrap; } void SetWrapForced(const bool wrap) noexcept { _wrapForced = wrap; }
bool WasWrapForced() const noexcept { return _wrapForced; } bool WasWrapForced() const noexcept { return _wrapForced; }
@ -54,8 +54,7 @@ public:
SHORT GetId() const noexcept { return _id; } SHORT GetId() const noexcept { return _id; }
void SetId(const SHORT id) noexcept { _id = id; } void SetId(const SHORT id) noexcept { _id = id; }
bool Reset(const TextAttribute Attr); bool Reset(const TextAttribute& Attr);
[[nodiscard]] HRESULT Resize(const unsigned short width);
void ClearColumn(const size_t column); void ClearColumn(const size_t column);
std::wstring GetText() const { return _charRow.GetText(); } std::wstring GetText() const { return _charRow.GetText(); }
@ -74,13 +73,12 @@ private:
CharRow _charRow; CharRow _charRow;
ATTR_ROW _attrRow; ATTR_ROW _attrRow;
LineRendition _lineRendition; LineRendition _lineRendition;
TextBuffer* _pParent; // non ownership pointer
SHORT _id; SHORT _id;
unsigned short _rowWidth;
// Occurs when the user runs out of text in a given row and we're forced to wrap the cursor to the next line // Occurs when the user runs out of text in a given row and we're forced to wrap the cursor to the next line
bool _wrapForced; bool _wrapForced;
// Occurs when the user runs out of text to support a double byte character and we're forced to the next line // Occurs when the user runs out of text to support a double byte character and we're forced to the next line
bool _doubleBytePadded; bool _doubleBytePadded;
TextBuffer* _pParent; // non ownership pointer
}; };
#ifdef UNIT_TESTING #ifdef UNIT_TESTING

View file

@ -85,10 +85,6 @@ public:
friend constexpr bool operator==(const TextAttribute& a, const TextAttribute& b) noexcept; friend constexpr bool operator==(const TextAttribute& a, const TextAttribute& b) noexcept;
friend constexpr bool operator!=(const TextAttribute& a, const TextAttribute& b) noexcept; friend constexpr bool operator!=(const TextAttribute& a, const TextAttribute& b) noexcept;
friend constexpr bool operator==(const TextAttribute& attr, const WORD& legacyAttr) noexcept;
friend constexpr bool operator!=(const TextAttribute& attr, const WORD& legacyAttr) noexcept;
friend constexpr bool operator==(const WORD& legacyAttr, const TextAttribute& attr) noexcept;
friend constexpr bool operator!=(const WORD& legacyAttr, const TextAttribute& attr) noexcept;
bool IsLegacy() const noexcept; bool IsLegacy() const noexcept;
bool IsBold() const noexcept; bool IsBold() const noexcept;

View file

@ -47,7 +47,7 @@ void UnicodeStorage::Erase(const key_type key) noexcept
// - rowMap - A map of the old row IDs to the new row IDs. // - rowMap - A map of the old row IDs to the new row IDs.
// - width - The width of the new row. Remove any items that are beyond the row width. // - width - The width of the new row. Remove any items that are beyond the row width.
// - Use nullopt if we're not resizing the width of the row, just renumbering the rows. // - Use nullopt if we're not resizing the width of the row, just renumbering the rows.
void UnicodeStorage::Remap(const std::unordered_map<SHORT, SHORT>& rowMap, const std::optional<SHORT> width) void UnicodeStorage::Remap(const std::unordered_map<SHORT, SHORT>& rowMap, SHORT width)
{ {
// Make a temporary map to hold all the new row positioning // Make a temporary map to hold all the new row positioning
std::unordered_map<key_type, mapped_type> newMap; std::unordered_map<key_type, mapped_type> newMap;
@ -58,18 +58,10 @@ void UnicodeStorage::Remap(const std::unordered_map<SHORT, SHORT>& rowMap, const
// Extract the old coordinate position // Extract the old coordinate position
const auto oldCoord = pair.first; const auto oldCoord = pair.first;
// Only try to short-circuit based on width if we were told it changed // If the column index is at/beyond the row width, don't bother copying it to the new map.
// by being given a new width value. if (oldCoord.X >= width)
if (width.has_value())
{ {
// Get the column ID continue;
const auto oldColId = oldCoord.X;
// If the column index is at/beyond the row width, don't bother copying it to the new map.
if (oldColId >= width.value())
{
continue;
}
} }
// Get the row ID from the position as that's what we need to remap // Get the row ID from the position as that's what we need to remap

View file

@ -55,7 +55,7 @@ public:
void Erase(const key_type key) noexcept; void Erase(const key_type key) noexcept;
void Remap(const std::unordered_map<SHORT, SHORT>& rowMap, const std::optional<SHORT> width); void Remap(const std::unordered_map<SHORT, SHORT>& rowMap, SHORT width);
private: private:
std::unordered_map<key_type, mapped_type> _map; std::unordered_map<key_type, mapped_type> _map;

View file

@ -31,21 +31,19 @@ TextBuffer::TextBuffer(const COORD screenBufferSize,
const TextAttribute defaultAttributes, const TextAttribute defaultAttributes,
const UINT cursorSize, const UINT cursorSize,
Microsoft::Console::Render::IRenderTarget& renderTarget) : Microsoft::Console::Render::IRenderTarget& renderTarget) :
_firstRow{ 0 },
_currentAttributes{ defaultAttributes }, _currentAttributes{ defaultAttributes },
_cursor{ cursorSize, *this }, _cursor{ cursorSize, *this },
_storage{}, _renderTarget{ renderTarget }
_unicodeStorage{},
_renderTarget{ renderTarget },
_size{},
_currentHyperlinkId{ 1 },
_currentPatternId{ 0 }
{ {
// initialize ROWs _charBuffer = _AllocateCharBuffer(screenBufferSize);
_storage.reserve(static_cast<size_t>(screenBufferSize.Y)); _storage.reserve(static_cast<size_t>(screenBufferSize.Y));
for (size_t i = 0; i < static_cast<size_t>(screenBufferSize.Y); ++i)
auto buffer = _charBuffer.get();
for (SHORT i = 0; i < screenBufferSize.Y; ++i)
{ {
_storage.emplace_back(static_cast<SHORT>(i), screenBufferSize.X, _currentAttributes, this); _storage.emplace_back(i, buffer, screenBufferSize.X, _currentAttributes, this);
buffer += screenBufferSize.X;
} }
_UpdateSize(); _UpdateSize();
@ -83,11 +81,9 @@ UINT TextBuffer::TotalRowCount() const noexcept
// - const reference to the requested row. Asserts if out of bounds. // - const reference to the requested row. Asserts if out of bounds.
const ROW& TextBuffer::GetRowByOffset(const size_t index) const const ROW& TextBuffer::GetRowByOffset(const size_t index) const
{ {
const size_t totalRows = TotalRowCount();
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows. // Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
const size_t offsetIndex = (_firstRow + index) % totalRows; const size_t offsetIndex = (_firstRow + index) % _storage.size();
return _storage.at(offsetIndex); return _storage[offsetIndex];
} }
// Routine Description: // Routine Description:
@ -99,11 +95,9 @@ const ROW& TextBuffer::GetRowByOffset(const size_t index) const
// - reference to the requested row. Asserts if out of bounds. // - reference to the requested row. Asserts if out of bounds.
ROW& TextBuffer::GetRowByOffset(const size_t index) ROW& TextBuffer::GetRowByOffset(const size_t index)
{ {
const size_t totalRows = TotalRowCount();
// Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows. // Rows are stored circularly, so the index you ask for is offset by the start position and mod the total of rows.
const size_t offsetIndex = (_firstRow + index) % totalRows; const size_t offsetIndex = (_firstRow + index) % _storage.size();
return _storage.at(offsetIndex); return _storage[offsetIndex];
} }
// Routine Description: // Routine Description:
@ -400,7 +394,7 @@ OutputCellIterator TextBuffer::WriteLine(const OutputCellIterator givenIt,
//Return Value: //Return Value:
// - true if we successfully inserted the character // - true if we successfully inserted the character
// - false otherwise (out of memory) // - false otherwise (out of memory)
bool TextBuffer::InsertCharacter(const std::wstring_view chars, bool TextBuffer::InsertCharacter(const std::wstring_view& chars,
const DbcsAttribute dbcsAttribute, const DbcsAttribute dbcsAttribute,
const TextAttribute attr) const TextAttribute attr)
{ {
@ -670,6 +664,15 @@ const Viewport TextBuffer::GetSize() const noexcept
return _size; return _size;
} }
wil::unique_virtualalloc_ptr<CharRowCell> TextBuffer::_AllocateCharBuffer(const COORD size)
{
const auto dx = static_cast<size_t>(size.X);
const auto dy = static_cast<size_t>(size.Y);
const auto buffer = static_cast<CharRowCell*>(VirtualAlloc(nullptr, dx * dy * sizeof(CharRowCell), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
THROW_IF_NULL_ALLOC(buffer);
return wil::unique_virtualalloc_ptr<CharRowCell>{ buffer };
}
void TextBuffer::_UpdateSize() void TextBuffer::_UpdateSize()
{ {
_size = Viewport::FromDimensions({ 0, 0 }, { gsl::narrow<SHORT>(_storage.at(0).size()), gsl::narrow<SHORT>(_storage.size()) }); _size = Viewport::FromDimensions({ 0, 0 }, { gsl::narrow<SHORT>(_storage.at(0).size()), gsl::narrow<SHORT>(_storage.size()) });
@ -778,7 +781,7 @@ void TextBuffer::ScrollRows(const SHORT firstRow, const SHORT size, const SHORT
// Renumber the IDs now that we've rearranged where the rows sit within the buffer. // Renumber the IDs now that we've rearranged where the rows sit within the buffer.
// Refreshing should also delegate to the UnicodeStorage to re-key all the stored unicode sequences (where applicable). // Refreshing should also delegate to the UnicodeStorage to re-key all the stored unicode sequences (where applicable).
_RefreshRowIDs(std::nullopt); _RefreshRowIDs(_size.Width());
} }
Cursor& TextBuffer::GetCursor() noexcept Cursor& TextBuffer::GetCursor() noexcept
@ -863,14 +866,14 @@ COORD TextBuffer::ScreenToBufferPosition(const COORD position) const
{ {
// Use shift right to quickly divide the X pos by 2 for double width lines. // Use shift right to quickly divide the X pos by 2 for double width lines.
const SHORT scale = IsDoubleWidthLine(position.Y) ? 1 : 0; const SHORT scale = IsDoubleWidthLine(position.Y) ? 1 : 0;
return { position.X >> scale, position.Y }; return { gsl::narrow_cast<SHORT>(position.X >> scale), position.Y };
} }
COORD TextBuffer::BufferToScreenPosition(const COORD position) const COORD TextBuffer::BufferToScreenPosition(const COORD position) const
{ {
// Use shift left to quickly multiply the X pos by 2 for double width lines. // Use shift left to quickly multiply the X pos by 2 for double width lines.
const SHORT scale = IsDoubleWidthLine(position.Y) ? 1 : 0; const SHORT scale = IsDoubleWidthLine(position.Y) ? 1 : 0;
return { position.X << scale, position.Y }; return { gsl::narrow_cast<SHORT>(position.X << scale), position.Y };
} }
// Routine Description: // Routine Description:
@ -896,49 +899,43 @@ void TextBuffer::Reset()
{ {
RETURN_HR_IF(E_INVALIDARG, newSize.X < 0 || newSize.Y < 0); RETURN_HR_IF(E_INVALIDARG, newSize.X < 0 || newSize.Y < 0);
try auto charBuffer = _AllocateCharBuffer(newSize);
const auto currentSize = GetSize().Dimensions();
const auto attributes = GetCurrentAttributes();
SHORT TopRow = 0; // new top row of the screen buffer
if (newSize.Y <= GetCursor().GetPosition().Y)
{ {
const auto currentSize = GetSize().Dimensions(); TopRow = GetCursor().GetPosition().Y - newSize.Y + 1;
const auto attributes = GetCurrentAttributes();
SHORT TopRow = 0; // new top row of the screen buffer
if (newSize.Y <= GetCursor().GetPosition().Y)
{
TopRow = GetCursor().GetPosition().Y - newSize.Y + 1;
}
const SHORT TopRowIndex = (GetFirstRowIndex() + TopRow) % currentSize.Y;
// rotate rows until the top row is at index 0
for (int i = 0; i < TopRowIndex; i++)
{
_storage.emplace_back(std::move(_storage.front()));
_storage.erase(_storage.begin());
}
_SetFirstRowIndex(0);
// realloc in the Y direction
// remove rows if we're shrinking
while (_storage.size() > static_cast<size_t>(newSize.Y))
{
_storage.pop_back();
}
// add rows if we're growing
while (_storage.size() < static_cast<size_t>(newSize.Y))
{
_storage.emplace_back(static_cast<short>(_storage.size()), newSize.X, attributes, this);
}
// Now that we've tampered with the row placement, refresh all the row IDs.
// Also take advantage of the row ID refresh loop to resize the rows in the X dimension
// and cleanup the UnicodeStorage characters that might fall outside the resized buffer.
_RefreshRowIDs(newSize.X);
// Update the cached size value
_UpdateSize();
} }
CATCH_RETURN(); const SHORT TopRowIndex = (GetFirstRowIndex() + TopRow) % currentSize.Y;
// rotate rows until the top row is at index 0
std::rotate(_storage.begin(), _storage.begin() + TopRowIndex, _storage.end());
_SetFirstRowIndex(0);
// realloc in the Y direction
// remove rows if we're shrinking
while (_storage.size() > static_cast<size_t>(newSize.Y))
{
_storage.pop_back();
}
// add rows if we're growing
while (_storage.size() < static_cast<size_t>(newSize.Y))
{
_storage.emplace_back(static_cast<short>(_storage.size()), nullptr, newSize.X, attributes, this);
}
// Now that we've tampered with the row placement, refresh all the row IDs.
// Also take advantage of the row ID refresh loop to resize the rows in the X dimension
// and cleanup the UnicodeStorage characters that might fall outside the resized buffer.
_RefreshRowIDs(newSize.X);
_RefreshRowWidth(charBuffer.get(), newSize.X);
// Update the cached size value
_UpdateSize();
_charBuffer = std::move(charBuffer);
return S_OK; return S_OK;
} }
@ -961,7 +958,7 @@ UnicodeStorage& TextBuffer::GetUnicodeStorage() noexcept
// any high unicode (UnicodeStorage) runs while we're already looping through the rows. // any high unicode (UnicodeStorage) runs while we're already looping through the rows.
// Arguments: // Arguments:
// - newRowWidth - Optional new value for the row width. // - newRowWidth - Optional new value for the row width.
void TextBuffer::_RefreshRowIDs(std::optional<SHORT> newRowWidth) void TextBuffer::_RefreshRowIDs(SHORT width)
{ {
std::unordered_map<SHORT, SHORT> rowMap; std::unordered_map<SHORT, SHORT> rowMap;
SHORT i = 0; SHORT i = 0;
@ -975,17 +972,19 @@ void TextBuffer::_RefreshRowIDs(std::optional<SHORT> newRowWidth)
// Also update the char row parent pointers as they can get shuffled up in the rotates. // Also update the char row parent pointers as they can get shuffled up in the rotates.
it.GetCharRow().UpdateParent(&it); it.GetCharRow().UpdateParent(&it);
// Resize the rows in the X dimension if we have a new width
if (newRowWidth.has_value())
{
// Realloc in the X direction
THROW_IF_FAILED(it.Resize(newRowWidth.value()));
}
} }
// Give the new mapping to Unicode Storage // Give the new mapping to Unicode Storage
_unicodeStorage.Remap(rowMap, newRowWidth); _unicodeStorage.Remap(rowMap, width);
}
void TextBuffer::_RefreshRowWidth(CharRowCell* data, size_t width) noexcept
{
for (auto& it : _storage)
{
it.GetCharRow().Resize(data, width);
data += width;
}
} }
void TextBuffer::_NotifyPaint(const Viewport& viewport) const void TextBuffer::_NotifyPaint(const Viewport& viewport) const
@ -1044,7 +1043,7 @@ Microsoft::Console::Render::IRenderTarget& TextBuffer::GetRenderTarget() noexcep
// - wordDelimiters: the delimiters defined as a part of the DelimiterClass::DelimiterChar // - wordDelimiters: the delimiters defined as a part of the DelimiterClass::DelimiterChar
// Return Value: // Return Value:
// - the delimiter class for the given char // - the delimiter class for the given char
const DelimiterClass TextBuffer::_GetDelimiterClassAt(const COORD pos, const std::wstring_view wordDelimiters) const const DelimiterClass TextBuffer::_GetDelimiterClassAt(const COORD pos, const std::wstring_view& wordDelimiters) const
{ {
return GetRowByOffset(pos.Y).GetCharRow().DelimiterClassAt(pos.X, wordDelimiters); return GetRowByOffset(pos.Y).GetCharRow().DelimiterClassAt(pos.X, wordDelimiters);
} }
@ -1060,7 +1059,7 @@ const DelimiterClass TextBuffer::_GetDelimiterClassAt(const COORD pos, const std
// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance. // - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance.
// Return Value: // Return Value:
// - The COORD for the first character on the "word" (inclusive) // - The COORD for the first character on the "word" (inclusive)
const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode, std::optional<til::point> limitOptional) const const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view& wordDelimiters, bool accessibilityMode, std::optional<til::point> limitOptional) const
{ {
// Consider a buffer with this text in it: // Consider a buffer with this text in it:
// " word other " // " word other "
@ -1110,7 +1109,7 @@ const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view
// - wordDelimiters - what characters are we considering for the separation of words // - wordDelimiters - what characters are we considering for the separation of words
// Return Value: // Return Value:
// - The COORD for the first character on the current/previous READABLE "word" (inclusive) // - The COORD for the first character on the current/previous READABLE "word" (inclusive)
const COORD TextBuffer::_GetWordStartForAccessibility(const COORD target, const std::wstring_view wordDelimiters) const const COORD TextBuffer::_GetWordStartForAccessibility(const COORD target, const std::wstring_view& wordDelimiters) const
{ {
COORD result = target; COORD result = target;
const auto bufferSize = GetSize(); const auto bufferSize = GetSize();
@ -1155,7 +1154,7 @@ const COORD TextBuffer::_GetWordStartForAccessibility(const COORD target, const
// - wordDelimiters - what characters are we considering for the separation of words // - wordDelimiters - what characters are we considering for the separation of words
// Return Value: // Return Value:
// - The COORD for the first character on the current word or delimiter run (stopped by the left margin) // - The COORD for the first character on the current word or delimiter run (stopped by the left margin)
const COORD TextBuffer::_GetWordStartForSelection(const COORD target, const std::wstring_view wordDelimiters) const const COORD TextBuffer::_GetWordStartForSelection(const COORD target, const std::wstring_view& wordDelimiters) const
{ {
COORD result = target; COORD result = target;
const auto bufferSize = GetSize(); const auto bufferSize = GetSize();
@ -1188,7 +1187,7 @@ const COORD TextBuffer::_GetWordStartForSelection(const COORD target, const std:
// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance. // - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance.
// Return Value: // Return Value:
// - The COORD for the last character on the "word" (inclusive) // - The COORD for the last character on the "word" (inclusive)
const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode, std::optional<til::point> limitOptional) const const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view& wordDelimiters, bool accessibilityMode, std::optional<til::point> limitOptional) const
{ {
// Consider a buffer with this text in it: // Consider a buffer with this text in it:
// " word other " // " word other "
@ -1226,7 +1225,7 @@ const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view w
// - limit - the last "valid" position in the text buffer (to improve performance) // - limit - the last "valid" position in the text buffer (to improve performance)
// Return Value: // Return Value:
// - The COORD for the first character of the next readable "word". If no next word, return one past the end of the buffer // - The COORD for the first character of the next readable "word". If no next word, return one past the end of the buffer
const COORD TextBuffer::_GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD limit) const const COORD TextBuffer::_GetWordEndForAccessibility(const COORD target, const std::wstring_view& wordDelimiters, const COORD limit) const
{ {
const auto bufferSize{ GetSize() }; const auto bufferSize{ GetSize() };
COORD result{ target }; COORD result{ target };
@ -1276,7 +1275,7 @@ const COORD TextBuffer::_GetWordEndForAccessibility(const COORD target, const st
// - wordDelimiters - what characters are we considering for the separation of words // - wordDelimiters - what characters are we considering for the separation of words
// Return Value: // Return Value:
// - The COORD for the last character of the current word or delimiter run (stopped by right margin) // - The COORD for the last character of the current word or delimiter run (stopped by right margin)
const COORD TextBuffer::_GetWordEndForSelection(const COORD target, const std::wstring_view wordDelimiters) const const COORD TextBuffer::_GetWordEndForSelection(const COORD target, const std::wstring_view& wordDelimiters) const
{ {
const auto bufferSize = GetSize(); const auto bufferSize = GetSize();
@ -1359,7 +1358,7 @@ void TextBuffer::_PruneHyperlinks()
// Return Value: // Return Value:
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary) // - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
// - pos - The COORD for the first character on the "word" (inclusive) // - pos - The COORD for the first character on the "word" (inclusive)
bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, std::optional<til::point> limitOptional) const bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view& wordDelimiters, std::optional<til::point> limitOptional) const
{ {
// move to the beginning of the next word // move to the beginning of the next word
// NOTE: _GetWordEnd...() returns the exclusive position of the "end of the word" // NOTE: _GetWordEnd...() returns the exclusive position of the "end of the word"
@ -1385,7 +1384,7 @@ bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view wordDelimite
// Return Value: // Return Value:
// - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary) // - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary)
// - pos - The COORD for the first character on the "word" (inclusive) // - pos - The COORD for the first character on the "word" (inclusive)
bool TextBuffer::MoveToPreviousWord(COORD& pos, std::wstring_view wordDelimiters) const bool TextBuffer::MoveToPreviousWord(COORD& pos, const std::wstring_view& wordDelimiters) const
{ {
// move to the beginning of the current word // move to the beginning of the current word
auto copy{ GetWordStart(pos, wordDelimiters, true) }; auto copy{ GetWordStart(pos, wordDelimiters, true) };
@ -1782,7 +1781,7 @@ const TextBuffer::TextAndColor TextBuffer::GetText(const bool includeCRLF,
// - string containing the generated HTML // - string containing the generated HTML
std::string TextBuffer::GenHTML(const TextAndColor& rows, std::string TextBuffer::GenHTML(const TextAndColor& rows,
const int fontHeightPoints, const int fontHeightPoints,
const std::wstring_view fontFaceName, const std::wstring_view& fontFaceName,
const COLORREF backgroundColor) const COLORREF backgroundColor)
{ {
try try
@ -1845,7 +1844,7 @@ std::string TextBuffer::GenHTML(const TextAndColor& rows,
const auto writeAccumulatedChars = [&](bool includeCurrent) { const auto writeAccumulatedChars = [&](bool includeCurrent) {
if (col >= startOffset) if (col >= startOffset)
{ {
const auto unescapedText = ConvertToA(CP_UTF8, std::wstring_view(rows.text.at(row)).substr(startOffset, col - startOffset + includeCurrent)); const auto unescapedText = ConvertToA(CP_UTF8, rows.text.at(row).substr(startOffset, col - startOffset + includeCurrent));
for (const auto c : unescapedText) for (const auto c : unescapedText)
{ {
switch (c) switch (c)
@ -1971,7 +1970,7 @@ std::string TextBuffer::GenHTML(const TextAndColor& rows,
// - htmlTitle - value used in title tag of html header. Used to name the application // - htmlTitle - value used in title tag of html header. Used to name the application
// Return Value: // Return Value:
// - string containing the generated RTF // - string containing the generated RTF
std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoints, const std::wstring_view fontFaceName, const COLORREF backgroundColor) std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoints, const std::wstring_view& fontFaceName, const COLORREF backgroundColor)
{ {
try try
{ {
@ -2033,7 +2032,7 @@ std::string TextBuffer::GenRTF(const TextAndColor& rows, const int fontHeightPoi
const auto writeAccumulatedChars = [&](bool includeCurrent) { const auto writeAccumulatedChars = [&](bool includeCurrent) {
if (col >= startOffset) if (col >= startOffset)
{ {
const auto unescapedText = ConvertToA(CP_UTF8, std::wstring_view(rows.text.at(row)).substr(startOffset, col - startOffset + includeCurrent)); const auto unescapedText = ConvertToA(CP_UTF8, rows.text.at(row).substr(startOffset, col - startOffset + includeCurrent));
for (const auto c : unescapedText) for (const auto c : unescapedText)
{ {
switch (c) switch (c)
@ -2411,9 +2410,9 @@ HRESULT TextBuffer::Reflow(TextBuffer& oldBuffer,
// - Adds or updates a hyperlink in our hyperlink table // - Adds or updates a hyperlink in our hyperlink table
// Arguments: // Arguments:
// - The hyperlink URI, the hyperlink id (could be new or old) // - The hyperlink URI, the hyperlink id (could be new or old)
void TextBuffer::AddHyperlinkToMap(std::wstring_view uri, uint16_t id) void TextBuffer::AddHyperlinkToMap(const std::wstring_view& uri, uint16_t id)
{ {
_hyperlinkMap[id] = uri; _hyperlinkMap.emplace(id, uri);
} }
// Method Description: // Method Description:
@ -2433,28 +2432,31 @@ std::wstring TextBuffer::GetHyperlinkUriFromId(uint16_t id) const
// - The user-defined id // - The user-defined id
// Return value: // Return value:
// - The internal hyperlink ID // - The internal hyperlink ID
uint16_t TextBuffer::GetHyperlinkId(std::wstring_view uri, std::wstring_view id) uint16_t TextBuffer::GetHyperlinkId(const std::wstring_view& uri, const std::wstring_view& id)
{ {
uint16_t numericId = 0; uint16_t numericId = 0;
if (id.empty()) if (id.empty())
{ {
// no custom id specified, return our internal count // no custom id specified, return our internal count
numericId = _currentHyperlinkId; numericId = _currentHyperlinkId++;
++_currentHyperlinkId;
} }
else else
{ {
// assign _currentHyperlinkId if the custom id does not already exist // We need to use both uri and id for hashing. See GH#7698
std::wstring newId{ id }; std::wstring key;
// hash the URL and add it to the custom ID - GH#7698 key.reserve(uri.size() + id.size());
newId += L"%" + std::to_wstring(std::hash<std::wstring_view>{}(uri)); key.append(uri);
const auto result = _hyperlinkCustomIdMap.emplace(newId, _currentHyperlinkId); key.append(id);
const auto result = _hyperlinkCustomIdMap.emplace(key, _currentHyperlinkId);
numericId = result.first->second;
if (result.second) if (result.second)
{ {
// the custom id did not already exist // the custom id did not already exist
_hyperlinkCustomIdMapReverse.insert_or_assign(_currentHyperlinkId, key);
++_currentHyperlinkId; ++_currentHyperlinkId;
} }
numericId = (*(result.first)).second;
} }
// _currentHyperlinkId could overflow, make sure its not 0 // _currentHyperlinkId could overflow, make sure its not 0
if (_currentHyperlinkId == 0) if (_currentHyperlinkId == 0)
@ -2472,13 +2474,11 @@ uint16_t TextBuffer::GetHyperlinkId(std::wstring_view uri, std::wstring_view id)
void TextBuffer::RemoveHyperlinkFromMap(uint16_t id) noexcept void TextBuffer::RemoveHyperlinkFromMap(uint16_t id) noexcept
{ {
_hyperlinkMap.erase(id); _hyperlinkMap.erase(id);
for (const auto& customIdPair : _hyperlinkCustomIdMap)
if (auto it = _hyperlinkCustomIdMapReverse.find(id); it != _hyperlinkCustomIdMapReverse.end())
{ {
if (customIdPair.second == id) _hyperlinkCustomIdMap.erase(it->second);
{ _hyperlinkCustomIdMapReverse.erase(it);
_hyperlinkCustomIdMap.erase(customIdPair.first);
break;
}
} }
} }
@ -2491,12 +2491,9 @@ void TextBuffer::RemoveHyperlinkFromMap(uint16_t id) noexcept
// - The custom ID if there was one, empty string otherwise // - The custom ID if there was one, empty string otherwise
std::wstring TextBuffer::GetCustomIdFromId(uint16_t id) const std::wstring TextBuffer::GetCustomIdFromId(uint16_t id) const
{ {
for (auto customIdPair : _hyperlinkCustomIdMap) if (auto it = _hyperlinkCustomIdMapReverse.find(id); it != _hyperlinkCustomIdMapReverse.end())
{ {
if (customIdPair.second == id) return it->second;
{
return customIdPair.first;
}
} }
return {}; return {};
} }
@ -2510,6 +2507,7 @@ void TextBuffer::CopyHyperlinkMaps(const TextBuffer& other)
{ {
_hyperlinkMap = other._hyperlinkMap; _hyperlinkMap = other._hyperlinkMap;
_hyperlinkCustomIdMap = other._hyperlinkCustomIdMap; _hyperlinkCustomIdMap = other._hyperlinkCustomIdMap;
_hyperlinkCustomIdMapReverse = other._hyperlinkCustomIdMapReverse;
_currentHyperlinkId = other._currentHyperlinkId; _currentHyperlinkId = other._currentHyperlinkId;
} }
@ -2520,7 +2518,7 @@ void TextBuffer::CopyHyperlinkMaps(const TextBuffer& other)
// - The regex pattern // - The regex pattern
// Return value: // Return value:
// - An ID that the caller should associate with the given pattern // - An ID that the caller should associate with the given pattern
const size_t TextBuffer::AddPatternRecognizer(const std::wstring_view regexString) const size_t TextBuffer::AddPatternRecognizer(const std::wstring_view& regexString)
{ {
++_currentPatternId; ++_currentPatternId;
_idsAndPatterns.emplace(std::make_pair(_currentPatternId, regexString)); _idsAndPatterns.emplace(std::make_pair(_currentPatternId, regexString));

View file

@ -98,7 +98,7 @@ public:
const std::optional<size_t> limitRight = std::nullopt); const std::optional<size_t> limitRight = std::nullopt);
bool InsertCharacter(const wchar_t wch, const DbcsAttribute dbcsAttribute, const TextAttribute attr); bool InsertCharacter(const wchar_t wch, const DbcsAttribute dbcsAttribute, const TextAttribute attr);
bool InsertCharacter(const std::wstring_view chars, const DbcsAttribute dbcsAttribute, const TextAttribute attr); bool InsertCharacter(const std::wstring_view& chars, const DbcsAttribute dbcsAttribute, const TextAttribute attr);
bool IncrementCursor(); bool IncrementCursor();
bool NewlineCursor(); bool NewlineCursor();
@ -141,10 +141,10 @@ public:
Microsoft::Console::Render::IRenderTarget& GetRenderTarget() noexcept; Microsoft::Console::Render::IRenderTarget& GetRenderTarget() noexcept;
const COORD GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const; const COORD GetWordStart(const COORD target, const std::wstring_view& wordDelimiters, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const;
const COORD GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const; const COORD GetWordEnd(const COORD target, const std::wstring_view& wordDelimiters, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const;
bool MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, std::optional<til::point> limitOptional = std::nullopt) const; bool MoveToNextWord(COORD& pos, const std::wstring_view& wordDelimiters, std::optional<til::point> limitOptional = std::nullopt) const;
bool MoveToPreviousWord(COORD& pos, const std::wstring_view wordDelimiters) const; bool MoveToPreviousWord(COORD& pos, const std::wstring_view& wordDelimiters) const;
const til::point GetGlyphStart(const til::point pos, std::optional<til::point> limitOptional = std::nullopt) const; const til::point GetGlyphStart(const til::point pos, std::optional<til::point> limitOptional = std::nullopt) const;
const til::point GetGlyphEnd(const til::point pos, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const; const til::point GetGlyphEnd(const til::point pos, bool accessibilityMode = false, std::optional<til::point> limitOptional = std::nullopt) const;
@ -153,9 +153,9 @@ public:
const std::vector<SMALL_RECT> GetTextRects(COORD start, COORD end, bool blockSelection, bool bufferCoordinates) const; const std::vector<SMALL_RECT> GetTextRects(COORD start, COORD end, bool blockSelection, bool bufferCoordinates) const;
void AddHyperlinkToMap(std::wstring_view uri, uint16_t id); void AddHyperlinkToMap(const std::wstring_view& uri, uint16_t id);
std::wstring GetHyperlinkUriFromId(uint16_t id) const; std::wstring GetHyperlinkUriFromId(uint16_t id) const;
uint16_t GetHyperlinkId(std::wstring_view uri, std::wstring_view id); uint16_t GetHyperlinkId(const std::wstring_view& uri, const std::wstring_view& id);
void RemoveHyperlinkFromMap(uint16_t id) noexcept; void RemoveHyperlinkFromMap(uint16_t id) noexcept;
std::wstring GetCustomIdFromId(uint16_t id) const; std::wstring GetCustomIdFromId(uint16_t id) const;
void CopyHyperlinkMaps(const TextBuffer& OtherBuffer); void CopyHyperlinkMaps(const TextBuffer& OtherBuffer);
@ -176,12 +176,12 @@ public:
static std::string GenHTML(const TextAndColor& rows, static std::string GenHTML(const TextAndColor& rows,
const int fontHeightPoints, const int fontHeightPoints,
const std::wstring_view fontFaceName, const std::wstring_view& fontFaceName,
const COLORREF backgroundColor); const COLORREF backgroundColor);
static std::string GenRTF(const TextAndColor& rows, static std::string GenRTF(const TextAndColor& rows,
const int fontHeightPoints, const int fontHeightPoints,
const std::wstring_view fontFaceName, const std::wstring_view& fontFaceName,
const COLORREF backgroundColor); const COLORREF backgroundColor);
struct PositionInformation struct PositionInformation
@ -195,60 +195,49 @@ public:
const std::optional<Microsoft::Console::Types::Viewport> lastCharacterViewport, const std::optional<Microsoft::Console::Types::Viewport> lastCharacterViewport,
std::optional<std::reference_wrapper<PositionInformation>> positionInfo); std::optional<std::reference_wrapper<PositionInformation>> positionInfo);
const size_t AddPatternRecognizer(const std::wstring_view regexString); const size_t AddPatternRecognizer(const std::wstring_view& regexString);
void ClearPatternRecognizers() noexcept; void ClearPatternRecognizers() noexcept;
void CopyPatterns(const TextBuffer& OtherBuffer); void CopyPatterns(const TextBuffer& OtherBuffer);
interval_tree::IntervalTree<til::point, size_t> GetPatterns(const size_t firstRow, const size_t lastRow) const; interval_tree::IntervalTree<til::point, size_t> GetPatterns(const size_t firstRow, const size_t lastRow) const;
private: private:
static wil::unique_virtualalloc_ptr<CharRowCell> _AllocateCharBuffer(const COORD size);
void _UpdateSize(); void _UpdateSize();
Microsoft::Console::Types::Viewport _size; void _RefreshRowIDs(SHORT width);
std::vector<ROW> _storage; void _RefreshRowWidth(CharRowCell* data, size_t width) noexcept;
Cursor _cursor;
SHORT _firstRow; // indexes top row (not necessarily 0)
TextAttribute _currentAttributes;
// storage location for glyphs that can't fit into the buffer normally
UnicodeStorage _unicodeStorage;
std::unordered_map<uint16_t, std::wstring> _hyperlinkMap;
std::unordered_map<std::wstring, uint16_t> _hyperlinkCustomIdMap;
uint16_t _currentHyperlinkId;
void _RefreshRowIDs(std::optional<SHORT> newRowWidth);
Microsoft::Console::Render::IRenderTarget& _renderTarget;
void _SetFirstRowIndex(const SHORT FirstRowIndex) noexcept; void _SetFirstRowIndex(const SHORT FirstRowIndex) noexcept;
COORD _GetPreviousFromCursor() const; COORD _GetPreviousFromCursor() const;
void _SetWrapOnCurrentRow(); void _SetWrapOnCurrentRow();
void _AdjustWrapOnCurrentRow(const bool fSet); void _AdjustWrapOnCurrentRow(const bool fSet);
void _NotifyPaint(const Microsoft::Console::Types::Viewport& viewport) const; void _NotifyPaint(const Microsoft::Console::Types::Viewport& viewport) const;
// Assist with maintaining proper buffer state for Double Byte character sequences // Assist with maintaining proper buffer state for Double Byte character sequences
bool _PrepareForDoubleByteSequence(const DbcsAttribute dbcsAttribute); bool _PrepareForDoubleByteSequence(const DbcsAttribute dbcsAttribute);
bool _AssertValidDoubleByteSequence(const DbcsAttribute dbcsAttribute); bool _AssertValidDoubleByteSequence(const DbcsAttribute dbcsAttribute);
ROW& _GetFirstRow(); ROW& _GetFirstRow();
ROW& _GetPrevRowNoWrap(const ROW& row); ROW& _GetPrevRowNoWrap(const ROW& row);
void _ExpandTextRow(SMALL_RECT& selectionRow) const; void _ExpandTextRow(SMALL_RECT& selectionRow) const;
const DelimiterClass _GetDelimiterClassAt(const COORD pos, const std::wstring_view& wordDelimiters) const;
const DelimiterClass _GetDelimiterClassAt(const COORD pos, const std::wstring_view wordDelimiters) const; const COORD _GetWordStartForAccessibility(const COORD target, const std::wstring_view& wordDelimiters) const;
const COORD _GetWordStartForAccessibility(const COORD target, const std::wstring_view wordDelimiters) const; const COORD _GetWordStartForSelection(const COORD target, const std::wstring_view& wordDelimiters) const;
const COORD _GetWordStartForSelection(const COORD target, const std::wstring_view wordDelimiters) const; const COORD _GetWordEndForAccessibility(const COORD target, const std::wstring_view& wordDelimiters, const COORD limit) const;
const COORD _GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD limit) const; const COORD _GetWordEndForSelection(const COORD target, const std::wstring_view& wordDelimiters) const;
const COORD _GetWordEndForSelection(const COORD target, const std::wstring_view wordDelimiters) const;
void _PruneHyperlinks(); void _PruneHyperlinks();
Microsoft::Console::Render::IRenderTarget& _renderTarget;
wil::unique_virtualalloc_ptr<CharRowCell> _charBuffer;
std::vector<ROW> _storage;
std::unordered_map<uint16_t, std::wstring> _hyperlinkMap;
std::unordered_map<std::wstring, uint16_t> _hyperlinkCustomIdMap;
std::unordered_map<uint16_t, std::wstring> _hyperlinkCustomIdMapReverse;
std::unordered_map<size_t, std::wstring> _idsAndPatterns; std::unordered_map<size_t, std::wstring> _idsAndPatterns;
size_t _currentPatternId; TextAttribute _currentAttributes;
UnicodeStorage _unicodeStorage;
Cursor _cursor;
Microsoft::Console::Types::Viewport _size;
uint16_t _currentHyperlinkId{ 1 };
size_t _currentPatternId{ 0 };
SHORT _firstRow{ 0 }; // indexes top row (not necessarily 0)
#ifdef UNIT_TESTING #ifdef UNIT_TESTING
friend class TextBufferTests; friend class TextBufferTests;

View file

@ -28,25 +28,6 @@ static constexpr bool _IsMouseMessage(UINT uMsg)
uMsg == WM_MOUSEMOVE || uMsg == WM_MOUSEWHEEL || uMsg == WM_MOUSEHWHEEL; uMsg == WM_MOUSEMOVE || uMsg == WM_MOUSEWHEEL || uMsg == WM_MOUSEHWHEEL;
} }
// Helper static function to ensure that all ambiguous-width glyphs are reported as narrow.
// See microsoft/terminal#2066 for more info.
static bool _IsGlyphWideForceNarrowFallback(const std::wstring_view /* glyph */) noexcept
{
return false; // glyph is not wide.
}
static bool _EnsureStaticInitialization()
{
// use C++11 magic statics to make sure we only do this once.
static bool initialized = []() {
// *** THIS IS A SINGLETON ***
SetGlyphWidthFallback(_IsGlyphWideForceNarrowFallback);
return true;
}();
return initialized;
}
LRESULT CALLBACK HwndTerminal::HwndTerminalWndProc( LRESULT CALLBACK HwndTerminal::HwndTerminalWndProc(
HWND hwnd, HWND hwnd,
UINT uMsg, UINT uMsg,
@ -176,8 +157,6 @@ HwndTerminal::HwndTerminal(HWND parentHwnd) :
_pfnWriteCallback{ nullptr }, _pfnWriteCallback{ nullptr },
_multiClickTime{ 500 } // this will be overwritten by the windows system double-click time _multiClickTime{ 500 } // this will be overwritten by the windows system double-click time
{ {
_EnsureStaticInitialization();
HINSTANCE hInstance = wil::GetModuleInstanceHandle(); HINSTANCE hInstance = wil::GetModuleInstanceHandle();
if (RegisterTermClass(hInstance)) if (RegisterTermClass(hInstance))
@ -220,7 +199,6 @@ HRESULT HwndTerminal::Initialize()
auto dxEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>(); auto dxEngine = std::make_unique<::Microsoft::Console::Render::DxEngine>();
RETURN_IF_FAILED(dxEngine->SetHwnd(_hwnd.get())); RETURN_IF_FAILED(dxEngine->SetHwnd(_hwnd.get()));
RETURN_IF_FAILED(dxEngine->Enable());
_renderer->AddRenderEngine(dxEngine.get()); _renderer->AddRenderEngine(dxEngine.get());
_UpdateFont(USER_DEFAULT_SCREEN_DPI); _UpdateFont(USER_DEFAULT_SCREEN_DPI);

View file

@ -35,25 +35,6 @@ constexpr const auto UpdatePatternLocationsInterval = std::chrono::milliseconds(
namespace winrt::Microsoft::Terminal::Control::implementation namespace winrt::Microsoft::Terminal::Control::implementation
{ {
// Helper static function to ensure that all ambiguous-width glyphs are reported as narrow.
// See microsoft/terminal#2066 for more info.
static bool _IsGlyphWideForceNarrowFallback(const std::wstring_view /* glyph */)
{
return false; // glyph is not wide.
}
static bool _EnsureStaticInitialization()
{
// use C++11 magic statics to make sure we only do this once.
static bool initialized = []() {
// *** THIS IS A SINGLETON ***
SetGlyphWidthFallback(_IsGlyphWideForceNarrowFallback);
return true;
}();
return initialized;
}
ControlCore::ControlCore(IControlSettings settings, ControlCore::ControlCore(IControlSettings settings,
TerminalConnection::ITerminalConnection connection) : TerminalConnection::ITerminalConnection connection) :
_connection{ connection }, _connection{ connection },
@ -61,8 +42,6 @@ namespace winrt::Microsoft::Terminal::Control::implementation
_desiredFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, { 0, DEFAULT_FONT_SIZE }, CP_UTF8 }, _desiredFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, { 0, DEFAULT_FONT_SIZE }, CP_UTF8 },
_actualFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, { 0, DEFAULT_FONT_SIZE }, CP_UTF8, false } _actualFont{ DEFAULT_FONT_FACE, 0, DEFAULT_FONT_WEIGHT, { 0, DEFAULT_FONT_SIZE }, CP_UTF8, false }
{ {
_EnsureStaticInitialization();
_terminal = std::make_unique<::Microsoft::Terminal::Core::Terminal>(); _terminal = std::make_unique<::Microsoft::Terminal::Core::Terminal>();
// Subscribe to the connection's disconnected event and call our connection closed handlers. // Subscribe to the connection's disconnected event and call our connection closed handlers.

View file

@ -19,6 +19,7 @@
#include "ControlCore.g.h" #include "ControlCore.g.h"
#include "../../renderer/base/Renderer.hpp" #include "../../renderer/base/Renderer.hpp"
#include "../../renderer/dx/DxRenderer.hpp" #include "../../renderer/dx/DxRenderer.hpp"
#include "../../renderer/atlas/AtlasEngine.h"
#include "../../renderer/uia/UiaRenderer.hpp" #include "../../renderer/uia/UiaRenderer.hpp"
#include "../../cascadia/TerminalCore/Terminal.hpp" #include "../../cascadia/TerminalCore/Terminal.hpp"
#include "../buffer/out/search.h" #include "../buffer/out/search.h"

View file

@ -147,6 +147,7 @@
<ProjectReference Include="..\..\types\lib\types.vcxproj" /> <ProjectReference Include="..\..\types\lib\types.vcxproj" />
<ProjectReference Include="..\..\buffer\out\lib\bufferout.vcxproj" /> <ProjectReference Include="..\..\buffer\out\lib\bufferout.vcxproj" />
<ProjectReference Include="$(OpenConsoleDir)src\renderer\base\lib\base.vcxproj" /> <ProjectReference Include="$(OpenConsoleDir)src\renderer\base\lib\base.vcxproj" />
<ProjectReference Include="$(OpenConsoleDir)src\renderer\atlas\atlas.vcxproj" />
<ProjectReference Include="..\..\renderer\dx\lib\dx.vcxproj" /> <ProjectReference Include="..\..\renderer\dx\lib\dx.vcxproj" />
<ProjectReference Include="..\..\renderer\uia\lib\uia.vcxproj" /> <ProjectReference Include="..\..\renderer\uia\lib\uia.vcxproj" />
<ProjectReference Include="..\..\terminal\parser\lib\parser.vcxproj" /> <ProjectReference Include="..\..\terminal\parser\lib\parser.vcxproj" />

View file

@ -51,6 +51,10 @@
#include <winrt/Microsoft.Terminal.TerminalConnection.h> #include <winrt/Microsoft.Terminal.TerminalConnection.h>
#include <winrt/Microsoft.Terminal.Core.h> #include <winrt/Microsoft.Terminal.Core.h>
#include <d3d11_1.h>
#include <dxgi1_3.h>
#include <dcomp.h>
#include <windows.ui.xaml.media.dxinterop.h> #include <windows.ui.xaml.media.dxinterop.h>
#include <TraceLoggingProvider.h> #include <TraceLoggingProvider.h>

View file

@ -37,6 +37,9 @@
<ProjectReference Include="$(OpenConsoleDir)src\terminal\parser\lib\parser.vcxproj"> <ProjectReference Include="$(OpenConsoleDir)src\terminal\parser\lib\parser.vcxproj">
<Project>{3ae13314-1939-4dfa-9c14-38ca0834050c}</Project> <Project>{3ae13314-1939-4dfa-9c14-38ca0834050c}</Project>
</ProjectReference> </ProjectReference>
<ProjectReference Include="$(OpenConsoleDir)src\renderer\atlas\atlas.vcxproj">
<Project>{21d07cec-24b8-458f-bc34-0866833c60b6}</Project>
</ProjectReference>
<ProjectReference Include="$(OpenConsoleDir)src\renderer\dx\lib\dx.vcxproj"> <ProjectReference Include="$(OpenConsoleDir)src\renderer\dx\lib\dx.vcxproj">
<Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project> <Project>{48d21369-3d7b-4431-9967-24e81292cf62}</Project>
</ProjectReference> </ProjectReference>

View file

@ -112,7 +112,7 @@
<SDLCheck>true</SDLCheck> <SDLCheck>true</SDLCheck>
<PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile> <PrecompiledHeaderFile>precomp.h</PrecompiledHeaderFile>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <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> <MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild> <MinimalRebuild>false</MinimalRebuild>
<RuntimeTypeInfo>false</RuntimeTypeInfo> <RuntimeTypeInfo>false</RuntimeTypeInfo>
@ -174,6 +174,11 @@
<!-- For Win32 (x86) ONLY ... we use all defaults for AMD64. No def for those. --> <!-- For Win32 (x86) ONLY ... we use all defaults for AMD64. No def for those. -->
<ItemDefinitionGroup Condition="'$(Platform)'=='Win32'"> <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
<ClCompile> <ClCompile>
<!--
KB4103718 dropped support for x86 CPUs without SSE2 on Windows 7 in 2018.
But this only affects Pentium III and older, which I'm sure can't even run VS 2019.
-->
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
<PreprocessorDefinitions>WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
</ItemDefinitionGroup> </ItemDefinitionGroup>

View file

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '15.0'">
<VisualStudioVersion>15.0</VisualStudioVersion>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x86">
<Configuration>Debug</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x86">
<Configuration>Release</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|AnyCPU">
<Configuration>Debug</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|AnyCPU">
<Configuration>Release</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup>
<WapProjPath Condition="'$(WapProjPath)'==''">$(MSBuildExtensionsPath)\Microsoft\DesktopBridge\</WapProjPath>
</PropertyGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.props" />
<PropertyGroup>
<ProjectGuid>44d35904-4dc6-4eec-86f2-6e3e341c95be</ProjectGuid>
<TargetPlatformVersion>10.0.20348.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.20348.0</TargetPlatformMinVersion>
<DefaultLanguage>en-US</DefaultLanguage>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
<EntryPointProjectUniqueName>..\exe\Host.EXE.vcxproj</EntryPointProjectUniqueName>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxAutoIncrementPackageRevision>False</AppxAutoIncrementPackageRevision>
<AppxSymbolPackageEnabled>False</AppxSymbolPackageEnabled>
<GenerateTestArtifacts>True</GenerateTestArtifacts>
<AppxBundlePlatforms>x64</AppxBundlePlatforms>
<HoursBetweenUpdateChecks>0</HoursBetweenUpdateChecks>
<PackageCertificateKeyFile>HostPackage_TemporaryKey.pfx</PackageCertificateKeyFile>
<AppxPackageSigningTimestampDigestAlgorithm>SHA256</AppxPackageSigningTimestampDigestAlgorithm>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AppxBundle>Always</AppxBundle>
</PropertyGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup>
<Content Include="Images\Square150x150Logo.scale-200.png" />
<Content Include="Images\Square44x44Logo.scale-200.png" />
</ItemGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
<ItemGroup>
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22414.2000-preview.rs-prerelease" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\exe\Host.EXE.vcxproj" />
<ProjectReference Include="..\ShellExtension\OpenConsoleShellExt.vcxproj" />
</ItemGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
IgnorableNamespaces="uap rescap uap3">
<Identity
Name="OpenConsole"
Publisher="CN=lhecker"
Version="1.0.0.0" />
<Properties>
<DisplayName>OpenConsole</DisplayName>
<PublisherDisplayName>lhecker</PublisherDisplayName>
<Logo></Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.0" MaxVersionTested="10.0.14393.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="OpenConsole"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png" Description="OpenConsole">
</uap:VisualElements>
<Extensions>
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:SurrogateServer DisplayName="OpenConsoleShellExt">
<com:Class Id="74cd627e-aad1-4ee4-9427-7c4db186ee59" Path="OpenConsoleShellExt\OpenConsoleShellExt.dll" ThreadingModel="STA"/>
</com:SurrogateServer>
</com:ComServer>
</com:Extension>
<desktop4:Extension Category="windows.fileExplorerContextMenus">
<desktop4:FileExplorerContextMenus>
<desktop5:ItemType Type="Directory">
<desktop5:Verb Id="OpenTerminalHere" Clsid="74cd627e-aad1-4ee4-9427-7c4db186ee59" />
</desktop5:ItemType>
<desktop5:ItemType Type="Directory\Background">
<desktop5:Verb Id="OpenTerminalHere" Clsid="74cd627e-aad1-4ee4-9427-7c4db186ee59" />
</desktop5:ItemType>
</desktop4:FileExplorerContextMenus>
</desktop4:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>

View file

@ -0,0 +1,4 @@
EXPORTS
DllCanUnloadNow PRIVATE
DllGetActivationFactory PRIVATE
DllGetClassObject PRIVATE

View file

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>{B321ECD6-18E2-4F07-BFB0-B63750CE0CBD}</ProjectGuid>
<ProjectName>OpenConsoleShellExt</ProjectName>
<RootNamespace>OpenConsole.ShellExtension</RootNamespace>
<!-- cppwinrt.build.pre.props depends on these settings: -->
<!-- build a dll, not exe (Application) -->
<ConfigurationType>DynamicLibrary</ConfigurationType>
<SubSystem>Console</SubSystem>
<!-- suppress a bunch of Windows Universal properties from cppwinrt.props -->
<OpenConsoleUniversalApp>false</OpenConsoleUniversalApp>
</PropertyGroup>
<Import Project="$(SolutionDir)src\cppwinrt.build.pre.props" />
<ItemGroup>
<ClInclude Include="OpenTerminalHere.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="OpenTerminalHere.cpp" />
<ClCompile Include="dllmain.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="$(ProjectName).def" />
</ItemGroup>
<!-- ========================= Project References ======================== -->
<Import Project="$(SolutionDir)src\cppwinrt.build.post.props" />
<ItemDefinitionGroup>
<Link>
<AdditionalDependencies>user32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
</ItemDefinitionGroup>
<!-- Override GetPackagingOutputs to roll up our DLL.
This is a heavily stripped version of the one in Microsoft.*.AppxPackage.targets.
-->
<PropertyGroup>
<_ContinueOnError Condition="'$(BuildingProject)' == 'true'">true</_ContinueOnError>
<_ContinueOnError Condition="'$(BuildingProject)' != 'true'">false</_ContinueOnError>
</PropertyGroup>
<Target Name="GetPackagingOutputs" Returns="@(PackagingOutputs)">
<CallTarget Targets="BuiltProjectOutputGroup">
<Output TaskParameter="TargetOutputs" ItemName="_BuiltProjectOutputGroupOutput" />
</CallTarget>
<ItemGroup>
<_PackagingOutputsUnexpanded Include="%(_BuiltProjectOutputGroupOutput.FinalOutputPath)">
<TargetPath>%(_BuiltProjectOutputGroupOutput.TargetPath)</TargetPath>
<OutputGroup>BuiltProjectOutputGroup</OutputGroup>
<ProjectName>$(ProjectName)</ProjectName>
</_PackagingOutputsUnexpanded>
</ItemGroup>
<CallTarget Targets="DebugSymbolsProjectOutputGroup">
<Output TaskParameter="TargetOutputs" ItemName="_DebugSymbolsProjectOutputGroupOutput" />
</CallTarget>
<ItemGroup>
<_PackagingOutputsUnexpanded Include="%(_DebugSymbolsProjectOutputGroupOutput.FinalOutputPath)">
<OutputGroup>DebugSymbolsProjectOutputGroup</OutputGroup>
<ProjectName>$(ProjectName)</ProjectName>
</_PackagingOutputsUnexpanded>
</ItemGroup>
<ItemGroup>
<PackagingOutputs Include="@(_PackagingOutputsUnexpanded)">
<TargetPath>%(Filename)%(Extension)</TargetPath>
</PackagingOutputs>
</ItemGroup>
</Target>
</Project>

View file

@ -0,0 +1,217 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "OpenTerminalHere.h"
#include <filesystem>
#include <wil/common.h>
#include <wil/stl.h>
#include <wil/win32_helpers.h>
#include <ShlObj_core.h>
#include <shlwapi.h>
#include <winrt/Windows.ApplicationModel.Resources.Core.h>
HRESULT OpenTerminalHere::Invoke(IShellItemArray* psiItemArray, IBindCtx* /*pBindContext*/)
try
{
std::wstring path;
if (psiItemArray == nullptr)
{
path = _GetPathFromExplorer();
if (path.empty())
{
return S_FALSE;
}
}
else
{
DWORD count;
psiItemArray->GetCount(&count);
winrt::com_ptr<IShellItem> psi;
wil::unique_cotaskmem_string pszName;
RETURN_IF_FAILED(psiItemArray->GetItemAt(0, psi.put()));
RETURN_IF_FAILED(psi->GetDisplayName(SIGDN_FILESYSPATH, &pszName));
path = std::wstring{ pszName.get() };
}
// Append a "\." to the given path, so that this will work in "C:\"
path.append(L"\\.");
std::filesystem::path applicationName{ wil::GetModuleFileNameW<std::wstring>(wil::GetModuleInstanceHandle()) };
applicationName.replace_filename(L"..\\Host.EXE\\OpenConsole.exe");
std::wstring commandLine;
commandLine.push_back(L'"');
commandLine.append(applicationName);
commandLine.append(L"\" pwsh.exe");
wil::unique_process_information _piClient;
STARTUPINFOEX siEx{ 0 };
siEx.StartupInfo.cb = sizeof(STARTUPINFOEX);
RETURN_IF_WIN32_BOOL_FALSE(CreateProcessW(
applicationName.c_str(), // lpApplicationName
commandLine.data(),
nullptr, // lpProcessAttributes
nullptr, // lpThreadAttributes
false, // bInheritHandles
EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT, // dwCreationFlags
nullptr, // lpEnvironment
path.data(),
&siEx.StartupInfo, // lpStartupInfo
&_piClient // lpProcessInformation
));
return S_OK;
}
CATCH_RETURN()
HRESULT OpenTerminalHere::GetToolTip(IShellItemArray* /*psiItemArray*/, LPWSTR* ppszInfoTip)
{
*ppszInfoTip = nullptr;
return E_NOTIMPL;
}
HRESULT OpenTerminalHere::GetTitle(IShellItemArray* /*psiItemArray*/, LPWSTR* ppszName)
{
return SHStrDupW(L"Open in OpenConsole", ppszName);
}
HRESULT OpenTerminalHere::GetState(IShellItemArray* /*psiItemArray*/, BOOL /*fOkToBeSlow*/, EXPCMDSTATE* pCmdState)
{
*pCmdState = ECS_ENABLED;
return S_OK;
}
HRESULT OpenTerminalHere::GetIcon(IShellItemArray* /*psiItemArray*/, LPWSTR* ppszIcon)
try
{
std::filesystem::path path{ wil::GetModuleFileNameW<std::wstring>(wil::GetModuleInstanceHandle()) };
path.replace_filename(L"..\\Host.EXE\\OpenConsole.exe,0");
return SHStrDupW(path.c_str(), ppszIcon);
}
CATCH_RETURN();
HRESULT OpenTerminalHere::GetFlags(EXPCMDFLAGS* pFlags)
{
*pFlags = ECF_DEFAULT;
return S_OK;
}
HRESULT OpenTerminalHere::GetCanonicalName(GUID* pguidCommandName)
{
*pguidCommandName = __uuidof(this);
return S_OK;
}
HRESULT OpenTerminalHere::EnumSubCommands(IEnumExplorerCommand** ppEnum)
{
*ppEnum = nullptr;
return E_NOTIMPL;
}
std::wstring OpenTerminalHere::_GetPathFromExplorer() const
{
using namespace std;
using namespace winrt;
wstring path;
HRESULT hr = NOERROR;
auto hwnd = ::GetForegroundWindow();
if (hwnd == nullptr)
{
return path;
}
TCHAR szName[MAX_PATH] = { 0 };
::GetClassName(hwnd, szName, MAX_PATH);
if (0 == StrCmp(szName, L"WorkerW") ||
0 == StrCmp(szName, L"Progman"))
{
//special folder: desktop
hr = ::SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, SHGFP_TYPE_CURRENT, szName);
if (FAILED(hr))
{
return path;
}
path = szName;
return path;
}
if (0 != StrCmp(szName, L"CabinetWClass"))
{
return path;
}
com_ptr<IShellWindows> shell;
try
{
shell = create_instance<IShellWindows>(CLSID_ShellWindows, CLSCTX_ALL);
}
catch (...)
{
//look like try_create_instance is not available no more
}
if (shell == nullptr)
{
return path;
}
com_ptr<IDispatch> disp;
wil::unique_variant variant;
variant.vt = VT_I4;
com_ptr<IWebBrowserApp> browser;
// look for correct explorer window
for (variant.intVal = 0;
shell->Item(variant, disp.put()) == S_OK;
variant.intVal++)
{
com_ptr<IWebBrowserApp> tmp;
if (FAILED(disp->QueryInterface(tmp.put())))
{
disp = nullptr; // get rid of DEBUG non-nullptr warning
continue;
}
HWND tmpHWND = NULL;
hr = tmp->get_HWND(reinterpret_cast<SHANDLE_PTR*>(&tmpHWND));
if (hwnd == tmpHWND)
{
browser = tmp;
disp = nullptr; // get rid of DEBUG non-nullptr warning
break; //found
}
disp = nullptr; // get rid of DEBUG non-nullptr warning
}
if (browser)
{
wil::unique_bstr url;
hr = browser->get_LocationURL(&url);
if (FAILED(hr))
{
return path;
}
wstring sUrl(url.get(), SysStringLen(url.get()));
DWORD size = MAX_PATH;
hr = ::PathCreateFromUrl(sUrl.c_str(), szName, &size, NULL);
if (SUCCEEDED(hr))
{
path = szName;
}
}
return path;
}

View file

@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#pragma once
#include <string>
#include <wrl.h>
#include <ShlObj.h>
using namespace Microsoft::WRL;
struct __declspec(uuid("74cd627e-aad1-4ee4-9427-7c4db186ee59")) OpenTerminalHere : public RuntimeClass<RuntimeClassFlags<ClassicCom | InhibitFtmBase>, IExplorerCommand>
{
#pragma region IExplorerCommand
STDMETHODIMP Invoke(IShellItemArray* psiItemArray, IBindCtx* pBindContext);
STDMETHODIMP GetToolTip(IShellItemArray* psiItemArray, LPWSTR* ppszInfoTip);
STDMETHODIMP GetTitle(IShellItemArray* psiItemArray, LPWSTR* ppszName);
STDMETHODIMP GetState(IShellItemArray* psiItemArray, BOOL fOkToBeSlow, EXPCMDSTATE* pCmdState);
STDMETHODIMP GetIcon(IShellItemArray* psiItemArray, LPWSTR* ppszIcon);
STDMETHODIMP GetFlags(EXPCMDFLAGS* pFlags);
STDMETHODIMP GetCanonicalName(GUID* pguidCommandName);
STDMETHODIMP EnumSubCommands(IEnumExplorerCommand** ppEnum);
#pragma endregion
private:
std::wstring _GetPathFromExplorer() const;
};
CoCreatableClass(OpenTerminalHere);

View file

@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include <wrl/module.h>
using namespace Microsoft::WRL;
__control_entrypoint(DllExport) STDAPI DllCanUnloadNow()
{
return Module<InProc>::GetModule().Terminate() ? S_OK : S_FALSE;
}
STDAPI DllGetActivationFactory(_In_ HSTRING activatableClassId, _COM_Outptr_ IActivationFactory** factory)
{
return Module<InProc>::GetModule().GetActivationFactory(activatableClassId, factory);
}
_Check_return_ STDAPI DllGetClassObject(_In_ REFCLSID rclsid, _In_ REFIID riid, _Outptr_ LPVOID FAR* ppv)
{
return Module<InProc>::GetModule().GetClassObject(rclsid, riid, ppv);
}
STDAPI_(BOOL)
DllMain(_In_opt_ HINSTANCE hinst, DWORD reason, _In_opt_ void*)
{
if (reason == DLL_PROCESS_ATTACH)
{
DisableThreadLibraryCalls(hinst);
}
return TRUE;
}

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Windows.CppWinRT" version="2.0.210309.3" targetFramework="native" />
</packages>

View file

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

View file

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

View file

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

View file

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

View file

@ -186,7 +186,7 @@ public:
bool IsTerminalScrolling() const noexcept; bool IsTerminalScrolling() const noexcept;
void SetTerminalScrolling(const bool terminalScrollingEnabled) noexcept; void SetTerminalScrolling(const bool terminalScrollingEnabled) noexcept;
bool GetUseDx() const noexcept; DWORD GetUseDx() const noexcept;
bool GetCopyColor() const noexcept; bool GetCopyColor() const noexcept;
private: private:
@ -230,7 +230,7 @@ private:
bool _fAutoReturnOnNewline; bool _fAutoReturnOnNewline;
bool _fRenderGridWorldwide; bool _fRenderGridWorldwide;
bool _fScreenReversed; bool _fScreenReversed;
bool _fUseDx; DWORD _fUseDx;
bool _fCopyColor; bool _fCopyColor;
std::array<COLORREF, XTERM_COLOR_TABLE_SIZE> _colorTable; 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, // 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. // 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([renderer = g.pRender](const std::wstring_view& glyph) -> bool {
SetGlyphWidthFallback(pfn); return renderer->IsGlyphWideByFont(glyph);
});
} }
catch (...) 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) if (glyph.size() < 1)
{ {

View file

@ -73,7 +73,8 @@
// Chromium Numerics (safe math) // Chromium Numerics (safe math)
#pragma warning(push) #pragma warning(push)
#pragma warning(disable:4100) // unreferenced parameter #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> #include <base/numerics/safe_math.h>
#pragma warning(pop) #pragma warning(pop)
@ -84,16 +85,15 @@
#define ENABLE_INTSAFE_SIGNED_FUNCTIONS #define ENABLE_INTSAFE_SIGNED_FUNCTIONS
#include <intsafe.h> #include <intsafe.h>
// LibPopCnt - Fast C/C++ bit population count library (on bits in an array)
#include <libpopcnt.h>
// Dynamic Bitset (optional dependency on LibPopCnt for perf at bit counting) // Dynamic Bitset (optional dependency on LibPopCnt for perf at bit counting)
// Variable-size compressed-storage header-only bit flag storage library. // Variable-size compressed-storage header-only bit flag storage library.
#pragma warning(push) #pragma warning(push)
#pragma warning(disable:4702) // unreachable code #pragma warning(disable : 4702) // unreachable code
#include <dynamic_bitset.hpp> #include <dynamic_bitset.hpp>
#pragma warning(pop) #pragma warning(pop)
#include <robin_hood.h>
// {fmt}, a C++20-compatible formatting library // {fmt}, a C++20-compatible formatting library
#include <fmt/format.h> #include <fmt/format.h>
#include <fmt/compile.h> #include <fmt/compile.h>

View file

@ -15,11 +15,11 @@ namespace til // Terminal Implementation Library. Also: "Today I Learned"
class _bitmap_const_iterator class _bitmap_const_iterator
{ {
public: public:
using iterator_category = typename std::input_iterator_tag; using iterator_category = std::input_iterator_tag;
using value_type = typename const til::rectangle; using value_type = const til::rectangle;
using difference_type = typename ptrdiff_t; using difference_type = ptrdiff_t;
using pointer = typename const til::rectangle*; using pointer = const til::rectangle*;
using reference = typename const til::rectangle&; using reference = const til::rectangle&;
_bitmap_const_iterator(const dynamic_bitset<unsigned long long, Allocator>& values, til::rectangle rc, ptrdiff_t pos) : _bitmap_const_iterator(const dynamic_bitset<unsigned long long, Allocator>& values, til::rectangle rc, ptrdiff_t pos) :
_values(values), _values(values),

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

@ -253,12 +253,6 @@ BgfxEngine::BgfxEngine(PVOID SharedViewBase, LONG DisplayHeight, LONG DisplayWid
return S_OK; return S_OK;
} }
[[nodiscard]] HRESULT BgfxEngine::IsGlyphWideByFont(const std::wstring_view /*glyph*/, _Out_ bool* const pResult) noexcept
{
*pResult = false;
return S_OK;
}
// Method Description: // Method Description:
// - Updates the window's title string. // - Updates the window's title string.
// Does nothing for BGFX. // Does nothing for BGFX.

View file

@ -70,7 +70,6 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override; [[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) 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;
protected: protected:
[[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring_view newTitle) noexcept override; [[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring_view newTitle) noexcept override;

View file

@ -30,6 +30,7 @@
#include "../../renderer/gdi/gdirenderer.hpp" #include "../../renderer/gdi/gdirenderer.hpp"
#if TIL_FEATURE_CONHOSTDXENGINE_ENABLED #if TIL_FEATURE_CONHOSTDXENGINE_ENABLED
#include "../../renderer/atlas/AtlasEngine.h"
#include "../../renderer/dx/DxRenderer.hpp" #include "../../renderer/dx/DxRenderer.hpp"
#endif #endif
@ -209,16 +210,18 @@ void Window::_UpdateSystemMetrics() const
// Ensure we have appropriate system metrics before we start constructing the window. // Ensure we have appropriate system metrics before we start constructing the window.
_UpdateSystemMetrics(); _UpdateSystemMetrics();
const bool useDx = pSettings->GetUseDx(); const auto useDx = pSettings->GetUseDx();
GdiEngine* pGdiEngine = nullptr; GdiEngine* pGdiEngine = nullptr;
#if TIL_FEATURE_CONHOSTDXENGINE_ENABLED #if TIL_FEATURE_CONHOSTDXENGINE_ENABLED
[[maybe_unused]] DxEngine* pDxEngine = nullptr; DxEngine* pDxEngine = nullptr;
AtlasEngine* pAtlasEngine = nullptr;
#endif #endif
try try
{ {
#if TIL_FEATURE_CONHOSTDXENGINE_ENABLED switch (useDx)
if (useDx)
{ {
#if TIL_FEATURE_CONHOSTDXENGINE_ENABLED
case 1:
pDxEngine = new DxEngine(); pDxEngine = new DxEngine();
// TODO: MSFT:21255595 make this less gross // TODO: MSFT:21255595 make this less gross
// Manually set the Dx Engine to Hwnd mode. When we're trying to // Manually set the Dx Engine to Hwnd mode. When we're trying to
@ -227,12 +230,16 @@ void Window::_UpdateSystemMetrics() const
// math in the hwnd mode, not the Composition mode. // math in the hwnd mode, not the Composition mode.
THROW_IF_FAILED(pDxEngine->SetHwnd(nullptr)); THROW_IF_FAILED(pDxEngine->SetHwnd(nullptr));
g.pRender->AddRenderEngine(pDxEngine); g.pRender->AddRenderEngine(pDxEngine);
} break;
else case 2:
pAtlasEngine = new AtlasEngine();
g.pRender->AddRenderEngine(pAtlasEngine);
break;
#endif #endif
{ default:
pGdiEngine = new GdiEngine(); pGdiEngine = new GdiEngine();
g.pRender->AddRenderEngine(pGdiEngine); g.pRender->AddRenderEngine(pGdiEngine);
break;
} }
} }
catch (...) catch (...)
@ -242,10 +249,6 @@ void Window::_UpdateSystemMetrics() const
if (NT_SUCCESS(status)) if (NT_SUCCESS(status))
{ {
SCREEN_INFORMATION& siAttached = GetScreenInfo();
siAttached.RefreshFontWithRenderer();
// Save reference to settings // Save reference to settings
_pSettings = pSettings; _pSettings = pSettings;
@ -324,7 +327,7 @@ void Window::_UpdateSystemMetrics() const
_hWnd = hWnd; _hWnd = hWnd;
#if TIL_FEATURE_CONHOSTDXENGINE_ENABLED #if TIL_FEATURE_CONHOSTDXENGINE_ENABLED
if (useDx) if (pDxEngine)
{ {
status = NTSTATUS_FROM_WIN32(HRESULT_CODE((pDxEngine->SetHwnd(hWnd)))); status = NTSTATUS_FROM_WIN32(HRESULT_CODE((pDxEngine->SetHwnd(hWnd))));
@ -333,6 +336,10 @@ void Window::_UpdateSystemMetrics() const
status = NTSTATUS_FROM_WIN32(HRESULT_CODE((pDxEngine->Enable()))); status = NTSTATUS_FROM_WIN32(HRESULT_CODE((pDxEngine->Enable())));
} }
} }
else if (pAtlasEngine)
{
status = NTSTATUS_FROM_WIN32(HRESULT_CODE((pAtlasEngine->SetHwnd(hWnd))));
}
else else
#endif #endif
{ {
@ -362,6 +369,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 // 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 // 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). // sizes, DPI, and non-primary monitors (see MSFT #2367234).
SCREEN_INFORMATION& siAttached = GetScreenInfo();
siAttached.PostUpdateWindowSize(); siAttached.PostUpdateWindowSize();
// Locate window theming modules and try to set the dark mode. // Locate window theming modules and try to set the dark mode.

View file

@ -28,6 +28,7 @@ USE_NATIVE_EH = 1
# Compiler Settings # Compiler Settings
# ------------------------------------- # -------------------------------------
MSC_OPTIMIZATION = /O2
MSC_WARNING_LEVEL = /W4 /WX MSC_WARNING_LEVEL = /W4 /WX
USER_C_FLAGS = $(USER_C_FLAGS) /utf-8 USER_C_FLAGS = $(USER_C_FLAGS) /utf-8
@ -43,12 +44,13 @@ INCLUDES= \
$(INCLUDES); \ $(INCLUDES); \
$(CONSOLE_SRC_PATH)\inc; \ $(CONSOLE_SRC_PATH)\inc; \
$(CONSOLE_SRC_PATH)\..\..\inc; \ $(CONSOLE_SRC_PATH)\..\..\inc; \
$(CONSOLE_SRC_PATH)\..\oss\dynamic_bitset; \ $(CONSOLE_SRC_PATH)\..\oss\boost\boost_1_73_0; \
$(CONSOLE_SRC_PATH)\..\oss\libpopcnt; \
$(CONSOLE_SRC_PATH)\..\oss\chromium; \ $(CONSOLE_SRC_PATH)\..\oss\chromium; \
$(CONSOLE_SRC_PATH)\..\oss\dynamic_bitset; \
$(CONSOLE_SRC_PATH)\..\oss\fmt\include; \ $(CONSOLE_SRC_PATH)\..\oss\fmt\include; \
$(CONSOLE_SRC_PATH)\..\oss\interval_tree; \ $(CONSOLE_SRC_PATH)\..\oss\interval_tree; \
$(CONSOLE_SRC_PATH)\..\oss\boost\boost_1_73_0; \ $(CONSOLE_SRC_PATH)\..\oss\libpopcnt; \
$(CONSOLE_SRC_PATH)\..\oss\robin-hood-hashing; \
$(MINWIN_INTERNAL_PRIV_SDK_INC_PATH_L); \ $(MINWIN_INTERNAL_PRIV_SDK_INC_PATH_L); \
$(MINWIN_RESTRICTED_PRIV_SDK_INC_PATH_L); \ $(MINWIN_RESTRICTED_PRIV_SDK_INC_PATH_L); \
$(MINCORE_INTERNAL_PRIV_SDK_INC_PATH_L); \ $(MINCORE_INTERNAL_PRIV_SDK_INC_PATH_L); \

View file

@ -188,12 +188,13 @@ DWORD GetRegistryValues(
if (pStateInfo == nullptr) if (pStateInfo == nullptr)
{ {
Status = RegistrySerialization::s_QueryValue(hConsoleKey, Status = RegistrySerialization::s_QueryValue(
CONSOLE_REGISTRY_CURRENTPAGE, hConsoleKey,
sizeof(dwValue), CONSOLE_REGISTRY_CURRENTPAGE,
REG_DWORD, sizeof(dwValue),
(PBYTE)&dwValue, REG_DWORD,
nullptr); (PBYTE)&dwValue,
nullptr);
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
dwRet = dwValue; dwRet = dwValue;
@ -211,9 +212,10 @@ DWORD GetRegistryValues(
} }
else else
{ {
Status = RegistrySerialization::s_OpenKey(hConsoleKey, Status = RegistrySerialization::s_OpenKey(
pStateInfo->OriginalTitle, hConsoleKey,
&hTitleKey); pStateInfo->OriginalTitle,
&hTitleKey);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
RegCloseKey(hConsoleKey); RegCloseKey(hConsoleKey);
@ -701,11 +703,12 @@ VOID SetRegistryValues(
// //
// Save the current page. // Save the current page.
// //
LOG_IF_FAILED(RegistrySerialization::s_SetValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_SetValue(
CONSOLE_REGISTRY_CURRENTPAGE, hConsoleKey,
REG_DWORD, CONSOLE_REGISTRY_CURRENTPAGE,
(BYTE*)&dwPage, REG_DWORD,
sizeof(dwPage))); (BYTE*)&dwPage,
sizeof(dwPage)));
// //
// Open the console title subkey unless we're changing the defaults. // Open the console title subkey unless we're changing the defaults.
@ -716,9 +719,10 @@ VOID SetRegistryValues(
} }
else else
{ {
Status = RegistrySerialization::s_CreateKey(hConsoleKey, Status = RegistrySerialization::s_CreateKey(
pStateInfo->OriginalTitle, hConsoleKey,
&hTitleKey); pStateInfo->OriginalTitle,
&hTitleKey);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
RegCloseKey(hConsoleKey); RegCloseKey(hConsoleKey);
@ -732,30 +736,33 @@ VOID SetRegistryValues(
// //
dwValue = pStateInfo->ScreenAttributes; dwValue = pStateInfo->ScreenAttributes;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_FILLATTR, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_FILLATTR,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
dwValue = pStateInfo->PopupAttributes; dwValue = pStateInfo->PopupAttributes;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_POPUPATTR, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_POPUPATTR,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
{ {
dwValue = pStateInfo->ColorTable[i]; dwValue = pStateInfo->ColorTable[i];
if (SUCCEEDED(StringCchPrintf(awchBuffer, ARRAYSIZE(awchBuffer), CONSOLE_REGISTRY_COLORTABLE, i))) if (SUCCEEDED(StringCchPrintf(awchBuffer, ARRAYSIZE(awchBuffer), CONSOLE_REGISTRY_COLORTABLE, i)))
{ {
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
awchBuffer, hTitleKey,
REG_DWORD, awchBuffer,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
} }
} }
@ -764,30 +771,33 @@ VOID SetRegistryValues(
// //
dwValue = pStateInfo->InsertMode; dwValue = pStateInfo->InsertMode;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_INSERTMODE, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_INSERTMODE,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
dwValue = pStateInfo->QuickEdit; dwValue = pStateInfo->QuickEdit;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_QUICKEDIT, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_QUICKEDIT,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
FAIL_FAST_IF(!(OEMCP != 0)); FAIL_FAST_IF(!(OEMCP != 0));
if (g_fEastAsianSystem) if (g_fEastAsianSystem)
{ {
dwValue = (DWORD)pStateInfo->CodePage; dwValue = (DWORD)pStateInfo->CodePage;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_CODEPAGE, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_CODEPAGE,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
} }
// //
@ -796,12 +806,13 @@ VOID SetRegistryValues(
dwValue = MAKELONG(pStateInfo->ScreenBufferSize.X, dwValue = MAKELONG(pStateInfo->ScreenBufferSize.X,
pStateInfo->ScreenBufferSize.Y); pStateInfo->ScreenBufferSize.Y);
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_BUFFERSIZE, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_BUFFERSIZE,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
// //
// Save window size // Save window size
@ -809,12 +820,13 @@ VOID SetRegistryValues(
dwValue = MAKELONG(pStateInfo->WindowSize.X, dwValue = MAKELONG(pStateInfo->WindowSize.X,
pStateInfo->WindowSize.Y); pStateInfo->WindowSize.Y);
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_WINDOWSIZE, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_WINDOWSIZE,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
// //
// Save window position // Save window position
@ -822,18 +834,19 @@ VOID SetRegistryValues(
if (pStateInfo->AutoPosition) if (pStateInfo->AutoPosition)
{ {
LOG_IF_FAILED(RegistrySerialization::s_DeleteValue(hTitleKey, CONSOLE_REGISTRY_WINDOWPOS)); LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_DeleteValue(hTitleKey, CONSOLE_REGISTRY_WINDOWPOS));
} }
else else
{ {
dwValue = MAKELONG(pStateInfo->WindowPosX, dwValue = MAKELONG(pStateInfo->WindowPosX,
pStateInfo->WindowPosY); pStateInfo->WindowPosY);
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_WINDOWPOS, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_WINDOWPOS,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
} }
// //
@ -842,107 +855,120 @@ VOID SetRegistryValues(
dwValue = MAKELONG(pStateInfo->FontSize.X, dwValue = MAKELONG(pStateInfo->FontSize.X,
pStateInfo->FontSize.Y); pStateInfo->FontSize.Y);
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_FONTSIZE, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_FONTSIZE,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
dwValue = pStateInfo->FontFamily; dwValue = pStateInfo->FontFamily;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_FONTFAMILY, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_FONTFAMILY,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
dwValue = pStateInfo->FontWeight; dwValue = pStateInfo->FontWeight;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_FONTWEIGHT, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_FONTWEIGHT,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, sizeof(dwValue)));
hTitleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
CONSOLE_REGISTRY_FACENAME, hConsoleKey,
REG_SZ, hTitleKey,
(BYTE*)(pStateInfo->FaceName), CONSOLE_REGISTRY_FACENAME,
(DWORD)(wcslen(pStateInfo->FaceName) + 1) * sizeof(TCHAR))); REG_SZ,
(BYTE*)(pStateInfo->FaceName),
(DWORD)(wcslen(pStateInfo->FaceName) + 1) * sizeof(TCHAR)));
// //
// Save cursor size // Save cursor size
// //
dwValue = pStateInfo->CursorSize; dwValue = pStateInfo->CursorSize;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_CURSORSIZE, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_CURSORSIZE,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
// //
// Save history buffer size and number // Save history buffer size and number
// //
dwValue = pStateInfo->HistoryBufferSize; dwValue = pStateInfo->HistoryBufferSize;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_HISTORYSIZE, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_HISTORYSIZE,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
dwValue = pStateInfo->NumberOfHistoryBuffers; dwValue = pStateInfo->NumberOfHistoryBuffers;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_HISTORYBUFS, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_HISTORYBUFS,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
dwValue = pStateInfo->HistoryNoDup; dwValue = pStateInfo->HistoryNoDup;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_HISTORYNODUP, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_HISTORYNODUP,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
// Save per-title V2 console state // Save per-title V2 console state
dwValue = pStateInfo->fWrapText; dwValue = pStateInfo->fWrapText;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_LINEWRAP, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_LINEWRAP,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
dwValue = pStateInfo->fFilterOnPaste; dwValue = pStateInfo->fFilterOnPaste;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_FILTERONPASTE, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_FILTERONPASTE,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
dwValue = pStateInfo->fCtrlKeyShortcutsDisabled; dwValue = pStateInfo->fCtrlKeyShortcutsDisabled;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_CTRLKEYSHORTCUTS_DISABLED, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_CTRLKEYSHORTCUTS_DISABLED,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
dwValue = pStateInfo->fLineSelection; dwValue = pStateInfo->fLineSelection;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_LINESELECTION, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_LINESELECTION,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
dwValue = pStateInfo->bWindowTransparency; dwValue = pStateInfo->bWindowTransparency;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_WINDOWALPHA, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_WINDOWALPHA,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
SetGlobalRegistryValues(); SetGlobalRegistryValues();
@ -954,50 +980,56 @@ VOID SetRegistryValues(
{ {
// Save cursor type and color // Save cursor type and color
dwValue = pStateInfo->CursorType; dwValue = pStateInfo->CursorType;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_CURSORTYPE, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_CURSORTYPE,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
dwValue = pStateInfo->CursorColor; dwValue = pStateInfo->CursorColor;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_CURSORCOLOR, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_CURSORCOLOR,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
dwValue = pStateInfo->InterceptCopyPaste; dwValue = pStateInfo->InterceptCopyPaste;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_INTERCEPTCOPYPASTE, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_INTERCEPTCOPYPASTE,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
dwValue = pStateInfo->TerminalScrolling; dwValue = pStateInfo->TerminalScrolling;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_TERMINALSCROLLING, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_TERMINALSCROLLING,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
dwValue = pStateInfo->DefaultForeground; dwValue = pStateInfo->DefaultForeground;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_DEFAULTFOREGROUND, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_DEFAULTFOREGROUND,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
dwValue = pStateInfo->DefaultBackground; dwValue = pStateInfo->DefaultBackground;
LOG_IF_FAILED(RegistrySerialization::s_UpdateValue(hConsoleKey, LOG_IF_NTSTATUS_FAILED(RegistrySerialization::s_UpdateValue(
hTitleKey, hConsoleKey,
CONSOLE_REGISTRY_DEFAULTBACKGROUND, hTitleKey,
REG_DWORD, CONSOLE_REGISTRY_DEFAULTBACKGROUND,
(BYTE*)&dwValue, REG_DWORD,
sizeof(dwValue))); (BYTE*)&dwValue,
sizeof(dwValue)));
} }
// //

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_DEFAULTFOREGROUND, SET_FIELD_AND_SIZE(_DefaultForeground) },
{ _RegPropertyType::Dword, CONSOLE_REGISTRY_DEFAULTBACKGROUND, SET_FIELD_AND_SIZE(_DefaultBackground) }, { _RegPropertyType::Dword, CONSOLE_REGISTRY_DEFAULTBACKGROUND, SET_FIELD_AND_SIZE(_DefaultBackground) },
{ _RegPropertyType::Boolean, CONSOLE_REGISTRY_TERMINALSCROLLING, SET_FIELD_AND_SIZE(_TerminalScrolling) }, { _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) } { _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]] [[nodiscard]]
NTSTATUS RegistrySerialization::s_DeleteValue(const HKEY hKey, _In_ PCWSTR const pwszValueName) 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: // 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() 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 GridLines 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]] ::Microsoft::Console::Types::Viewport GetViewportInCharacters(const ::Microsoft::Console::Types::Viewport& viewInPixels) const noexcept;
[[nodiscard]] ::Microsoft::Console::Types::Viewport GetViewportInPixels(const ::Microsoft::Console::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

@ -7,20 +7,7 @@
#include "../inc/FontInfoBase.hpp" #include "../inc/FontInfoBase.hpp"
bool operator==(const FontInfoBase& a, const FontInfoBase& b) FontInfoBase::FontInfoBase(const std::wstring_view& faceName, const unsigned char family, const unsigned int weight, const bool fSetDefaultRasterFont, const unsigned int codePage) noexcept :
{
return a._faceName == b._faceName &&
a._weight == b._weight &&
a._family == b._family &&
a._codePage == b._codePage &&
a._fDefaultRasterSetFromEngine == b._fDefaultRasterSetFromEngine;
}
FontInfoBase::FontInfoBase(const std::wstring_view faceName,
const unsigned char family,
const unsigned int weight,
const bool fSetDefaultRasterFont,
const unsigned int codePage) :
_faceName(faceName), _faceName(faceName),
_family(family), _family(family),
_weight(weight), _weight(weight),
@ -30,20 +17,16 @@ FontInfoBase::FontInfoBase(const std::wstring_view faceName,
ValidateFont(); ValidateFont();
} }
FontInfoBase::FontInfoBase(const FontInfoBase& fibFont) : bool FontInfoBase::operator==(const FontInfoBase& other) noexcept
FontInfoBase(fibFont.GetFaceName(),
fibFont.GetFamily(),
fibFont.GetWeight(),
fibFont.WasDefaultRasterSetFromEngine(),
fibFont.GetCodePage())
{ {
return _faceName == other._faceName &&
_weight == other._weight &&
_family == other._family &&
_codePage == other._codePage &&
_fDefaultRasterSetFromEngine == other._fDefaultRasterSetFromEngine;
} }
FontInfoBase::~FontInfoBase() unsigned char FontInfoBase::GetFamily() const noexcept
{
}
unsigned char FontInfoBase::GetFamily() const
{ {
return _family; return _family;
} }
@ -51,22 +34,22 @@ unsigned char FontInfoBase::GetFamily() const
// When the default raster font is forced set from the engine, this is how we differentiate it from a simple apply. // When the default raster font is forced set from the engine, this is how we differentiate it from a simple apply.
// Default raster font is internally represented as a blank face name and zeros for weight, family, and size. This is // Default raster font is internally represented as a blank face name and zeros for weight, family, and size. This is
// the hint for the engine to use whatever comes back from GetStockObject(OEM_FIXED_FONT) (at least in the GDI world). // the hint for the engine to use whatever comes back from GetStockObject(OEM_FIXED_FONT) (at least in the GDI world).
bool FontInfoBase::WasDefaultRasterSetFromEngine() const bool FontInfoBase::WasDefaultRasterSetFromEngine() const noexcept
{ {
return _fDefaultRasterSetFromEngine; return _fDefaultRasterSetFromEngine;
} }
unsigned int FontInfoBase::GetWeight() const unsigned int FontInfoBase::GetWeight() const noexcept
{ {
return _weight; return _weight;
} }
const std::wstring_view FontInfoBase::GetFaceName() const noexcept const std::wstring& FontInfoBase::GetFaceName() const noexcept
{ {
return _faceName; return _faceName;
} }
unsigned int FontInfoBase::GetCodePage() const unsigned int FontInfoBase::GetCodePage() const noexcept
{ {
return _codePage; return _codePage;
} }
@ -77,21 +60,15 @@ unsigned int FontInfoBase::GetCodePage() const
// Arguments: // Arguments:
// - buffer: the buffer into which to copy characters // - buffer: the buffer into which to copy characters
// - size: the size of buffer // - size: the size of buffer
HRESULT FontInfoBase::FillLegacyNameBuffer(gsl::span<wchar_t> buffer) const void FontInfoBase::FillLegacyNameBuffer(wchar_t (&buffer)[LF_FACESIZE]) const noexcept
try
{ {
auto toCopy = std::min<size_t>(buffer.size() - 1, _faceName.size()); const auto toCopy = std::min(std::size(buffer) - 1, _faceName.size());
auto last = std::copy(_faceName.cbegin(), _faceName.cbegin() + toCopy, buffer.begin()); auto last = std::copy_n(_faceName.data(), toCopy, &buffer[0]);
std::fill(last, buffer.end(), L'\0'); *last = L'\0';
return S_OK;
} }
CATCH_RETURN();
// NOTE: this method is intended to only be used from the engine itself to respond what font it has chosen. // NOTE: this method is intended to only be used from the engine itself to respond what font it has chosen.
void FontInfoBase::SetFromEngine(const std::wstring_view faceName, void FontInfoBase::SetFromEngine(const std::wstring_view& faceName, const unsigned char family, const unsigned int weight, const bool fSetDefaultRasterFont) noexcept
const unsigned char family,
const unsigned int weight,
const bool fSetDefaultRasterFont)
{ {
_faceName = faceName; _faceName = faceName;
_family = family; _family = family;
@ -101,12 +78,12 @@ void FontInfoBase::SetFromEngine(const std::wstring_view faceName,
// Internally, default raster font is represented by empty facename, and zeros for weight, family, and size. Since // Internally, default raster font is represented by empty facename, and zeros for weight, family, and size. Since
// FontInfoBase doesn't have sizing information, this helper checks everything else. // FontInfoBase doesn't have sizing information, this helper checks everything else.
bool FontInfoBase::IsDefaultRasterFontNoSize() const bool FontInfoBase::IsDefaultRasterFontNoSize() const noexcept
{ {
return (_weight == 0 && _family == 0 && _faceName.empty()); return (_weight == 0 && _family == 0 && _faceName.empty());
} }
void FontInfoBase::ValidateFont() void FontInfoBase::ValidateFont() noexcept
{ {
// If we were given a blank name, it meant raster fonts, which to us is always Terminal. // If we were given a blank name, it meant raster fonts, which to us is always Terminal.
if (!IsDefaultRasterFontNoSize() && s_pFontDefaultList != nullptr) if (!IsDefaultRasterFontNoSize() && s_pFontDefaultList != nullptr)
@ -115,8 +92,7 @@ void FontInfoBase::ValidateFont()
if (_faceName == DEFAULT_TT_FONT_FACENAME) if (_faceName == DEFAULT_TT_FONT_FACENAME)
{ {
std::wstring defaultFontFace; std::wstring defaultFontFace;
if (SUCCEEDED(s_pFontDefaultList->RetrieveDefaultFontNameForCodepage(GetCodePage(), if (SUCCEEDED(s_pFontDefaultList->RetrieveDefaultFontNameForCodepage(GetCodePage(), defaultFontFace)))
defaultFontFace)))
{ {
_faceName = defaultFontFace; _faceName = defaultFontFace;
@ -128,14 +104,14 @@ void FontInfoBase::ValidateFont()
} }
} }
bool FontInfoBase::IsTrueTypeFont() const bool FontInfoBase::IsTrueTypeFont() const noexcept
{ {
return WI_IsFlagSet(_family, TMPF_TRUETYPE); return WI_IsFlagSet(_family, TMPF_TRUETYPE);
} }
Microsoft::Console::Render::IFontDefaultList* FontInfoBase::s_pFontDefaultList; Microsoft::Console::Render::IFontDefaultList* FontInfoBase::s_pFontDefaultList;
void FontInfoBase::s_SetFontDefaultList(_In_ Microsoft::Console::Render::IFontDefaultList* const pFontDefaultList) void FontInfoBase::s_SetFontDefaultList(_In_ Microsoft::Console::Render::IFontDefaultList* const pFontDefaultList) noexcept
{ {
s_pFontDefaultList = pFontDefaultList; s_pFontDefaultList = pFontDefaultList;
} }

View file

@ -5,13 +5,25 @@
#include "../inc/FontInfoDesired.hpp" #include "../inc/FontInfoDesired.hpp"
bool operator==(const FontInfoDesired& a, const FontInfoDesired& b) FontInfoDesired::FontInfoDesired(const std::wstring_view& faceName, const unsigned char family, const unsigned int weight, const COORD coordSizeDesired, const unsigned int codePage) noexcept :
FontInfoBase(faceName, family, weight, false, codePage),
_coordSizeDesired(coordSizeDesired)
{ {
return (static_cast<FontInfoBase>(a) == static_cast<FontInfoBase>(b) &&
a._coordSizeDesired == b._coordSizeDesired);
} }
COORD FontInfoDesired::GetEngineSize() const FontInfoDesired::FontInfoDesired(const FontInfo& fiFont) noexcept :
FontInfoBase(fiFont),
_coordSizeDesired(fiFont.GetUnscaledSize())
{
}
bool FontInfoDesired::operator==(const FontInfoDesired& other) noexcept
{
return FontInfoBase::operator==(other) &&
_coordSizeDesired == other._coordSizeDesired;
}
COORD FontInfoDesired::GetEngineSize() const noexcept
{ {
COORD coordSize = _coordSizeDesired; COORD coordSize = _coordSizeDesired;
if (IsTrueTypeFont()) if (IsTrueTypeFont())
@ -22,30 +34,12 @@ COORD FontInfoDesired::GetEngineSize() const
return coordSize; return coordSize;
} }
FontInfoDesired::FontInfoDesired(const std::wstring_view faceName,
const unsigned char family,
const unsigned int weight,
const COORD coordSizeDesired,
const unsigned int codePage) :
FontInfoBase(faceName, family, weight, false, codePage),
_coordSizeDesired(coordSizeDesired)
{
}
FontInfoDesired::FontInfoDesired(const FontInfo& fiFont) :
FontInfoBase(fiFont),
_coordSizeDesired(fiFont.GetUnscaledSize())
{
}
// This helper determines if this object represents the default raster font. This can either be because internally we're // This helper determines if this object represents the default raster font. This can either be because internally we're
// using the empty facename and zeros for size, weight, and family, or it can be because we were given explicit // using the empty facename and zeros for size, weight, and family, or it can be because we were given explicit
// dimensions from the engine that were the result of loading the default raster font. See GdiEngine::_GetProposedFont(). // dimensions from the engine that were the result of loading the default raster font. See GdiEngine::_GetProposedFont().
bool FontInfoDesired::IsDefaultRasterFont() const bool FontInfoDesired::IsDefaultRasterFont() const noexcept
{ {
// Either the raster was set from the engine... // Either the raster was set from the engine...
// OR the face name is empty with a size of 0x0 or 8x12. // OR the face name is empty with a size of 0x0 or 8x12.
return WasDefaultRasterSetFromEngine() || (GetFaceName().empty() && return WasDefaultRasterSetFromEngine() || (GetFaceName().empty() && (_coordSizeDesired == COORD{ 0, 0 } || _coordSizeDesired == COORD{ 8, 12 }));
((_coordSizeDesired.X == 0 && _coordSizeDesired.Y == 0) ||
(_coordSizeDesired.X == 8 && _coordSizeDesired.Y == 12)));
} }

View file

@ -7,38 +7,25 @@
using namespace Microsoft::Console; using namespace Microsoft::Console;
using namespace Microsoft::Console::Render; using namespace Microsoft::Console::Render;
RenderEngineBase::RenderEngineBase() : HRESULT RenderEngineBase::InvalidateTitle() noexcept
_titleChanged(false),
_lastFrameTitle(L"")
{ {
} _titleChanged = true;
HRESULT RenderEngineBase::InvalidateTitle(const std::wstring_view proposedTitle) noexcept
{
if (proposedTitle != _lastFrameTitle)
{
_titleChanged = true;
}
return S_OK; return S_OK;
} }
HRESULT RenderEngineBase::UpdateTitle(const std::wstring_view newTitle) noexcept HRESULT RenderEngineBase::UpdateTitle(const std::wstring_view newTitle) noexcept
{ {
HRESULT hr = S_FALSE; if (!_titleChanged)
if (newTitle != _lastFrameTitle)
{ {
RETURN_IF_FAILED(_DoUpdateTitle(newTitle)); return S_FALSE;
_lastFrameTitle = newTitle;
_titleChanged = false;
hr = S_OK;
} }
return hr;
RETURN_IF_FAILED(_DoUpdateTitle(newTitle));
_titleChanged = false;
return S_OK;
} }
HRESULT RenderEngineBase::UpdateSoftFont(const gsl::span<const uint16_t> /*bitPattern*/, HRESULT RenderEngineBase::UpdateSoftFont(const gsl::span<const uint16_t> /*bitPattern*/, const SIZE /*cellSize*/, const size_t /*centeringHint*/) noexcept
const SIZE /*cellSize*/,
const size_t /*centeringHint*/) noexcept
{ {
return S_FALSE; return S_FALSE;
} }
@ -53,9 +40,7 @@ HRESULT RenderEngineBase::ResetLineTransform() noexcept
return S_FALSE; return S_FALSE;
} }
HRESULT RenderEngineBase::PrepareLineTransform(const LineRendition /*lineRendition*/, HRESULT RenderEngineBase::PrepareLineTransform(const LineRendition /*lineRendition*/, const size_t /*targetRow*/, const size_t /*viewportLeft*/) noexcept
const size_t /*targetRow*/,
const size_t /*viewportLeft*/) noexcept
{ {
return S_FALSE; return S_FALSE;
} }
@ -74,5 +59,13 @@ HRESULT RenderEngineBase::PrepareLineTransform(const LineRendition /*lineRenditi
// - Blocks until the engine is able to render without blocking. // - Blocks until the engine is able to render without blocking.
void RenderEngineBase::WaitUntilCanRender() noexcept void RenderEngineBase::WaitUntilCanRender() noexcept
{ {
// do nothing by default Sleep(8);
}
// Routine Description:
// - Uses the currently selected font to determine how wide the given character will be when rendered.
[[nodiscard]] HRESULT RenderEngineBase::IsGlyphWideByFont(const std::wstring_view& /*glyph*/, _Out_ bool* const pResult) noexcept
{
*pResult = false;
return S_FALSE;
} }

View file

@ -5,19 +5,7 @@
#include "../inc/FontInfo.hpp" #include "../inc/FontInfo.hpp"
bool operator==(const FontInfo& a, const FontInfo& b) FontInfo::FontInfo(const std::wstring_view& faceName, const unsigned char family, const unsigned int weight, const COORD coordSize, const unsigned int codePage, const bool fSetDefaultRasterFont) noexcept :
{
return (static_cast<FontInfoBase>(a) == static_cast<FontInfoBase>(b) &&
a._coordSize == b._coordSize &&
a._coordSizeUnscaled == b._coordSizeUnscaled);
}
FontInfo::FontInfo(const std::wstring_view faceName,
const unsigned char family,
const unsigned int weight,
const COORD coordSize,
const unsigned int codePage,
const bool fSetDefaultRasterFont /* = false */) :
FontInfoBase(faceName, family, weight, fSetDefaultRasterFont, codePage), FontInfoBase(faceName, family, weight, fSetDefaultRasterFont, codePage),
_coordSize(coordSize), _coordSize(coordSize),
_coordSizeUnscaled(coordSize), _coordSizeUnscaled(coordSize),
@ -26,39 +14,29 @@ FontInfo::FontInfo(const std::wstring_view faceName,
ValidateFont(); ValidateFont();
} }
FontInfo::FontInfo(const FontInfo& fiFont) : bool FontInfo::operator==(const FontInfo& other) noexcept
FontInfoBase(fiFont),
_coordSize(fiFont.GetSize()),
_coordSizeUnscaled(fiFont.GetUnscaledSize())
{ {
return FontInfoBase::operator==(other) &&
_coordSize == other._coordSize &&
_coordSizeUnscaled == other._coordSizeUnscaled;
} }
COORD FontInfo::GetUnscaledSize() const COORD FontInfo::GetUnscaledSize() const noexcept
{ {
return _coordSizeUnscaled; return _coordSizeUnscaled;
} }
COORD FontInfo::GetSize() const COORD FontInfo::GetSize() const noexcept
{ {
return _coordSize; return _coordSize;
} }
void FontInfo::SetFromEngine(const std::wstring_view faceName, void FontInfo::SetFromEngine(const std::wstring_view& faceName, const unsigned char family, const unsigned int weight, const bool fSetDefaultRasterFont, const COORD coordSize, const COORD coordSizeUnscaled) noexcept
const unsigned char family,
const unsigned int weight,
const bool fSetDefaultRasterFont,
const COORD coordSize,
const COORD coordSizeUnscaled)
{ {
FontInfoBase::SetFromEngine(faceName, FontInfoBase::SetFromEngine(faceName, family, weight, fSetDefaultRasterFont);
family,
weight,
fSetDefaultRasterFont);
_coordSize = coordSize; _coordSize = coordSize;
_coordSizeUnscaled = coordSizeUnscaled; _coordSizeUnscaled = coordSizeUnscaled;
ValidateFont();
_ValidateCoordSize();
} }
bool FontInfo::GetFallback() const noexcept bool FontInfo::GetFallback() const noexcept
@ -71,12 +49,7 @@ void FontInfo::SetFallback(const bool didFallback) noexcept
_didFallback = didFallback; _didFallback = didFallback;
} }
void FontInfo::ValidateFont() void FontInfo::ValidateFont() noexcept
{
_ValidateCoordSize();
}
void FontInfo::_ValidateCoordSize()
{ {
// a (0,0) font is okay for the default raster font, as we will eventually set the dimensions based on the font GDI // a (0,0) font is okay for the default raster font, as we will eventually set the dimensions based on the font GDI
// passes back to us. // passes back to us.

View file

@ -69,11 +69,6 @@ Renderer::~Renderer()
auto tries = maxRetriesForRenderEngine; auto tries = maxRetriesForRenderEngine;
while (tries > 0) while (tries > 0)
{ {
if (_destructing)
{
return S_FALSE;
}
const auto hr = _PaintFrameForEngine(pEngine); const auto hr = _PaintFrameForEngine(pEngine);
if (E_PENDING == hr) if (E_PENDING == hr)
{ {
@ -487,7 +482,7 @@ void Renderer::TriggerTitleChange()
const auto newTitle = _pData->GetConsoleTitle(); const auto newTitle = _pData->GetConsoleTitle();
FOREACH_ENGINE(pEngine) FOREACH_ENGINE(pEngine)
{ {
LOG_IF_FAILED(pEngine->InvalidateTitle(newTitle)); LOG_IF_FAILED(pEngine->InvalidateTitle());
} }
_NotifyPaintFrame(); _NotifyPaintFrame();
} }
@ -593,7 +588,7 @@ bool Renderer::s_IsSoftFontChar(const std::wstring_view& v, const size_t firstSo
// - glyph - the utf16 encoded codepoint to test // - glyph - the utf16 encoded codepoint to test
// Return Value: // Return Value:
// - True if the codepoint is full-width (two wide), false if it is half-width (one wide). // - True if the codepoint is full-width (two wide), false if it is half-width (one wide).
bool Renderer::IsGlyphWideByFont(const std::wstring_view glyph) bool Renderer::IsGlyphWideByFont(const std::wstring_view& glyph)
{ {
bool fIsFullWidth = false; bool fIsFullWidth = false;
@ -761,7 +756,7 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
// Retrieve the first pattern id // Retrieve the first pattern id
auto patternIds = _pData->GetPatternId(target); auto patternIds = _pData->GetPatternId(target);
// Determine whether we're using a soft font. // Determine whether we're using a soft font.
auto usingSoftFont = s_IsSoftFontChar(it->Chars(), _firstSoftFontChar, _lastSoftFontChar); auto usingSoftFont = _isSoftFontChar(it->Chars());
// And hold the point where we should start drawing. // And hold the point where we should start drawing.
auto screenPoint = target; auto screenPoint = target;
@ -808,7 +803,7 @@ void Renderer::_PaintBufferOutputHelper(_In_ IRenderEngine* const pEngine,
{ {
COORD thisPoint{ screenPoint.X + gsl::narrow<SHORT>(cols), screenPoint.Y }; COORD thisPoint{ screenPoint.X + gsl::narrow<SHORT>(cols), screenPoint.Y };
const auto thisPointPatterns = _pData->GetPatternId(thisPoint); const auto thisPointPatterns = _pData->GetPatternId(thisPoint);
const auto thisUsingSoftFont = s_IsSoftFontChar(it->Chars(), _firstSoftFontChar, _lastSoftFontChar); const auto thisUsingSoftFont = _isSoftFontChar(it->Chars());
const auto changedPatternOrFont = patternIds != thisPointPatterns || usingSoftFont != thisUsingSoftFont; const auto changedPatternOrFont = patternIds != thisPointPatterns || usingSoftFont != thisUsingSoftFont;
if (color != it->TextAttr() || changedPatternOrFont) if (color != it->TextAttr() || changedPatternOrFont)
{ {

View file

@ -73,7 +73,7 @@ namespace Microsoft::Console::Render
const FontInfoDesired& FontInfoDesired, const FontInfoDesired& FontInfoDesired,
_Out_ FontInfo& FontInfo) override; _Out_ FontInfo& FontInfo) override;
bool IsGlyphWideByFont(const std::wstring_view glyph) override; bool IsGlyphWideByFont(const std::wstring_view& glyph) override;
void EnablePainting() override; void EnablePainting() override;
void WaitForPaintCompletionAndDisable(const DWORD dwTimeoutMs) override; void WaitForPaintCompletionAndDisable(const DWORD dwTimeoutMs) override;
@ -108,6 +108,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT _PaintTitle(IRenderEngine* const pEngine); [[nodiscard]] HRESULT _PaintTitle(IRenderEngine* const pEngine);
[[nodiscard]] std::optional<CursorOptions> _GetCursorInfo(); [[nodiscard]] std::optional<CursorOptions> _GetCursorInfo();
[[nodiscard]] HRESULT _PrepareRenderInfo(_In_ IRenderEngine* const pEngine); [[nodiscard]] HRESULT _PrepareRenderInfo(_In_ IRenderEngine* const pEngine);
bool _isSoftFontChar(const std::wstring_view& v) const noexcept;
std::array<IRenderEngine*, 2> _engines{}; std::array<IRenderEngine*, 2> _engines{};
IRenderData* _pData = nullptr; // Non-ownership pointer IRenderData* _pData = nullptr; // Non-ownership pointer

View file

@ -61,7 +61,7 @@ RenderThread::~RenderThread()
// Return Value: // Return Value:
// - S_OK if we succeeded, else an HRESULT corresponding to a failure to create // - S_OK if we succeeded, else an HRESULT corresponding to a failure to create
// an Event or Thread. // an Event or Thread.
[[nodiscard]] HRESULT RenderThread::Initialize(IRenderer* const pRendererParent) noexcept [[nodiscard]] HRESULT RenderThread::Initialize(_In_ IRenderer* const pRendererParent) noexcept
{ {
_pRenderer = pRendererParent; _pRenderer = pRendererParent;
@ -213,12 +213,6 @@ DWORD WINAPI RenderThread::_ThreadProc()
LOG_IF_FAILED(_pRenderer->PaintFrame()); LOG_IF_FAILED(_pRenderer->PaintFrame());
SetEvent(_hPaintCompletedEvent); SetEvent(_hPaintCompletedEvent);
// extra check before we sleep since it's a "long" activity, relatively speaking.
if (_fKeepRunning)
{
Sleep(s_FrameLimitMilliseconds);
}
} }
return S_OK; return S_OK;

View file

@ -37,8 +37,6 @@ namespace Microsoft::Console::Render
static DWORD WINAPI s_ThreadProc(_In_ LPVOID lpParameter); static DWORD WINAPI s_ThreadProc(_In_ LPVOID lpParameter);
DWORD WINAPI _ThreadProc(); DWORD WINAPI _ThreadProc();
static DWORD const s_FrameLimitMilliseconds = 8;
HANDLE _hThread; HANDLE _hThread;
HANDLE _hEvent; 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. // - See https://docs.microsoft.com/en-us/windows/uwp/gaming/reduce-latency-with-dxgi-1-3-swap-chains.
void DxEngine::WaitUntilCanRender() noexcept void DxEngine::WaitUntilCanRender() noexcept
{ {
if (!_swapChainFrameLatencyWaitableObject) // DxEngine isn't really performant and holds the console lock for at least 20ms per (full) frame.
{ // Sleeping 8ms per frame thus increases throughput of the concurrently running VtEngine.
return; Sleep(8);
}
const auto ret = WaitForSingleObjectEx( if (_swapChainFrameLatencyWaitableObject)
_swapChainFrameLatencyWaitableObject.get(),
1000, // 1 second timeout (shouldn't ever occur)
true);
if (ret != WAIT_OBJECT_0)
{ {
LOG_WIN32_MSG(ret, "Waiting for swap chain frame latency waitable object returned error or timeout."); WaitForSingleObjectEx(_swapChainFrameLatencyWaitableObject.get(), 1000, true);
} }
} }
@ -2135,7 +2130,7 @@ CATCH_RETURN();
// - pResult - True if it should take two columns. False if it should take one. // - pResult - True if it should take two columns. False if it should take one.
// Return Value: // Return Value:
// - S_OK or relevant DirectWrite error. // - S_OK or relevant DirectWrite error.
[[nodiscard]] HRESULT DxEngine::IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept [[nodiscard]] HRESULT DxEngine::IsGlyphWideByFont(const std::wstring_view& glyph, _Out_ bool* const pResult) noexcept
try try
{ {
RETURN_HR_IF_NULL(E_INVALIDARG, pResult); RETURN_HR_IF_NULL(E_INVALIDARG, pResult);

View file

@ -119,7 +119,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override; [[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) 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 IsGlyphWideByFont(const std::wstring_view& glyph, _Out_ bool* const pResult) noexcept override;
[[nodiscard]] ::Microsoft::Console::Types::Viewport GetViewportInCharacters(const ::Microsoft::Console::Types::Viewport& viewInPixels) noexcept; [[nodiscard]] ::Microsoft::Console::Types::Viewport GetViewportInCharacters(const ::Microsoft::Console::Types::Viewport& viewInPixels) noexcept;
[[nodiscard]] ::Microsoft::Console::Types::Viewport GetViewportInPixels(const ::Microsoft::Console::Types::Viewport& viewInCharacters) noexcept; [[nodiscard]] ::Microsoft::Console::Types::Viewport GetViewportInPixels(const ::Microsoft::Console::Types::Viewport& viewInCharacters) noexcept;

View file

@ -78,7 +78,7 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override; [[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) 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 IsGlyphWideByFont(const std::wstring_view& glyph, _Out_ bool* const pResult) noexcept override;
protected: protected:
[[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring_view newTitle) noexcept override; [[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring_view newTitle) noexcept override;

View file

@ -38,7 +38,7 @@ using namespace Microsoft::Console::Render;
// - pResult - receives return value, True if it is full-width (2 wide). False if it is half-width (1 wide). // - pResult - receives return value, True if it is full-width (2 wide). False if it is half-width (1 wide).
// Return Value: // Return Value:
// - S_OK // - S_OK
[[nodiscard]] HRESULT GdiEngine::IsGlyphWideByFont(const std::wstring_view glyph, _Out_ bool* const pResult) noexcept [[nodiscard]] HRESULT GdiEngine::IsGlyphWideByFont(const std::wstring_view& glyph, _Out_ bool* const pResult) noexcept
{ {
bool isFullWidth = false; bool isFullWidth = false;

View file

@ -610,7 +610,7 @@ GdiEngine::~GdiEngine()
// NOTE: not using what GDI gave us because some fonts don't quite roundtrip (e.g. MS Gothic and VL Gothic) // NOTE: not using what GDI gave us because some fonts don't quite roundtrip (e.g. MS Gothic and VL Gothic)
lf.lfPitchAndFamily = (FIXED_PITCH | FF_MODERN); lf.lfPitchAndFamily = (FIXED_PITCH | FF_MODERN);
RETURN_IF_FAILED(FontDesired.FillLegacyNameBuffer(gsl::make_span(lf.lfFaceName))); FontDesired.FillLegacyNameBuffer(lf.lfFaceName);
// Create font. // Create font.
hFont.reset(CreateFontIndirectW(&lf)); hFont.reset(CreateFontIndirectW(&lf));

View file

@ -28,40 +28,21 @@ Author(s):
class FontInfo : public FontInfoBase class FontInfo : public FontInfoBase
{ {
public: public:
FontInfo(const std::wstring_view faceName, FontInfo(const std::wstring_view& faceName, const unsigned char family, const unsigned int weight, const COORD coordSize, const unsigned int codePage, const bool fSetDefaultRasterFont = false) noexcept;
const unsigned char family,
const unsigned int weight,
const COORD coordSize,
const unsigned int codePage,
const bool fSetDefaultRasterFont = false);
FontInfo(const FontInfo& fiFont); bool operator==(const FontInfo& other) noexcept;
COORD GetSize() const;
COORD GetUnscaledSize() const;
void SetFromEngine(const std::wstring_view faceName,
const unsigned char family,
const unsigned int weight,
const bool fSetDefaultRasterFont,
const COORD coordSize,
const COORD coordSizeUnscaled);
COORD GetSize() const noexcept;
COORD GetUnscaledSize() const noexcept;
void SetFromEngine(const std::wstring_view& faceName, const unsigned char family, const unsigned int weight, const bool fSetDefaultRasterFont, const COORD coordSize, const COORD coordSizeUnscaled) noexcept;
bool GetFallback() const noexcept; bool GetFallback() const noexcept;
void SetFallback(const bool didFallback) noexcept; void SetFallback(const bool didFallback) noexcept;
void ValidateFont() noexcept;
void ValidateFont();
friend bool operator==(const FontInfo& a, const FontInfo& b);
private: private:
void _ValidateCoordSize();
COORD _coordSize; COORD _coordSize;
COORD _coordSizeUnscaled; COORD _coordSizeUnscaled;
bool _didFallback; bool _didFallback;
}; };
bool operator==(const FontInfo& a, const FontInfo& b);
// SET AND UNSET CONSOLE_OEMFONT_DISPLAY unless we can get rid of the stupid recoding in the conhost side. // SET AND UNSET CONSOLE_OEMFONT_DISPLAY unless we can get rid of the stupid recoding in the conhost side.

View file

@ -26,40 +26,25 @@ static constexpr wchar_t DEFAULT_RASTER_FONT_FACENAME[]{ L"Terminal" };
class FontInfoBase class FontInfoBase
{ {
public: public:
FontInfoBase(const std::wstring_view faceName, FontInfoBase(const std::wstring_view& faceName, const unsigned char family, const unsigned int weight, const bool fSetDefaultRasterFont, const unsigned int uiCodePage) noexcept;
const unsigned char family,
const unsigned int weight,
const bool fSetDefaultRasterFont,
const unsigned int uiCodePage);
FontInfoBase(const FontInfoBase& fibFont); bool operator==(const FontInfoBase& other) noexcept;
~FontInfoBase(); unsigned char GetFamily() const noexcept;
unsigned int GetWeight() const noexcept;
unsigned char GetFamily() const; const std::wstring& GetFaceName() const noexcept;
unsigned int GetWeight() const; unsigned int GetCodePage() const noexcept;
const std::wstring_view GetFaceName() const noexcept; void FillLegacyNameBuffer(wchar_t (&buffer)[LF_FACESIZE]) const noexcept;
unsigned int GetCodePage() const; bool IsTrueTypeFont() const noexcept;
void SetFromEngine(const std::wstring_view& faceName, const unsigned char family, const unsigned int weight, const bool fSetDefaultRasterFont) noexcept;
HRESULT FillLegacyNameBuffer(gsl::span<wchar_t> buffer) const; bool WasDefaultRasterSetFromEngine() const noexcept;
void ValidateFont() noexcept;
bool IsTrueTypeFont() const;
void SetFromEngine(const std::wstring_view faceName,
const unsigned char family,
const unsigned int weight,
const bool fSetDefaultRasterFont);
bool WasDefaultRasterSetFromEngine() const;
void ValidateFont();
static Microsoft::Console::Render::IFontDefaultList* s_pFontDefaultList; static Microsoft::Console::Render::IFontDefaultList* s_pFontDefaultList;
static void s_SetFontDefaultList(_In_ Microsoft::Console::Render::IFontDefaultList* const pFontDefaultList); static void s_SetFontDefaultList(_In_ Microsoft::Console::Render::IFontDefaultList* const pFontDefaultList) noexcept;
friend bool operator==(const FontInfoBase& a, const FontInfoBase& b);
protected: protected:
bool IsDefaultRasterFontNoSize() const; bool IsDefaultRasterFontNoSize() const noexcept;
private: private:
std::wstring _faceName; std::wstring _faceName;
@ -68,5 +53,3 @@ private:
unsigned int _codePage; unsigned int _codePage;
bool _fDefaultRasterSetFromEngine; bool _fDefaultRasterSetFromEngine;
}; };
bool operator==(const FontInfoBase& a, const FontInfoBase& b);

View file

@ -24,21 +24,14 @@ Author(s):
class FontInfoDesired : public FontInfoBase class FontInfoDesired : public FontInfoBase
{ {
public: public:
FontInfoDesired(const std::wstring_view faceName, FontInfoDesired(const std::wstring_view& faceName, const unsigned char family, const unsigned int weight, const COORD coordSizeDesired, const unsigned int uiCodePage) noexcept;
const unsigned char family, FontInfoDesired(const FontInfo& fiFont) noexcept;
const unsigned int weight,
const COORD coordSizeDesired,
const unsigned int uiCodePage);
FontInfoDesired(const FontInfo& fiFont); bool operator==(const FontInfoDesired& other) noexcept;
COORD GetEngineSize() const; COORD GetEngineSize() const noexcept;
bool IsDefaultRasterFont() const; bool IsDefaultRasterFont() const noexcept;
friend bool operator==(const FontInfoDesired& a, const FontInfoDesired& b);
private: private:
COORD _coordSizeDesired; COORD _coordSizeDesired;
}; };
bool operator==(const FontInfoDesired& a, const FontInfoDesired& b);

View file

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

View file

@ -58,7 +58,7 @@ namespace Microsoft::Console::Render
const FontInfoDesired& FontInfoDesired, const FontInfoDesired& FontInfoDesired,
_Out_ FontInfo& FontInfo) = 0; _Out_ FontInfo& FontInfo) = 0;
virtual bool IsGlyphWideByFont(const std::wstring_view glyph) = 0; virtual bool IsGlyphWideByFont(const std::wstring_view& glyph) = 0;
virtual void EnablePainting() = 0; virtual void EnablePainting() = 0;
virtual void WaitForPaintCompletionAndDisable(const DWORD dwTimeoutMs) = 0; virtual void WaitForPaintCompletionAndDisable(const DWORD dwTimeoutMs) = 0;

View file

@ -24,40 +24,27 @@ namespace Microsoft::Console::Render
class RenderEngineBase : public IRenderEngine class RenderEngineBase : public IRenderEngine
{ {
public: public:
RenderEngineBase() = default;
~RenderEngineBase() = 0; ~RenderEngineBase() = 0;
protected:
RenderEngineBase();
RenderEngineBase(const RenderEngineBase&) = default; RenderEngineBase(const RenderEngineBase&) = default;
RenderEngineBase(RenderEngineBase&&) = default; RenderEngineBase(RenderEngineBase&&) = default;
RenderEngineBase& operator=(const RenderEngineBase&) = default; RenderEngineBase& operator=(const RenderEngineBase&) = default;
RenderEngineBase& operator=(RenderEngineBase&&) = default; RenderEngineBase& operator=(RenderEngineBase&&) = default;
public: [[nodiscard]] HRESULT InvalidateTitle() noexcept override;
[[nodiscard]] HRESULT InvalidateTitle(const std::wstring_view proposedTitle) noexcept override;
[[nodiscard]] HRESULT UpdateTitle(const std::wstring_view newTitle) noexcept override; [[nodiscard]] HRESULT UpdateTitle(const std::wstring_view newTitle) noexcept override;
[[nodiscard]] HRESULT UpdateSoftFont(const gsl::span<const uint16_t> bitPattern, const SIZE cellSize, const size_t centeringHint) noexcept override;
[[nodiscard]] HRESULT UpdateSoftFont(const gsl::span<const uint16_t> bitPattern,
const SIZE cellSize,
const size_t centeringHint) noexcept override;
[[nodiscard]] HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept override; [[nodiscard]] HRESULT PrepareRenderInfo(const RenderFrameInfo& info) noexcept override;
[[nodiscard]] HRESULT ResetLineTransform() noexcept override; [[nodiscard]] HRESULT ResetLineTransform() noexcept override;
[[nodiscard]] HRESULT PrepareLineTransform(const LineRendition lineRendition, [[nodiscard]] HRESULT PrepareLineTransform(const LineRendition lineRendition, const size_t targetRow, const size_t viewportLeft) noexcept override;
const size_t targetRow,
const size_t viewportLeft) noexcept override;
[[nodiscard]] virtual bool RequiresContinuousRedraw() noexcept override; [[nodiscard]] virtual bool RequiresContinuousRedraw() noexcept override;
void WaitUntilCanRender() noexcept override; void WaitUntilCanRender() noexcept override;
[[nodiscard]] HRESULT IsGlyphWideByFont(const std::wstring_view& glyph, _Out_ bool* const pResult) noexcept override;
protected: protected:
[[nodiscard]] virtual HRESULT _DoUpdateTitle(const std::wstring_view newTitle) noexcept = 0; [[nodiscard]] virtual HRESULT _DoUpdateTitle(const std::wstring_view newTitle) noexcept = 0;
bool _titleChanged; bool _titleChanged = false;
std::wstring _lastFrameTitle;
}; };
inline Microsoft::Console::Render::RenderEngineBase::~RenderEngineBase() {} inline Microsoft::Console::Render::RenderEngineBase::~RenderEngineBase() {}

View file

@ -261,6 +261,13 @@ CATCH_RETURN();
return S_OK; 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: // Routine Description:
// - Used to perform longer running presentation steps outside the lock so the // - Used to perform longer running presentation steps outside the lock so the
// other threads can continue. // other threads can continue.
@ -453,18 +460,6 @@ CATCH_RETURN();
return S_FALSE; return S_FALSE;
} }
// Routine Description:
// - Currently unused by this renderer.
// Arguments:
// - glyph - The glyph run to process for column width.
// - pResult - True if it should take two columns. False if it should take one.
// Return Value:
// - S_OK or relevant DirectWrite error.
[[nodiscard]] HRESULT UiaEngine::IsGlyphWideByFont(const std::wstring_view /*glyph*/, _Out_ bool* const /*pResult*/) noexcept
{
return S_FALSE;
}
// Method Description: // Method Description:
// - Updates the window's title string. // - Updates the window's title string.
// - Currently unused by this renderer. // - Currently unused by this renderer.

View file

@ -36,12 +36,10 @@ namespace Microsoft::Console::Render
// IRenderEngine Members // IRenderEngine Members
[[nodiscard]] HRESULT StartPaint() noexcept override; [[nodiscard]] HRESULT StartPaint() noexcept override;
[[nodiscard]] HRESULT EndPaint() noexcept override; [[nodiscard]] HRESULT EndPaint() noexcept override;
void WaitUntilCanRender() noexcept override;
[[nodiscard]] HRESULT Present() noexcept override; [[nodiscard]] HRESULT Present() noexcept override;
[[nodiscard]] HRESULT PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept override; [[nodiscard]] HRESULT PrepareForTeardown(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT ScrollFrame() noexcept override; [[nodiscard]] HRESULT ScrollFrame() noexcept override;
[[nodiscard]] HRESULT Invalidate(const SMALL_RECT* const psrRegion) noexcept override; [[nodiscard]] HRESULT Invalidate(const SMALL_RECT* const psrRegion) noexcept override;
[[nodiscard]] HRESULT InvalidateCursor(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 InvalidateSystem(const RECT* const prcDirtyClient) noexcept override;
@ -49,30 +47,18 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT InvalidateScroll(const COORD* const pcoordDelta) noexcept override; [[nodiscard]] HRESULT InvalidateScroll(const COORD* const pcoordDelta) noexcept override;
[[nodiscard]] HRESULT InvalidateAll() noexcept override; [[nodiscard]] HRESULT InvalidateAll() noexcept override;
[[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept override; [[nodiscard]] HRESULT InvalidateCircling(_Out_ bool* const pForcePaint) noexcept override;
[[nodiscard]] HRESULT PaintBackground() noexcept override; [[nodiscard]] HRESULT PaintBackground() noexcept override;
[[nodiscard]] HRESULT PaintBufferLine(gsl::span<const Cluster> const clusters, [[nodiscard]] HRESULT PaintBufferLine(gsl::span<const Cluster> const clusters, COORD const coord, bool const fTrimLeft, const bool lineWrapped) noexcept override;
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 PaintBufferGridLines(GridLineSet const lines, COLORREF const color, size_t const cchLine, COORD const coordTarget) noexcept override;
[[nodiscard]] HRESULT PaintSelection(const SMALL_RECT rect) noexcept override; [[nodiscard]] HRESULT PaintSelection(const SMALL_RECT rect) noexcept override;
[[nodiscard]] HRESULT PaintCursor(const CursorOptions& options) 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 UpdateDrawingBrushes(const TextAttribute& textAttributes, [[nodiscard]] HRESULT UpdateFont(const FontInfoDesired& FontInfoDesired, _Out_ FontInfo& FontInfo) noexcept override;
const gsl::not_null<IRenderData*> pData, [[nodiscard]] HRESULT UpdateDpi(const int iDpi) noexcept override;
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 UpdateViewport(const SMALL_RECT srNewViewport) 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 GetProposedFont(const FontInfoDesired& fiFontInfoDesired, FontInfo& fiFontInfo, int const iDpi) noexcept override;
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override; [[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) 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;
protected: protected:
[[nodiscard]] HRESULT _DoUpdateTitle(const std::wstring_view newTitle) noexcept override; [[nodiscard]] HRESULT _DoUpdateTitle(const std::wstring_view newTitle) noexcept override;

View file

@ -23,20 +23,6 @@ using namespace Microsoft::Console::Types;
return S_OK; return S_OK;
} }
// Routine Description:
// - Uses the currently selected font to determine how wide the given character will be when rendered.
// - NOTE: Only supports determining half-width/full-width status for CJK-type languages (e.g. is it 1 character wide or 2. a.k.a. is it a rectangle or square.)
// Arguments:
// - glyph - utf16 encoded codepoint to check
// - pResult - receives return value, True if it is full-width (2 wide). False if it is half-width (1 wide).
// Return Value:
// - S_FALSE: This is unsupported by the VT Renderer and should use another engine's value.
[[nodiscard]] HRESULT VtEngine::IsGlyphWideByFont(const std::wstring_view /*glyph*/, _Out_ bool* const pResult) noexcept
{
*pResult = false;
return S_FALSE;
}
// Routine Description: // Routine Description:
// - Performs a "CombineRect" with the "OR" operation. // - Performs a "CombineRect" with the "OR" operation.
// - Basically extends the existing rect outward to also encompass the passed-in region. // - Basically extends the existing rect outward to also encompass the passed-in region.

View file

@ -88,7 +88,6 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override; [[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) 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 SuppressResizeRepaint() noexcept; [[nodiscard]] HRESULT SuppressResizeRepaint() noexcept;

View file

@ -402,12 +402,6 @@ RECT WddmConEngine::GetDisplaySize()
return S_OK; return S_OK;
} }
[[nodiscard]] HRESULT WddmConEngine::IsGlyphWideByFont(const std::wstring_view /*glyph*/, _Out_ bool* const pResult) noexcept
{
*pResult = false;
return S_OK;
}
// Method Description: // Method Description:
// - Updates the window's title string. // - Updates the window's title string.
// Does nothing for WddmCon. // Does nothing for WddmCon.

View file

@ -62,7 +62,6 @@ namespace Microsoft::Console::Render
[[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override; [[nodiscard]] HRESULT GetDirtyArea(gsl::span<const til::rectangle>& area) noexcept override;
[[nodiscard]] HRESULT GetFontSize(_Out_ COORD* const pFontSize) 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;
protected: protected:
[[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring_view newTitle) noexcept override; [[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring_view newTitle) noexcept override;

View file

@ -1325,7 +1325,8 @@ void StateMachine::_EventCsiParam(const wchar_t wch)
// - wch - Character that triggered the event // - wch - Character that triggered the event
// Return Value: // Return Value:
// - <none> // - <none>
void StateMachine::_EventOscParam(const wchar_t wch) noexcept #pragma warning(suppress : 26440) // Function ... can be declared 'noexcept' (f.6).
void StateMachine::_EventOscParam(const wchar_t wch)
{ {
_trace.TraceOnEvent(L"OscParam"); _trace.TraceOnEvent(L"OscParam");
if (_isOscTerminator(wch)) if (_isOscTerminator(wch))
@ -1577,7 +1578,8 @@ void StateMachine::_EventDcsEntry(const wchar_t wch)
// - wch - Character that triggered the event // - wch - Character that triggered the event
// Return Value: // Return Value:
// - <none> // - <none>
void StateMachine::_EventDcsIgnore() noexcept #pragma warning(suppress : 26440) // Function ... can be declared 'noexcept' (f.6).
void StateMachine::_EventDcsIgnore(const wchar_t /*wch*/)
{ {
_trace.TraceOnEvent(L"DcsIgnore"); _trace.TraceOnEvent(L"DcsIgnore");
_ActionIgnore(); _ActionIgnore();
@ -1697,7 +1699,8 @@ void StateMachine::_EventDcsPassThrough(const wchar_t wch)
// - wch - Character that triggered the event // - wch - Character that triggered the event
// Return Value: // Return Value:
// - <none> // - <none>
void StateMachine::_EventSosPmApcString(const wchar_t /*wch*/) noexcept #pragma warning(suppress : 26440) // Function ... can be declared 'noexcept' (f.6).
void StateMachine::_EventSosPmApcString(const wchar_t /*wch*/)
{ {
_trace.TraceOnEvent(L"SosPmApcString"); _trace.TraceOnEvent(L"SosPmApcString");
_ActionIgnore(); _ActionIgnore();
@ -1738,52 +1741,34 @@ void StateMachine::ProcessCharacter(const wchar_t wch)
_ActionInterrupt(); _ActionInterrupt();
_EnterEscape(); _EnterEscape();
} }
else else if (_state < VTStates::TotalStates)
{ {
static constexpr alignas(64) void (StateMachine::*funcs[])(wchar_t) = {
&StateMachine::_EventGround, // VTStates::Ground
&StateMachine::_EventEscape, // VTStates::Escape
&StateMachine::_EventEscapeIntermediate, // VTStates::EscapeIntermediate
&StateMachine::_EventCsiEntry, // VTStates::CsiEntry
&StateMachine::_EventCsiIntermediate, // VTStates::CsiIntermediate
&StateMachine::_EventCsiIgnore, // VTStates::CsiIgnore
&StateMachine::_EventCsiParam, // VTStates::CsiParam
&StateMachine::_EventOscParam, // VTStates::OscParam
&StateMachine::_EventOscString, // VTStates::OscString
&StateMachine::_EventOscTermination, // VTStates::OscTermination
&StateMachine::_EventSs3Entry, // VTStates::Ss3Entry
&StateMachine::_EventSs3Param, // VTStates::Ss3Param
&StateMachine::_EventVt52Param, // VTStates::Vt52Param
&StateMachine::_EventDcsEntry, // VTStates::DcsEntry
&StateMachine::_EventDcsIgnore, // VTStates::DcsIgnore
&StateMachine::_EventDcsIntermediate, // VTStates::DcsIntermediate
&StateMachine::_EventDcsParam, // VTStates::DcsParam
&StateMachine::_EventDcsPassThrough, // VTStates::DcsPassThrough
&StateMachine::_EventSosPmApcString, // VTStates::SosPmApcString
};
// Then pass to the current state as an event // Then pass to the current state as an event
switch (_state) // Invalid _state values will jump to address 0, which is fine I guess.
{ #pragma warning(suppress : 26482) // Only index into arrays using constant expressions (bounds.2).
case VTStates::Ground: (this->*funcs[WI_EnumValue(_state)])(wch);
return _EventGround(wch);
case VTStates::Escape:
return _EventEscape(wch);
case VTStates::EscapeIntermediate:
return _EventEscapeIntermediate(wch);
case VTStates::CsiEntry:
return _EventCsiEntry(wch);
case VTStates::CsiIntermediate:
return _EventCsiIntermediate(wch);
case VTStates::CsiIgnore:
return _EventCsiIgnore(wch);
case VTStates::CsiParam:
return _EventCsiParam(wch);
case VTStates::OscParam:
return _EventOscParam(wch);
case VTStates::OscString:
return _EventOscString(wch);
case VTStates::OscTermination:
return _EventOscTermination(wch);
case VTStates::Ss3Entry:
return _EventSs3Entry(wch);
case VTStates::Ss3Param:
return _EventSs3Param(wch);
case VTStates::Vt52Param:
return _EventVt52Param(wch);
case VTStates::DcsEntry:
return _EventDcsEntry(wch);
case VTStates::DcsIgnore:
return _EventDcsIgnore();
case VTStates::DcsIntermediate:
return _EventDcsIntermediate(wch);
case VTStates::DcsParam:
return _EventDcsParam(wch);
case VTStates::DcsPassThrough:
return _EventDcsPassThrough(wch);
case VTStates::SosPmApcString:
return _EventSosPmApcString(wch);
default:
return;
}
} }
} }
// Method Description: // Method Description:

View file

@ -100,22 +100,22 @@ namespace Microsoft::Console::VirtualTerminal
void _EventCsiIntermediate(const wchar_t wch); void _EventCsiIntermediate(const wchar_t wch);
void _EventCsiIgnore(const wchar_t wch); void _EventCsiIgnore(const wchar_t wch);
void _EventCsiParam(const wchar_t wch); void _EventCsiParam(const wchar_t wch);
void _EventOscParam(const wchar_t wch) noexcept; void _EventOscParam(const wchar_t wch);
void _EventOscString(const wchar_t wch); void _EventOscString(const wchar_t wch);
void _EventOscTermination(const wchar_t wch); void _EventOscTermination(const wchar_t wch);
void _EventSs3Entry(const wchar_t wch); void _EventSs3Entry(const wchar_t wch);
void _EventSs3Param(const wchar_t wch); void _EventSs3Param(const wchar_t wch);
void _EventVt52Param(const wchar_t wch); void _EventVt52Param(const wchar_t wch);
void _EventDcsEntry(const wchar_t wch); void _EventDcsEntry(const wchar_t wch);
void _EventDcsIgnore() noexcept; void _EventDcsIgnore(const wchar_t wch);
void _EventDcsIntermediate(const wchar_t wch); void _EventDcsIntermediate(const wchar_t wch);
void _EventDcsParam(const wchar_t wch); void _EventDcsParam(const wchar_t wch);
void _EventDcsPassThrough(const wchar_t wch); void _EventDcsPassThrough(const wchar_t wch);
void _EventSosPmApcString(const wchar_t wch) noexcept; void _EventSosPmApcString(const wchar_t wch);
void _AccumulateTo(const wchar_t wch, size_t& value) noexcept; void _AccumulateTo(const wchar_t wch, size_t& value) noexcept;
enum class VTStates enum class VTStates : uint_fast8_t
{ {
Ground, Ground,
Escape, Escape,
@ -135,7 +135,8 @@ namespace Microsoft::Console::VirtualTerminal
DcsIntermediate, DcsIntermediate,
DcsParam, DcsParam,
DcsPassThrough, DcsPassThrough,
SosPmApcString SosPmApcString,
TotalStates
}; };
Microsoft::Console::VirtualTerminal::ParserTracing _trace; Microsoft::Console::VirtualTerminal::ParserTracing _trace;

View file

@ -9,12 +9,12 @@ namespace
// used to store range data in CodepointWidthDetector's internal map // used to store range data in CodepointWidthDetector's internal map
struct UnicodeRange final struct UnicodeRange final
{ {
unsigned int lowerBound; uint32_t lowerBound;
unsigned int upperBound; uint32_t upperBound;
CodepointWidth width; CodepointWidth width;
}; };
static bool operator<(const UnicodeRange& range, const unsigned int searchTerm) noexcept static bool operator<(const UnicodeRange& range, const uint32_t searchTerm) noexcept
{ {
return range.upperBound < searchTerm; return range.upperBound < searchTerm;
} }
@ -323,56 +323,46 @@ namespace
}; };
} }
// Routine Description:
// - Constructs an instance of the CodepointWidthDetector class
CodepointWidthDetector::CodepointWidthDetector() noexcept :
_fallbackCache{},
_pfnFallbackMethod{}
{
}
// Routine Description: // Routine Description:
// - returns the width type of codepoint as fast as we can by using quick lookup table and fallback cache. // - returns the width type of codepoint as fast as we can by using quick lookup table and fallback cache.
// Arguments: // Arguments:
// - glyph - the utf16 encoded codepoint to search for // - glyph - the utf16 encoded codepoint to search for
// Return Value: // Return Value:
// - the width type of the codepoint // - 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
try
{ {
THROW_HR_IF(E_INVALIDARG, glyph.empty()); #pragma warning(suppress : 26494) // Variable 'codepoint' is uninitialized. Always initialize an object (type.5).
if (glyph.size() == 1) uint32_t codepoint;
switch (glyph.size())
{ {
// We first attempt to look at our custom quick lookup table of char width preferences. case 1:
const auto width = GetQuickCharWidth(glyph.front()); codepoint = til::at(glyph, 0);
break;
case 2:
codepoint = (til::at(glyph, 0) & 0x3FF) << 10;
codepoint |= til::at(glyph, 1) & 0x3FF;
codepoint += 0x10000;
break;
default:
throw std::invalid_argument("invalid UTF16 scalar value pair");
}
// If it's invalid, the quick width had no opinion, so go to the lookup table. auto width = _lookupGlyphWidth(codepoint);
if (width == CodepointWidth::Invalid)
{ if (width == CodepointWidth::Ambiguous && _pfnFallbackMethod)
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;
}
}
else
{ {
return _lookupGlyphWidthWithCache(glyph); width = _checkFallbackViaCache(codepoint, glyph) ? CodepointWidth::Wide : CodepointWidth::Ambiguous;
} }
return width;
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
// If we got this far, we couldn't figure it out.
// It's better to be too wide than too narrow.
return glyph.empty() ? CodepointWidth::Ambiguous : CodepointWidth::Wide;
} }
// Routine Description: // Routine Description:
@ -383,13 +373,7 @@ CodepointWidth CodepointWidthDetector::GetWidth(const std::wstring_view glyph) c
// - true if wch is wide // - true if wch is wide
bool CodepointWidthDetector::IsWide(const wchar_t wch) const noexcept bool CodepointWidthDetector::IsWide(const wchar_t wch) const noexcept
{ {
try return IsWide({ &wch, 1 });
{
return IsWide({ &wch, 1 });
}
CATCH_LOG();
return true;
} }
// Routine Description: // Routine Description:
@ -398,7 +382,7 @@ bool CodepointWidthDetector::IsWide(const wchar_t wch) const noexcept
// - glyph - the utf16 encoded codepoint to check width of // - glyph - the utf16 encoded codepoint to check width of
// Return Value: // Return Value:
// - true if codepoint is wide // - 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; return GetWidth(glyph) == CodepointWidth::Wide;
} }
@ -409,64 +393,24 @@ bool CodepointWidthDetector::IsWide(const std::wstring_view glyph) const
// - glyph - the utf16 encoded codepoint to search for // - glyph - the utf16 encoded codepoint to search for
// Return Value: // Return Value:
// - the width type of the codepoint // - the width type of the codepoint
CodepointWidth CodepointWidthDetector::_lookupGlyphWidth(const std::wstring_view glyph) const CodepointWidth CodepointWidthDetector::_lookupGlyphWidth(uint32_t codepoint) const
{ {
if (glyph.empty()) // No need to check ASCII
if (codepoint >= 0x80)
{ {
return CodepointWidth::Invalid; const auto it = std::lower_bound(s_wideAndAmbiguousTable.begin(), s_wideAndAmbiguousTable.end(), codepoint);
}
const auto codepoint = _extractCodepoint(glyph); // For characters that are not _in_ the table, lower_bound will return the nearest item that is.
const auto it = std::lower_bound(s_wideAndAmbiguousTable.begin(), s_wideAndAmbiguousTable.end(), codepoint); // 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)
// 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. return it->width;
if (it != s_wideAndAmbiguousTable.end() && codepoint >= it->lowerBound && codepoint <= it->upperBound) }
{
return it->width;
} }
return CodepointWidth::Narrow; 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: // Routine Description:
// - Checks the fallback function but caches the results until the font changes // - 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 // because the lookup function is usually very expensive and will return the same results
@ -474,47 +418,18 @@ CodepointWidth CodepointWidthDetector::_lookupGlyphWidthWithCache(const std::wst
// Arguments: // Arguments:
// - glyph - the utf16 encoded codepoint to check width of // - glyph - the utf16 encoded codepoint to check width of
// - true if codepoint is wide or false if it is narrow // - true if codepoint is wide or false if it is narrow
bool CodepointWidthDetector::_checkFallbackViaCache(const std::wstring_view glyph) const bool CodepointWidthDetector::_checkFallbackViaCache(uint32_t codepoint, const std::wstring_view& glyph) const
{ {
const std::wstring findMe{ glyph };
// TODO: Cache needs to be emptied when font changes. // TODO: Cache needs to be emptied when font changes.
const auto it = _fallbackCache.find(findMe); const auto it = _fallbackCache.find(codepoint);
if (it == _fallbackCache.end()) if (it != _fallbackCache.end())
{
auto result = _pfnFallbackMethod(glyph);
_fallbackCache.insert_or_assign(findMe, result);
return result;
}
else
{ {
return it->second; return it->second;
} }
}
// Routine Description: const auto result = _pfnFallbackMethod(glyph);
// - extract unicode codepoint from utf16 encoding _fallbackCache.insert_or_assign(codepoint, result);
// Arguments: return result;
// - glyph - the utf16 encoded codepoint convert
// Return Value:
// - the codepoint being stored
unsigned int CodepointWidthDetector::_extractCodepoint(const std::wstring_view glyph) noexcept
{
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;
}
} }
// Method Description: // Method Description:
@ -527,9 +442,9 @@ unsigned int CodepointWidthDetector::_extractCodepoint(const std::wstring_view g
// - pfnFallback - the function to use as the fallback method. // - pfnFallback - the function to use as the fallback method.
// Return Value: // Return Value:
// - <none> // - <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: // Method Description:
@ -542,5 +457,6 @@ void CodepointWidthDetector::SetFallbackMethod(std::function<bool(const std::wst
// - <none> // - <none>
void CodepointWidthDetector::NotifyFontChanged() const noexcept 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(); _fallbackCache.clear();
} }

View file

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

View file

@ -134,7 +134,7 @@ void TermControlUiaTextRange::_TranslatePointFromScreen(LPPOINT screenPoint) con
screenPoint->y = includeOffsets(screenPoint->y, boundingRect.top, padding.top, scaleFactor); screenPoint->y = includeOffsets(screenPoint->y, boundingRect.top, padding.top, scaleFactor);
} }
const COORD TermControlUiaTextRange::_getScreenFontSize() const const COORD TermControlUiaTextRange::_getScreenFontSize() const noexcept
{ {
// Do NOT get the font info from IRenderData. It is a dummy font info. // Do NOT get the font info from IRenderData. It is a dummy font info.
// Instead, the font info is saved in the TermControl. So we have to // Instead, the font info is saved in the TermControl. So we have to

View file

@ -57,6 +57,6 @@ namespace Microsoft::Terminal
protected: protected:
void _TranslatePointToScreen(LPPOINT clientPoint) const override; void _TranslatePointToScreen(LPPOINT clientPoint) const override;
void _TranslatePointFromScreen(LPPOINT screenPoint) const override; void _TranslatePointFromScreen(LPPOINT screenPoint) const override;
const COORD _getScreenFontSize() const override; const COORD _getScreenFontSize() const noexcept override;
}; };
} }

View file

@ -1313,7 +1313,7 @@ IFACEMETHODIMP UiaTextRangeBase::GetChildren(_Outptr_result_maybenull_ SAFEARRAY
#pragma endregion #pragma endregion
const COORD UiaTextRangeBase::_getScreenFontSize() const const COORD UiaTextRangeBase::_getScreenFontSize() const noexcept
{ {
COORD coordRet = _pData->GetFontInfo().GetSize(); COORD coordRet = _pData->GetFontInfo().GetSize();

View file

@ -146,7 +146,7 @@ namespace Microsoft::Console::Types
RECT _getTerminalRect() const; RECT _getTerminalRect() const;
virtual const COORD _getScreenFontSize() const; virtual const COORD _getScreenFontSize() const noexcept;
const unsigned int _getViewportHeight(const SMALL_RECT viewport) const noexcept; const unsigned int _getViewportHeight(const SMALL_RECT viewport) const noexcept;
const Viewport _getOptimizedBufferSize() const noexcept; const Viewport _getOptimizedBufferSize() const noexcept;

View file

@ -16,24 +16,21 @@ Author:
#include "convert.hpp" #include "convert.hpp"
#include <functional> #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 // use to measure the width of a codepoint
class CodepointWidthDetector final class CodepointWidthDetector final
{ {
public: public:
CodepointWidthDetector() noexcept; CodepointWidthDetector() noexcept = default;
CodepointWidthDetector(const CodepointWidthDetector&) = delete; CodepointWidthDetector(const CodepointWidthDetector&) = delete;
CodepointWidthDetector(CodepointWidthDetector&&) = delete; CodepointWidthDetector(CodepointWidthDetector&&) = delete;
~CodepointWidthDetector() = default;
CodepointWidthDetector& operator=(const CodepointWidthDetector&) = delete; CodepointWidthDetector& operator=(const CodepointWidthDetector&) = delete;
CodepointWidthDetector& operator=(CodepointWidthDetector&&) = delete; CodepointWidthDetector& operator=(CodepointWidthDetector&&) = delete;
CodepointWidth GetWidth(const std::wstring_view glyph) const; CodepointWidth GetWidth(const std::wstring_view& glyph) const noexcept;
bool IsWide(const std::wstring_view glyph) const; bool IsWide(const std::wstring_view& glyph) const noexcept;
bool IsWide(const wchar_t wch) 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; void NotifyFontChanged() const noexcept;
#ifdef UNIT_TESTING #ifdef UNIT_TESTING
@ -41,11 +38,9 @@ public:
#endif #endif
private: private:
CodepointWidth _lookupGlyphWidth(const std::wstring_view glyph) const; CodepointWidth _lookupGlyphWidth(uint32_t codepoint) const;
CodepointWidth _lookupGlyphWidthWithCache(const std::wstring_view glyph) const noexcept; bool _checkFallbackViaCache(uint32_t codepoint, const std::wstring_view& glyph) const;
bool _checkFallbackViaCache(const std::wstring_view glyph) const;
static unsigned int _extractCodepoint(const std::wstring_view glyph) noexcept;
mutable std::unordered_map<std::wstring, bool> _fallbackCache; mutable robin_hood::unordered_flat_map<uint32_t, bool> _fallbackCache;
std::function<bool(std::wstring_view)> _pfnFallbackMethod; std::function<bool(const std::wstring_view&)> _pfnFallbackMethod;
}; };

View file

@ -12,7 +12,7 @@ Abstract:
#include <functional> #include <functional>
#include <string_view> #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; 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; void NotifyGlyphWidthFontChanged() noexcept;