// Copyright (c) 2010-2014 SharpDX - Alexandre Mutel // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; using System.Runtime.InteropServices; using SharpDX.Mathematics.Interop; namespace SharpDX.DirectWrite { public partial class TextAnalyzer { /// /// Returns an interface for performing text analysis. /// /// A reference to a DirectWrite factory /// HRESULT IDWriteFactory::CreateTextAnalyzer([Out] IDWriteTextAnalyzer** textAnalyzer) public TextAnalyzer(Factory factory) { factory.CreateTextAnalyzer(this); } /// /// Gets the glyphs (TODO doc) /// /// The text string. /// Length of the text. /// The font face. /// if set to true [is sideways]. /// if set to true [is right to left]. /// The script analysis. /// Name of the locale. /// The number substitution. /// The features. /// The feature range lengths. /// The max glyph count. /// The cluster map. /// The text props. /// The glyph indices. /// The glyph props. /// The actual glyph count. /// /// If the method succeeds, it returns . /// /// HRESULT IDWriteTextAnalyzer::GetGlyphs([In, Buffer] const wchar_t* textString,[In] unsigned int textLength,[In] IDWriteFontFace* fontFace,[In] BOOL isSideways,[In] BOOL isRightToLeft,[In] const DWRITE_SCRIPT_ANALYSIS* scriptAnalysis,[In, Buffer, Optional] const wchar_t* localeName,[In, Optional] IDWriteNumberSubstitution* numberSubstitution,[In, Optional] const void** features,[In, Buffer, Optional] const unsigned int* featureRangeLengths,[In] unsigned int featureRanges,[In] unsigned int maxGlyphCount,[Out, Buffer] unsigned short* clusterMap,[Out, Buffer] DWRITE_SHAPING_TEXT_PROPERTIES* textProps,[Out, Buffer] unsigned short* glyphIndices,[Out, Buffer] DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProps,[Out] unsigned int* actualGlyphCount) public void GetGlyphs(string textString, int textLength, SharpDX.DirectWrite.FontFace fontFace, bool isSideways, bool isRightToLeft, SharpDX.DirectWrite.ScriptAnalysis scriptAnalysis, string localeName, SharpDX.DirectWrite.NumberSubstitution numberSubstitution, FontFeature[][] features, int[] featureRangeLengths, int maxGlyphCount, short[] clusterMap, SharpDX.DirectWrite.ShapingTextProperties[] textProps, short[] glyphIndices, SharpDX.DirectWrite.ShapingGlyphProperties[] glyphProps, out int actualGlyphCount) { var pFeatures = AllocateFeatures(features); try { GetGlyphs( textString, textLength, fontFace, isSideways, isRightToLeft, scriptAnalysis, localeName, numberSubstitution, pFeatures, featureRangeLengths, featureRangeLengths == null ? 0 : featureRangeLengths.Length, maxGlyphCount, clusterMap, textProps, glyphIndices, glyphProps, out actualGlyphCount); } finally { if (pFeatures != IntPtr.Zero) Marshal.FreeHGlobal(pFeatures); } } /// /// Gets the glyph placements. /// /// The text string. /// The cluster map. /// The text props. /// Length of the text. /// The glyph indices. /// The glyph props. /// The glyph count. /// The font face. /// Size of the font in ems. /// if set to true [is sideways]. /// if set to true [is right to left]. /// The script analysis. /// Name of the locale. /// The features. /// The feature range lengths. /// The glyph advances. /// The glyph offsets. /// /// If the method succeeds, it returns . /// /// HRESULT IDWriteTextAnalyzer::GetGlyphPlacements([In, Buffer] const wchar_t* textString,[In, Buffer] const unsigned short* clusterMap,[In, Buffer] DWRITE_SHAPING_TEXT_PROPERTIES* textProps,[In] unsigned int textLength,[In, Buffer] const unsigned short* glyphIndices,[In, Buffer] const DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProps,[In] unsigned int glyphCount,[In] IDWriteFontFace* fontFace,[In] float fontEmSize,[In] BOOL isSideways,[In] BOOL isRightToLeft,[In] const DWRITE_SCRIPT_ANALYSIS* scriptAnalysis,[In, Buffer, Optional] const wchar_t* localeName,[In, Optional] const void** features,[In, Buffer, Optional] const unsigned int* featureRangeLengths,[In] unsigned int featureRanges,[Out, Buffer] float* glyphAdvances,[Out, Buffer] DWRITE_GLYPH_OFFSET* glyphOffsets) public void GetGlyphPlacements(string textString, short[] clusterMap, SharpDX.DirectWrite.ShapingTextProperties[] textProps, int textLength, short[] glyphIndices, SharpDX.DirectWrite.ShapingGlyphProperties[] glyphProps, int glyphCount, SharpDX.DirectWrite.FontFace fontFace, float fontEmSize, bool isSideways, bool isRightToLeft, SharpDX.DirectWrite.ScriptAnalysis scriptAnalysis, string localeName, FontFeature[][] features, int[] featureRangeLengths, float[] glyphAdvances, SharpDX.DirectWrite.GlyphOffset[] glyphOffsets) { var pFeatures = AllocateFeatures(features); try { GetGlyphPlacements( textString, clusterMap, textProps, textLength, glyphIndices, glyphProps, glyphCount, fontFace, fontEmSize, isSideways, isRightToLeft, scriptAnalysis, localeName, pFeatures, featureRangeLengths, featureRangeLengths == null ? 0 : featureRangeLengths.Length, glyphAdvances, glyphOffsets ); } finally { if (pFeatures != IntPtr.Zero) Marshal.FreeHGlobal(pFeatures); } } /// /// Gets the GDI compatible glyph placements. /// /// The text string. /// The cluster map. /// The text props. /// Length of the text. /// The glyph indices. /// The glyph props. /// The glyph count. /// The font face. /// Size of the font em. /// The pixels per dip. /// The transform. /// if set to true [use GDI natural]. /// if set to true [is sideways]. /// if set to true [is right to left]. /// The script analysis. /// Name of the locale. /// The features. /// The feature range lengths. /// The glyph advances. /// The glyph offsets. /// /// If the method succeeds, it returns . /// /// HRESULT IDWriteTextAnalyzer::GetGdiCompatibleGlyphPlacements([In, Buffer] const wchar_t* textString,[In, Buffer] const unsigned short* clusterMap,[In, Buffer] DWRITE_SHAPING_TEXT_PROPERTIES* textProps,[In] unsigned int textLength,[In, Buffer] const unsigned short* glyphIndices,[In, Buffer] const DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProps,[In] unsigned int glyphCount,[In] IDWriteFontFace* fontFace,[In] float fontEmSize,[In] float pixelsPerDip,[In, Optional] const DWRITE_MATRIX* transform,[In] BOOL useGdiNatural,[In] BOOL isSideways,[In] BOOL isRightToLeft,[In] const DWRITE_SCRIPT_ANALYSIS* scriptAnalysis,[In, Buffer, Optional] const wchar_t* localeName,[In, Optional] const void** features,[In, Buffer, Optional] const unsigned int* featureRangeLengths,[In] unsigned int featureRanges,[Out, Buffer] float* glyphAdvances,[Out, Buffer] DWRITE_GLYPH_OFFSET* glyphOffsets) public void GetGdiCompatibleGlyphPlacements(string textString, short[] clusterMap, SharpDX.DirectWrite.ShapingTextProperties[] textProps, int textLength, short[] glyphIndices, SharpDX.DirectWrite.ShapingGlyphProperties[] glyphProps, int glyphCount, SharpDX.DirectWrite.FontFace fontFace, float fontEmSize, float pixelsPerDip, RawMatrix3x2? transform, bool useGdiNatural, bool isSideways, bool isRightToLeft, SharpDX.DirectWrite.ScriptAnalysis scriptAnalysis, string localeName, FontFeature[][] features, int[] featureRangeLengths, float[] glyphAdvances, SharpDX.DirectWrite.GlyphOffset[] glyphOffsets) { var pFeatures = AllocateFeatures(features); try { GetGdiCompatibleGlyphPlacements( textString, clusterMap, textProps, textLength, glyphIndices, glyphProps, glyphCount, fontFace, fontEmSize, pixelsPerDip, transform, useGdiNatural, isSideways, isRightToLeft, scriptAnalysis, localeName, pFeatures, featureRangeLengths, featureRangeLengths == null ? 0 : featureRangeLengths.Length, glyphAdvances, glyphOffsets ); } finally { if (pFeatures != IntPtr.Zero) Marshal.FreeHGlobal(pFeatures); } } /// /// Allocates the features from the jagged array.. /// /// The features. /// A pointer to the allocated native features or 0 if features is null or empty. private static IntPtr AllocateFeatures(FontFeature[][] features) { unsafe { var pFeatures = (byte*)0; if (features != null && features.Length > 0) { // Calculate the total size of the buffer to allocate: // (0) (1) (2) // ------------------------------------------------------------- // | array | TypographicFeatures || FontFeatures || // | ptr to (1) | | | || || // | | ptr to FontFeatures || || // ------------------------------------------------------------- // Offset in bytes to (1) int offsetToTypographicFeatures = sizeof(IntPtr) * features.Length; // Add offset (1) and Size in bytes to (1) int calcSize = offsetToTypographicFeatures + sizeof(TypographicFeatures) * features.Length; // Calculate size (2) foreach (var fontFeature in features) { if (fontFeature == null) throw new ArgumentNullException("features", "FontFeature[] inside features array cannot be null."); // calcSize += typographicFeatures.Length * sizeof(FontFeature) calcSize += sizeof(FontFeature) * fontFeature.Length; } // Allocate the whole buffer pFeatures = (byte*)Marshal.AllocHGlobal(calcSize); // Pointer to (1) var pTypographicFeatures = (TypographicFeatures*)(pFeatures + offsetToTypographicFeatures); // Pointer to (2) var pFontFeatures = (FontFeature*)(pTypographicFeatures + features.Length); // Iterate on features and copy them to (2) for (int i = 0; i < features.Length; i++) { // Write array pointers in (0) ((void**)pFeatures)[i] = pTypographicFeatures; var featureSet = features[i]; // Write TypographicFeatures in (1) pTypographicFeatures->Features = (IntPtr)pFontFeatures; pTypographicFeatures->FeatureCount = featureSet.Length; pTypographicFeatures++; // Write FontFeatures in (2) for (int j = 0; j < featureSet.Length; j++) { *pFontFeatures = featureSet[j]; pFontFeatures++; } } } return (IntPtr)pFeatures; } } } }