Ejemplo 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();
                    }
                }
            }
        }
Ejemplo n.º 2
0
        unsafe void GetGlyphPlacementsForControlCharacters(
            IntPtr pTextString,
            uint textLength,
            Font font,
            TextFormattingMode textFormattingMode,
            double fontEmSize,
            double scalingFactor,
            bool isSideways,
            float pixelsPerDip,
            uint glyphCount,
            ushort *pGlyphIndices, /* [in] glyphCount */
            int *glyphAdvances,    /* glyphCount */
            [Out] out GlyphOffset[] glyphOffsets
            )
        {
            if (glyphCount != textLength)
            {
                throw new ArgumentException("glyphCount must equal textLength");
            }

            glyphOffsets = new GlyphOffset[textLength];
            FontFace fontFace = font.GetFontFace();

            try
            {
                int hyphenAdvanceWidth = -1;
                for (uint i = 0; i < textLength; ++i)
                {
                    // LS will sometimes replace soft hyphens (which are invisible) with hyphens (which are visible).
                    // So if we are in this code then LS actually did this replacement and we need to display the hyphen (x002D)
                    if (Marshal.ReadInt16(pTextString, (int)i * 2) == CharHyphen)
                    {
                        if (hyphenAdvanceWidth == -1)
                        {
                            GlyphMetrics glyphMetrics;

                            if (textFormattingMode == TextFormattingMode.Ideal)
                            {
                                fontFace.GetDesignGlyphMetrics(pGlyphIndices + i, 1, &glyphMetrics);
                            }
                            else
                            {
                                fontFace.GetDisplayGlyphMetrics(
                                    pGlyphIndices + i,
                                    1,
                                    &glyphMetrics,
                                    (float)fontEmSize,
                                    textFormattingMode != TextFormattingMode.Display,
                                    isSideways,
                                    pixelsPerDip);
                            }
                            double approximatedHyphenAW = Math.Round(glyphMetrics.AdvanceWidth * fontEmSize / font.Metrics.DesignUnitsPerEm * pixelsPerDip) / pixelsPerDip;
                            hyphenAdvanceWidth = (int)Math.Round(approximatedHyphenAW * scalingFactor);
                        }

                        glyphAdvances[i] = hyphenAdvanceWidth;
                    }
                    else
                    {
                        glyphAdvances[i] = 0;
                    }
                    glyphOffsets[i].du = 0;
                    glyphOffsets[i].dv = 0;
                }
            }
            finally
            {
                fontFace.Release();
            }
        }