Beispiel #1
0
        internal FormatSettings(
            TextFormatterImp    formatter,
            TextSource          textSource,
            TextRunCacheImp     runCache,
            ParaProp            pap,
            TextLineBreak       previousLineBreak,
            bool                isSingleLineFormatting,
            TextFormattingMode  textFormattingMode,
            bool                isSideways
            )
        {
            _isSideways     = isSideways;
            _textFormattingMode = textFormattingMode;
            _formatter      = formatter;
            _textSource     = textSource;
            _runCache       = runCache;
            _pap            = pap;
            _digitState     = new DigitState();
            _previousLineBreak = previousLineBreak;
            _maxLineWidth      = Constants.IdealInfiniteWidth;

            if (isSingleLineFormatting)
            {
                // Apply text indent on each line in single line mode
                _textIndent = _pap.Indent;
            }
        }
Beispiel #2
0
        /// <summary>
        /// Construct an instance of TextFormatter implementation with the specified context
        /// </summary>
        /// <param name="soleContext"></param>
        /// <remarks>
        /// TextFormatter created via this special ctor takes a specified context and uses it as the only known
        /// context within its entire lifetime. It prohibits reentering of TextFormatter during formatting as only
        /// one context is allowed. This restriction is critical to the optimal break algorithm supported by the current
        /// version of PTLS.
        /// </remarks>
        internal TextFormatterImp(TextFormatterContext soleContext, TextFormattingMode textFormattingMode)
        {
            _textFormattingMode = textFormattingMode;

            if (soleContext != null)
                _contextList.Add(soleContext);

            _multipleContextProhibited = (_contextList.Count != 0);
        }
        public static void SetTextFormattingMode(DependencyObject element, TextFormattingMode value)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            element.SetValue(TextFormattingModeProperty, value);
        }
Beispiel #4
0
        public static void SetTextFormattingMode(FrameworkElement element, TextFormattingMode value)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            element.SetValue(TextFormattingModeProperty, value);
        }
Beispiel #5
0
        //-------------------------------------------------------------------
        //
        //  Internal Methods
        //
        //-------------------------------------------------------------------

        #region Internal Methods

        /// <summary>
        /// Acquires new PTS Context and associates it with new owner.
        /// </summary>
        /// <param name="ptsContext">Context used to communicate with PTS component.</param>
        internal static PtsHost AcquireContext(PtsContext ptsContext, TextFormattingMode textFormattingMode)
        {
            PtsCache ptsCache = ptsContext.Dispatcher.PtsCache as PtsCache;
            if (ptsCache == null)
            {
                ptsCache = new PtsCache(ptsContext.Dispatcher);
                ptsContext.Dispatcher.PtsCache = ptsCache;
            }
            return ptsCache.AcquireContextCore(ptsContext, textFormattingMode);
        }
Beispiel #6
0
        /// <summary>
        /// Client to create a new instance of TextFormatter
        /// </summary>
        /// <returns>New instance of TextFormatter</returns>
        static public TextFormatter Create(TextFormattingMode textFormattingMode)
        {
            if ((int)textFormattingMode < 0 || (int)textFormattingMode > 1)
            {
                throw new System.ComponentModel.InvalidEnumArgumentException("textFormattingMode", (int)textFormattingMode, typeof(TextFormattingMode));
            }

            // create a new instance of TextFormatter which allows the use of multiple contexts.
            return(new TextFormatterImp(textFormattingMode));
        }
Beispiel #7
0
        /// <summary>
        /// Client to create a new instance of TextFormatter 
        /// </summary> 
        /// <returns>New instance of TextFormatter</returns>
        static public TextFormatter Create(TextFormattingMode textFormattingMode) 
        {
            if ((int)textFormattingMode < 0 || (int)textFormattingMode > 1)
            {
                throw new System.ComponentModel.InvalidEnumArgumentException("textFormattingMode", (int)textFormattingMode, typeof(TextFormattingMode)); 
            }
 
            // create a new instance of TextFormatter which allows the use of multiple contexts. 
            return new TextFormatterImp(textFormattingMode);
        } 
 /// <summary>
 /// Ensures the PtsContext exists.
 /// </summary>
 private void EnsurePtsContext()
 {
     if (_ptsContext == null)
     {
         TextFormattingMode textFormattingMode = TextOptions.GetTextFormattingMode(this.PropertyOwner);
         _ptsContext        = new PtsContext(true, textFormattingMode);
         _textFormatterHost = new TextFormatterHost(_ptsContext.TextFormatter, textFormattingMode);
         _section           = new MS.Internal.PtsHost.Section(this);
     }
 }
Beispiel #9
0
 /// <summary>
 /// Empty private constructor
 /// </summary>
 private FullTextLine(TextFormattingMode textFormattingMode, bool justify, double pixelsPerDip) : base(pixelsPerDip)
 {
     _textFormattingMode = textFormattingMode;
     if (justify)
     {
         _statusFlags |= StatusFlags.IsJustified;
     }
     _metrics = new TextMetrics();
     _metrics._pixelsPerDip = pixelsPerDip;
 }
Beispiel #10
0
 // Token: 0x06006A7B RID: 27259 RVA: 0x001E4664 File Offset: 0x001E2864
 private void EnsurePtsContext()
 {
     if (this._ptsContext == null)
     {
         TextFormattingMode textFormattingMode = TextOptions.GetTextFormattingMode(this.PropertyOwner);
         this._ptsContext        = new PtsContext(true, textFormattingMode);
         this._textFormatterHost = new TextFormatterHost(this._ptsContext.TextFormatter, textFormattingMode, this._owner.PixelsPerDip);
         this._section           = new Section(this);
     }
 }
        /// <summary>
        /// Construct an instance of TextFormatter implementation with the specified context
        /// </summary>
        /// <param name="soleContext"></param>
        /// <remarks>
        /// TextFormatter created via this special ctor takes a specified context and uses it as the only known
        /// context within its entire lifetime. It prohibits reentering of TextFormatter during formatting as only
        /// one context is allowed. This restriction is critical to the optimal break algorithm supported by the current
        /// version of PTLS.
        /// </remarks>
        internal TextFormatterImp(TextFormatterContext soleContext, TextFormattingMode textFormattingMode)
        {
            _textFormattingMode = textFormattingMode;

            if (soleContext != null)
            {
                _contextList.Add(soleContext);
            }

            _multipleContextProhibited = (_contextList.Count != 0);
        }
Beispiel #12
0
        internal static PtsHost AcquireContext(PtsContext ptsContext, TextFormattingMode textFormattingMode)
        {
            PtsCache ptsCache = ptsContext.Dispatcher.PtsCache as PtsCache;

            if (ptsCache == null)
            {
                ptsCache = new PtsCache(ptsContext.Dispatcher);
                ptsContext.Dispatcher.PtsCache = ptsCache;
            }
            return(ptsCache.AcquireContextCore(ptsContext, textFormattingMode));
        }
 internal static double RoundDip(double value, TextFormattingMode textFormattingMode)
 {
     if (TextFormattingMode.Display == textFormattingMode)
     {
         return(RoundDipForDisplayMode(value));
     }
     else
     {
         return(value);
     }
 }
 internal TextFormatterHost(TextFormatter textFormatter, TextFormattingMode textFormattingMode)
 {
     if (textFormatter == null)
     {
         TextFormatter = TextFormatter.FromCurrentDispatcher(textFormattingMode);
     }
     else
     {
         TextFormatter = textFormatter;
     }
 }
Beispiel #15
0
 internal TextFormatterHost(TextFormatter textFormatter, TextFormattingMode textFormattingMode)
 {
     if(textFormatter == null)
     {
         TextFormatter = TextFormatter.FromCurrentDispatcher(textFormattingMode);
     }
     else
     {
         TextFormatter = textFormatter;
     }
 }
Beispiel #16
0
        internal PtsContext(bool isOptimalParagraphEnabled, TextFormattingMode textFormattingMode)
        {
            _pages = new ArrayList(1);
            _pageBreakRecords = new ArrayList(1);
            _unmanagedHandles = new HandleIndex[_defaultHandlesCapacity]; // Limit initial size
            _isOptimalParagraphEnabled = isOptimalParagraphEnabled;

            BuildFreeList(1); // 1 is the first free index in UnmanagedHandles array

            // Acquire PTS Context
            _ptsHost = PtsCache.AcquireContext(this, textFormattingMode);
        }
Beispiel #17
0
        //-------------------------------------------------------------------
        //
        //  Constructors
        //
        //-------------------------------------------------------------------

        #region Constructors

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <remarks>
        /// The array of entries initially can store up to 16 entries. Upon
        /// adding elements the capacity increased in multiples of two as
        /// required. The first element always contains index to the next
        /// free entry. All free entries are forming a linked list.
        /// </remarks>
        internal PtsContext(bool isOptimalParagraphEnabled, TextFormattingMode textFormattingMode)
        {
            _pages                     = new ArrayList(1);
            _pageBreakRecords          = new ArrayList(1);
            _unmanagedHandles          = new HandleIndex[_defaultHandlesCapacity]; // Limit initial size
            _isOptimalParagraphEnabled = isOptimalParagraphEnabled;

            BuildFreeList(1); // 1 is the first free index in UnmanagedHandles array

            // Acquire PTS Context
            _ptsHost = PtsCache.AcquireContext(this, textFormattingMode);
        }
 // Token: 0x06006ADD RID: 27357 RVA: 0x001E958E File Offset: 0x001E778E
 internal TextFormatterHost(TextFormatter textFormatter, TextFormattingMode textFormattingMode, double pixelsPerDip)
 {
     if (textFormatter == null)
     {
         this.TextFormatter = TextFormatter.FromCurrentDispatcher(textFormattingMode);
     }
     else
     {
         this.TextFormatter = textFormatter;
     }
     base.PixelsPerDip = pixelsPerDip;
 }
Beispiel #19
0
            public FormattedTextBuilder([NotNull] IFontInfo fontInfo, string text)
            {
                mFontInfo = fontInfo ?? throw new ArgumentNullException(nameof(fontInfo));
                mText     = text ?? string.Empty;

                mCulture            = CultureInfo.CurrentCulture;
                mFlowDirection      = System.Windows.FlowDirection.LeftToRight;
                mForeground         = Brushes.Black;
                mNumberSubstitution = null;
                mTextFormattingMode = System.Windows.Media.TextFormattingMode.Display;

                mDpi = typeof(SystemParameters).GetProperty("Dpi", BindingFlags.NonPublic | BindingFlags.Static)?.GetValue(null, null) as double? ?? 96.0;
            }
Beispiel #20
0
        /// <summary>
        /// Lookup characters nominal glyphs and width
        /// </summary>
        /// <param name="charBufferRange">character buffer range</param>
        /// <param name="emSize">height of Em</param>
        /// <param name="toIdeal"> scaling factor from real to ideal unit </param>
        /// <param name="nominalWidths">glyph nominal advances in ideal units</param>
        /// <param name="idealWidth">total width in ideal units</param>
        /// <returns>true for success</returns>
        /// <remarks>This function is only used in fast path, and can only be called
        /// if CheckFastPathNominalGlyphs has previously returned true.</remarks>
        internal void GetCharacterNominalWidthsAndIdealWidth(
            CharacterBufferRange charBufferRange,
            double emSize,
            float pixelsPerDip,
            double toIdeal,
            TextFormattingMode textFormattingMode,
            bool isSideways,
            out int[]            nominalWidths,
            out int idealWidth
            )
        {
            // This function should only be called if CheckFastPathNominalGlyphs has
            // returned true so we can assume the ITypefaceMetrics is a GlyphTypeface.
            GlyphTypeface glyphTypeface = TryGetGlyphTypeface();

            Invariant.Assert(glyphTypeface != null);

            MS.Internal.Text.TextInterface.GlyphMetrics[] glyphMetrics = BufferCache.GetGlyphMetrics(charBufferRange.Length);

            glyphTypeface.GetGlyphMetricsOptimized(charBufferRange,
                                                   emSize,
                                                   pixelsPerDip,
                                                   textFormattingMode,
                                                   isSideways,
                                                   glyphMetrics);

            nominalWidths = new int[charBufferRange.Length];
            idealWidth    = 0;

            if (TextFormattingMode.Display == textFormattingMode)
            {
                double designToEm = emSize / glyphTypeface.DesignEmHeight;
                for (int i = 0; i < charBufferRange.Length; i++)
                {
                    nominalWidths[i] = (int)Math.Round(TextFormatterImp.RoundDipForDisplayMode(glyphMetrics[i].AdvanceWidth * designToEm, pixelsPerDip) * toIdeal);
                    idealWidth      += nominalWidths[i];
                }
            }
            else
            {
                double designToEm = emSize * toIdeal / glyphTypeface.DesignEmHeight;
                for (int i = 0; i < charBufferRange.Length; i++)
                {
                    nominalWidths[i] = (int)Math.Round(glyphMetrics[i].AdvanceWidth * designToEm);
                    idealWidth      += nominalWidths[i];
                }
            }

            BufferCache.ReleaseGlyphMetrics(glyphMetrics);
        }
Beispiel #21
0
        protected FormattedText buildFormattedText(String Text, FontInfo Font, CharDisplayInfo cdi, DrawingContext dc)
        {
            TextFormattingMode tfm = TextFormattingMode.Display;
            FormattedText      ft  = new FormattedText(Text,
                                                       CultureInfo.CurrentCulture,
                                                       FlowDirection.LeftToRight,
                                                       Font.Typeface,
                                                       Font.PointSize,
                                                       ZColorCheck.ZColorToBrush(cdi.ForegroundColor, ColorType.Foreground),
                                                       _substituion, tfm);

            setStyle(cdi, Text.Length, ft);

            return(ft);
        }
Beispiel #22
0
        internal void GetShapeableText(
            Typeface typeface,
            CharacterBufferReference characterBufferReference,
            int stringLength,
            TextRunProperties textRunProperties,
            CultureInfo digitCulture,
            bool isRightToLeftParagraph,
            IList <TextShapeableSymbols> shapeableList,
            IShapeableTextCollector collector,
            TextFormattingMode textFormattingMode
            )
        {
            if (!typeface.Symbol)
            {
                Lookup(typeface).GetShapeableText(
                    characterBufferReference,
                    stringLength,
                    textRunProperties,
                    digitCulture,
                    isRightToLeftParagraph,
                    shapeableList,
                    collector,
                    textFormattingMode
                    );
            }
            else
            {
                // It's a non-Unicode ("symbol") font, where code points have non-standard meanings. We
                // therefore want to bypass the usual itemization and font linking. Instead, just map
                // everything to the default script and first GlyphTypeface.

                ShapeTypeface shapeTypeface = new ShapeTypeface(
                    typeface.TryGetGlyphTypeface(),
                    null // device font
                    );

                collector.Add(
                    shapeableList,
                    new CharacterBufferRange(characterBufferReference, stringLength),
                    textRunProperties,
                    new MS.Internal.Text.TextInterface.ItemProps(),
                    shapeTypeface,
                    1.0,   // scale in Em
                    false, // null shape
                    textFormattingMode
                    );
            }
        }
Beispiel #23
0
        internal void GetShapeableText(
            Typeface                    typeface, 
            CharacterBufferReference    characterBufferReference,
            int                         stringLength,
            TextRunProperties           textRunProperties,
            CultureInfo                 digitCulture, 
            bool                        isRightToLeftParagraph,
            IList<TextShapeableSymbols> shapeableList, 
            IShapeableTextCollector     collector, 
            TextFormattingMode              textFormattingMode
            ) 
        {
            if (!typeface.Symbol)
            {
                Lookup(typeface).GetShapeableText( 
                    characterBufferReference,
                    stringLength, 
                    textRunProperties, 
                    digitCulture,
                    isRightToLeftParagraph, 
                    shapeableList,
                    collector,
                    textFormattingMode
                    ); 
            }
            else 
            { 
                // It's a non-Unicode ("symbol") font, where code points have non-standard meanings. We
                // therefore want to bypass the usual itemization and font linking. Instead, just map 
                // everything to the default script and first GlyphTypeface.

                ShapeTypeface shapeTypeface = new ShapeTypeface(
                    typeface.TryGetGlyphTypeface(), 
                    null // device font
                    ); 
 
                collector.Add(
                    shapeableList, 
                    new CharacterBufferRange(characterBufferReference, stringLength),
                    textRunProperties,
                    new MS.Internal.Text.TextInterface.ItemProps(),
                    shapeTypeface, 
                    1.0,   // scale in Em
                    false,  // null shape 
                    textFormattingMode 
                    );
            } 
        }
Beispiel #24
0
        /// <summary>
        /// Determine the width of the margin, using the number of visible digits (e.g. 5) to construct
        /// a model string (e.g. "88888").
        /// </summary>
        private void DetermineMarginWidth()
        {
            string template = _showMilliseconds ? "XX:XX.XXX" : "XX:XX";

            if (_showHours)
            {
                template = "XX:" + template;
            }

            TextFormattingMode textFormattingMode = _textView.FormattedLineSource.UseDisplayMode ? TextFormattingMode.Display : TextFormattingMode.Ideal;
            FormattedText      formattedText      = new FormattedText(template, CultureInfo.InvariantCulture, FlowDirection.LeftToRight,
                                                                      _formatting.Typeface, _formatting.FontRenderingEmSize, Brushes.Black,
                                                                      TimeStampVisual.InvariantNumberSubstitution, textFormattingMode);

            base.MinWidth = formattedText.Width;
        }
Beispiel #25
0
        [FriendAccessAllowed]   // used by Framework
        static internal TextFormatter FromCurrentDispatcher(TextFormattingMode textFormattingMode)
        {
            Dispatcher dispatcher = Dispatcher.CurrentDispatcher;

            if (dispatcher == null)
            {
                throw new ArgumentException(SR.Get(SRID.CurrentDispatcherNotFound));
            }

            TextFormatter defaultTextFormatter;

            if (textFormattingMode == TextFormattingMode.Display)
            {
                defaultTextFormatter = (TextFormatterImp)dispatcher.Reserved4;
            }
            else
            {
                defaultTextFormatter = (TextFormatterImp)dispatcher.Reserved1;
            }

            if (defaultTextFormatter == null)
            {
                lock (_staticLock)
                {
                    if (defaultTextFormatter == null)
                    {
                        // Default formatter has not been created for this dispatcher,
                        // create a new one and stick it to the dispatcher.
                        defaultTextFormatter = Create(textFormattingMode);

                        if (textFormattingMode == TextFormattingMode.Display)
                        {
                            dispatcher.Reserved4 = defaultTextFormatter;
                        }
                        else
                        {
                            dispatcher.Reserved1 = defaultTextFormatter;
                        }
                    }
                }
            }

            Invariant.Assert(defaultTextFormatter != null);
            return(defaultTextFormatter);
        }
Beispiel #26
0
        private IntPtr CreatePTSContext(int index, TextFormattingMode textFormattingMode)
        {
            PtsHost ptsHost;
            IntPtr  installedObjects;
            int     installedObjectsCount;
            TextFormatterContext textFormatterContext;
            IntPtr context;

            ptsHost = _contextPool[index].PtsHost;
            Invariant.Assert(ptsHost != null);


            InitInstalledObjectsInfo(ptsHost, ref _contextPool[index].SubtrackParaInfo, ref _contextPool[index].SubpageParaInfo, out installedObjects, out installedObjectsCount);
            _contextPool[index].InstalledObjects = installedObjects;


            InitGenericInfo(ptsHost, (IntPtr)(index + 1), installedObjects, installedObjectsCount, ref _contextPool[index].ContextInfo);


            InitFloaterObjInfo(ptsHost, ref _contextPool[index].FloaterInit);
            InitTableObjInfo(ptsHost, ref _contextPool[index].TableobjInit);


            if (_contextPool[index].IsOptimalParagraphEnabled)
            {
                textFormatterContext = new TextFormatterContext();
                TextPenaltyModule penaltyModule    = textFormatterContext.GetTextPenaltyModule();
                IntPtr            ptsPenaltyModule = penaltyModule.DangerousGetHandle();

                _contextPool[index].TextPenaltyModule            = penaltyModule;
                _contextPool[index].ContextInfo.ptsPenaltyModule = ptsPenaltyModule;
                _contextPool[index].TextFormatter = TextFormatter.CreateFromContext(textFormatterContext, textFormattingMode);



                GC.SuppressFinalize(_contextPool[index].TextPenaltyModule);
            }


            PTS.Validate(PTS.CreateDocContext(ref _contextPool[index].ContextInfo, out context));

            return(context);
        }
 /// <summary>
 /// Construct a shapeable characters object
 /// </summary>
 /// <remarks>
 /// The shapeTypeface parameter can be null if and only if CheckFastPathNominalGlyphs
 /// has previously returned true.
 /// </remarks>
 internal TextShapeableCharacters(
     CharacterBufferRange    characterRange,
     TextRunProperties       properties,
     double                  emSize,
     ItemProps               textItem,
     ShapeTypeface           shapeTypeface,
     bool                    nullShape,
     TextFormattingMode      textFormattingMode,
     bool isSideways
     )
 {
     _isSideways = isSideways;
     _textFormattingMode = textFormattingMode;
     _characterBufferRange = characterRange;
     _properties = properties;
     _emSize = emSize;
     _textItem = textItem;
     _shapeTypeface = shapeTypeface;
     _nullShape = nullShape;
 }
 /// <summary>
 /// Construct a shapeable characters object
 /// </summary>
 /// <remarks>
 /// The shapeTypeface parameter can be null if and only if CheckFastPathNominalGlyphs
 /// has previously returned true.
 /// </remarks>
 internal TextShapeableCharacters(
     CharacterBufferRange characterRange,
     TextRunProperties properties,
     double emSize,
     ItemProps textItem,
     ShapeTypeface shapeTypeface,
     bool nullShape,
     TextFormattingMode textFormattingMode,
     bool isSideways
     )
 {
     _isSideways           = isSideways;
     _textFormattingMode   = textFormattingMode;
     _characterBufferRange = characterRange;
     _properties           = properties;
     _emSize        = emSize;
     _textItem      = textItem;
     _shapeTypeface = shapeTypeface;
     _nullShape     = nullShape;
 }
        /// <summary>
        /// Lookup characters nominal glyphs and width
        /// </summary>
        /// <param name="charBufferRange">character buffer range</param>
        /// <param name="emSize">height of Em</param>
        /// <param name="toIdeal"> scaling factor from real to ideal unit </param>
        /// <param name="nominalWidths">glyph nominal advances in ideal units</param>
        /// <returns>true for success</returns>
        /// <remarks>This function is only used in fast path, and can only be called
        /// if CheckFastPathNominalGlyphs has previously returned true.</remarks>
        internal void GetCharacterNominalWidthsAndIdealWidth(
            CharacterBufferRange charBufferRange,
            double emSize,
            double toIdeal,
            TextFormattingMode textFormattingMode,
            bool isSideways,
            out int[]            nominalWidths
            )
        {
            int idealWidth;

            GetCharacterNominalWidthsAndIdealWidth(
                charBufferRange,
                emSize,
                toIdeal,
                textFormattingMode,
                isSideways,
                out nominalWidths,
                out idealWidth
                );
        }
 public DiagramStyleCache(IDiagramStyleProvider diagramStyleProvider)
 {
     Background    = diagramStyleProvider.Background;
     Foreground    = diagramStyleProvider.Foreground;
     DiagramFill   = diagramStyleProvider.DiagramFill;
     DiagramStroke = diagramStyleProvider.DiagramStroke;
     FontStyle     = diagramStyleProvider.FontStyle;
     FontSize      = diagramStyleProvider.FontSize;
     FontFamily    = diagramStyleProvider.FontFamily;
     FontStretch   = diagramStyleProvider.FontStretch;
     FontWeight    = diagramStyleProvider.FontWeight;
     AdditionalResourceDictionary = diagramStyleProvider.AdditionalResourceDictionary;
     ClipToBounds        = diagramStyleProvider.ClipToBounds;
     SnapsToDevicePixels = diagramStyleProvider.SnapsToDevicePixels;
     UseLayoutRounding   = diagramStyleProvider.UseLayoutRounding;
     EdgeMode            = diagramStyleProvider.EdgeMode;
     ClearTypeHint       = diagramStyleProvider.ClearTypeHint;
     TextRenderingMode   = diagramStyleProvider.TextRenderingMode;
     TextHintingMode     = diagramStyleProvider.TextHintingMode;
     TextFormattingMode  = TextFormattingMode;
 }
Beispiel #31
0
        private FormattedText buildFormattedText(String Text, FontInfo Font, bool UseDisplayMode,
                                                 List <FontChanges> changes, DrawingContext dc)
        {
            TextFormattingMode tfm = TextFormattingMode.Display;
            FormattedText      ft  = new FormattedText(Text,
                                                       CultureInfo.CurrentCulture,
                                                       FlowDirection.LeftToRight,
                                                       Font.Typeface,
                                                       Font.PointSize,
                                                       ZColorCheck.ZColorToBrush(fColor, ColorType.Foreground),
                                                       _substituion, tfm);

            if (changes != null)
            {
                foreach (FontChanges fc in changes)
                {
                    setStyle(fc.FandS, fc, ft, dc);
                }
            }

            return(ft);
        }
Beispiel #32
0
 /// <summary>
 /// Recommended baseline-to-baseline distance for text in this font.
 /// </summary>
 public double LineSpacing(double emSize, double toReal, double pixelsPerDip, TextFormattingMode textFormattingMode)
 {
     if (textFormattingMode == TextFormattingMode.Ideal)
     {
         return(((IFontFamily)this).LineSpacingDesign * emSize);
     }
     else
     {
         // If the composite font has a pre specified LineSpacing then we respect it in calculating the
         // linespacing but we round it since Compatible metrics are pixel aligned.
         if (_fontInfo.LineSpacing != 0)
         {
             return(Math.Round(_fontInfo.LineSpacing * emSize));
         }
         // If the composite font has no specifed LineSpacing then we get the compatible font metrics of the
         // first fontfamily in the composite font.
         else
         {
             return(GetFirstFontFamily().LineSpacing(emSize, toReal, pixelsPerDip, textFormattingMode));
         }
     }
 }
        /// <summary>
        /// Validate all the relevant text formatting initial settings and package them
        /// </summary>
        private FormatSettings PrepareFormatSettings(
            TextSource textSource,
            int firstCharIndex,
            double paragraphWidth,
            TextParagraphProperties paragraphProperties,
            TextLineBreak previousLineBreak,
            TextRunCache textRunCache,
            bool useOptimalBreak,
            bool isSingleLineFormatting,
            TextFormattingMode textFormattingMode
            )
        {
            VerifyTextFormattingArguments(
                textSource,
                firstCharIndex,
                paragraphWidth,
                paragraphProperties,
                textRunCache
                );

            if (textRunCache.Imp == null)
            {
                // No run cache object available, create one
                textRunCache.Imp = new TextRunCacheImp();
            }

            // initialize formatting settings
            return(new FormatSettings(
                       this,
                       textSource,
                       textRunCache.Imp,
                       new ParaProp(this, paragraphProperties, useOptimalBreak),
                       previousLineBreak,
                       isSingleLineFormatting,
                       textFormattingMode,
                       false
                       ));
        }
        private PtsHost AcquireContextCore(PtsContext ptsContext, TextFormattingMode textFormattingMode)
        {
            int num = 0;

            while (num < this._contextPool.Count && (this._contextPool[num].InUse || this._contextPool[num].IsOptimalParagraphEnabled != ptsContext.IsOptimalParagraphEnabled))
            {
                num++;
            }
            if (num == this._contextPool.Count)
            {
                this._contextPool.Add(new PtsCache.ContextDesc());
                this._contextPool[num].IsOptimalParagraphEnabled = ptsContext.IsOptimalParagraphEnabled;
                this._contextPool[num].PtsHost         = new PtsHost();
                this._contextPool[num].PtsHost.Context = this.CreatePTSContext(num, textFormattingMode);
            }
            if (this._contextPool[num].IsOptimalParagraphEnabled)
            {
                ptsContext.TextFormatter = this._contextPool[num].TextFormatter;
            }
            this._contextPool[num].InUse = true;
            this._contextPool[num].Owner = new WeakReference(ptsContext);
            return(this._contextPool[num].PtsHost);
        }
        /// <summary>
        /// Compare text formatter real values - since values are rounded in Display mode, comparison
        /// must also round and only return true if one rounded value is greater than the other.
        /// </summary>
        /// <param name="x">First value to compare.</param>
        /// <param name="y">Second value to compare.</param>
        /// <param name="mode">Text formatting mode.</param>
        /// <returns>1 if x greater than y, -1 if x less than y, 0 if x == y</returns>
        internal static int CompareReal(double x, double y, TextFormattingMode mode)
        {
            double xDisplay = x;
            double yDisplay = y;

            if (mode == TextFormattingMode.Display)
            {
                xDisplay = RoundDipForDisplayMode(x);
                yDisplay = RoundDipForDisplayMode(y);
            }

            if (xDisplay > yDisplay)
            {
                return(1);
            }

            if (xDisplay < yDisplay)
            {
                return(-1);
            }

            return(0);
        }
Beispiel #36
0
        private PtsHost AcquireContextCore(PtsContext ptsContext, TextFormattingMode textFormattingMode)
        {
            int index;


            for (index = 0; index < _contextPool.Count; index++)
            {
                if (!_contextPool[index].InUse &&
                    _contextPool[index].IsOptimalParagraphEnabled == ptsContext.IsOptimalParagraphEnabled)
                {
                    break;
                }
            }


            if (index == _contextPool.Count)
            {
                _contextPool.Add(new ContextDesc());
                _contextPool[index].IsOptimalParagraphEnabled = ptsContext.IsOptimalParagraphEnabled;
                _contextPool[index].PtsHost         = new PtsHost();
                _contextPool[index].PtsHost.Context = CreatePTSContext(index, textFormattingMode);
            }



            if (_contextPool[index].IsOptimalParagraphEnabled)
            {
                ptsContext.TextFormatter = _contextPool[index].TextFormatter;
            }


            _contextPool[index].InUse = true;
            _contextPool[index].Owner = new WeakReference(ptsContext);

            return(_contextPool[index].PtsHost);
        }
Beispiel #37
0
        /// <summary> 
        /// Scan through specified character string checking for valid character
        /// nominal glyph.
        /// </summary>
        /// <param name="charBufferRange">character buffer range</param> 
        /// <param name="emSize">height of Em</param>
        /// <param name="scalingFactor">This is the factor by which we will scale up 
        /// the metrics. Typically this value to used to convert metrics from the real 
        /// space to the ideal space</param>
        /// <param name="widthMax">maximum width allowed</param> 
        /// <param name="keepAWord">do not stop arbitrarily in the middle of a word</param>
        /// <param name="numberSubstitution">digits require complex shaping</param>
        /// <param name="cultureInfo">CultureInfo of the text</param>
        /// <param name="stringLengthFit">number of character fit in given width</param> 
        /// <returns>whether the specified string can be optimized by nominal glyph lookup</returns>
        internal bool CheckFastPathNominalGlyphs( 
            CharacterBufferRange    charBufferRange, 
            double                  emSize,
            double                  scalingFactor, 
            double                  widthMax,
            bool                    keepAWord,
            bool                    numberSubstitution,
            CultureInfo             cultureInfo, 
            TextFormattingMode      textFormattingMode,
            bool                    isSideways, 
            out int                 stringLengthFit 
            )
        { 
            stringLengthFit = 0;

            if (CachedTypeface.NullFont) return false;
 
            GlyphTypeface glyphTypeface = TryGetGlyphTypeface();
 
            if (glyphTypeface == null) return false; 

            double totalWidth = 0; 
            int i = 0;

            ushort blankGlyph = glyphTypeface.BlankGlyphIndex;
            ushort glyph = blankGlyph; 

            ushort charFlagsMask = numberSubstitution ? 
                (ushort)(CharacterAttributeFlags.CharacterComplex | CharacterAttributeFlags.CharacterDigit) : 
                (ushort)CharacterAttributeFlags.CharacterComplex;
            ushort charFlags = 0; 
            ushort charFastTextCheck = (ushort)(CharacterAttributeFlags.CharacterFastText | CharacterAttributeFlags.CharacterIdeo);

            bool symbolTypeface = glyphTypeface.Symbol;
            if (symbolTypeface) 
            {
                // we don't care what code points are present if it's a non-Unicode font such as Symbol or Wingdings; 
                // the code points don't have any standardized meanings, and we always want to bypass shaping 
                charFlagsMask = 0;
            } 

            bool ignoreWidths = widthMax == double.MaxValue;
            ushort[] glyphIndices = BufferCache.GetUShorts(charBufferRange.Length);
            MS.Internal.Text.TextInterface.GlyphMetrics[] glyphMetrics = ignoreWidths ? null : BufferCache.GetGlyphMetrics(charBufferRange.Length); 

            glyphTypeface.GetGlyphMetricsOptimized(charBufferRange, 
                                                   emSize, 
                                                   glyphIndices,
                                                   glyphMetrics, 
                                                   textFormattingMode,
                                                   isSideways
                                                   );
 
            double designToEm = emSize / glyphTypeface.DesignEmHeight;
 
            // 
            // This block will advance until one of:
            // 1. The end of the charBufferRange is reached 
            // 2. The charFlags have some of the charFlagsMask values
            // 3. The glyph is BlankGlyph (space)
            // 4. Glyph index is 0 (unless symbol font)
            // 
            // At this point totalWidth includes all of the widths including the stop character (which fits above)
            // i indexes the next character (not included in the width) 
            // 
            if(keepAWord)
            { 
                do
                {
                    char ch = charBufferRange[i++];
                    if (ch == TextStore.CharLineFeed || ch == TextStore.CharCarriageReturn) 
                    {
                        --i; 
                        break; 
                    }
                    else 
                    {
                        int charClass = (int)Classification.GetUnicodeClassUTF16(ch);
                        charFlags = Classification.CharAttributeOf(charClass).Flags;
                        charFastTextCheck &= charFlags; 

                        glyph = glyphIndices[i-1]; 
                        if (!ignoreWidths) 
                        {
                            totalWidth += TextFormatterImp.RoundDip(glyphMetrics[i - 1].AdvanceWidth * designToEm, textFormattingMode) * scalingFactor; 
                        }
                    }
                } while(
                        i < charBufferRange.Length 
                    &&  ((charFlags & charFlagsMask) == 0)
                    &&  (glyph != 0 || symbolTypeface) 
                    &&  glyph != blankGlyph 
                    );
 
                // i is now at a character immediately following a leading blank
            }

            // 
            // This block will advance until one of:
            // 1. The end of the charBufferRange is reached 
            // 2. The charFlags have some of the charFlagsMask values 
            // 3. Glyph index is 0 (unless symbol font)
            // 4. totalWidth > widthMax 
            //

            while(
                    i < charBufferRange.Length 
                &&  (ignoreWidths || totalWidth <= widthMax)
                &&  ((charFlags & charFlagsMask) == 0) 
                &&  (glyph != 0 || symbolTypeface) 
                )
            { 
                char ch = charBufferRange[i++];
                if (ch == TextStore.CharLineFeed || ch == TextStore.CharCarriageReturn)
                {
                    --i; 
                    break;
                } 
                else 
                {
                    int charClass = (int)Classification.GetUnicodeClassUTF16(ch); 
                    charFlags = Classification.CharAttributeOf(charClass).Flags;
                    charFastTextCheck &= charFlags;

                    glyph = glyphIndices[i-1]; 
                    if (!ignoreWidths)
                    { 
                        totalWidth += TextFormatterImp.RoundDip(glyphMetrics[i - 1].AdvanceWidth * designToEm, textFormattingMode) * scalingFactor; 
                    }
                } 
            }

            BufferCache.ReleaseUShorts(glyphIndices);
            glyphIndices = null; 
            BufferCache.ReleaseGlyphMetrics(glyphMetrics);
            glyphMetrics = null; 
 
            if (symbolTypeface)
            { 
                // always optimize for non-Unicode font as we don't support shaping or typographic features;
                // we also don't fall back from non-Unicode fonts so we don't care if there are missing glyphs
                stringLengthFit = i;
                return true; 
            }
 
            if (glyph == 0) 
            {
                // character is not supported by the font 
                return false;
            }

            if ((charFlags & charFlagsMask) != 0) 
            {
                // complex character encountered, exclude it 
                Debug.Assert(i > 0); 

                if(--i <= 0) 
                {
                    // first char is complex, fail the call
                    return false;
                } 
            }
 
            stringLengthFit = i; 
            TypographyAvailabilities typography = glyphTypeface.FontFaceLayoutInfo.TypographyAvailabilities;
 
            if ((charFastTextCheck & (byte) CharacterAttributeFlags.CharacterFastText) != 0)
            {
                // all input code points are Fast Text
                if ((typography & 
                         (  TypographyAvailabilities.FastTextTypographyAvailable
                          | TypographyAvailabilities.FastTextMajorLanguageLocalizedFormAvailable 
                         ) 
                     ) != 0
                   ) 
                {
                    // Considered too risky to optimize. It is either because the font
                    // has required features or the font has 'locl' lookup for major languages.
                    return false; 
                }
                else if ((typography & TypographyAvailabilities.FastTextExtraLanguageLocalizedFormAvailable) != 0) 
                { 
                    // The font has 'locl' lookup for FastText code points for non major languages.
                    // Check whether the input is major langauge. If it is, we are still good to optimize. 
                    return MajorLanguages.Contains(cultureInfo);
                }
                else
                { 
                    // No FastText flags are present, safe to optimize
                    return true; 
                } 
            }
            else if ((charFastTextCheck & (byte) CharacterAttributeFlags.CharacterIdeo) != 0) 
            {
                // The input are all ideographs, check the IdeoTypographyAvailable bit. It is safe if
                // the bit is not set.
                return ((typography & TypographyAvailabilities.IdeoTypographyAvailable) == 0); 
            }
            else 
            { 
                // for all the rest of the cases, just check whether there is any required typography
                // present at all. If none exists, it is optimizable. We might under-optimize here but 
                // it will be non-major languages.
                return ((typography & TypographyAvailabilities.Available) == 0);
            }
        } 
Beispiel #38
0
 internal double LineSpacing(double emSize, double toReal, double pixelsPerDip, TextFormattingMode textFormattingMode)
 { 
     return CachedTypeface.FirstFontFamily.LineSpacing(emSize, toReal, pixelsPerDip, textFormattingMode); 
 }
Beispiel #39
0
        /// <summary>
        /// Client to create a new instance of TextFormatter from the specified TextFormatter context 
        /// </summary>
        /// <param name="soleContext">TextFormatter context</param> 
        /// <returns>New instance of TextFormatter</returns> 
#if OPTIMALBREAK_API
        static public TextFormatter CreateFromContext(TextFormatterContext soleContext, TextFormattingMode textFormattingMode) 
Beispiel #40
0
 /// <summary>
 /// Construct an instance of TextFormatter implementation
 /// </summary>
 internal TextFormatterImp(TextFormattingMode textFormattingMode)
     : this(null, textFormattingMode)
 { }
Beispiel #41
0
        /// <summary>
        /// Break a run of text into individually shape items.
        /// Shape items are delimited by 
        ///     Change of writing system
        ///     Change of glyph typeface
        /// </summary>
        IList<TextShapeableSymbols> ITextSymbols.GetTextShapeableSymbols(
            GlyphingCache               glyphingCache,
            CharacterBufferReference    characterBufferReference,
            int                         length,
            bool                        rightToLeft,
            bool                        isRightToLeftParagraph,
            CultureInfo                 digitCulture,
            TextModifierScope           textModifierScope,
            TextFormattingMode          textFormattingMode,
            bool                        isSideways
            )
        {
            if (characterBufferReference.CharacterBuffer == null)
            {
                throw new ArgumentNullException("characterBufferReference.CharacterBuffer");
            }
            
            int offsetToFirstChar = characterBufferReference.OffsetToFirstChar - _characterBufferReference.OffsetToFirstChar;

            Debug.Assert(characterBufferReference.CharacterBuffer == _characterBufferReference.CharacterBuffer);
            Debug.Assert(offsetToFirstChar >= 0 && offsetToFirstChar < _length);

            if (    length < 0 
                ||  offsetToFirstChar + length > _length)
            {
                length = _length - offsetToFirstChar;
            }

            // Get the actual text run properties in effect, after invoking any
            // text modifiers that may be in scope.
            TextRunProperties textRunProperties = _textRunProperties;
            if (textModifierScope != null)
            {
                textRunProperties = textModifierScope.ModifyProperties(textRunProperties);
            }

            if (!rightToLeft)
            {
                // Fast loop early out for run with all non-complex characters
                // which can be optimized by not going thru shaping engine.

                int nominalLength;

                if (textRunProperties.Typeface.CheckFastPathNominalGlyphs(
                    new CharacterBufferRange(characterBufferReference, length),
                    textRunProperties.FontRenderingEmSize,
                    1.0,
                    double.MaxValue,    // widthMax
                    true,               // keepAWord
                    digitCulture != null,
                    CultureMapper.GetSpecificCulture(textRunProperties.CultureInfo),
                    textFormattingMode,
                    isSideways,
                    false, //breakOnTabs
                    out nominalLength
                    ) && length == nominalLength)
                {
                    return new TextShapeableCharacters[]
                    {
                        new TextShapeableCharacters(
                            new CharacterBufferRange(characterBufferReference, nominalLength),
                            textRunProperties,
                            textRunProperties.FontRenderingEmSize,                        
                            new MS.Internal.Text.TextInterface.ItemProps(),
                            null,   // shapeTypeface (no shaping required)
                            false,   // nullShape,
                            textFormattingMode,
                            isSideways
                            )
                    };
                }
            }

            IList<TextShapeableSymbols> shapeables = new List<TextShapeableSymbols>(2);

            glyphingCache.GetShapeableText(
                textRunProperties.Typeface,
                characterBufferReference,
                length,
                textRunProperties,
                digitCulture,
                isRightToLeftParagraph,
                shapeables,
                this as IShapeableTextCollector,
                textFormattingMode
                );

            return shapeables;
        }
 private FullTextLine(TextFormattingMode textFormattingMode, bool justify)
 {
     _textFormattingMode = textFormattingMode;
     if (justify)
     {
         _statusFlags |= StatusFlags.IsJustified;
     }
     _metrics = new TextMetrics();
     _ploline = new SecurityCriticalDataForSet<IntPtr>(IntPtr.Zero);
 }
Beispiel #43
0
		public FormattedTextCache(bool useDisplayMode) {
			textFormattingMode = useDisplayMode ? TextFormattingMode.Display : TextFormattingMode.Ideal;
			dict = new Dictionary<TextFormattingRunProperties, Info>();
		}
Beispiel #44
0
        public FormattedTextSymbols(
            GlyphingCache glyphingCache,
            TextRun       textSymbols,
            bool          rightToLeft,
            double        scalingFactor,
            TextFormattingMode textFormattingMode,
            bool isSideways
            )
        {

            _textFormattingMode = textFormattingMode;
            _isSideways = isSideways;
            ITextSymbols  symbols = textSymbols as ITextSymbols;

            Debug.Assert(symbols != null);

            // break down a single text run into pieces
            IList<TextShapeableSymbols> shapeables = symbols.GetTextShapeableSymbols(
                glyphingCache,
                textSymbols.CharacterBufferReference,
                textSymbols.Length,
                rightToLeft,  // This is a bool indicating the RTL
                              // based on the bidi level of text (if applicable). 
                              // For FormattedTextSymbols it is equal to paragraph flow direction.

                rightToLeft,  // This is the flow direction of the paragraph as 
                              // specified by the user. DWrite needs the paragraph
                              // flow direction of the paragraph 
                              // while WPF algorithms need the RTL of the text based on 
                              // Bidi if possible.

                null, // cultureInfo
                null,  // textModifierScope
                _textFormattingMode,
                _isSideways
                );

            Debug.Assert(shapeables != null && shapeables.Count > 0);

            _rightToLeft = rightToLeft;
            _glyphs = new Glyphs[shapeables.Count];

            CharacterBuffer charBuffer = textSymbols.CharacterBufferReference.CharacterBuffer;
            int offsetToFirstChar = textSymbols.CharacterBufferReference.OffsetToFirstChar;

            int i = 0;
            int ich = 0;

            while (i < shapeables.Count)
            {
                TextShapeableSymbols current = shapeables[i] as TextShapeableSymbols;
                Debug.Assert(current != null);

                int cch = current.Length;
                int j;

                // make a separate character buffer for glyphrun persistence
                char[] charArray = new char[cch];
                for (j = 0; j < cch; j++)
                    charArray[j] = charBuffer[offsetToFirstChar + ich + j];

                if (current.IsShapingRequired)
                {
                    ushort[] clusterMap;
                    ushort[] glyphIndices;
                    int[] glyphAdvances;
                    GlyphOffset[] glyphOffsets;


                    // 





                    unsafe
                    {
                        fixed (char* fixedCharArray = &charArray[0])
                        {
                            MS.Internal.Text.TextInterface.TextAnalyzer textAnalyzer = MS.Internal.FontCache.DWriteFactory.Instance.CreateTextAnalyzer();

                            GlyphTypeface glyphTypeface = current.GlyphTypeFace;
                            DWriteFontFeature[][] fontFeatures;
                            uint[] fontFeatureRanges;
                            uint unsignedCch = checked((uint)cch);
                            LSRun.CompileFeatureSet(current.Properties.TypographyProperties, unsignedCch, out fontFeatures, out fontFeatureRanges);

                       
                            textAnalyzer.GetGlyphsAndTheirPlacements(
                                (ushort*)fixedCharArray,
                                unsignedCch,
                                glyphTypeface.FontDWrite,
                                glyphTypeface.BlankGlyphIndex,
                                false,   // no sideway support yet
                                /************************************************************************************************/
                                //
                                rightToLeft,
                                current.Properties.CultureInfo,
                                /************************************************************************************************/
                                fontFeatures,
                                fontFeatureRanges,
                                current.Properties.FontRenderingEmSize,
                                scalingFactor,
                                Util.PixelsPerDip,
                                _textFormattingMode,
                                current.ItemProps,
                                out clusterMap,
                                out glyphIndices,
                                out glyphAdvances,
                                out glyphOffsets
                                );
                        }
                        _glyphs[i] = new Glyphs(
                           current,
                           charArray,
                           glyphAdvances,
                           clusterMap,
                           glyphIndices,
                           glyphOffsets,
                           scalingFactor
                           );
                    }
                                        
                }
                else
                {
                    // shaping not required, 
                    // bypass glyphing process altogether
                    int[] nominalAdvances = new int[charArray.Length];
                    
                    unsafe
                    {
                        fixed (char* fixedCharArray = &charArray[0])
                        fixed (int* fixedNominalAdvances = &nominalAdvances[0])
                        {
                            current.GetAdvanceWidthsUnshaped(
                                fixedCharArray,
                                cch,
                                scalingFactor, // format resolution specified per em,
                                fixedNominalAdvances
                                );
                        }
                    }

                    _glyphs[i] = new Glyphs(
                        current,
                        charArray,
                        nominalAdvances,
                        scalingFactor
                        );
                }

                i++;
                ich += cch;
            }
        }
Beispiel #45
0
        /// <summary>
        /// Construct a FormattedText object.
        /// </summary>
        /// <param name="textToFormat">String of text to be displayed.</param>
        /// <param name="culture">Culture of text.</param>
        /// <param name="flowDirection">Flow direction of text.</param>
        /// <param name="typeface">Type face used to display text.</param>
        /// <param name="emSize">Font em size in visual units (1/96 of an inch).</param>
        /// <param name="foreground">Foreground brush used to render text.</param>
        /// <param name="numberSubstitution">Number substitution behavior to apply to the text; can be null,
        /// in which case the default number number method for the text culture is used.</param>
        public FormattedText(
            string textToFormat,
            CultureInfo culture,
            FlowDirection flowDirection,
            Typeface typeface,
            double emSize,
            Brush foreground,
            NumberSubstitution numberSubstitution,
            TextFormattingMode textFormattingMode)
        {
            if (textToFormat == null)
                throw new ArgumentNullException("textToFormat");

            if (typeface == null)
                throw new ArgumentNullException("typeface");

            ValidateCulture(culture);
            ValidateFlowDirection(flowDirection, "flowDirection");
            ValidateFontSize(emSize);

            _textFormattingMode = textFormattingMode;
            _text = textToFormat;
            GenericTextRunProperties runProps = new GenericTextRunProperties(
                                     typeface,
                                     emSize,
                                     12.0f, // default hinting size
                                     null,  // decorations
                                     foreground,
                                     null,  // highlight background
                                     BaselineAlignment.Baseline,
                                     culture,
                                     numberSubstitution
                                     );
            _latestPosition = _formatRuns.SetValue(0, _text.Length, runProps, _latestPosition);

            _defaultParaProps = new GenericTextParagraphProperties(
                flowDirection,
                TextAlignment.Left,
                false,
                false,
                runProps,
                TextWrapping.WrapWithOverflow,
                0,  // line height not specified
                0   // indentation not specified
                );

            InvalidateMetrics();
        }
Beispiel #46
0
        /// <summary> 
        /// Lookup characters nominal glyphs and width
        /// </summary> 
        /// <param name="charBufferRange">character buffer range</param>
        /// <param name="emSize">height of Em</param>
        /// <param name="toIdeal"> scaling factor from real to ideal unit </param>
        /// <param name="nominalWidths">glyph nominal advances in ideal units</param> 
        /// <param name="idealWidth">total width in ideal units</param>
        /// <returns>true for success</returns> 
        /// <remarks>This function is only used in fast path, and can only be called 
        /// if CheckFastPathNominalGlyphs has previously returned true.</remarks>
        internal void GetCharacterNominalWidthsAndIdealWidth( 
            CharacterBufferRange charBufferRange,
            double               emSize,
            double               toIdeal,
            TextFormattingMode   textFormattingMode, 
            bool                 isSideways,
            out int[]            nominalWidths, 
            out int              idealWidth 
            )
        { 
            // This function should only be called if CheckFastPathNominalGlyphs has
            // returned true so we can assume the ITypefaceMetrics is a GlyphTypeface.
            GlyphTypeface glyphTypeface = TryGetGlyphTypeface();
            Invariant.Assert(glyphTypeface != null); 

            MS.Internal.Text.TextInterface.GlyphMetrics[] glyphMetrics = BufferCache.GetGlyphMetrics(charBufferRange.Length); 
 
            glyphTypeface.GetGlyphMetricsOptimized(charBufferRange,
                                                   emSize, 
                                                   textFormattingMode,
                                                   isSideways,
                                                   glyphMetrics);
 
            nominalWidths = new int[charBufferRange.Length];
            idealWidth = 0; 
 
            if (TextFormattingMode.Display == textFormattingMode)
            { 
                double designToEm = emSize / glyphTypeface.DesignEmHeight;
                for (int i = 0; i < charBufferRange.Length; i++)
                {
                    nominalWidths[i] = (int)Math.Round(TextFormatterImp.RoundDipForDisplayMode(glyphMetrics[i].AdvanceWidth * designToEm) * toIdeal); 
                    idealWidth += nominalWidths[i];
                } 
            } 
            else
            { 
                double designToEm = emSize * toIdeal / glyphTypeface.DesignEmHeight;
                for (int i = 0; i < charBufferRange.Length; i++)
                {
                    nominalWidths[i] = (int)Math.Round(glyphMetrics[i].AdvanceWidth * designToEm); 
                    idealWidth += nominalWidths[i];
                } 
            } 

            BufferCache.ReleaseGlyphMetrics(glyphMetrics); 
        }
Beispiel #47
0
        /// <summary>
        /// Compare text formatter real values - since values are rounded in Display mode, comparison
        /// must also round and only return true if one rounded value is greater than the other.
        /// </summary>
        /// <param name="x">First value to compare.</param>
        /// <param name="y">Second value to compare.</param>
        /// <param name="mode">Text formatting mode.</param>
        /// <returns>1 if x greater than y, -1 if x less than y, 0 if x == y</returns>
        internal static int CompareReal(double x, double y, TextFormattingMode mode)
        {
            double xDisplay = x;
            double yDisplay = y;

            if (mode == TextFormattingMode.Display)
            {
                xDisplay = RoundDipForDisplayMode(x);
                yDisplay = RoundDipForDisplayMode(y);
            }

            if (xDisplay > yDisplay)
            {
                return 1;
            }

            if (xDisplay < yDisplay)
            {
                return -1;
            }

            return 0;
        }
 /// <summary>
 /// Returns whether the conditions are met to make it possible to process tabs
 /// in the simple shaping path.
 /// </summary>
 static private bool CanProcessTabsInSimpleShapingPath(
     ParaProp           textParagraphProperties,
     TextFormattingMode textFormattingMode
     )
 {
     return (textParagraphProperties.Tabs == null && textParagraphProperties.DefaultIncrementalTab > 0);
 }
Beispiel #49
0
        /// <summary>
        /// Add shapeable text object to the list
        /// </summary>
        void IShapeableTextCollector.Add(
            IList<TextShapeableSymbols>  shapeables,
            CharacterBufferRange         characterBufferRange,
            TextRunProperties            textRunProperties,
            MS.Internal.Text.TextInterface.ItemProps textItem,
            ShapeTypeface                shapeTypeface,
            double                       emScale,
            bool                         nullShape,
            TextFormattingMode               textFormattingMode
            )
        {
            Debug.Assert(shapeables != null);

            shapeables.Add(
                new TextShapeableCharacters(
                    characterBufferRange,
                    textRunProperties,
                    textRunProperties.FontRenderingEmSize * emScale,
                    textItem,
                    shapeTypeface,
                    nullShape,
                    textFormattingMode,
                    false
                    )
                );
        }
Beispiel #50
0
 internal static double RoundDip(double value, TextFormattingMode textFormattingMode)
 {
     if (TextFormattingMode.Display == textFormattingMode)
     {
         return RoundDipForDisplayMode(value);
     }
     else
     {
         return value;
     }
 }
 internal double LineSpacing(double emSize, double toReal, double pixelsPerDip, TextFormattingMode textFormattingMode)
 {
     return(CachedTypeface.FirstFontFamily.LineSpacing(emSize, toReal, pixelsPerDip, textFormattingMode));
 }
Beispiel #52
0
        internal void GetShapeableText(
            CharacterBufferReference    characterBufferReference,
            int                         stringLength, 
            TextRunProperties           textRunProperties,
            CultureInfo                 digitCulture, 
            bool                        isRightToLeftParagraph, 
            IList<TextShapeableSymbols> shapeableList,
            IShapeableTextCollector     collector, 
            TextFormattingMode          textFormattingMode
            )
        {
            SpanVector<int> cachedScaledTypefaceIndexSpans; 

            int ichItem = 0; 
 
            CharacterBufferRange unicodeString = new CharacterBufferRange(
                characterBufferReference, 
                stringLength
                );

            CultureInfo culture = textRunProperties.CultureInfo; 
            IList<Span> spans;
 
            GCHandle gcHandle; 
            IntPtr ptext = characterBufferReference.CharacterBuffer.PinAndGetCharacterPointer(characterBufferReference.OffsetToFirstChar, out gcHandle);
 
            // Contextual number substitution cannot be performed on the run level, since it depends
            // on context - nearest preceding strong character. For this reason, contextual number
            // substitutions has been already done (TextStore.CreateLSRunsUniformBidiLevel) and
            // digitCulture has been updated to reflect culture which is dependent on the context. 
            // NumberSubstitutionMethod.AsCulture method can be resolved to Context, hence it also needs to be resolved to appropriate
            // not ambiguous method. 
            // Both of those values (Context and AsCulture) are resolved to one of following: European, Traditional or NativeNational, 
            // which can be safely handled by DWrite without getting context information.
            bool ignoreUserOverride; 
            NumberSubstitutionMethod numberSubstitutionMethod = DigitState.GetResolvedSubstitutionMethod(textRunProperties, digitCulture, out ignoreUserOverride);

            // Itemize the text based on DWrite's text analysis for scripts and number substitution.
            unsafe 
            {
                checked 
                { 
                    spans = MS.Internal.Text.TextInterface.TextAnalyzer.Itemize(
                        (ushort*)ptext.ToPointer(), 
                        (uint)stringLength,
                        culture,
                        MS.Internal.FontCache.DWriteFactory.Instance,
                        isRightToLeftParagraph, 
                        digitCulture,
                        ignoreUserOverride, 
                        (uint)numberSubstitutionMethod, 
                        ClassificationUtility.Instance,
                        UnsafeNativeMethods.CreateTextAnalysisSink, 
                        UnsafeNativeMethods.GetScriptAnalysisList,
                        UnsafeNativeMethods.GetNumberSubstitutionList,
                        UnsafeNativeMethods.CreateTextAnalysisSource
                        ); 
                }
 
            } 
            characterBufferReference.CharacterBuffer.UnpinCharacterPointer(gcHandle);
 
            SpanVector itemSpans = new SpanVector(null, new FrugalStructList<Span>((ICollection<Span>)spans));

            cachedScaledTypefaceIndexSpans = new SpanVector<int>(-1);
            foreach(Span itemSpan in itemSpans) 
            {
                MapItem( 
                    new CharacterBufferRange( 
                        unicodeString,
                        ichItem, 
                        itemSpan.length
                        ),
                    culture,
                    itemSpan, 
                    ref cachedScaledTypefaceIndexSpans,
                    ichItem 
                    ); 

                #if DEBUG 
                ValidateMapResult(
                    ichItem,
                    itemSpan.length,
                    ref cachedScaledTypefaceIndexSpans 
                    );
                #endif 
 
                ichItem += itemSpan.length;
            } 


            Debug.Assert(ichItem == unicodeString.Length);
 
            // intersect item spans with shapeable spans to create span of shapeable runs
 
            int ich = 0; 

            SpanRider itemSpanRider = new SpanRider(itemSpans); 
            SpanRider<int> typefaceIndexSpanRider = new SpanRider<int>(cachedScaledTypefaceIndexSpans);

            while(ich < unicodeString.Length)
            { 
                itemSpanRider.At(ich);
                typefaceIndexSpanRider.At(ich); 
 
                int index = typefaceIndexSpanRider.CurrentValue;
                Debug.Assert(index >= 0); 

                int cch = unicodeString.Length - ich;
                cch = Math.Min(cch, itemSpanRider.Length);
                cch = Math.Min(cch, typefaceIndexSpanRider.Length); 

                ScaledShapeTypeface scaledShapeTypeface = _cachedScaledTypefaces[index]; 
 
                collector.Add(
                    shapeableList, 
                    new CharacterBufferRange(
                        unicodeString,
                        ich,
                        cch 
                        ),
                    textRunProperties, 
                    (MS.Internal.Text.TextInterface.ItemProps)itemSpanRider.CurrentElement, 
                    scaledShapeTypeface.ShapeTypeface,
                    scaledShapeTypeface.ScaleInEm, 
                    scaledShapeTypeface.NullShape,
                    textFormattingMode
                    );
 
                ich += cch;
            } 
        } 
Beispiel #53
0
        /// <summary>
        /// Validate all the relevant text formatting initial settings and package them
        /// </summary>
        private FormatSettings PrepareFormatSettings(
            TextSource                  textSource,
            int                         firstCharIndex,
            double                      paragraphWidth,
            TextParagraphProperties     paragraphProperties,
            TextLineBreak               previousLineBreak,
            TextRunCache                textRunCache,
            bool                        useOptimalBreak,
            bool                        isSingleLineFormatting,
            TextFormattingMode              textFormattingMode
            )
        {
            VerifyTextFormattingArguments(
                textSource,
                firstCharIndex,
                paragraphWidth,
                paragraphProperties,
                textRunCache
                );

            if (textRunCache.Imp == null)
            {
                // No run cache object available, create one
                textRunCache.Imp = new TextRunCacheImp();
            }

            // initialize formatting settings
            return new FormatSettings(
                this,
                textSource,
                textRunCache.Imp,
                new ParaProp(this, paragraphProperties, useOptimalBreak),
                previousLineBreak,
                isSingleLineFormatting,
                textFormattingMode,
                false
                );
        }
Beispiel #54
0
 /// <summary>
 /// Recommended baseline-to-baseline distance for text in this font.
 /// </summary>
 public double LineSpacing(double emSize, double toReal, double pixelsPerDip, TextFormattingMode textFormattingMode)
 {            
     if (textFormattingMode == TextFormattingMode.Ideal)
     {
         return ((IFontFamily)this).LineSpacingDesign * emSize;
     }
     else
     {
         // If the composite font has a pre specified LineSpacing then we respect it in calculating the 
         // linespacing but we round it since Compatible metrics are pixel aligned.
         if (_fontInfo.LineSpacing != 0)
         {
             return Math.Round(_fontInfo.LineSpacing * emSize);
         }
         // If the composite font has no specifed LineSpacing then we get the compatible font metrics of the
         // first fontfamily in the composite font.
         else
         {
             return GetFirstFontFamily().LineSpacing(emSize, toReal, pixelsPerDip, textFormattingMode);
         }
     }         
 }
Beispiel #55
0
        [FriendAccessAllowed]   // used by Framework
        static internal TextFormatter CreateFromContext(TextFormatterContext soleContext, TextFormattingMode textFormattingMode)
#endif 
        {
            // create a new instance of TextFormatter for the specified context. 
            // This creation prohibits the use of multiple contexts within the same TextFormatter via reentrance. 
            return new TextFormatterImp(soleContext, textFormattingMode);
        } 
Beispiel #56
0
        [FriendAccessAllowed]   // used by Framework 
        static internal TextFormatter FromCurrentDispatcher(TextFormattingMode textFormattingMode)
        { 
            Dispatcher dispatcher = Dispatcher.CurrentDispatcher;

            if (dispatcher == null)
                throw new ArgumentException(SR.Get(SRID.CurrentDispatcherNotFound)); 

            TextFormatter defaultTextFormatter; 
            if (textFormattingMode == TextFormattingMode.Display) 
            {
                defaultTextFormatter = (TextFormatterImp)dispatcher.Reserved4; 
            }
            else
            {
                defaultTextFormatter = (TextFormatterImp)dispatcher.Reserved1; 
            }
 
            if (defaultTextFormatter == null) 
            {
                lock (_staticLock) 
                {
                    if (defaultTextFormatter == null)
                    {
                        // Default formatter has not been created for this dispatcher, 
                        // create a new one and stick it to the dispatcher.
                        defaultTextFormatter = Create(textFormattingMode); 
 
                        if (textFormattingMode == TextFormattingMode.Display)
                        { 
                            dispatcher.Reserved4 = defaultTextFormatter;
                        }
                        else
                        { 
                            dispatcher.Reserved1 = defaultTextFormatter;
                        } 
                    } 
                }
            } 

            Invariant.Assert(defaultTextFormatter != null);
            return defaultTextFormatter;
        } 
        /// <summary>
        /// Scan through specified character string checking for valid character
        /// nominal glyph.
        /// </summary>
        /// <param name="charBufferRange">character buffer range</param>
        /// <param name="emSize">height of Em</param>
        /// <param name="scalingFactor">This is the factor by which we will scale up
        /// the metrics. Typically this value to used to convert metrics from the real
        /// space to the ideal space</param>
        /// <param name="widthMax">maximum width allowed</param>
        /// <param name="keepAWord">do not stop arbitrarily in the middle of a word</param>
        /// <param name="numberSubstitution">digits require complex shaping</param>
        /// <param name="cultureInfo">CultureInfo of the text</param>
        /// <param name="textFormattingMode">The TextFormattingMode used (Ideal vs. Display)</param>
        /// <param name="isSideways">Indicates whether to rotate glyphs.</param>
        /// <param name="breakOnTabs">Determines whether to stop checking at a tab and
        /// break the run there</param>
        /// <param name="stringLengthFit">number of character fit in given width</param>
        /// <returns>whether the specified string can be optimized by nominal glyph lookup</returns>
        internal bool CheckFastPathNominalGlyphs(
            CharacterBufferRange charBufferRange,
            double emSize,
            double scalingFactor,
            double widthMax,
            bool keepAWord,
            bool numberSubstitution,
            CultureInfo cultureInfo,
            TextFormattingMode textFormattingMode,
            bool isSideways,
            bool breakOnTabs,
            out int stringLengthFit
            )
        {
            stringLengthFit = 0;

            if (CachedTypeface.NullFont)
            {
                return(false);
            }

            GlyphTypeface glyphTypeface = TryGetGlyphTypeface();

            if (glyphTypeface == null)
            {
                return(false);
            }

            double totalWidth = 0;
            int    i          = 0;

            ushort blankGlyph = glyphTypeface.BlankGlyphIndex;
            ushort glyph      = blankGlyph;

            ushort charFlagsMask = numberSubstitution ?
                                   (ushort)(CharacterAttributeFlags.CharacterComplex | CharacterAttributeFlags.CharacterDigit) :
                                   (ushort)CharacterAttributeFlags.CharacterComplex;
            ushort charFlags         = 0;
            ushort charFastTextCheck = (ushort)(CharacterAttributeFlags.CharacterFastText | CharacterAttributeFlags.CharacterIdeo);

            bool symbolTypeface = glyphTypeface.Symbol;

            if (symbolTypeface)
            {
                // we don't care what code points are present if it's a non-Unicode font such as Symbol or Wingdings;
                // the code points don't have any standardized meanings, and we always want to bypass shaping
                charFlagsMask = 0;
            }

            bool ignoreWidths = widthMax == double.MaxValue;

            ushort[] glyphIndices = BufferCache.GetUShorts(charBufferRange.Length);
            MS.Internal.Text.TextInterface.GlyphMetrics[] glyphMetrics = ignoreWidths ? null : BufferCache.GetGlyphMetrics(charBufferRange.Length);

            glyphTypeface.GetGlyphMetricsOptimized(charBufferRange,
                                                   emSize,
                                                   glyphIndices,
                                                   glyphMetrics,
                                                   textFormattingMode,
                                                   isSideways
                                                   );

            double designToEm = emSize / glyphTypeface.DesignEmHeight;

            //
            // This block will advance until one of:
            // 1. The end of the charBufferRange is reached
            // 2. The charFlags have some of the charFlagsMask values
            // 3. The glyph is BlankGlyph (space)
            // 4. Glyph index is 0 (unless symbol font)
            //
            // At this point totalWidth includes all of the widths including the stop character (which fits above)
            // i indexes the next character (not included in the width)
            //
            if (keepAWord)
            {
                do
                {
                    char ch = charBufferRange[i++];
                    if (ch == TextStore.CharLineFeed || ch == TextStore.CharCarriageReturn || (breakOnTabs && ch == TextStore.CharTab))
                    {
                        --i;
                        break;
                    }
                    else
                    {
                        int charClass = (int)Classification.GetUnicodeClassUTF16(ch);
                        charFlags          = Classification.CharAttributeOf(charClass).Flags;
                        charFastTextCheck &= charFlags;

                        glyph = glyphIndices[i - 1];
                        if (!ignoreWidths)
                        {
                            totalWidth += TextFormatterImp.RoundDip(glyphMetrics[i - 1].AdvanceWidth * designToEm, textFormattingMode) * scalingFactor;
                        }
                    }
                } while(
                    i < charBufferRange.Length &&
                    ((charFlags & charFlagsMask) == 0) &&
                    (glyph != 0 || symbolTypeface) &&
                    glyph != blankGlyph
                    );

                // i is now at a character immediately following a leading blank
            }

            //
            // This block will advance until one of:
            // 1. The end of the charBufferRange is reached
            // 2. The charFlags have some of the charFlagsMask values
            // 3. Glyph index is 0 (unless symbol font)
            // 4. totalWidth > widthMax
            //

            while (
                i < charBufferRange.Length &&
                (ignoreWidths || totalWidth <= widthMax) &&
                ((charFlags & charFlagsMask) == 0) &&
                (glyph != 0 || symbolTypeface)
                )
            {
                char ch = charBufferRange[i++];
                if (ch == TextStore.CharLineFeed || ch == TextStore.CharCarriageReturn || (breakOnTabs && ch == TextStore.CharTab))
                {
                    --i;
                    break;
                }
                else
                {
                    int charClass = (int)Classification.GetUnicodeClassUTF16(ch);
                    charFlags          = Classification.CharAttributeOf(charClass).Flags;
                    charFastTextCheck &= charFlags;

                    glyph = glyphIndices[i - 1];
                    if (!ignoreWidths)
                    {
                        totalWidth += TextFormatterImp.RoundDip(glyphMetrics[i - 1].AdvanceWidth * designToEm, textFormattingMode) * scalingFactor;
                    }
                }
            }

            BufferCache.ReleaseUShorts(glyphIndices);
            glyphIndices = null;
            BufferCache.ReleaseGlyphMetrics(glyphMetrics);
            glyphMetrics = null;

            if (symbolTypeface)
            {
                // always optimize for non-Unicode font as we don't support shaping or typographic features;
                // we also don't fall back from non-Unicode fonts so we don't care if there are missing glyphs
                stringLengthFit = i;
                return(true);
            }

            if (glyph == 0)
            {
                // character is not supported by the font
                return(false);
            }

            if ((charFlags & charFlagsMask) != 0)
            {
                // complex character encountered, exclude it
                Debug.Assert(i > 0);

                if (--i <= 0)
                {
                    // first char is complex, fail the call
                    return(false);
                }
            }

            stringLengthFit = i;
            TypographyAvailabilities typography = glyphTypeface.FontFaceLayoutInfo.TypographyAvailabilities;

            if ((charFastTextCheck & (byte)CharacterAttributeFlags.CharacterFastText) != 0)
            {
                // all input code points are Fast Text
                if ((typography &
                     (TypographyAvailabilities.FastTextTypographyAvailable
                      | TypographyAvailabilities.FastTextMajorLanguageLocalizedFormAvailable
                     )
                     ) != 0
                    )
                {
                    // Considered too risky to optimize. It is either because the font
                    // has required features or the font has 'locl' lookup for major languages.
                    return(false);
                }
                else if ((typography & TypographyAvailabilities.FastTextExtraLanguageLocalizedFormAvailable) != 0)
                {
                    // The font has 'locl' lookup for FastText code points for non major languages.
                    // Check whether the input is major langauge. If it is, we are still good to optimize.
                    return(MajorLanguages.Contains(cultureInfo));
                }
                else
                {
                    // No FastText flags are present, safe to optimize
                    return(true);
                }
            }
            else if ((charFastTextCheck & (byte)CharacterAttributeFlags.CharacterIdeo) != 0)
            {
                // The input are all ideographs, check the IdeoTypographyAvailable bit. It is safe if
                // the bit is not set.
                return((typography & TypographyAvailabilities.IdeoTypographyAvailable) == 0);
            }
            else
            {
                // for all the rest of the cases, just check whether there is any required typography
                // present at all. If none exists, it is optimizable. We might under-optimize here but
                // it will be non-major languages.
                return((typography & TypographyAvailabilities.Available) == 0);
            }
        }
Beispiel #58
0
        private PtsHost AcquireContextCore(PtsContext ptsContext, TextFormattingMode textFormattingMode)
        {
            int index;

            // Look for the first free PTS Context.
            for (index = 0; index < _contextPool.Count; index++)
            {
                if (!_contextPool[index].InUse &&
                    _contextPool[index].IsOptimalParagraphEnabled == ptsContext.IsOptimalParagraphEnabled)
                {
                    break;
                }
            }

            // Create new PTS Context, if cannot find free one.
            if (index == _contextPool.Count)
            {
                _contextPool.Add(new ContextDesc());
                _contextPool[index].IsOptimalParagraphEnabled = ptsContext.IsOptimalParagraphEnabled;
                _contextPool[index].PtsHost = new PtsHost();
                _contextPool[index].PtsHost.Context = CreatePTSContext(index, textFormattingMode);
            }

            // Initialize TextFormatter, if optimal paragraph is enabled.
            // Optimal paragraph requires new TextFormatter for every PTS Context.
            if (_contextPool[index].IsOptimalParagraphEnabled)
            {
                ptsContext.TextFormatter = _contextPool[index].TextFormatter;
            }

            // Assign PTS Context to new owner.
            _contextPool[index].InUse = true;
            _contextPool[index].Owner = new WeakReference(ptsContext);

            return _contextPool[index].PtsHost;
        }
Beispiel #59
0
 public FormattedTextCache(bool useDisplayMode)
 {
     textFormattingMode = useDisplayMode ? TextFormattingMode.Display : TextFormattingMode.Ideal;
     dict = new Dictionary <TextFormattingRunProperties, Info>();
 }
Beispiel #60
0
        private IntPtr CreatePTSContext(int index, TextFormattingMode textFormattingMode)
        {
            PtsHost ptsHost;
            IntPtr installedObjects;
            int installedObjectsCount;
            TextFormatterContext textFormatterContext;
            IntPtr context;

            ptsHost = _contextPool[index].PtsHost;
            Invariant.Assert(ptsHost != null);

            // Create installed object info.
            InitInstalledObjectsInfo(ptsHost, ref _contextPool[index].SubtrackParaInfo, ref _contextPool[index].SubpageParaInfo, out installedObjects, out installedObjectsCount);
            _contextPool[index].InstalledObjects = installedObjects;

            // Create generic callbacks info.
            InitGenericInfo(ptsHost, (IntPtr)(index + 1), installedObjects, installedObjectsCount, ref _contextPool[index].ContextInfo);

            // Preallocated floater and table info.
            InitFloaterObjInfo(ptsHost, ref _contextPool[index].FloaterInit);
            InitTableObjInfo(ptsHost, ref _contextPool[index].TableobjInit);

            // Setup for optimal paragraph
            if (_contextPool[index].IsOptimalParagraphEnabled)
            {
                textFormatterContext = new TextFormatterContext();
                TextPenaltyModule penaltyModule = textFormatterContext.GetTextPenaltyModule();
                IntPtr ptsPenaltyModule = penaltyModule.DangerousGetHandle();

                _contextPool[index].TextPenaltyModule = penaltyModule;
                _contextPool[index].ContextInfo.ptsPenaltyModule = ptsPenaltyModule;
                _contextPool[index].TextFormatter = TextFormatter.CreateFromContext(textFormatterContext, textFormattingMode);

                // Explicitly take the penalty module object out of finalization queue;
                // PTSCache must manage lifetime of the penalty module explicitly by calling
                // TextPenaltyModule.Dispose to ensure proper destruction order of PTSContext
                // and the penalty module (PTS context must be destroyed first).
                GC.SuppressFinalize(_contextPool[index].TextPenaltyModule);
            }

            // Create PTS Context
            PTS.Validate(PTS.CreateDocContext(ref _contextPool[index].ContextInfo, out context));

            return context;
        }