Exemplo n.º 1
0
        unsafe public void GetGlyphPlacements(
            IntPtr textString,
            ushort *clusterMap,            /* textLength */
            ushort *textProps,             /* textLength */
            uint textLength,
            ushort *glyphIndices,          /* glyphCount */
            ushort *glyphProps,            /* glyphCount */
            uint glyphCount,
            Font font,
            double fontEmSize,
            double scalingFactor,
            bool isSideways,
            bool isRightToLeft,
            CultureInfo cultureInfo,
            DWriteFontFeature[][]   features,
            uint[]                  featureRangeLengths,
            TextFormattingMode textFormattingMode,
            ItemProps itemProps,
            float pixelsPerDip,
            int *glyphAdvances,                /* glyphCount */
            [Out] out GlyphOffset[] glyphOffsets
            )
        {
            // Shaping should not have taken place if ScriptAnalysis is NULL!
            Debug.Assert(itemProps.ScriptAnalysis != null);

            // These are control characters and WPF will not display control characters.
            if (GetScriptShapes(itemProps) != DWriteScriptShapes.Default)
            {
                GetGlyphPlacementsForControlCharacters(
                    textString,
                    textLength,
                    font,
                    textFormattingMode,
                    fontEmSize,
                    scalingFactor,
                    isSideways,
                    pixelsPerDip,
                    glyphCount,
                    glyphIndices,
                    glyphAdvances,
                    out glyphOffsets
                    );
            }
            else
            {
                float[]             dwriteGlyphAdvances = new float[glyphCount];
                DWriteGlyphOffset[] dwriteGlyphOffsets  = null;

                var featureRangeLengthsNonNull = featureRangeLengths != null ? featureRangeLengths : new uint[0];
                fixed(uint *pFeatureRangeLengthsPinned = featureRangeLengthsNonNull)
                {
                    GCHandle[] dwriteFontFeaturesGCHandles = null;
                    uint       featureRanges = 0;

                    IntPtr[] dwriteTypographicFeatures       = null;
                    IntPtr   dwriteTypographicFeaturesMemory = IntPtr.Zero;
                    uint *   pFeatureRangeLengths            = null;

                    if (features != null)
                    {
                        pFeatureRangeLengths            = pFeatureRangeLengthsPinned;
                        featureRanges                   = (uint)featureRangeLengths.Length;
                        dwriteTypographicFeatures       = new IntPtr[featureRanges];
                        dwriteFontFeaturesGCHandles     = new GCHandle[featureRanges];
                        dwriteTypographicFeatures       = new IntPtr[featureRanges];
                        dwriteTypographicFeaturesMemory = Marshal.AllocCoTaskMem(Marshal.SizeOf <DWriteTypographicFeatures>() * (int)featureRanges);
                    }

                    FontFace fontFace       = font.GetFontFace();
                    IntPtr   scriptAnalysis = itemProps.ScriptAnalysisCoTaskMem();

                    try
                    {
                        string       localeName = cultureInfo.IetfLanguageTag;
                        DWriteMatrix transform  = Factory.GetIdentityTransform();

                        if (features != null)
                        {
                            for (uint i = 0; i < featureRanges; ++i)
                            {
                                dwriteFontFeaturesGCHandles[i] = GCHandle.Alloc(features[i], GCHandleType.Pinned);
                                var new_feature = new DWriteTypographicFeatures();
                                new_feature.features         = dwriteFontFeaturesGCHandles[i].AddrOfPinnedObject();
                                new_feature.featureCount     = features[i].Length;
                                dwriteTypographicFeatures[i] = dwriteTypographicFeaturesMemory + (int)i * Marshal.SizeOf <DWriteTypographicFeatures>();
                                Marshal.StructureToPtr <DWriteTypographicFeatures>(new_feature, dwriteTypographicFeatures[i], false);
                            }
                        }

                        float fontEmSizeFloat = (float)fontEmSize;

                        dwriteGlyphOffsets = new DWriteGlyphOffset[glyphCount];
                        if (textFormattingMode == TextFormattingMode.Ideal)
                        {
                            try {
                                _textAnalyzer.GetGlyphPlacements(
                                    textString,
                                    clusterMap,
                                    textProps,
                                    textLength,
                                    glyphIndices,
                                    glyphProps,
                                    glyphCount,
                                    fontFace.DWriteFontFaceNoAddRef,
                                    fontEmSizeFloat,
                                    isSideways,
                                    isRightToLeft,
                                    scriptAnalysis,
                                    localeName,
                                    dwriteTypographicFeatures,
                                    pFeatureRangeLengths,
                                    featureRanges,
                                    dwriteGlyphAdvances,
                                    dwriteGlyphOffsets
                                    );
                            }
                            catch (ArgumentException)
                            {
                                // If pLocaleName is unsupported (e.g. "prs-af"), DWrite returns E_INVALIDARG.
                                // Try again with the default mapping.
                                _textAnalyzer.GetGlyphPlacements(
                                    textString,
                                    clusterMap,
                                    textProps,
                                    textLength,
                                    glyphIndices,
                                    glyphProps,
                                    glyphCount,
                                    fontFace.DWriteFontFaceNoAddRef,
                                    fontEmSizeFloat,
                                    isSideways,
                                    isRightToLeft,
                                    scriptAnalysis,
                                    null,
                                    dwriteTypographicFeatures,
                                    pFeatureRangeLengths,
                                    featureRanges,
                                    dwriteGlyphAdvances,
                                    dwriteGlyphOffsets
                                    );
                            }
                        }
                        else
                        {
                            Debug.Assert(textFormattingMode == TextFormattingMode.Display);

                            try {
                                _textAnalyzer.GetGdiCompatibleGlyphPlacements(
                                    textString,
                                    clusterMap,
                                    textProps,
                                    textLength,
                                    glyphIndices,
                                    glyphProps,
                                    glyphCount,
                                    fontFace.DWriteFontFaceNoAddRef,
                                    fontEmSizeFloat,
                                    pixelsPerDip,
                                    ref transform,
                                    false,
                                    isSideways,
                                    isRightToLeft,
                                    scriptAnalysis,
                                    localeName,
                                    dwriteTypographicFeatures,
                                    pFeatureRangeLengths,
                                    featureRanges,
                                    dwriteGlyphAdvances,
                                    dwriteGlyphOffsets
                                    );
                            }
                            catch (ArgumentException) {
                                // If pLocaleName is unsupported (e.g. "prs-af"), DWrite returns E_INVALIDARG.
                                // Try again with the default mapping.
                                _textAnalyzer.GetGdiCompatibleGlyphPlacements(
                                    textString,
                                    clusterMap,
                                    textProps,
                                    textLength,
                                    glyphIndices,
                                    glyphProps,
                                    glyphCount,
                                    fontFace.DWriteFontFaceNoAddRef,
                                    fontEmSizeFloat,
                                    pixelsPerDip,
                                    ref transform,
                                    false,
                                    isSideways,
                                    isRightToLeft,
                                    scriptAnalysis,
                                    null,
                                    dwriteTypographicFeatures,
                                    pFeatureRangeLengths,
                                    featureRanges,
                                    dwriteGlyphAdvances,
                                    dwriteGlyphOffsets
                                    );
                            }
                        }

                        glyphOffsets = new GlyphOffset[glyphCount];
                        if (textFormattingMode == TextFormattingMode.Ideal)
                        {
                            for (uint i = 0; i < glyphCount; ++i)
                            {
                                glyphAdvances[i]   = (int)Math.Round(dwriteGlyphAdvances[i] * fontEmSize * scalingFactor / fontEmSizeFloat);
                                glyphOffsets[i].du = (int)(dwriteGlyphOffsets[i].AdvanceOffset * scalingFactor);
                                glyphOffsets[i].dv = (int)(dwriteGlyphOffsets[i].AscenderOffset * scalingFactor);
                            }
                        }
                        else
                        {
                            for (uint i = 0; i < glyphCount; ++i)
                            {
                                glyphAdvances[i]   = (int)Math.Round(dwriteGlyphAdvances[i] * scalingFactor);
                                glyphOffsets[i].du = (int)(dwriteGlyphOffsets[i].AdvanceOffset * scalingFactor);
                                glyphOffsets[i].dv = (int)(dwriteGlyphOffsets[i].AscenderOffset * scalingFactor);
                            }
                        }
                    }
                    finally
                    {
                        Marshal.FreeCoTaskMem(scriptAnalysis);

                        if (features != null)
                        {
                            for (uint i = 0; i < featureRanges; ++i)
                            {
                                dwriteFontFeaturesGCHandles[i].Free();
                            }
                            Marshal.FreeCoTaskMem(dwriteTypographicFeaturesMemory);
                        }

                        fontFace.Release();
                    }
                }
            }
        }
Exemplo n.º 2
0
        public unsafe void GetGlyphs(
            IntPtr textString,
            uint textLength,
            Font font,
            ushort blankGlyphIndex,
            bool isSideways,
            bool isRightToLeft,
            CultureInfo cultureInfo,
            DWriteFontFeature[][]                        features,
            uint[]                                       featureRangeLengths,
            uint maxGlyphCount,
            TextFormattingMode textFormattingMode,
            ItemProps itemProps,
            ushort *clusterMap,                                                     /* textLength */
            ushort *textProps,                                                      /* textLength */
            ushort *glyphIndices,                                                   /* maxGlyphCount */
            ushort *glyphProps,                                                     /* maxGlyphCount */
            int *pfCanGlyphAlone,                                                   /* textLength */
            [Out] out uint actualGlyphCount
            )
        {
            // Shaping should not have taken place if ScriptAnalysis is NULL!
            Debug.Assert(itemProps.ScriptAnalysis != null);

            // These are control characters and WPF will not display control characters.
            if (GetScriptShapes(itemProps) != DWriteScriptShapes.Default)
            {
                FontFace fontFace = font.GetFontFace();
                try
                {
                    GetBlankGlyphsForControlCharacters(
                        textString,
                        textLength,
                        fontFace,
                        blankGlyphIndex,
                        maxGlyphCount,
                        clusterMap,
                        glyphIndices,
                        pfCanGlyphAlone,
                        out actualGlyphCount
                        );
                }
                finally
                {
                    fontFace.Release();
                }
            }
            else
            {
                string localeName = cultureInfo.IetfLanguageTag;
                var    featureRangeLengthsNonNull = (featureRangeLengths != null) ? featureRangeLengths : new uint[0];
                fixed(uint *pFeatureRangeLengthsPinned = featureRangeLengthsNonNull)
                {
                    uint *pFeatureRangeLengths = null;

                    uint featureRanges = 0;

                    GCHandle[] dwriteFontFeaturesGCHandles     = null;
                    IntPtr[]   dwriteTypographicFeatures       = null;
                    IntPtr     dwriteTypographicFeaturesMemory = IntPtr.Zero;

                    if (features != null)
                    {
                        pFeatureRangeLengths            = pFeatureRangeLengthsPinned;
                        featureRanges                   = (uint)featureRangeLengths.Length;
                        dwriteFontFeaturesGCHandles     = new GCHandle[featureRanges];
                        dwriteTypographicFeatures       = new IntPtr[featureRanges];
                        dwriteTypographicFeaturesMemory = Marshal.AllocCoTaskMem(Marshal.SizeOf <DWriteTypographicFeatures>() * (int)featureRanges);
                    }

                    FontFace fontFace = font.GetFontFace();

                    try
                    {
                        if (features != null)
                        {
                            for (uint i = 0; i < featureRanges; ++i)
                            {
                                dwriteFontFeaturesGCHandles[i] = GCHandle.Alloc(features[i], GCHandleType.Pinned);
                                var new_feature = new DWriteTypographicFeatures();
                                new_feature.features         = dwriteFontFeaturesGCHandles[i].AddrOfPinnedObject();
                                new_feature.featureCount     = features[i].Length;
                                dwriteTypographicFeatures[i] = dwriteTypographicFeaturesMemory + (int)i * Marshal.SizeOf <DWriteTypographicFeatures>();
                                Marshal.StructureToPtr <DWriteTypographicFeatures>(new_feature, dwriteTypographicFeatures[i], false);
                            }
                        }


                        uint   glyphCount           = 0;
                        IntPtr dwriteScriptAnalysis = itemProps.ScriptAnalysisCoTaskMem();

                        int hr = _textAnalyzer.GetGlyphs(
                            textString,
                            /*checked*/ ((uint)textLength),
                            fontFace.DWriteFontFaceNoAddRef,
                            isSideways,
                            isRightToLeft,
                            dwriteScriptAnalysis,
                            localeName,
                            itemProps.NumberSubstitution,
                            dwriteTypographicFeatures,
                            pFeatureRangeLengths,
                            featureRanges,
                            /*checked*/ ((uint)maxGlyphCount),
                            clusterMap,
                            textProps,
                            glyphIndices,
                            glyphProps,
                            out glyphCount
                            );

                        if (unchecked ((int)0x80070057) == hr)                // E_INVALIDARG
                        {
                            // If pLocaleName is unsupported (e.g. "prs-af"), DWrite returns E_INVALIDARG.
                            // Try again with the default mapping.
                            hr = _textAnalyzer.GetGlyphs(
                                textString,
                                /*checked*/ ((uint)textLength),
                                fontFace.DWriteFontFaceNoAddRef,
                                isSideways,
                                isRightToLeft,
                                dwriteScriptAnalysis,
                                null,
                                itemProps.NumberSubstitution,
                                dwriteTypographicFeatures,
                                pFeatureRangeLengths,
                                featureRanges,
                                /*checked*/ ((uint)maxGlyphCount),
                                clusterMap,
                                textProps,
                                glyphIndices,
                                glyphProps,
                                out glyphCount
                                );
                        }

                        Marshal.FreeCoTaskMem(dwriteScriptAnalysis);

                        if (features != null)
                        {
                            for (uint i = 0; i < featureRanges; ++i)
                            {
                                dwriteFontFeaturesGCHandles[i].Free();
                            }
                            Marshal.FreeCoTaskMem(dwriteTypographicFeaturesMemory);
                        }

                        if (hr == unchecked ((int)0x8007007a))                // HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
                        {
                            // Actual glyph count is not returned by DWrite unless the call tp GetGlyphs succeeds.
                            // It must be re-estimated in case the first estimate was not adequate.
                            // The following calculation is a refactoring of DWrite's logic ( 3*stringLength/2 + 16) after 3 retries.
                            // We'd rather go directly to the maximum buffer size we are willing to allocate than pay the cost of continuously retrying.
                            actualGlyphCount = 27 * maxGlyphCount / 8 + 76;
                        }
                        else
                        {
                            Marshal.ThrowExceptionForHR(hr);
                            if (pfCanGlyphAlone != null)
                            {
                                for (uint i = 0; i < textLength; ++i)
                                {
                                    pfCanGlyphAlone[i] = (DWriteBitfieldUtils.ShapingText_IsShapedAlone(textProps[i])) ? 1 : 0;
                                }
                            }

                            actualGlyphCount = glyphCount;
                        }
                    }
                    finally
                    {
                        fontFace.Release();
                    }
                }
            }
        }