Repository: microsoft/terminal
File: src/renderer/atlas/AtlasEngine.api.cpp (C++)

Code before:

    // At the time of writing:
    // When Win+D is pressed, `TriggerRedrawCursor` is called and a render pass is initiated.
    // As conhost is in the background, GetClientRect will return {0,0} and we'll get called with {0,0}.
    // This isn't a valid value for _api.sizeInPixel and would crash _recreateSizeDependentResources().
    if (_api.sizeInPixel != newSize && newSize != u16x2{})
    {
        _api.sizeInPixel = newSize;
        _api.cellCount = _api.sizeInPixel / _api.fontMetrics.cellSize;
        WI_SetFlag(_api.invalidations, ApiInvalidations::Size);
    }

    return S_OK;
}

void AtlasEngine::ToggleShaderEffects() noexcept
{
}

[[nodiscard]] HRESULT AtlasEngine::UpdateFont(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, const std::unordered_map<std::wstring_view, uint32_t>& features, const std::unordered_map<std::wstring_view, float>& axes) noexcept
try
{
    std::vector<DWRITE_FONT_FEATURE> fontFeatures;
    if (!features.empty())
    {
        fontFeatures.reserve(features.size() + 3);

        // All of these features are enabled by default by DirectWrite.
        // If you want to (and can) peek into the source of DirectWrite
        // you can look for the "GenericDefaultGsubFeatures" and "GenericDefaultGposFeatures" arrays.
        // Gsub is for GetGlyphs() and Gpos for GetGlyphPlacements().
        //
        // GH#10774: Apparently specifying all of the features is just redundant.
        fontFeatures.emplace_back(DWRITE_FONT_FEATURE{ DWRITE_FONT_FEATURE_TAG_STANDARD_LIGATURES, 1 });
        fontFeatures.emplace_back(DWRITE_FONT_FEATURE{ DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_LIGATURES, 1 });
        fontFeatures.emplace_back(DWRITE_FONT_FEATURE{ DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_ALTERNATES, 1 });

        for (const auto& p : features)
        {
            if (p.first.size() == 4)
            {
                const auto s = p.first.data();
                switch (const auto tag = DWRITE_MAKE_FONT_FEATURE_TAG(s[0], s[1], s[2], s[3]))
                {
                case DWRITE_FONT_FEATURE_TAG_STANDARD_LIGATURES:
                    fontFeatures[0].parameter = p.second;
                    break;
                case DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_LIGATURES:
                    fontFeatures[1].parameter = p.second;
                    break;
                case DWRITE_FONT_FEATURE_TAG_CONTEXTUAL_ALTERNATES:

Review comment (bug):
Windows Terminal ignores the HRESULT this function returns and will simply crash with a division by 0 error if it wasn't for this new code. This implements font fallback in a similar way as DxEngine does.

In the future Terminal shouldn't ignore the HRESULT and call UpdateFont() with fallback fonts itself until this method succeeds.

Code after:
    u16x2 newSize;
    RETURN_IF_FAILED(vec2_narrow(pixels.cx, pixels.cy, newSize));

    // At the time of writing:
    // When Win+D is pressed, `TriggerRedrawCursor` is called and a render pass is initiated.
    // As conhost is in the background, GetClientRect will return {0,0} and we'll get called with {0,0}.
    // This isn't a valid value for _api.sizeInPixel and would crash _recreateSizeDependentResources().
    if (_api.sizeInPixel != newSize && newSize != u16x2{})
    {
        _api.sizeInPixel = newSize;
        _api.cellCount = _api.sizeInPixel / _api.fontMetrics.cellSize;
        WI_SetFlag(_api.invalidations, ApiInvalidations::Size);
    }

    return S_OK;
}

void AtlasEngine::ToggleShaderEffects() noexcept
{
}

[[nodiscard]] HRESULT AtlasEngine::UpdateFont(const FontInfoDesired& fontInfoDesired, FontInfo& fontInfo, const std::unordered_map<std::wstring_view, uint32_t>& features, const std::unordered_map<std::wstring_view, float>& axes) noexcept
{
    static constexpr std::array fallbackFaceNames{ static_cast<const wchar_t*>(nullptr), L"Consolas", L"Lucida Console", L"Courier New" };
    auto it = fallbackFaceNames.begin();
    const auto end = fallbackFaceNames.end();

    for (;;)
    {
        try
        {
            _updateFont(*it, fontInfoDesired, fontInfo, features, axes);
            return S_OK;
        }
        catch (...)
        {
            ++it;
            if (it == end)
            {
                RETURN_CAUGHT_EXCEPTION();
            }
            else
            {
                LOG_CAUGHT_EXCEPTION();
            }
        }
    }
}

void AtlasEngine::UpdateHyperlinkHoveredId(const uint16_t hoveredId) noexcept
{