Repository: microsoft/terminal
File: src/renderer/dx/DxFontRenderData.cpp (C++)

Code before:
                                                     nullptr,
                                                     fontInfo.GetWeight(),
                                                     fontInfo.GetStyle(),
                                                     fontInfo.GetStretch(),
                                                     _fontSize,
                                                     localeName.data(),
                                                     &format));

    // If the OS supports IDWriteTextFormat3, set the font axes
    ::Microsoft::WRL::ComPtr<IDWriteTextFormat3> format3;
    if (!_axesVector.empty() && !FAILED(format->QueryInterface(IID_PPV_ARGS(&format3))))
    {
        if (!_useUserWeight)
        {
            // Remove the user set weight if we were told not to use it
            // (only remove it from the list we are about to pass to the text format,
            //  don't delete it from our internal axes vector)
            std::vector<DWRITE_FONT_AXIS_VALUE> axesWithoutWeight;
            for (const auto axis : _axesVector)
            {
                if (axis.axisTag != DWRITE_FONT_AXIS_TAG_WEIGHT)
                {
                    axesWithoutWeight.emplace_back(axis);
                }
            }
            format3->SetFontAxisValues(axesWithoutWeight.data(), gsl::narrow<uint32_t>(axesWithoutWeight.size()));
        }
        else
        {
            format3->SetFontAxisValues(_axesVector.data(), gsl::narrow<uint32_t>(_axesVector.size()));
        }
    }

    return format;
}


Review comment (suggestion):
We know the approximate size of `axesWithoutWeight`, so it'd be easy to add a quick `axesWithoutWeight.reserve(_axesVector.size())` call in there.

But you could prevent this temporary allocation entirely by modifying `DxFontRenderData::_SetAxes` similar to this (pseudo-code):
```cpp
struct DxFontRenderData {
	// ...
    std::vector<DWRITE_FONT_AXIS_VALUE> _axesVectorWithBold;
    gsl::span<DWRITE_FONT_AXIS_VALUE> _axesVector;
}

// ...

void DxFontRenderData::_SetAxes(const std::unordered_map<std::wstring_view, float>& axes)
{
    _axesVectorWithBold.clear();
    _didUserSetAxes = false;

    // Update our axis map with the provided axes
    if (!axes.empty())
    {
        bool hasBold = false;

#pragma warning(suppress : 26445) // the analyzer doesn't like reference to string_view
        for (const auto& [axis, value] : axes)
        {
            if (axis.length() == TAG_LENGTH)
            {
                const auto dwriteTag = DWRITE_MAKE_FONT_AXIS_TAG(til::at(axis, 0), til::at(axis, 1), til::at(axis, 2), til::at(axis, 3));
                hasBold |= dwriteTag == DWRITE_FONT_AXIS_TAG_WEIGHT;
                _axesVectorWithBold.emplace_back(DWRITE_FONT_AXIS_VALUE{ dwriteTag, value });
            }
        }

        _didUserSetAxes = true;
        _axesVector = gsl::make_span(_axesVectorWithBold);

        if (!hasBold) {
            _axesVectorWithBold.emplace_back(DWRITE_FONT_AXIS_TAG_WEIGHT);
        }
    }
}
```

Afterwards you can remove the loop from `_BuildTextFormat` and just use the two members as you need.

Axes are only modified extremely seldom, whereas something like `DxFontRenderData::_BuildTextFormat` is run thousands of times per second, which makes aggressive caching a good idea under all circumstances as far as I can see.

Code after:
    // But if the resulting gap isn't big enough even to register as a thicker
    // line, it's better to place the second line slightly above the first.
    if (lineMetrics.underlineOffset2 < lineMetrics.underlineOffset + lineMetrics.gridlineWidth)
    {
        lineMetrics.underlineOffset2 = lineMetrics.underlineOffset - lineMetrics.gridlineWidth;
    }

    // We also add half the stroke width to the offsets, since the line
    // coordinates designate the center of the line.
    lineMetrics.underlineOffset += lineMetrics.underlineWidth / 2.0f;
    lineMetrics.underlineOffset2 += lineMetrics.underlineWidth / 2.0f;
    lineMetrics.strikethroughOffset += lineMetrics.strikethroughWidth / 2.0f;

    _lineMetrics = lineMetrics;

    _glyphCell = actual.GetSize();
}

Microsoft::WRL::ComPtr<IDWriteTextFormat> DxFontRenderData::_BuildTextFormat(const DxFontInfo fontInfo, const std::wstring_view localeName)
{
    Microsoft::WRL::ComPtr<IDWriteTextFormat> format;
    THROW_IF_FAILED(_dwriteFactory->CreateTextFormat(fontInfo.GetFamilyName().data(),
                                                     nullptr,
                                                     fontInfo.GetWeight(),
                                                     fontInfo.GetStyle(),
                                                     fontInfo.GetStretch(),
                                                     _fontSize,
                                                     localeName.data(),
                                                     &format));

    // If the OS supports IDWriteTextFormat3, set the font axes
    ::Microsoft::WRL::ComPtr<IDWriteTextFormat3> format3;
    if (!FAILED(format->QueryInterface(IID_PPV_ARGS(&format3))))
    {
        if (_inhibitUserWeight && !_axesVectorWithoutWeight.empty())
        {
            format3->SetFontAxisValues(_axesVectorWithoutWeight.data(), gsl::narrow<uint32_t>(_axesVectorWithoutWeight.size()));
        }
        else if (!_inhibitUserWeight && !_axesVector.empty())
        {
            format3->SetFontAxisValues(_axesVector.data(), gsl::narrow<uint32_t>(_axesVector.size()));
        }
    }

    return format;
}