コード例 #1
0
        /// <summary>
        /// Returns a list of Typographic Variants for a character supported by the font.
        /// </summary>
        public static List <TypographyFeatureInfo> GetCharacterVariants(FontVariant font, Models.Character character)
        {
            var textAnalyzer = new CanvasTextAnalyzer(character.Char, CanvasTextDirection.TopToBottomThenLeftToRight);
            KeyValuePair <CanvasCharacterRange, CanvasAnalyzedScript> analyzed = textAnalyzer.GetScript().First();

            List <TypographyFeatureInfo> supported = new List <TypographyFeatureInfo>
            {
                TypographyFeatureInfo.None
            };

            foreach (var feature in font.XamlTypographyFeatures)
            {
                if (feature == TypographyFeatureInfo.None)
                {
                    continue;
                }

                var    glyphs  = textAnalyzer.GetGlyphs(analyzed.Key, font.FontFace, 24, false, false, analyzed.Value);
                bool[] results = font.FontFace.GetTypographicFeatureGlyphSupport(analyzed.Value, feature.Feature, glyphs);

                if (results.Any(r => r))
                {
                    supported.Add(feature);
                }
            }

            return(supported);
        }
コード例 #2
0
        public TypographyHandler(string text)
        {
            var textAnalyzer = new CanvasTextAnalyzer(text, CanvasTextDirection.TopToBottomThenLeftToRight);

            _analyzedScript = textAnalyzer.GetScript();

            TypographyOptions = new List <TypographyFeatureInfo>
            {
                new TypographyFeatureInfo(CanvasTypographyFeatureName.None)
            };
        }
コード例 #3
0
            public TypographyHandler(string text)
            {
                var textAnalyzer = new CanvasTextAnalyzer(text, CanvasTextDirection.TopToBottomThenLeftToRight);
                analyzedScript = textAnalyzer.GetScript();

                TypographyOptions = new List<TypographyFeatureInfo>();
                TypographyOptions.Add(new TypographyFeatureInfo(CanvasTypographyFeatureName.None));

                CurrentMode = Mode.BuildTypographyList;
                FeatureToHighlight = CanvasTypographyFeatureName.None;
            }
コード例 #4
0
            public TypographyHandler(string text)
            {
                var textAnalyzer = new CanvasTextAnalyzer(text, CanvasTextDirection.TopToBottomThenLeftToRight);

                analyzedScript = textAnalyzer.GetScript();

                TypographyOptions = new List <TypographyFeatureInfo>();
                TypographyOptions.Add(new TypographyFeatureInfo(CanvasTypographyFeatureName.None));

                CurrentMode        = Mode.BuildTypographyList;
                FeatureToHighlight = CanvasTypographyFeatureName.None;
            }
コード例 #5
0
        void SplitJustifiedGlyphsIntoRuns(CanvasTextAnalyzer textAnalyzer, LayoutBox layoutBox, CanvasGlyph[] justifiedGlyphs, bool needsAdditionalJustificationCharacters)
        {
            int glyphIndex = 0;

            float xPosition = (float)layoutBox.Rectangle.Right;

            for (int i = 0; i < layoutBox.GlyphRuns.Count; i++)
            {
                if (layoutBox.GlyphRuns[i].Glyphs.Count == 0)
                {
                    continue;
                }

                int originalGlyphCountForThisRun = layoutBox.GlyphRuns[i].Glyphs.Count;

                if (needsAdditionalJustificationCharacters)
                {
                    // Replace the glyph data, since justification can modify glyphs
                    CanvasGlyph[] justifiedGlyphsForThisGlyphRun = new CanvasGlyph[layoutBox.GlyphRuns[i].Glyphs.Count];
                    for (int j = 0; j < layoutBox.GlyphRuns[i].Glyphs.Count; j++)
                    {
                        justifiedGlyphsForThisGlyphRun[j] = justifiedGlyphs[glyphIndex + j];
                    }

                    CanvasCharacterRange range = layoutBox.GlyphRuns[i].GetRange();

                    var glyphRunClusterMap = layoutBox.GlyphRuns[i].GetClusterMap(range);
                    var glyphRunShaping    = layoutBox.GlyphRuns[i].GetShaping();

                    CanvasGlyph[] newSetOfGlyphs = textAnalyzer.AddGlyphsAfterJustification(
                        layoutBox.GlyphRuns[i].FormattingSpan.FontFace,
                        layoutBox.GlyphRuns[i].FormattingSpan.FontSize,
                        layoutBox.GlyphRuns[i].FormattingSpan.Script,
                        glyphRunClusterMap,
                        layoutBox.GlyphRuns[i].Glyphs.ToArray(),
                        justifiedGlyphsForThisGlyphRun,
                        glyphRunShaping);

                    layoutBox.GlyphRuns[i].Glyphs = new List <CanvasGlyph>(newSetOfGlyphs);
                }
                else
                {
                    for (int j = 0; j < layoutBox.GlyphRuns[i].Glyphs.Count; j++)
                    {
                        layoutBox.GlyphRuns[i].Glyphs[j] = justifiedGlyphs[glyphIndex + j];
                    }
                }

                glyphIndex += originalGlyphCountForThisRun;
            }
        }
コード例 #6
0
        private void EnsureLayout(CanvasControl sender)
        {
            if (!needsLayout)
            {
                return;
            }

            var geometry = GetLayoutGeometry(sender);

            string text       = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer lacinia odio lectus, eget luctus felis tincidunt sit amet. Maecenas vel ex porttitor, ultrices nunc feugiat, porttitor quam. Cras non interdum urna. In sagittis tempor leo quis laoreet. Sed pretium tellus ut commodo viverra. Ut volutpat in risus at aliquam. Sed faucibus vitae dolor ut commodo. Mauris mollis rhoncus libero ut porttitor. Suspendisse at egestas nunc. Proin non neque nibh. Mauris eu ornare arcu. Etiam non sem eleifend, imperdiet erat at, hendrerit ante. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Integer porttitor mauris eu pulvinar commodo. Interdum et malesuada fames ac ante ipsum primis in faucibus. Mauris ultricies fermentum sem sed consequat. Vestibulum iaculis dui nulla, nec pharetra dolor gravida in. Pellentesque vel nisi urna. Donec gravida nunc sed pellentesque feugiat. Aliquam iaculis enim non enim ultrices aliquam. In at leo sed lorem interdum bibendum at non enim.";
            var    textFormat = new CanvasTextFormat();

            textFormat.FontFamily = fontPicker.CurrentFontFamily;

            CanvasTextAnalyzer textAnalyzer = new CanvasTextAnalyzer(text, CanvasTextDirection.LeftToRightThenTopToBottom);

            //
            // Figure out what fonts to use.
            //
            var fontResult = textAnalyzer.ChooseFonts(textFormat);

            //
            // Perform a script analysis on the text.
            //
            var scriptAnalysis = textAnalyzer.AnalyzeScript();

            float maxLineSpacing = 0;
            List <FormattingSpan> formattingSpans = EvaluateFormattingSpans(textAnalyzer, fontResult, scriptAnalysis, out maxLineSpacing);

            //
            // Perform line break analysis.
            //
            var breakpoints = textAnalyzer.AnalyzeBreakpoints();

            //
            // Get the rectangles to layout text into.
            //
            layoutRectangles = SplitGeometryIntoRectangles(geometry, maxLineSpacing, sender);

            //
            // Insert glyph runs into the layout boxes.
            //
            glyphRuns = CreateGlyphRuns(layoutRectangles, formattingSpans, breakpoints);

            if (ShouldJustify)
            {
                Justify(textAnalyzer, glyphRuns, layoutRectangles);
            }

            needsLayout = false;
        }
コード例 #7
0
        void JustifyLine(CanvasTextAnalyzer textAnalyzer, LayoutBox layoutBox)
        {
            CanvasGlyph[] allGlyphs;
            var           justificationOpportunities = GetJustificationOpportunities(textAnalyzer, layoutBox, out allGlyphs);

            CanvasGlyph[] justifiedGlyphs = textAnalyzer.ApplyJustificationOpportunities(
                (float)layoutBox.Rectangle.Width,
                justificationOpportunities,
                allGlyphs);

            bool needsJustificationCharacters = layoutBox.GlyphRuns[0].FormattingSpan.NeedsAdditionalJustificationCharacters;

            SplitJustifiedGlyphsIntoRuns(textAnalyzer, layoutBox, justifiedGlyphs, needsJustificationCharacters);
        }
コード例 #8
0
        void JustifyLine(CanvasTextAnalyzer textAnalyzer, List <GlyphRun> glyphRuns, int startingGlyphRunIndex, int endingGlyphRunIndex, float layoutWidth, int glyphCountForLine)
        {
            CanvasGlyph[] allGlyphs;
            var           justificationOpportunities = GetJustificationOpportunities(textAnalyzer, startingGlyphRunIndex, endingGlyphRunIndex, glyphCountForLine, out allGlyphs);

            CanvasGlyph[] justifiedGlyphs = textAnalyzer.ApplyJustificationOpportunities(
                layoutWidth,
                justificationOpportunities,
                allGlyphs);

            bool needsJustificationCharacters = glyphRuns[startingGlyphRunIndex].FormattingSpan.NeedsAdditionalJustificationCharacters;

            SplitJustifiedGlyphsIntoRuns(textAnalyzer, startingGlyphRunIndex, endingGlyphRunIndex, justifiedGlyphs, needsJustificationCharacters);
        }
コード例 #9
0
        void Justify(CanvasTextAnalyzer textAnalyzer, List <LayoutBox> layoutBoxes)
        {
            if (layoutBoxes.Count == 0)
            {
                return;
            }

            for (int i = 0; i < layoutBoxes.Count; i++)
            {
                if (layoutBoxes[i].GlyphRuns.Count == 0)
                {
                    return;
                }

                JustifyLine(textAnalyzer, layoutBoxes[i]);
            }
        }
コード例 #10
0
        public static List <TypographyFeatureInfo> GetSupportedTypographyFeatures(FontVariant variant)
        {
            Dictionary <string, TypographyFeatureInfo> features = new Dictionary <string, TypographyFeatureInfo>();
            var analyzer = new CanvasTextAnalyzer(variant.GetCharString(), CanvasTextDirection.LeftToRightThenTopToBottom);

            {
                foreach (var script in analyzer.GetScript())
                {
                    foreach (var feature in variant.FontFace.GetSupportedTypographicFeatureNames(script.Value))
                    {
                        var info = new TypographyFeatureInfo(feature);
                        if (!features.ContainsKey(info.DisplayName))
                        {
                            features.Add(info.DisplayName, info);
                        }
                    }
                }
            }

            return(features.Values.OrderBy(f => f.DisplayName).ToList());
        }
コード例 #11
0
        CanvasJustificationOpportunity[] GetJustificationOpportunities(CanvasTextAnalyzer textAnalyzer, LayoutBox layoutBox, out CanvasGlyph[] allGlyphs)
        {
            int layoutBoxGlyphCount = layoutBox.GetGlyphCount();

            CanvasJustificationOpportunity[] justificationOpportunities = new CanvasJustificationOpportunity[layoutBoxGlyphCount];
            allGlyphs = new CanvasGlyph[layoutBoxGlyphCount];

            int glyphIndex = 0;

            for (int i = 0; i < layoutBox.GlyphRuns.Count; i++)
            {
                if (layoutBox.GlyphRuns[i].Glyphs.Count == 0)
                {
                    continue;
                }

                CanvasCharacterRange range = layoutBox.GlyphRuns[i].GetRange();

                var glyphRunClusterMap = layoutBox.GlyphRuns[i].GetClusterMap(range);
                var glyphRunShaping    = layoutBox.GlyphRuns[i].GetShaping();

                var justificationOpportunitiesThisGlyphRun = textAnalyzer.GetJustificationOpportunities(
                    range,
                    layoutBox.GlyphRuns[i].FormattingSpan.FontFace,
                    layoutBox.GlyphRuns[i].FormattingSpan.FontSize,
                    layoutBox.GlyphRuns[i].FormattingSpan.Script,
                    glyphRunClusterMap,
                    glyphRunShaping);

                for (int j = 0; j < layoutBox.GlyphRuns[i].Glyphs.Count; ++j)
                {
                    justificationOpportunities[glyphIndex + j] = justificationOpportunitiesThisGlyphRun[j];
                    allGlyphs[glyphIndex + j] = layoutBox.GlyphRuns[i].Glyphs[j];
                }
                glyphIndex += layoutBox.GlyphRuns[i].Glyphs.Count;
            }

            return(justificationOpportunities);
        }
コード例 #12
0
        CanvasJustificationOpportunity[] GetJustificationOpportunities(CanvasTextAnalyzer textAnalyzer, int startingGlyphRunIndex, int endingGlyphRunIndex, int glyphCount, out CanvasGlyph[] allGlyphs)
        {
            CanvasJustificationOpportunity[] justificationOpportunities = new CanvasJustificationOpportunity[glyphCount];
            allGlyphs = new CanvasGlyph[glyphCount];

            int glyphIndex = 0;

            for (int i = startingGlyphRunIndex; i < endingGlyphRunIndex; ++i)
            {
                if (glyphRuns[i].Glyphs.Count == 0)
                {
                    continue;
                }

                CanvasCharacterRange range = glyphRuns[i].GetRange();

                var glyphRunClusterMap = glyphRuns[i].GetClusterMap(range);
                var glyphRunShaping    = glyphRuns[i].GetShaping();

                var justificationOpportunitiesThisGlyphRun = textAnalyzer.GetJustificationOpportunities(
                    range,
                    glyphRuns[i].FormattingSpan.FontFace,
                    glyphRuns[i].FormattingSpan.FontSize,
                    glyphRuns[i].FormattingSpan.Script,
                    glyphRunClusterMap,
                    glyphRunShaping);

                for (int j = 0; j < glyphRuns[i].Glyphs.Count; ++j)
                {
                    justificationOpportunities[glyphIndex + j] = justificationOpportunitiesThisGlyphRun[j];
                    allGlyphs[glyphIndex + j] = glyphRuns[i].Glyphs[j];
                }
                glyphIndex += glyphRuns[i].Glyphs.Count;
            }

            return(justificationOpportunities);
        }
コード例 #13
0
        void Justify(CanvasTextAnalyzer textAnalyzer, List <GlyphRun> glyphRuns, List <Rect> layoutRectangles)
        {
            if (glyphRuns.Count == 0)
            {
                return;
            }

            int startingGlyphRunIndex = 0;
            int glyphCountForLine     = 0;

            for (int i = 0; i < glyphRuns.Count; i++)
            {
                if (glyphRuns[i].Glyphs.Count == 0)
                {
                    continue;
                }

                bool lineNumberChanged = i > 0 && glyphRuns[i].LineNumber != glyphRuns[i - 1].LineNumber;

                if (lineNumberChanged)
                {
                    int endingGlyphRunIndex = i;
                    var layoutWidth         = (float)layoutRectangles[glyphRuns[i - 1].LineNumber].Width;
                    JustifyLine(textAnalyzer, glyphRuns, startingGlyphRunIndex, endingGlyphRunIndex, layoutWidth, glyphCountForLine);

                    startingGlyphRunIndex = endingGlyphRunIndex;
                    glyphCountForLine     = 0;
                }

                glyphCountForLine += glyphRuns[i].Glyphs.Count;
            }

            // Do the last line, too.
            var lastLineLayoutWidth = (float)layoutRectangles[glyphRuns[glyphRuns.Count - 1].LineNumber].Width;

            JustifyLine(textAnalyzer, glyphRuns, startingGlyphRunIndex, glyphRuns.Count, lastLineLayoutWidth, glyphCountForLine);
        }
コード例 #14
0
        List <FormattingSpan> EvaluateFormattingSpans(
            CanvasTextAnalyzer textAnalyzer,
            IReadOnlyList <KeyValuePair <CanvasCharacterRange, CanvasScaledFont> > fontRuns,
            IReadOnlyList <KeyValuePair <CanvasCharacterRange, CanvasAnalyzedScript> > scriptRuns,
            IReadOnlyList <KeyValuePair <CanvasCharacterRange, CanvasAnalyzedBidi> > bidiRuns,
            out float maxLineSpacing)
        {
            maxLineSpacing = 0;

            //
            // Divide up our text space into spans of uniform font face, script and bidi.
            //

            List <FormattingSpan> formattingSpans = new List <FormattingSpan>();

            FormattingSpanHelper formattingSpanHelper = new FormattingSpanHelper(fontRuns, scriptRuns, bidiRuns);

            while (!formattingSpanHelper.IsDone())
            {
                var scriptProperties = textAnalyzer.GetScriptProperties(formattingSpanHelper.Script);

                float fontSize = desiredFontSize * formattingSpanHelper.ScaledFont.ScaleFactor;

                FormattingSpan formattingSpan = new FormattingSpan();

                int[]  clusterMap;
                bool[] isShapedAlone;
                CanvasGlyphShaping[] glyphShaping;

                // Evaluate which glyphs comprise the text.
                formattingSpan.Glyphs = textAnalyzer.GetGlyphs(
                    formattingSpanHelper.Range,
                    formattingSpanHelper.ScaledFont.FontFace,
                    fontSize,
                    false, // isSideways
                    formattingSpanHelper.Bidi.ResolvedLevel % 2 == 1,
                    formattingSpanHelper.Script,
                    "",
                    null,
                    null,
                    out clusterMap,
                    out isShapedAlone,
                    out glyphShaping);

                formattingSpan.FontFace     = formattingSpanHelper.ScaledFont.FontFace;
                formattingSpan.FontSize     = fontSize;
                formattingSpan.Script       = formattingSpanHelper.Script;
                formattingSpan.ClusterMap   = clusterMap;
                formattingSpan.GlyphShaping = glyphShaping;
                formattingSpan.Range        = formattingSpanHelper.Range;
                formattingSpan.BidiLevel    = formattingSpanHelper.Bidi.ResolvedLevel;
                formattingSpan.NeedsAdditionalJustificationCharacters = scriptProperties.JustificationCharacter != null;

                formattingSpans.Add(formattingSpan);

                //
                // For text which contains non-uniform font faces, CanvasTextLayout takes the maximum of
                // all of line spacings and applies it as the overall line spacing. We do the same thing, here.
                //
                maxLineSpacing = System.Math.Max(maxLineSpacing, GetLineSpacing(formattingSpan.FontFace, fontSize));

                formattingSpanHelper.MoveNext();
            }

            return(formattingSpans);
        }
コード例 #15
0
        private void EnsureLayout(CanvasControl sender)
        {
            if (!needsLayout)
            {
                return;
            }

            var geometry = GetLayoutGeometry(sender);

            string text;

            if (CurrentTextOption == TextOption.English)
            {
                text =
                    "Win2D is an easy-to-use Windows Runtime API for immediate mode 2D graphics rendering with GPU acceleration. " +
                    "It is available to C# and C++ developers writing Windows apps for Windows 8.1, Windows Phone 8.1 and Windows " +
                    "10. It utilizes the power of Direct2D, and integrates seamlessly with XAML and CoreWindow. The CanvasTextAnalyzer " +
                    "class identifies what glyphs are needed to render a piece of text, including the font fallbacks to properly " +
                    "handle different languages.  Example Gallery uses it to create this Custom Text Layouts example, which wordwraps text " +
                    "to fill an arbitrary geometric shape.";
            }
            else
            {
                //
                // Storing bi-directional text as a contiguous literal causes problems in VS; it will attempt to reorder the bi-di levels
                // in the script, and it reorders them wrongly (doesn't match Word, Outlook, other programs). This works around it
                // by separating some of them out.
                //
                // This text string contains control characters around 'C#' and C++' to ensure they are drawn with the correct
                // directionality. Higher-level editors like Word use this same mechanism, since a full, correct Bidi ordering
                // isn't sufficient for them.
                //
                text =
                    "Win2D هو API  لنظام التشغيل ويندوز سهل الاستخدام لتقديم الرسومات الثنائية الابعاد " + "(2D)" +
                    "مع تسارع المعالج الجرافيك. متاح للمطورين \u202aC#\u202c و \u202aC+ +\u202c لتطوير تطبيقات الويندوز لإصدارات " +
                    "8.1،   10 و هاتف الويندوز إصدار 8.1. فإنه يستخدم قوة Direct2D، ويدمج بسهولة مع XAML وCoreWindows ." +
                    "الفئة CanvasTextAnalyzer يحدد ما هي الرموز المطلوبة لتقديم قطعة من " +
                    "النص، بما في ذلك أساسات الخط إلى التعامل مع لغات مختلفة. Example Gallery يستخدم هذه الطقنيه لعرض كيفية التعامل مع النصوص.";
            }

            // Duplicate the text, so that it fills more reading space.
            text = text + text;

            var textFormat = new CanvasTextFormat();

            textFormat.FontFamily = fontPicker.CurrentFontFamily;

            var textDirection = CurrentTextDirection == TextDirection.LeftToRight ?
                                CanvasTextDirection.LeftToRightThenTopToBottom : CanvasTextDirection.RightToLeftThenTopToBottom;

            CanvasTextAnalyzer textAnalyzer = new CanvasTextAnalyzer(text, textDirection);

            //
            // Figure out what fonts to use.
            //
            var fontResult = textAnalyzer.GetFonts(textFormat);

            //
            // Perform a script analysis on the text.
            //
            var scriptAnalysis = textAnalyzer.GetScript();

            //
            // Perform bidi analysis.
            //
            var bidiAnalysis = textAnalyzer.GetBidi();

            float maxLineSpacing = 0;
            List <FormattingSpan> formattingSpans = EvaluateFormattingSpans(textAnalyzer, fontResult, scriptAnalysis, bidiAnalysis, out maxLineSpacing);

            //
            // Perform line break analysis.
            //
            var breakpoints = textAnalyzer.GetBreakpoints();

            //
            // Get the rectangles to layout text into.
            //
            layoutRectangles = SplitGeometryIntoRectangles(geometry, maxLineSpacing, sender);

            //
            // Insert glyph runs into the layout boxes.
            //
            layoutBoxes = CreateGlyphRuns(layoutRectangles, formattingSpans, breakpoints);

            if (ShouldJustify)
            {
                Justify(textAnalyzer, layoutBoxes);
            }

            needsLayout = false;
        }
コード例 #16
0
        List <FormattingSpan> EvaluateFormattingSpans(
            CanvasTextAnalyzer textAnalyzer,
            IReadOnlyList <KeyValuePair <CanvasCharacterRange, CanvasScaledFont> > fontRuns,
            IReadOnlyList <KeyValuePair <CanvasCharacterRange, CanvasAnalyzedScript> > scriptRuns,
            out float maxLineSpacing)
        {
            maxLineSpacing = 0;

            List <FormattingSpan> formattingSpans = new List <FormattingSpan>();

            //
            // Divide up our text space into spans of uniform font face and uniform script.
            //
            foreach (var scriptRun in scriptRuns)
            {
                var scriptProperties = textAnalyzer.GetScriptProperties(scriptRun.Value);

                bool isRightToLeft = IsRightToLeft(scriptProperties.IsoScriptNumber);

                foreach (var fontRun in fontRuns)
                {
                    int fontMatchEnd = fontRun.Key.CharacterIndex + fontRun.Key.CharacterCount;
                    int scriptEnd    = scriptRun.Key.CharacterIndex + scriptRun.Key.CharacterCount;

                    if (fontRun.Key.CharacterIndex > scriptEnd)
                    {
                        continue;
                    }

                    if (fontMatchEnd < scriptRun.Key.CharacterIndex)
                    {
                        continue;
                    }

                    int rangeStart = System.Math.Max(fontRun.Key.CharacterIndex, scriptRun.Key.CharacterIndex);
                    int rangeEnd   = System.Math.Min(fontMatchEnd, scriptEnd);
                    int length     = rangeEnd - rangeStart;

                    float fontSize = desiredFontSize * fontRun.Value.ScaleFactor;

                    FormattingSpan formattingSpan = new FormattingSpan();
                    formattingSpan.IsRightToLeft = isRightToLeft;

                    int[]  clusterMap;
                    bool[] isShapedAlone;
                    CanvasGlyphShaping[] glyphShaping;

                    CanvasCharacterRange range = new CanvasCharacterRange {
                        CharacterIndex = rangeStart, CharacterCount = length
                    };

                    // Evaluate which glyphs comprise the text.
                    formattingSpan.Glyphs = textAnalyzer.GetGlyphs(
                        range,
                        fontRun.Value.FontFace,
                        fontSize,
                        false, // isSideways
                        formattingSpan.IsRightToLeft,
                        scriptRun.Value,
                        "",
                        null,
                        null,
                        out clusterMap,
                        out isShapedAlone,
                        out glyphShaping);

                    formattingSpan.FontFace     = fontRun.Value.FontFace;
                    formattingSpan.FontSize     = fontSize;
                    formattingSpan.Script       = scriptRun.Value;
                    formattingSpan.ClusterMap   = clusterMap;
                    formattingSpan.GlyphShaping = glyphShaping;
                    formattingSpan.Range        = range;
                    formattingSpan.NeedsAdditionalJustificationCharacters = scriptProperties.JustificationCharacter != null;

                    formattingSpans.Add(formattingSpan);

                    //
                    // For text which contains non-uniform font faces, CanvasTextLayout takes the maximum of
                    // all of line spacings and applies it as the overall line spacing. We do the same thing, here.
                    //
                    maxLineSpacing = System.Math.Max(maxLineSpacing, GetLineSpacing(formattingSpan.FontFace, fontSize));
                }
            }

            return(formattingSpans);
        }
コード例 #17
0
        void SplitJustifiedGlyphsIntoRuns(CanvasTextAnalyzer textAnalyzer, int startingGlyphRunIndex, int endingGlyphRunIndex, CanvasGlyph[] justifiedGlyphs, bool needsAdditionalJustificationCharacters)
        {
            int glyphIndex = 0;

            float xPosition = glyphRuns[startingGlyphRunIndex].Position.X;

            for (int i = startingGlyphRunIndex; i < endingGlyphRunIndex; ++i)
            {
                if (glyphRuns[i].Glyphs.Count == 0)
                {
                    continue;
                }

                // Adjust glyph run positioning based on justification
                glyphRuns[i].Position = new Vector2()
                {
                    X = xPosition, Y = glyphRuns[i].Position.Y
                };

                // Update running total glyph run advance
                for (int j = 0; j < glyphRuns[i].Glyphs.Count; j++)
                {
                    xPosition += glyphRuns[i].Glyphs[j].Advance;
                }

                if (needsAdditionalJustificationCharacters)
                {
                    // Replace the glyph data, since justification can modify glyphs
                    CanvasGlyph[] justifiedGlyphsForThisGlyphRun = new CanvasGlyph[glyphRuns[i].Glyphs.Count];
                    for (int j = 0; j < glyphRuns[i].Glyphs.Count; j++)
                    {
                        justifiedGlyphsForThisGlyphRun[j] = justifiedGlyphs[glyphIndex + j];
                    }

                    CanvasCharacterRange range = glyphRuns[i].GetRange();

                    var glyphRunClusterMap = glyphRuns[i].GetClusterMap(range);
                    var glyphRunShaping    = glyphRuns[i].GetShaping();

                    CanvasGlyph[] newSetOfGlyphs = textAnalyzer.AddGlyphsAfterJustification(
                        glyphRuns[i].FormattingSpan.FontFace,
                        glyphRuns[i].FormattingSpan.FontSize,
                        glyphRuns[i].FormattingSpan.Script,
                        glyphRunClusterMap,
                        glyphRuns[i].Glyphs.ToArray(),
                        justifiedGlyphsForThisGlyphRun,
                        glyphRunShaping);

                    glyphRuns[i].Glyphs = new List <CanvasGlyph>(newSetOfGlyphs);
                }
                else
                {
                    for (int j = 0; j < glyphRuns[i].Glyphs.Count; j++)
                    {
                        glyphRuns[i].Glyphs[j] = justifiedGlyphs[glyphIndex + j];
                    }
                }

                glyphIndex += glyphRuns[i].Glyphs.Count;
            }
        }