We now truncate the font name as it goes out to GDI APIs, in console API servicing, and in the propsheet. I attempted to defer truncating the font to as far up the stack as possible, so as to make FontInfo usable for the broadest set of cases. There were a couple questions that came up: I know that `Settings` gets memset (memsat?) by the registry deserializer, and perhaps that's another place for us to tackle. Right now, this pull request enables fonts whose names are >= 32 characters _in Windows Terminal only_, but the underpinnings are there for conhost as well. We'd need to explicitly break at the API, or perhaps return a failure or log something to telemetry. * Should we log truncation at the API boundary to telemetry? -> Later; followup filed (#3123) * Should we fix Settings here, or later? -> Later; followup filed (#3123) * `TrueTypeFontList` is built out of things in winconp, the private console header. Concern about interop structures. -> Not used for interop, followup filed to clean it up (#3123) * Is `unsigned int` right for codepage? For width? -> Yes: codepage became UINT (from WORD) when we moved from Win16 to Win32 This commit also includes a workaround for #3170. Growing CONSOLE_INFORMATION made us lose the struct layout lottery during release builds, and this was an expedient fix. Closes #602. Related to #3123.
142 lines
4.8 KiB
C++
142 lines
4.8 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#include "precomp.h"
|
|
|
|
#include <cwchar>
|
|
|
|
#include "..\inc\FontInfoBase.hpp"
|
|
|
|
bool operator==(const FontInfoBase& a, const FontInfoBase& b)
|
|
{
|
|
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),
|
|
_family(family),
|
|
_weight(weight),
|
|
_fDefaultRasterSetFromEngine(fSetDefaultRasterFont),
|
|
_codePage(codePage)
|
|
{
|
|
ValidateFont();
|
|
}
|
|
|
|
FontInfoBase::FontInfoBase(const FontInfoBase& fibFont) :
|
|
FontInfoBase(fibFont.GetFaceName(),
|
|
fibFont.GetFamily(),
|
|
fibFont.GetWeight(),
|
|
fibFont.WasDefaultRasterSetFromEngine(),
|
|
fibFont.GetCodePage())
|
|
{
|
|
}
|
|
|
|
FontInfoBase::~FontInfoBase()
|
|
{
|
|
}
|
|
|
|
unsigned char FontInfoBase::GetFamily() const
|
|
{
|
|
return _family;
|
|
}
|
|
|
|
// 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
|
|
// 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
|
|
{
|
|
return _fDefaultRasterSetFromEngine;
|
|
}
|
|
|
|
unsigned int FontInfoBase::GetWeight() const
|
|
{
|
|
return _weight;
|
|
}
|
|
|
|
const std::wstring_view FontInfoBase::GetFaceName() const
|
|
{
|
|
return _faceName;
|
|
}
|
|
|
|
unsigned int FontInfoBase::GetCodePage() const
|
|
{
|
|
return _codePage;
|
|
}
|
|
|
|
// Method Description:
|
|
// - Populates a fixed-length **null-terminated** buffer with the name of this font, truncating it as necessary.
|
|
// Positions within the buffer that are not filled by the font name are zeroed.
|
|
// Arguments:
|
|
// - buffer: the buffer into which to copy characters
|
|
// - size: the size of buffer
|
|
HRESULT FontInfoBase::FillLegacyNameBuffer(gsl::span<wchar_t> buffer) const
|
|
try
|
|
{
|
|
auto toCopy = std::min<size_t>(buffer.size() - 1, _faceName.size());
|
|
auto last = std::copy(_faceName.cbegin(), _faceName.cbegin() + toCopy, buffer.begin());
|
|
std::fill(last, buffer.end(), 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.
|
|
void FontInfoBase::SetFromEngine(const std::wstring_view faceName,
|
|
const unsigned char family,
|
|
const unsigned int weight,
|
|
const bool fSetDefaultRasterFont)
|
|
{
|
|
_faceName = faceName;
|
|
_family = family;
|
|
_weight = weight;
|
|
_fDefaultRasterSetFromEngine = fSetDefaultRasterFont;
|
|
}
|
|
|
|
// 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.
|
|
bool FontInfoBase::IsDefaultRasterFontNoSize() const
|
|
{
|
|
return (_weight == 0 && _family == 0 && _faceName.empty());
|
|
}
|
|
|
|
void FontInfoBase::ValidateFont()
|
|
{
|
|
// If we were given a blank name, it meant raster fonts, which to us is always Terminal.
|
|
if (!IsDefaultRasterFontNoSize() && s_pFontDefaultList != nullptr)
|
|
{
|
|
// If we have a list of default fonts and our current font is the placeholder for the defaults, substitute here.
|
|
if (_faceName == DEFAULT_TT_FONT_FACENAME)
|
|
{
|
|
std::wstring defaultFontFace;
|
|
if (SUCCEEDED(s_pFontDefaultList->RetrieveDefaultFontNameForCodepage(GetCodePage(),
|
|
defaultFontFace)))
|
|
{
|
|
_faceName = defaultFontFace;
|
|
|
|
// If we're assigning a default true type font name, make sure the family is also set to TrueType
|
|
// to help GDI select the appropriate font when we actually create it.
|
|
_family = TMPF_TRUETYPE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FontInfoBase::IsTrueTypeFont() const
|
|
{
|
|
return WI_IsFlagSet(_family, TMPF_TRUETYPE);
|
|
}
|
|
|
|
Microsoft::Console::Render::IFontDefaultList* FontInfoBase::s_pFontDefaultList;
|
|
|
|
void FontInfoBase::s_SetFontDefaultList(_In_ Microsoft::Console::Render::IFontDefaultList* const pFontDefaultList)
|
|
{
|
|
s_pFontDefaultList = pFontDefaultList;
|
|
}
|