示例#1
0
		public static int GetLength(this TextLine textLine, TextRun endOfLine) {
			int length = textLine.Length;
			var textRuns = textLine.GetTextRunSpans();
			if (textRuns.Count > 0 && textRuns[textRuns.Count - 1].Value == endOfLine)
				return length - endOfLine.Length;
			return length;
		}
示例#2
0
		public NormalizedSpan(TextRun textRun, Int32 startCharacterIndex)
		{
			_textRun = textRun;
			_length = _textRun.Length;
			_startCharacterIndex = startCharacterIndex;
			_canSplitOrMerge = false;
		}
 /// <summary>
 /// Construct a text trailing word ellipsis collapsing properties
 /// </summary>
 /// <param name="width">width in which collapsing is constrained to</param>
 /// <param name="textRunProperties">text run properties of ellispis symbol</param>
 public TextTrailingWordEllipsis(
     double              width,
     TextRunProperties   textRunProperties
     )
 {
     _width = width;
     _ellipsis = new TextCharacters(StringHorizontalEllipsis, textRunProperties);
 }
示例#4
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;
            }
        }
示例#5
0
 /// <summary>
 /// Construct a character string object by extracting text info from text run
 /// </summary>
 internal CharacterBufferRange(TextRun textRun)
 {
     _charBufferRef = textRun.CharacterBufferReference;
     _length        = textRun.Length;
 }
示例#6
0
        internal CharacterBufferRange FetchTextRun(
            int             cpFetch,
            int             cpFirst,
            out TextRun     textRun,
            out int         runLength
            )
        {
            int offsetToFirstCp;
            textRun = _runCache.FetchTextRun(this, cpFetch, cpFirst, out offsetToFirstCp, out runLength);

            CharacterBufferRange charString;

            switch (TextRunInfo.GetRunType(textRun))
            {
                case Plsrun.Text:
                {
                    CharacterBufferReference charBufferRef = textRun.CharacterBufferReference;

                    charString = new CharacterBufferRange(
                        charBufferRef.CharacterBuffer,
                        charBufferRef.OffsetToFirstChar + offsetToFirstCp,
                        runLength
                        );

                    break;
                }

                case Plsrun.InlineObject:                   
                    Debug.Assert(offsetToFirstCp == 0);
                    unsafe
                    {
                        charString = new CharacterBufferRange((char*) TextStore.PwchObjectReplacement, 1);
                    }
                    break;

                case Plsrun.LineBreak:
                    Debug.Assert(offsetToFirstCp == 0);
                    unsafe
                    {
                        //
                        // Line break is to be represented as "Line Separator" such that 
                        // it doesn't terminate the optimal paragraph formatting session, but still breaks the line
                        // unambiguously. 
                        //
                        charString = new CharacterBufferRange((char*) TextStore.PwchLineSeparator, 1);
                    }
                    break;       
                    
                case Plsrun.ParaBreak:
                    Debug.Assert(offsetToFirstCp == 0);
                    unsafe
                    {
                        // 
                        // Paragraph break is special as it also terminates the paragraph. 
                        // It should be represented as "Paragraph Separator" such that it will be correctly handled
                        // in Bidi and Optimal paragraph formatting.
                        //
                        charString = new CharacterBufferRange((char*) TextStore.PwchParaSeparator, 1);
                    }       
                    break;
                    
                case Plsrun.Hidden:
                    unsafe
                    {
                        charString = new CharacterBufferRange((char*) TextStore.PwchHidden, 1);
                    }
                    break;

                default:
                    charString = CharacterBufferRange.Empty;
                    break;
            }

            return charString;
        }
 /// <summary>
 /// Construct simple text run
 /// </summary>
 /// <param name="length">run length</param>
 /// <param name="textRun">text run</param>
 /// <param name="flags">run flags</param>
 private SimpleRun(
     int              length,
     TextRun          textRun,
     Flags            flags,
     TextFormatterImp textFormatterImp
     )
 {
     Length = length;
     TextRun = textRun;
     RunFlags = flags;
     _textFormatterImp = textFormatterImp;
 }
        /// <summary>
        /// Create simple run of text,
        /// returning null if the specified text run cannot be correctly formatted as simple run
        /// </summary>
        static internal SimpleRun CreateSimpleTextRun(
            CharacterBufferRange    charBufferRange,
            TextRun                 textRun,
            TextFormatterImp        formatter,
            int                     widthLeft,
            bool                    emergencyWrap,
            bool                    breakOnTabs
            )
        {
            Invariant.Assert(textRun is TextCharacters);

            SimpleRun run = new SimpleRun(formatter);
            run.CharBufferReference = charBufferRange.CharacterBufferReference;
            run.TextRun = textRun;

            if (!run.TextRun.Properties.Typeface.CheckFastPathNominalGlyphs(
                charBufferRange,
                run.EmSize,
                1.0,
                formatter.IdealToReal(widthLeft),
                !emergencyWrap,
                false,
                CultureMapper.GetSpecificCulture(run.TextRun.Properties.CultureInfo),
                formatter.TextFormattingMode,
                false,          //No support for isSideways
                breakOnTabs,
                out run.Length
                ))
            {
                // Getting nominal glyphs is not supported by the font,
                // or it is but it results in low typographic quality text
                // e.g. OpenType support is not utilized.
                return null;
            }

            run.TextRun.Properties.Typeface.GetCharacterNominalWidthsAndIdealWidth(
                new CharacterBufferRange(run.CharBufferReference, run.Length),
                run.EmSize,
                TextFormatterImp.ToIdeal,
                formatter.TextFormattingMode,
                false,
                out run.NominalAdvances,
                out run.IdealWidth
                );

            return run;
        }
        /// <summary>
        /// Returns a simple text run that represents a Tab.
        /// </summary>
        /// <param name="settings">text formatting settings</param>
        /// <param name="textRun">text run</param>
        /// <param name="idealRunOffsetUnRounded">run's offset from the beginning of the line</param>
        static private SimpleRun CreateSimpleRunForTab(
            FormatSettings settings,
            TextRun textRun,
            int idealRunOffsetUnRounded
            )
        {
            if (settings == null || textRun == null || textRun.Properties == null || textRun.Properties.Typeface == null)
            {
                return null;
            }

            GlyphTypeface glyphTypeface = textRun.Properties.Typeface.TryGetGlyphTypeface();

            // Check whether the font has the space character. If not then we have to go through
            // font fallback.
            // We are not calling CreateSimpleTextRun() because CheckFastPathNominalGlyphs()
            // can fail if a font has TypographicAvailabilities. We are simply rendering a space
            // so we don't realy care about TypographicFeatures. This is a perf optimization.
            if (glyphTypeface == null || !glyphTypeface.HasCharacter(' '))
            {
                return null;
            }

            // The full shaping path converts tabs to spaces.
            // Note: In order to get exactly the same metrics as we did in FullTextLine (specifically ink bounding box)
            // we need to "Draw" a space in place of a Tab (previously we were just ignoring the Tab and rendering nothing)
            // which turned out to give different overhang and extent values than those returned using the full shaping path.
            // So in order to avoid vertical jiggling when a line is changed from SimpleTextLine to FullTextLine by adding/removing
            // a complex character, we need to do the same thing as the full shaping path and draw a space for each tab.
            TextRun modifedTextRun = new TextCharacters(" ", textRun.Properties);
            CharacterBufferRange characterBufferRange = new CharacterBufferRange(modifedTextRun);
            SimpleRun run = new SimpleRun(1, modifedTextRun, Flags.Tab, settings.Formatter);
            run.CharBufferReference = characterBufferRange.CharacterBufferReference;
            run.TextRun.Properties.Typeface.GetCharacterNominalWidthsAndIdealWidth(
                    characterBufferRange,
                    run.EmSize,
                    TextFormatterImp.ToIdeal,
                    settings.Formatter.TextFormattingMode,
                    false,
                    out run.NominalAdvances
                    );

            int idealIncrementalTab = TextFormatterImp.RealToIdeal(settings.Pap.DefaultIncrementalTab);

            // Here we get the next tab stop without snapping the metrics to pixels.
            // We do the pixel snapping on the final position of the tab stop (and not on the IncrementalTab)
            // to achieve the same results as those in full shaping.
            int idealNextTabStopUnRounded = ((idealRunOffsetUnRounded / idealIncrementalTab) + 1) * idealIncrementalTab;

            run.IdealWidth = run.NominalAdvances[0] = idealNextTabStopUnRounded - idealRunOffsetUnRounded;
            return run;
        }
        /// <summary>
        /// Creating a simple text run
        /// </summary>
        /// <param name="settings">text formatting settings</param>
        /// <param name="charString">character string associated to textrun</param>
        /// <param name="textRun">text run</param>
        /// <param name="cp">first cp of the run</param>
        /// <param name="cpFirst">first cp of the line</param>
        /// <param name="runLength">run length</param>
        /// <param name="widthLeft">maximum run width</param>
        /// <param name="idealRunOffsetUnRounded">run's offset from the beginning of the line</param>
        /// <returns>a SimpleRun object</returns>
        static public SimpleRun Create(
            FormatSettings          settings,
            CharacterBufferRange    charString,
            TextRun                 textRun,
            int                     cp,
            int                     cpFirst,
            int                     runLength,
            int                     widthLeft,
            int                     idealRunOffsetUnRounded
            )
        {
            SimpleRun run = null;

            if (textRun is TextCharacters)
            {
                if (    textRun.Properties.BaselineAlignment != BaselineAlignment.Baseline
                    ||  (textRun.Properties.TextEffects != null && textRun.Properties.TextEffects.Count != 0)
                    )
                {
                    // fast path does not handle the following conditions
                    //  o  non-default baseline alignment
                    //  o  text drawing effect (
                    return null;
                }

                TextDecorationCollection textDecorations = textRun.Properties.TextDecorations;

                if (    textDecorations != null
                    &&  textDecorations.Count != 0
                    &&  !textDecorations.ValueEquals(TextDecorations.Underline))
                {
                    // we only support a single underline
                    return null;
                }

                settings.DigitState.SetTextRunProperties(textRun.Properties);
                if (settings.DigitState.RequiresNumberSubstitution)
                {
                    // don't support number substitution in fast path
                    return null;
                }

                bool canProcessTabsInSimpleShapingPath = CanProcessTabsInSimpleShapingPath(
                                                                settings.Pap,
                                                                settings.Formatter.TextFormattingMode
                                                                );

                if (charString[0] == TextStore.CharCarriageReturn)
                {
                    // CR in the middle of text stream treated as explicit paragraph break
                    // simple hard line break
                    runLength = 1;
                    if (charString.Length > 1 && charString[1] == TextStore.CharLineFeed)
                    {
                        runLength = 2;
                    }
                    // This path handles the case where the backing store breaks the text run in between
                    // a Carriage Return and a Line Feed. So we fetch the next run to check whether the next
                    // character is a line feed.
                    else if (charString.Length == 1)
                    {
                        // Prefetch to check for line feed.
                        TextRun newRun;
                        int newRunLength;
                        CharacterBufferRange newBufferRange = settings.FetchTextRun(
                            cp + 1,
                            cpFirst,
                            out newRun,
                            out newRunLength
                            );

                        if (newBufferRange.Length > 0 && newBufferRange[0] == TextStore.CharLineFeed)
                        {
                            // Merge the 2 runs.
                            int lengthOfRun = 2;
                            char[] characterArray = new char[lengthOfRun];
                            characterArray[0] = TextStore.CharCarriageReturn;
                            characterArray[1] = TextStore.CharLineFeed;
                            TextRun mergedTextRun = new TextCharacters(characterArray, 0, lengthOfRun, textRun.Properties);
                            return new SimpleRun(lengthOfRun, mergedTextRun, (Flags.EOT | Flags.Ghost), settings.Formatter);
                        }

                    }
                    return new SimpleRun(runLength, textRun, (Flags.EOT | Flags.Ghost), settings.Formatter);
                }
                else if (charString[0] == TextStore.CharLineFeed)
                {
                    // LF in the middle of text stream treated as explicit paragraph break
                    // simple hard line break
                    runLength = 1;
                    return new SimpleRun(runLength, textRun, (Flags.EOT | Flags.Ghost), settings.Formatter);
                }
                else if (canProcessTabsInSimpleShapingPath && charString[0] == TextStore.CharTab)
                {
                    return CreateSimpleRunForTab(settings,
                                                 textRun,
                                                 idealRunOffsetUnRounded);
                }

                // attempt to create a simple run for text
                run = CreateSimpleTextRun(
                    charString,
                    textRun,
                    settings.Formatter,
                    widthLeft,
                    settings.Pap.EmergencyWrap,
                    canProcessTabsInSimpleShapingPath
                    );

                if (run == null)
                {
                    // fail to create simple text run, the run content is too complex
                    return null;
                }

                // Check for underline condition
                if (textDecorations != null && textDecorations.Count == 1 )
                {
                    run.Underline = textDecorations[0];
                }
            }
            else if (textRun is TextEndOfLine)
            {
                run = new SimpleRun(runLength, textRun, (Flags.EOT | Flags.Ghost), settings.Formatter);
            }
            else if (textRun is TextHidden)
            {
                // hidden run
                run = new SimpleRun(runLength, textRun, Flags.Ghost, settings.Formatter);
            }

            return run;
        }
示例#11
0
 /// <summary>
 /// Constructing TextRunBounds
 /// </summary>
 internal TextRunBounds(
     Rect        bounds,
     int         cpFirst,
     int         cpEnd,
     TextRun     textRun
     )
 {
     _cpFirst = cpFirst;
     _cch = cpEnd - cpFirst;
     _bounds = bounds;
     _textRun = textRun;
 }
示例#12
0
        /// <summary>
        /// Map TextRun type to known plsrun type 
        /// </summary> 
        internal static Plsrun GetRunType(TextRun textRun)
        { 
            if (textRun is ITextSymbols || textRun is TextShapeableSymbols)
                return Plsrun.Text;

            if (textRun is TextEmbeddedObject) 
                return Plsrun.InlineObject;
 
            if (textRun is TextEndOfParagraph) 
                return Plsrun.ParaBreak;
 
            if (textRun is TextEndOfLine)
                return Plsrun.LineBreak;

            // Other text run type are all considered hidden by LS 
            return Plsrun.Hidden;
        } 
示例#13
0
        /// <summary>
        /// Constructing a textrun info
        /// </summary> 
        /// <param name="charBufferRange">characte buffer range for the run</param>
        /// <param name="textRunLength">textrun length</param> 
        /// <param name="offsetToFirstCp">character offset to run first cp</param> 
        /// <param name="textRun">text run</param>
        /// <param name="lsRunType">the internal LS run type </param> 
        /// <param name="charFlags">character attribute flags</param>
        /// <param name="digitCulture">digit culture for the run</param>
        /// <param name="contextualSubstitution">contextual number substitution for the run</param>
        /// <param name="symbolTypeface">if true, indicates a text run in a symbol (i.e., non-Unicode) font</param> 
        /// <param name="modifierScope">The current TextModifier scope for this TextRunInfo</param>
        internal TextRunInfo( 
            CharacterBufferRange charBufferRange, 
            int                  textRunLength,
            int                  offsetToFirstCp, 
            TextRun              textRun,
            Plsrun               lsRunType,
            ushort               charFlags,
            CultureInfo          digitCulture, 
            bool                 contextualSubstitution,
            bool                 symbolTypeface, 
            TextModifierScope    modifierScope 
            )
        { 
            _charBufferRange = charBufferRange;
            _textRunLength = textRunLength;
            _offsetToFirstCp = offsetToFirstCp;
            _textRun = textRun; 
            _plsrun = lsRunType;
            _charFlags = charFlags; 
            _digitCulture = digitCulture; 
            _runFlags = 0;
            _modifierScope = modifierScope; 

            if (contextualSubstitution)
            {
                _runFlags |= (ushort)RunFlags.ContextualSubstitution; 
            }
 
            if (symbolTypeface) 
            {
                _runFlags |= (ushort)RunFlags.IsSymbol; 
            }
        }