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

Code before:
}

// Routine Description:
// - Uses the internal text information and the analyzers/font information from construction
//   to determine the complexity of the text inside this layout, compute the subsections (or runs)
//   that contain similar property information, and stores that information internally.
// - We determine line breakpoints, bidirectional information, the script properties,
//   number substitution, and font fallback properties in this function.
// Arguments:
// - <none> - Uses internal state
// Return Value:
// - S_OK or suitable DirectWrite or STL error code
[[nodiscard]] HRESULT CustomTextLayout::_AnalyzeRuns() noexcept
{
    try
    {
        // We're going to need the text length in UINT32 format for the DWrite calls.
        // Convert it once up front.
        const auto textLength = gsl::narrow<UINT32>(_text.size());

        // Initially start out with one result that covers the entire range.
        // This result will be subdivided by the analysis processes.
        _runs.resize(1);
        auto& initialRun = _runs.front();
        initialRun.textLength = textLength;
        initialRun.bidiLevel = (_readingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);

        // Allocate enough room to have one breakpoint per code unit.
        _breakpoints.resize(_text.size());

        RETURN_IF_FAILED(_AnalyzeTextComplexity());

        if (!_isEntireTextSimple)
        {
            RETURN_IF_FAILED(_fontRenderData->Analyzer()->AnalyzeLineBreakpoints(this, 0, textLength, this));
        }

        std::vector<std::pair<UINT32, UINT32>> complexRanges;
        for (auto& run : _runs)
        {
            if (!run.isTextSimple)
            {
                complexRanges.push_back(std::make_pair(run.textStart, run.textLength));
            }
        }

        for (auto &range : complexRanges)
        {
            // Call each of the analyzers in sequence, recording their results.
            RETURN_IF_FAILED(_fontRenderData->Analyzer()->AnalyzeBidi(this, range.first, range.second, this));
            RETURN_IF_FAILED(_fontRenderData->Analyzer()->AnalyzeScript(this, range.first, range.second, this));

Review comment (suggestion):
I don't think we need the separate boolean or route for "is entire text simple" anymore. I think (and hope) that if the whole thing is simple, it should follow the same code path as if any individual piece of it is simple. So it should just be the loop that either does complex analysis or simple. And if the loop only loops once, then the entire thing was simple.

Code after:
// - Uses the internal text information and the analyzers/font information from construction
//   to determine the complexity of the text inside this layout, compute the subsections (or runs)
//   that contain similar property information, and stores that information internally.
// - We determine line breakpoints, bidirectional information, the script properties,
//   number substitution, and font fallback properties in this function.
// Arguments:
// - <none> - Uses internal state
// Return Value:
// - S_OK or suitable DirectWrite or STL error code
[[nodiscard]] HRESULT CustomTextLayout::_AnalyzeRuns() noexcept
{
    try
    {
        // We're going to need the text length in UINT32 format for the DWrite calls.
        // Convert it once up front.
        const auto textLength = gsl::narrow<UINT32>(_text.size());

        // Initially start out with one result that covers the entire range.
        // This result will be subdivided by the analysis processes.
        _runs.resize(1);
        auto& initialRun = _runs.front();
        initialRun.textLength = textLength;
        initialRun.bidiLevel = (_readingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);

        // Allocate enough room to have one breakpoint per code unit.
        _breakpoints.resize(_text.size());

        RETURN_IF_FAILED(_AnalyzeTextComplexity());

        std::vector<std::pair<UINT32, UINT32>> complexRanges;
        for (auto& run : _runs)
        {
            if (!run.isTextSimple)
            {
                complexRanges.push_back(std::make_pair(run.textStart, run.textLength));
            }
        }

        for (auto& range : complexRanges)
        {
            // Call each of the analyzers in sequence, recording their results.
            RETURN_IF_FAILED(_fontRenderData->Analyzer()->AnalyzeLineBreakpoints(this, range.first, range.second, this));
            RETURN_IF_FAILED(_fontRenderData->Analyzer()->AnalyzeBidi(this, range.first, range.second, this));
            RETURN_IF_FAILED(_fontRenderData->Analyzer()->AnalyzeScript(this, range.first, range.second, this));
            RETURN_IF_FAILED(_fontRenderData->Analyzer()->AnalyzeNumberSubstitution(this, range.first, range.second, this));
            // Perform our custom font fallback analyzer that mimics the pattern of the real analyzers.
            RETURN_IF_FAILED(_AnalyzeFontFallback(this, range.first, range.second));
        }

        // Ensure that a font face is attached to every run
        for (auto& run : _runs)