Skip to content

Commit

Permalink
Add support for downloadable soft fonts (#10011)
Browse files Browse the repository at this point in the history
This PR adds conhost support for downloadable soft fonts - also known as
dynamically redefinable character sets (DRCS) - using the `DECDLD`
escape sequence.

These fonts are typically designed to work on a specific terminal model,
and each model tends to have a different character cell size. So in
order to support as many models as possible, the code attempts to detect
the original target size of the font, and then scale the glyphs to fit
our current cell size.

Once a font has been downloaded to the terminal, it can be designated in
the same way you would a standard character set, using an `SCS` escape
sequence. The identification string for the set is defined by the
`DECDLD` sequence. Internally we map the characters in this set to code
points `U+EF20` to `U+EF7F` in the Unicode private use are (PUA).

Then in the renderer, any characters in that range are split off into
separate runs, which get painted with a special font. The font itself is
dynamically generated as an in-memory resource, constructed from the
downloaded character bitmaps which have been scaled to the appropriate
size.

If no soft fonts are in use, then no mapping of the PUA code points will
take place, so this shouldn't interfere with anyone using those code
points for something else, as along as they aren't also trying to use
soft fonts. I also tried to pick a PUA range that hadn't already been
snatched up by Nerd Fonts, but if we do receive reports of a conflict,
it's easy enough to change.

## Validation Steps Performed

I added an adapter test that runs through a bunch of parameter
variations for the `DECDLD` sequence, to make sure we're correctly
detecting the font sizes for most of the known DEC terminal models.

I've also tested manually on a wide range of existing fonts, of varying
dimensions, and from multiple sources, and made sure they all worked
reasonably well.

Closes #9164
  • Loading branch information
j4james committed Aug 6, 2021
1 parent dcbf7c7 commit 90ff261
Show file tree
Hide file tree
Showing 51 changed files with 1,903 additions and 116 deletions.
1 change: 1 addition & 0 deletions .github/actions/spelling/allow/apis.txt
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ SRWLOCK
STDCPP
STDMETHOD
strchr
strcpy
streambuf
strtoul
Stubless
Expand Down
14 changes: 14 additions & 0 deletions .github/actions/spelling/expect/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ brandings
BRK
Browsable
bsearch
Bspace
bstr
BTNFACE
buf
Expand Down Expand Up @@ -270,10 +271,12 @@ cmder
CMDEXT
Cmdlet
cmdline
cmh
CMOUSEBUTTONS
cmp
cmpeq
cmt
cmw
cmyk
CNL
cnt
Expand Down Expand Up @@ -406,11 +409,13 @@ csbiex
csharp
CSHORT
CSIDL
Cspace
csproj
Csr
csrmsg
CSRSS
csrutil
css
cstdarg
cstddef
cstdio
Expand Down Expand Up @@ -509,6 +514,7 @@ DECAWM
DECCKM
DECCOLM
DECDHL
DECDLD
DECDWL
DECEKBD
DECID
Expand Down Expand Up @@ -789,6 +795,7 @@ FONTENUMPROC
FONTFACE
FONTFAMILY
FONTHEIGHT
FONTINFO
fontlist
FONTOK
FONTSIZE
Expand Down Expand Up @@ -902,6 +909,7 @@ github
gitlab
gle
globals
GLYPHENTRY
gmail
GMEM
GNUC
Expand Down Expand Up @@ -950,6 +958,7 @@ hdrstop
HEIGHTSCROLL
hfile
hfont
hfontresource
hglobal
hhh
HHmm
Expand Down Expand Up @@ -1272,6 +1281,7 @@ locsrc
locstudio
Loewen
LOGFONT
LOGFONTA
LOGFONTW
logissue
lowercased
Expand Down Expand Up @@ -1935,6 +1945,7 @@ realloc
reamapping
rects
redef
redefinable
Redir
redirector
redist
Expand Down Expand Up @@ -1980,6 +1991,7 @@ rfc
rftp
rgb
rgba
RGBCOLOR
rgbi
rgci
rgfae
Expand Down Expand Up @@ -2149,6 +2161,7 @@ SIGDN
SINGLEFLAG
SINGLETHREADED
siup
sixel
SIZEBOX
sizeof
SIZESCROLL
Expand Down Expand Up @@ -2754,6 +2767,7 @@ WTo
wtof
wtoi
WTs
WTSOFTFONT
wtw
wtypes
Wubi
Expand Down
24 changes: 24 additions & 0 deletions src/host/getset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1639,6 +1639,30 @@ void DoSrvEndHyperlink(SCREEN_INFORMATION& screenInfo)
screenInfo.GetTextBuffer().SetCurrentAttributes(attr);
}

// Routine Description:
// - A private API call for updating the active soft font.
// Arguments:
// - bitPattern - An array of scanlines representing all the glyphs in the font.
// - cellSize - The cell size for an individual glyph.
// - centeringHint - The horizontal extent that glyphs are offset from center.
// Return Value:
// - S_OK if we succeeded, otherwise the HRESULT of the failure.
[[nodiscard]] HRESULT DoSrvUpdateSoftFont(const gsl::span<const uint16_t> bitPattern,
const SIZE cellSize,
const size_t centeringHint) noexcept
{
try
{
auto* pRender = ServiceLocator::LocateGlobals().pRender;
if (pRender)
{
pRender->UpdateSoftFont(bitPattern, cellSize, centeringHint);
}
return S_OK;
}
CATCH_RETURN();
}

// Routine Description:
// - A private API call for forcing the renderer to repaint the screen. If the
// input screen buffer is not the active one, then just do nothing. We only
Expand Down
4 changes: 4 additions & 0 deletions src/host/getset.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ void DoSrvAddHyperlink(SCREEN_INFORMATION& screenInfo,

void DoSrvEndHyperlink(SCREEN_INFORMATION& screenInfo);

[[nodiscard]] HRESULT DoSrvUpdateSoftFont(const gsl::span<const uint16_t> bitPattern,
const SIZE cellSize,
const size_t centeringHint) noexcept;

void DoSrvPrivateRefreshWindow(const SCREEN_INFORMATION& screenInfo);

[[nodiscard]] HRESULT DoSrvSetConsoleOutputCodePage(const unsigned int codepage);
Expand Down
15 changes: 15 additions & 0 deletions src/host/outputStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -818,3 +818,18 @@ bool ConhostInternalGetSet::PrivateEndHyperlink() const
DoSrvEndHyperlink(_io.GetActiveOutputBuffer());
return true;
}

// Routine Description:
// - Replaces the active soft font with the given bit pattern.
// Arguments:
// - bitPattern - An array of scanlines representing all the glyphs in the font.
// - cellSize - The cell size for an individual glyph.
// - centeringHint - The horizontal extent that glyphs are offset from center.
// Return Value:
// - true if successful (see DoSrvUpdateSoftFont). false otherwise.
bool ConhostInternalGetSet::PrivateUpdateSoftFont(const gsl::span<const uint16_t> bitPattern,
const SIZE cellSize,
const size_t centeringHint) noexcept
{
return SUCCEEDED(DoSrvUpdateSoftFont(bitPattern, cellSize, centeringHint));
}
4 changes: 4 additions & 0 deletions src/host/outputStream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ class ConhostInternalGetSet final : public Microsoft::Console::VirtualTerminal::
bool PrivateAddHyperlink(const std::wstring_view uri, const std::wstring_view params) const override;
bool PrivateEndHyperlink() const override;

bool PrivateUpdateSoftFont(const gsl::span<const uint16_t> bitPattern,
const SIZE cellSize,
const size_t centeringHint) noexcept override;

private:
Microsoft::Console::IIoProvider& _io;
};
Loading

0 comments on commit 90ff261

Please sign in to comment.