terminal/src/renderer/base/FontInfoBase.cpp
Dustin L. Howett b664761c79 Allow FontInfo{,Base,Desired} to store a font name > 32 wch (#3107)
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.
2019-10-14 21:23:45 -07:00

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;
}