IFACEMETHODIMP CanvasTextAnalyzer::GetGlyphsWithAllOptions()

in winrt/lib/text/CanvasTextAnalyzer.cpp [907:1072]


IFACEMETHODIMP CanvasTextAnalyzer::GetGlyphsWithAllOptions(
    CanvasCharacterRange characterRange,
    ICanvasFontFace* fontFace,
    float fontSize,
    boolean isSideways,
    boolean isRightToLeft,
    CanvasAnalyzedScript script,
    HSTRING locale,
    ICanvasNumberSubstitution* numberSubstitution,
    IVectorView<IKeyValuePair<CanvasCharacterRange, CanvasTypography*>*>* typographyRanges,
    uint32_t* clusterMapIndexCount,
    int** clusterMapIndexElements,
    uint32_t* isShapedAloneCount,
    boolean** isShapedAloneElements,
    uint32_t* glyphShapingCount,
    CanvasGlyphShaping** glyphShapingElements,
    uint32_t* valueCount,
    CanvasGlyph** valueElements)
{
    return ExceptionBoundary(
        [&]
        {
            CheckInPointer(fontFace);
            CheckAndClearOutPointer(valueElements);

            ThrowIfNegative(characterRange.CharacterIndex);
            ThrowIfNegative(characterRange.CharacterCount);

            wchar_t const* text;
            uint32_t textLength;

            text = WindowsGetStringRawBuffer(m_text, &textLength);

            ThrowIfInvalidCharacterRange(textLength, characterRange);

            text += characterRange.CharacterIndex;
            textLength = characterRange.CharacterCount;

            auto dwriteScriptAnalysis = ToDWriteScriptAnalysis(script);

            std::vector<uint16_t> clusterMap;
            clusterMap.resize(textLength);

            std::vector<DWRITE_SHAPING_TEXT_PROPERTIES> shapingTextProperties;
            shapingTextProperties.resize(textLength);

            auto dwriteFontFace = As<ICanvasFontFaceInternal>(fontFace)->GetRealizedFontFace();
            
            ComPtr<IDWriteNumberSubstitution> dwriteNumberSubstitution;
            if (numberSubstitution)
                dwriteNumberSubstitution = GetWrappedResource<IDWriteNumberSubstitution>(numberSubstitution);

            uint32_t typographyRangeCount = 0;
            DWriteTypographyRangeData dwriteTypographyRangeData;
            if (typographyRanges)
            {
                GetDWriteTypographyRanges(characterRange, typographyRanges, &typographyRangeCount, &dwriteTypographyRangeData);
            }

            std::vector<DWRITE_TYPOGRAPHIC_FEATURES> featuresPerSpan;

            std::vector<uint16_t> glyphIndices;

            std::vector<DWRITE_SHAPING_GLYPH_PROPERTIES> shapingGlyphProperties;

            uint32_t actualGlyphCount{};    
            RetryWithIncreasingGlyphCount(
                textLength,
                [&](uint32_t maxGlyphCount)
                {
                    glyphIndices.resize(maxGlyphCount);

                    shapingGlyphProperties.resize(maxGlyphCount);

                    return m_customFontManager->GetTextAnalyzer()->GetGlyphs(
                        text,
                        textLength,
                        dwriteFontFace.Get(),
                        isSideways,
                        isRightToLeft,
                        &dwriteScriptAnalysis,
                        WindowsGetStringRawBuffer(locale, nullptr),
                        dwriteNumberSubstitution.Get(),
                        typographyRanges ? dwriteTypographyRangeData.FeatureDataPointers.data() : nullptr,
                        typographyRanges ? dwriteTypographyRangeData.FeatureRangeLengths.data() : nullptr,
                        typographyRangeCount,
                        maxGlyphCount,
                        clusterMap.data(),
                        shapingTextProperties.data(),
                        glyphIndices.data(),
                        shapingGlyphProperties.data(),
                        &actualGlyphCount);
                });

            std::vector<float> glyphAdvances;
            glyphAdvances.resize(actualGlyphCount);

            std::vector<DWRITE_GLYPH_OFFSET> glyphOffsets;
            glyphOffsets.resize(actualGlyphCount);

            ThrowIfFailed(m_customFontManager->GetTextAnalyzer()->GetGlyphPlacements(
                text,
                clusterMap.data(),
                shapingTextProperties.data(),
                textLength,
                glyphIndices.data(),
                shapingGlyphProperties.data(),
                actualGlyphCount,
                dwriteFontFace.Get(),
                fontSize,
                isSideways,
                isRightToLeft,
                &dwriteScriptAnalysis,
                WindowsGetStringRawBuffer(locale, nullptr),
                typographyRanges ? dwriteTypographyRangeData.FeatureDataPointers.data() : nullptr,
                typographyRanges ? dwriteTypographyRangeData.FeatureRangeLengths.data() : nullptr,
                typographyRangeCount,
                glyphAdvances.data(),
                glyphOffsets.data()));

            ComArray<CanvasGlyph> glyphs(actualGlyphCount);
            for (uint32_t i = 0; i < actualGlyphCount; ++i)
            {
                glyphs[i].Index = glyphIndices[i];
                glyphs[i].Advance = glyphAdvances[i];
                glyphs[i].AdvanceOffset = glyphOffsets[i].advanceOffset;
                glyphs[i].AscenderOffset = glyphOffsets[i].ascenderOffset;
            }
            glyphs.Detach(valueCount, valueElements);

            if (clusterMapIndexElements)
            {
                auto clusterMapResult = TransformToComArray<int>(clusterMap.begin(), clusterMap.end(), 
                    [](uint16_t value)
                    {
                        return static_cast<int>(value);
                    });
                clusterMapResult.Detach(clusterMapIndexCount, clusterMapIndexElements);
            }

            if (isShapedAloneElements)
            {
                auto isShapedAloneResult = TransformToComArray<boolean>(shapingTextProperties.begin(), shapingTextProperties.end(),
                    [](DWRITE_SHAPING_TEXT_PROPERTIES const& value)
                    {
                        return !!value.isShapedAlone;
                    });
                isShapedAloneResult.Detach(isShapedAloneCount, isShapedAloneElements);
            }

            if (glyphShapingElements)
            {
                auto glyphShaping = TransformToComArray<CanvasGlyphShaping>(shapingGlyphProperties.begin(), shapingGlyphProperties.begin() + actualGlyphCount,
                    [](DWRITE_SHAPING_GLYPH_PROPERTIES const& dwriteValue)
                    {
                        CanvasGlyphShaping result{};
                        result.Justification = ToCanvasGlyphJustification(dwriteValue.justification);
                        result.IsClusterStart = dwriteValue.isClusterStart;
                        result.IsDiacritic = dwriteValue.isDiacritic;
                        result.IsZeroWidthSpace = dwriteValue.isZeroWidthSpace;
                        return result;
                    });
                glyphShaping.Detach(glyphShapingCount, glyphShapingElements);
            }
        });
}