コード例 #1
0
        public void TestEquationWithOperatorsAndRelations()
        {
            var mathList = MathLists.FromString("2x+3=y");
            var display  = Typesetter <TFont, TGlyph> .CreateLine(mathList, _font, _context, LineStyle.Display);

            Assert.Equal(LinePosition.Regular, display.LinePosition);
            Assert.Equal(new Range(0, 6), display.Range);
            Assert.False(display.HasScript);
            Assert.Equal(Range.UndefinedInt, display.IndexInParent);
            Assert.Single(display.Displays);

            var line = display.Displays[0] as TextLineDisplay <TFont, TGlyph>;

            Assert.Equal(6, line.Atoms.Length);
            Assert.Equal("2x+3=y", line.StringText());
            Assert.Equal(new PointF(), line.Position);
            Assert.Equal(new Range(0, 6), line.Range);
            Assert.False(line.HasScript);

            Assert.Equal(display.Ascent, line.Ascent);
            Assert.Equal(display.Width, line.Width);
            Assert.Equal(display.Descent, line.Descent);

            Assertions.ApproximatelyEqual(14, display.Ascent, 0.01);
            Assertions.ApproximatelyEqual(4, display.Descent, 0.01);
            Assertions.ApproximatelyEqual(80, display.Width, 0.01);
        }
コード例 #2
0
        public void TestVariablesAndNumbers()
        {
            var mathList = MathLists.FromString("xy2w");

            var display = Typesetter <TFont, TGlyph> .CreateLine(mathList, _font, _context, LineStyle.Display);

            Assert.NotNull(display);
            Assert.Equal(LinePosition.Regular, display.LinePosition);
            Assert.Equal(new PointF(), display.Position);
            Assert.Equal(new Range(0, 4), display.Range);
            Assert.False(display.HasScript);
            Assert.Equal(Range.UndefinedInt, display.IndexInParent);
            Assert.Single(display.Displays);

            var sub0 = display.Displays[0];
            var line = sub0 as TextLineDisplay <TFont, TGlyph>;

            Assert.NotNull(line);
            Assert.Equal(4, line.Atoms.Length);
            Assert.Equal("xy2w", line.StringText());
            Assert.Equal(new PointF(), line.Position);
            Assert.Equal(new Range(0, 4), line.Range);
            Assert.False(line.HasScript);

            Assert.Equal(display.Ascent, line.Ascent);
            Assert.Equal(display.Descent, line.Descent);
            Assert.Equal(display.Width, line.Width);
            Assertions.ApproximatelyEqual(14, display.Ascent, 0.01);
            Assertions.ApproximatelyEqual(4, display.Descent, 0.01);
            Assertions.ApproximatelyEqual(40, display.Width, 0.01);
        }
コード例 #3
0
        private static void RunTypeset(CommandLineOptions commandLineOptions)
        {
            var typesetter         = new Typesetter();
            var documentFormatting = new DocumentFormatting(
                commandLineOptions.FontFamily,
                commandLineOptions.PageSize,
                commandLineOptions.PageMargin,
                commandLineOptions.LineHeight,
                commandLineOptions.FontSize,
                commandLineOptions.PrintPageNumbers,
                commandLineOptions.PrintMarginals);

            var documentMetadata = new DocumentMetadata(
                commandLineOptions.Title,
                documentFormatting);

            var markdownPages = commandLineOptions.InputFilePaths.Select(File.ReadAllText).ToArray();

            Console.WriteLine("Typesetting document, please wait...");
            var stream = typesetter.CreatePdfDocument(documentMetadata, markdownPages);

            using var fileStream = new FileStream(commandLineOptions.OutputFilepath, FileMode.Create);
            stream.CopyTo(fileStream);

            Console.WriteLine($"Finished! {commandLineOptions.OutputFilepath} has been created");
        }
コード例 #4
0
 public Renderer()
 {
     _fontLoader   = new FontLoader();
     _textMeasurer = new HyperfontTextMeasurer(_fontLoader);
     _typesetter   = new Typesetter(_textMeasurer);
     _exporter     = new PNGExporter(_fontLoader);
     _parser       = new LaTeXParser();
 }
コード例 #5
0
ファイル: _Typesetter.cs プロジェクト: Gillibald/CSharpMath
 internal static int GetInterElementSpaceArrayIndexForType <TFont, TGlyph>(Typesetter <TFont, TGlyph> t, MathAtomType atomType)
     where TFont : MathFont <TGlyph>
 {
     switch (atomType)
     {
     case MathAtomType.RaiseBox: return(0); //Same as Color
     }
     return(-1);                            // If reach here, then WILL THROW
 }
コード例 #6
0
ファイル: MathPainter.cs プロジェクト: kharbSachin/CSharpMath
 protected override void UpdateDisplayCore(float unused)
 {
     if (_displayChanged)
     {
         Display = Content == null
   ? null
   : Typesetter.CreateLine(Content, Fonts, TypesettingContext.Instance, LineStyle);
         _displayChanged = false;
     }
 }
コード例 #7
0
        public void TestSuperScript()
        {
            var mathList    = new MathList();
            var x           = MathAtoms.ForCharacter('x');
            var superscript = new MathList {
                MathAtoms.ForCharacter('2')
            };

            x.Superscript = superscript;
            mathList.Add(x);

            var display = Typesetter <TFont, TGlyph> .CreateLine(mathList, _font, _context, LineStyle.Display);

            Assert.NotNull(display);

            Assert.Equal(LinePosition.Regular, display.LinePosition);
            Assert.Equal(new PointF(), display.Position);
            Assert.Equal(new Range(0, 1), display.Range);
            Assert.False(display.HasScript);
            Assert.Equal(display.IndexInParent, Range.UndefinedInt);
            Assert.Equal(2, display.Displays.Count());

            var super0 = display.Displays[0];
            var line   = super0 as TextLineDisplay <TFont, TGlyph>;

            Assert.NotNull(line);
            Assert.Single(line.Atoms);
            Assert.Equal("x", line.StringText());
            Assert.Equal(new PointF(), line.Position);
            Assert.True(line.HasScript);

            var super1 = display.Displays[1] as ListDisplay <TFont, TGlyph>;

            Assert.NotNull(super1);
            Assert.Equal(LinePosition.Superscript, super1.LinePosition);
            var super1Position = super1.Position;

            Assertions.ApproximatePoint(10.32, 7.26, super1Position, 0.01); // may change as we implement more details?
            Assert.Equal(new Range(0, 1), super1.Range);
            Assert.False(super1.HasScript);
            Assert.Equal(0, super1.IndexInParent);
            Assert.Single(super1.Displays);

            var super10 = super1.Displays[0] as TextLineDisplay <TFont, TGlyph>;

            Assert.NotNull(super10);
            Assert.Single(super10.Atoms);
            Assert.Equal(new PointF(), super10.Position);
            Assert.False(super10.HasScript);

            Assertions.ApproximatelyEqual(17.06, display.Ascent, 0.01);
            Assertions.ApproximatelyEqual(4, display.Descent, 0.01);
        }
コード例 #8
0
        public void TestRadical()
        {
            var mathList = new MathList {
                new Radical {
                    Radicand = new MathList {
                        MathAtoms.ForCharacter('1')
                    }
                }
            };

            var display = Typesetter <TFont, TGlyph> .CreateLine(mathList, _font, _context, LineStyle.Display);

            Assert.Equal(LinePosition.Regular, display.LinePosition);
            Assert.Equal(new PointF(), display.Position);
            Assert.Equal(new Range(0, 1), display.Range);
            Assert.False(display.HasScript);
            Assert.Equal(Range.UndefinedInt, display.IndexInParent);
            Assert.Single(display.Displays);

            var radical = display.Displays[0] as RadicalDisplay <TFont, TGlyph>;

            Assert.Equal(new Range(0, 1), radical.Range);
            Assert.False(radical.HasScript);
            Assert.Equal(new PointF(), radical.Position);
            Assert.NotNull(radical.Radicand);
            Assert.Null(radical.Degree);

            var display2 = radical.Radicand as ListDisplay <TFont, TGlyph>;

            Assert.NotNull(display2);
            Assert.Equal(LinePosition.Regular, display2.LinePosition);
            Assertions.ApproximatePoint(10, 0, display2.Position, 0.01);
            Assert.Equal(new Range(0, 1), display2.Range);
            Assert.False(display2.HasScript);
            Assert.Equal(Range.UndefinedInt, display2.IndexInParent);
            Assert.Single(display2.Displays);

            var line2 = display2.Displays[0] as TextLineDisplay <TFont, TGlyph>;

            Assert.Single(line2.Atoms);
            Assert.Equal("1", line2.StringText());
            Assert.Equal(new PointF(), line2.Position);
            Assert.Equal(new Range(0, 1), line2.Range);
            Assert.False(line2.HasScript);

            Assertions.ApproximatelyEqual(18.56, display.Ascent, 0.01);
            Assertions.ApproximatelyEqual(4, display.Descent, 0.01);
            Assertions.ApproximatelyEqual(20, display.Width, 0.01);
        }
コード例 #9
0
ファイル: TextPipeline.cs プロジェクト: fealty/Typesetting
        public TextPipeline(FontDevice fontDevice)
        {
            Contract.Requires(fontDevice != null);

            _FontDevice = fontDevice;

            _TextAnalyzer = new Analyzer(_FontDevice.Factory);
            _AggregatorSink = new AggregatorSink();
            _Aggregator = new Aggregator(_AggregatorSink);
            _ShaperSink = new ShaperSink();
            _Shaper = new Shaper(_FontDevice, _ShaperSink);
            _FormatterSink = new FormatterSink();
            _Formatter = new Formatter(_FormatterSink);
            _TypesetterSink = new TypesetterSink();
            _Typesetter = new Typesetter(_TypesetterSink);
            _GeometryCache = new TextGeometryCache();
        }
コード例 #10
0
        internal static void CreateDisplayAtom <TFont, TGlyph>(Typesetter <TFont, TGlyph> t, I_ExtensionAtom atom)
            where TFont : IFont <TGlyph>
        {
            switch (atom.AtomType)
            {
            case MathAtomType.RaiseBox:
                t.AddDisplayLine(false);
                var raiseBox      = atom as RaiseBox;
                var raisedDisplay = Typesetter <TFont, TGlyph> .CreateLine(raiseBox.InnerList, t._font, t._context, t._style);

                var raisedPosition = t._currentPosition;
                raisedPosition.Y      += raiseBox.Raise.ActualLength(t._mathTable, t._font);
                raisedDisplay.Position = raisedPosition;
                t._currentPosition.X  += raisedDisplay.Width;
                t._displayAtoms.Add(raisedDisplay);
                break;
            }
        }
コード例 #11
0
        public void TestRaiseBox()
        {
            var mathList = new MathList {
                new Atoms.Extension.RaiseBox {
                    InnerList = new MathList {
                        MathAtoms.ForCharacter('r')
                    },
                    Raise = new Space(3 * Structures.Space.Point)
                }
            };

            var display = Typesetter <TFont, TGlyph> .CreateLine(mathList, _font, _context, LineStyle.Display);

            Assert.Equal(LinePosition.Regular, display.LinePosition);
            Assert.Equal(new Range(0, 1), display.Range);
            Assert.False(display.HasScript);
            Assert.Equal(Range.UndefinedInt, display.IndexInParent);
            Assert.Single(display.Displays);

            var display2 = display.Displays[0] as ListDisplay <TFont, TGlyph>;

            Assert.Equal(LinePosition.Regular, display2.LinePosition);
            Assert.Equal(new PointF(0, 3), display2.Position);
            Assert.Equal(new Range(0, 1), display2.Range);
            Assert.False(display2.HasScript);
            Assert.Equal(Range.UndefinedInt, display2.IndexInParent);
            Assert.Equal(1, display2.Displays.Count);

            var line = display2.Displays[0] as TextLineDisplay <TFont, TGlyph>;

            Assert.Single(line.Atoms);
            Assert.Equal("r", line.StringText());
            Assert.Equal(new PointF(), line.Position);
            Assert.False(line.HasScript);

            Assertions.ApproximatelyEqual(17, display.Ascent, 0.01);
            Assertions.ApproximatelyEqual(1, display.Descent, 0.01);
            Assertions.ApproximatelyEqual(10, display.Width, 0.01);
        }
コード例 #12
0
 public static MathListDisplay<TFont, TGlyph> CreateLine<TFont, TGlyph>(this TypesettingContext<TFont, TGlyph> context, IMathList list, TFont font, LineStyle style)
   where TFont: MathFont<TGlyph> {
   return Typesetter<TFont, TGlyph>.CreateLine(list, font, context, style);
   }
コード例 #13
0
ファイル: Program.cs プロジェクト: MikielAgutu/Typeset
 static void Main(string[] args)
 {
     var typesetter = new Typesetter();
 }
コード例 #14
0
 public TypesetterTests()
 {
     _textMeasurer = new TestTextMeasurer();
     _typesetter   = new Typesetter(_textMeasurer);
 }
コード例 #15
0
ファイル: TextLayoutter.cs プロジェクト: Gillibald/CSharpMath
        public static (Displays relative, Displays absolute) Layout(TextAtom input, Fonts inputFont, float canvasWidth)
        {
            if (input == null)
            {
                return
                    (new Displays(Array.Empty <IDisplay <Fonts, Glyph> >()),
                     new Displays(Array.Empty <IDisplay <Fonts, Glyph> >()));
            }
            float accumulatedHeight     = 0;
            TextDisplayLineBuilder line = new TextDisplayLineBuilder();

            void BreakLine(List <IDisplay <Fonts, Glyph> > displayList)
            {
                accumulatedHeight += line.Ascent;
                line.Clear(0, -accumulatedHeight, displayList.Add, () => accumulatedHeight += line.Descent);
            }

            void AddDisplaysWithLineBreaks(TextAtom atom, Fonts fonts,
                                           List <IDisplay <Fonts, Glyph> > displayList,
                                           List <IDisplay <Fonts, Glyph> > displayMathList,
                                           FontStyle style        = FontStyle.Roman, /*FontStyle.Default is FontStyle.Italic, FontStyle.Roman is no change to characters*/
                                           Structures.Color?color = null)
            {
                IDisplay <Fonts, Glyph> display;

                switch (atom)
                {
                case TextAtom.List list:
                    foreach (var a in list.Content)
                    {
                        AddDisplaysWithLineBreaks(a, fonts, displayList, displayMathList, style, color);
                    }
                    break;

                case TextAtom.Style st:
                    AddDisplaysWithLineBreaks(st.Content, fonts, displayList, displayMathList, st.FontStyle, color);
                    break;

                case TextAtom.Size sz:
                    AddDisplaysWithLineBreaks(sz.Content, new Fonts(fonts, sz.PointSize), displayList, displayMathList, style, color);
                    break;

                case TextAtom.Color c:
                    AddDisplaysWithLineBreaks(c.Content, fonts, displayList, displayMathList, style, c.Colour);
                    break;

                case TextAtom.Space sp:
                    //Allow space at start of line since user explicitly specified its length
                    //Also \par generates this kind of spaces
                    line.AddSpace(sp.Content.ActualLength(MathTable.Instance, fonts));
                    break;

                case TextAtom.Newline n:
                    BreakLine(displayList);
                    break;

                case TextAtom.Math m when m.DisplayStyle:
                    BreakLine(displayList);
#warning Replace 12 with a more appropriate spacing
                    accumulatedHeight += 12;
                    display            = Typesetter <Fonts, Glyph> .CreateLine(m.Content, fonts, TypesettingContext.Instance, LineStyle.Display);

                    if (color != null)
                    {
                        display.SetTextColorRecursive(color);
                    }
                    accumulatedHeight += display.Ascent;
                    display.Position   = new System.Drawing.PointF(
                        IPainterExtensions.GetDisplayPosition(display.Width, display.Ascent, display.Descent, fonts.PointSize, false, canvasWidth, float.NaN, TextAlignment.Top, default, default, default).X,
                        -accumulatedHeight);
                    accumulatedHeight += display.Descent;
                    accumulatedHeight += 12;
                    if (color != null)
                    {
                        display.SetTextColorRecursive(color);
                    }
                    displayMathList.Add(display);
                    break;

                    void FinalizeInlineDisplay(float ascentMin, bool forbidAtLineStart = false)
                    {
                        if (color != null)
                        {
                            display.SetTextColorRecursive(color);
                        }
                        if (line.Width + display.Width > canvasWidth && !forbidAtLineStart)
                        {
                            BreakLine(displayList);
                        }
                        line.Add(display, ascentMin);
                    }

                case TextAtom.Text t:
                    var content = UnicodeFontChanger.Instance.ChangeFont(t.Content, style);
                    var glyphs  = GlyphFinder.Instance.FindGlyphs(fonts, content);
                    //Calling Select(g => g.Typeface).Distinct() speeds up query up to 10 times,
                    //Calling Max(Func<,>) instead of Select(Func<,>).Max() speeds up query 2 times
                    float maxLineSpacing = glyphs.Select(g => g.Typeface).Distinct().Max(tf =>
                                                                                         tf.CalculateRecommendLineSpacing() *
                                                                                         tf.CalculateScaleToPixelFromPointSize(fonts.PointSize)
                                                                                         );
                    display = new TextRunDisplay <Fonts, Glyph>(Display.Text.AttributedGlyphRuns.Create(content, glyphs, fonts, false), t.Range, TypesettingContext.Instance);
                    FinalizeInlineDisplay(maxLineSpacing);
                    break;

                case TextAtom.Math m:
                    if (m.DisplayStyle)
                    {
                        throw new InvalidCodePathException("Display style maths should have been handled above this switch.");
                    }
                    display = Typesetter <Fonts, Glyph> .CreateLine(m.Content, fonts, TypesettingContext.Instance, Enumerations.LineStyle.Text);

                    FinalizeInlineDisplay(fonts.MathTypeface.CalculateRecommendLineSpacing() *
                                          fonts.MathTypeface.CalculateScaleToPixelFromPointSize(fonts.PointSize));
                    break;

                case TextAtom.ControlSpace cs:
                    var spaceGlyph = GlyphFinder.Instance.Lookup(fonts, ' ');
                    display = new TextRunDisplay <Fonts, Glyph>(Display.Text.AttributedGlyphRuns.Create(" ", new[] { spaceGlyph }, fonts, false), cs.Range, TypesettingContext.Instance);
                    FinalizeInlineDisplay(spaceGlyph.Typeface.CalculateRecommendLineSpacing() *
                                          spaceGlyph.Typeface.CalculateScaleToPixelFromPointSize(fonts.PointSize),
                                          forbidAtLineStart: true); //No spaces at start of line
                    break;

                case null:
                    throw new InvalidOperationException("TextAtoms should never be null. You must have sneaked one in.");

                case var a:
                    throw new InvalidCodePathException($"There should not be an unknown type of TextAtom. However, one with type {a.GetType()} was encountered.");
                }
            }

            var relativePositionList = new List <IDisplay <Fonts, Glyph> >();
            var absolutePositionList = new List <IDisplay <Fonts, Glyph> >();
            AddDisplaysWithLineBreaks(input, inputFont, relativePositionList, absolutePositionList);
            BreakLine(relativePositionList); //remember to finalize the last line
            return(new Displays(relativePositionList),
                   new Displays(absolutePositionList));
        }
コード例 #16
0
 void TestOuter(string latex, int rangeMax, double ascent, double descent, double width,
                params System.Action <IDisplay <TFont, TGlyph> >[] inspectors) =>
 TestList(rangeMax, ascent, descent, width, 0, 0, LinePosition.Regular, Range.UndefinedInt, inspectors)
     (Typesetter.CreateLine(LaTeXParserTest.ParseLaTeX(latex), _font, _context, LineStyle.Display));
コード例 #17
0
 internal static ListDisplay <TFont, TGlyph> ParseLaTeXToDisplay(string latex) =>
 Typesetter.CreateLine(LaTeXParserTest.ParseLaTeX(latex), _font, _context, LineStyle.Display);
コード例 #18
0
        public static (Display relative, Display absolute) Layout
            (TextAtom input, Fonts inputFont, float canvasWidth, float additionalLineSpacing)
        {
#warning Multiply these constants by resolution
            const float abovedisplayskip = 12, abovedisplayshortskip = 0,
                        belowdisplayskip = 12, belowdisplayshortskip = 7;
            if (input == null)
            {
                return
                    (new Display(Array.Empty <IDisplay <Fonts, Glyph> >()),
                     new Display(Array.Empty <IDisplay <Fonts, Glyph> >()));
            }
            float accumulatedHeight = 0;
            //indicator of the need to apply belowdisplay(short)skip when line break
            bool afterDisplayMaths = false;
            void BreakLine(TextLayoutLineBuilder line, List <IDisplay <Fonts, Glyph> > displayList,
                           List <IDisplay <Fonts, Glyph> > displayMathList, bool appendLineGap = true)
            {
                if (afterDisplayMaths)
                {
                    accumulatedHeight +=
                        line.Width > displayMathList.Last().Position.X
                      ? belowdisplayskip
                      : belowdisplayshortskip;
                    afterDisplayMaths = false;
                }
                line.Clear(0, -accumulatedHeight, displayList,
                           ref accumulatedHeight, true, appendLineGap, additionalLineSpacing);
            }

            //variables captured by this method are currently unchangable by TextAtoms
            void AddDisplaysWithLineBreaks(
                TextAtom atom,
                Fonts fonts,
                TextLayoutLineBuilder line,
                List <IDisplay <Fonts, Glyph> > displayList,
                List <IDisplay <Fonts, Glyph> > displayMathList,
                FontStyle style,
                Color?color
                )
            {
                IDisplay <Fonts, Glyph> display;

                switch (atom)
                {
                case TextAtom.List list:
                    foreach (var a in list.Content)
                    {
                        AddDisplaysWithLineBreaks
                            (a, fonts, line, displayList, displayMathList, style, color);
                    }
                    break;

                case TextAtom.Style st:
                    AddDisplaysWithLineBreaks
                        (st.Content, fonts, line, displayList, displayMathList, st.FontStyle, color);
                    break;

                case TextAtom.Size sz:
                    AddDisplaysWithLineBreaks
                        (sz.Content, new Fonts(fonts, sz.PointSize), line, displayList,
                        displayMathList, style, color);
                    break;

                case TextAtom.Color c:
                    AddDisplaysWithLineBreaks
                        (c.Content, fonts, line, displayList, displayMathList, style, c.Colour);
                    break;

                case TextAtom.Space sp:
                    //Allow space at start of line since user explicitly specified its length
                    //Also \par generates this kind of spaces
                    line.AddSpace(sp.Content.ActualLength(MathTable.Instance, fonts));
                    break;

                case TextAtom.Newline n:
                    BreakLine(line, displayList, displayMathList);
                    break;

                case TextAtom.Math m when m.DisplayStyle:
                    var lastLineWidth = line.Width;
                    BreakLine(line, displayList, displayMathList, false);
                    display = Typesetter.CreateLine(m.Content, fonts, TypesettingContext.Instance, LineStyle.Display);
                    var displayX = IPainterExtensions.GetDisplayPosition
                                       (display.Width, display.Ascent, display.Descent,
                                       fonts.PointSize, false, canvasWidth, float.NaN,
                                       TextAlignment.Top, default, default, default).X;
                    //\because When displayList.LastOrDefault() is null,
                    //the false condition is selected
                    //\therefore Append abovedisplayshortskip which defaults
                    //to 0 when nothing is above the display-style maths
                    accumulatedHeight +=
                        lastLineWidth > displayX ? abovedisplayskip : abovedisplayshortskip;
                    accumulatedHeight += display.Ascent;
                    display.Position   = new System.Drawing.PointF(displayX, -accumulatedHeight);
                    accumulatedHeight += display.Descent;
                    afterDisplayMaths  = true;
                    if (color != null)
                    {
                        display.SetTextColorRecursive(color);
                    }
                    displayMathList.Add(display);
                    break;

                    void FinalizeInlineDisplay(float ascender, float rawDescender,
                                               float lineGap, bool forbidAtLineStart = false)
                    {
                        if (color != null)
                        {
                            display.SetTextColorRecursive(color);
                        }
                        if (line.Width + display.Width > canvasWidth && !forbidAtLineStart)
                        {
                            BreakLine(line, displayList, displayMathList);
                        }
                        //rawDescender is taken directly from font file and is negative,
                        //while IDisplay.Descender is positive
                        line.Add(display, ascender, -rawDescender, lineGap);
                    }

                case TextAtom.Text t:
                    var content = UnicodeFontChanger.Instance.ChangeFont(t.Content, style);
                    var glyphs  = GlyphFinder.Instance.FindGlyphs(fonts, content);
                    //Calling Select(g => g.Typeface).Distinct() speeds up query up to 10 times,
                    //Calling Max(Func<,>) instead of Select(Func<,>).Max() speeds up query 2 times
                    var typefaces = glyphs.Select(g => g.Typeface).Distinct().ToList();
                    display = new TextRunDisplay <Fonts, Glyph>(
                        new AttributedGlyphRun <Fonts, Glyph>(content, glyphs, fonts),
                        t.Range, TypesettingContext.Instance
                        );
                    FinalizeInlineDisplay(
                        typefaces.Max(tf => tf.Ascender * tf.CalculateScaleToPixelFromPointSize(fonts.PointSize)),
                        typefaces.Min(tf => tf.Descender * tf.CalculateScaleToPixelFromPointSize(fonts.PointSize)),
                        typefaces.Max(tf => tf.LineGap * tf.CalculateScaleToPixelFromPointSize(fonts.PointSize))
                        );
                    break;

                case TextAtom.Math m:
                    if (m.DisplayStyle)
                    {
                        throw new InvalidCodePathException
                                  ("Display style maths should have been handled above this switch.");
                    }
                    display = Typesetter.CreateLine(m.Content, fonts, TypesettingContext.Instance, LineStyle.Text);
                    var scale = fonts.MathTypeface.CalculateScaleToPixelFromPointSize(fonts.PointSize);
                    FinalizeInlineDisplay(fonts.MathTypeface.Ascender * scale,
                                          fonts.MathTypeface.Descender * scale, fonts.MathTypeface.LineGap * scale);
                    break;

                case TextAtom.ControlSpace cs:
                    var spaceGlyph = GlyphFinder.Instance.Lookup(fonts, ' ');
                    display = new TextRunDisplay <Fonts, Glyph>(
                        new AttributedGlyphRun <Fonts, Glyph>(" ", new[] { spaceGlyph }, fonts),
                        cs.Range, TypesettingContext.Instance
                        );
                    scale = spaceGlyph.Typeface.CalculateScaleToPixelFromPointSize(fonts.PointSize);
                    FinalizeInlineDisplay(spaceGlyph.Typeface.Ascender * scale,
                                          spaceGlyph.Typeface.Descender * scale,
                                          spaceGlyph.Typeface.LineGap * scale,
                                          forbidAtLineStart: true); //No spaces at start of line
                    break;

                case TextAtom.Accent a:
                    var accentGlyph = GlyphFinder.Instance.FindGlyphForCharacterAtIndex(
                        fonts, a.AccentChar.Length - 1, a.AccentChar
                        );
                    scale = accentGlyph.Typeface.CalculateScaleToPixelFromPointSize(fonts.PointSize);
                    var accenteeDisplayList = new List <IDisplay <Fonts, Glyph> >();
                    var invalidDisplayMaths = new List <IDisplay <Fonts, Glyph> >();
                    var accentDisplayLine   = new TextLayoutLineBuilder();
                    AddDisplaysWithLineBreaks(a.Content, fonts, accentDisplayLine,
                                              accenteeDisplayList, invalidDisplayMaths, style, color);
                    float _ = default;
                    accentDisplayLine.Clear
                        (0, 0, accenteeDisplayList, ref _, false, false, additionalLineSpacing);
                    System.Diagnostics.Debug.Assert(invalidDisplayMaths.Count == 0,
                                                    "Display maths inside an accentee is unsupported -- ignoring display maths");
                    var accentee            = new Display(accenteeDisplayList);
                    var accenteeCodepoint   = a.Content.SingleChar(style);
                    var accenteeSingleGlyph =
                        accenteeCodepoint.HasValue
                          ? GlyphFinder.Instance.Lookup(fonts, accenteeCodepoint.GetValueOrDefault())
                          : GlyphFinder.Instance.EmptyGlyph;

                    var accentDisplay = new AccentDisplay <Fonts, Glyph>(
                        Typesetter.CreateAccentGlyphDisplay(
                            accentee, accenteeSingleGlyph, accentGlyph,
                            TypesettingContext.Instance, fonts, a.Range
                            ), accentee);
                    display = accentDisplay;
                    //accentDisplay.Ascent does not take account of accent glyph's extra height
                    //-> accent will be out of bounds if it is on the first line
                    FinalizeInlineDisplay(
                        Math.Max(accentGlyph.Typeface.Ascender * scale,
                                 accentDisplay.Accent.Position.Y + accentDisplay.Ascent),
                        accentGlyph.Typeface.Descender * scale,
                        accentGlyph.Typeface.LineGap * scale);
                    break;

                case TextAtom.Comment _:
                    break;

                case null:
                    throw new InvalidOperationException
                              ("TextAtoms should never be null. You must have sneaked one in.");

                case var a:
                    throw new InvalidCodePathException
                              ($"There should not be an unknown type of TextAtom. However, one with type {a.GetType()} was encountered.");
                }
            }

            var relativePositionList = new List <IDisplay <Fonts, Glyph> >();
            var absolutePositionList = new List <IDisplay <Fonts, Glyph> >();
            var globalLine           = new TextLayoutLineBuilder();
            AddDisplaysWithLineBreaks(
                input,
                inputFont,
                globalLine,
                relativePositionList,
                absolutePositionList,
                FontStyle.Roman /*FontStyle.Default is FontStyle.Italic, FontStyle.Roman is no change to characters*/,
                null
                );
            BreakLine(globalLine, relativePositionList, absolutePositionList); //remember to finalize the last line
            return(new Display(relativePositionList), new Display(absolutePositionList));
        }
コード例 #19
0
        public void TestSuperSubscript()
        {
            var mathList    = new MathList();
            var x           = MathAtoms.ForCharacter('x');
            var superscript = new MathList {
                MathAtoms.ForCharacter('2')
            };
            var subscript = new MathList {
                MathAtoms.ForCharacter('1')
            };

            x.Subscript   = subscript;
            x.Superscript = superscript;
            mathList.Add(x);

            var display = Typesetter <TFont, TGlyph> .CreateLine(mathList, _font, _context, LineStyle.Display);

            Assert.NotNull(display);
            Assert.Equal(LinePosition.Regular, display.LinePosition);
            Assert.Equal(new PointF(), display.Position);
            Assert.Equal(new Range(0, 1), display.Range);
            Assert.False(display.HasScript);
            Assert.Equal(Range.UndefinedInt, display.IndexInParent);
            Assert.Equal(3, display.Displays.Count());

            var line = display.Displays[0] as TextLineDisplay <TFont, TGlyph>;

            Assert.Single(line.Atoms);
            Assert.Equal("x", line.StringText());
            Assert.Equal(new PointF(), line.Position);
            Assert.True(line.HasScript);

            var display2 = display.Displays[1] as ListDisplay <TFont, TGlyph>;

            Assert.Equal(LinePosition.Superscript, display2.LinePosition);
            Assertions.ApproximatePoint(10.32, 9.68, display2.Position, 0.01);
            Assert.Equal(new Range(0, 1), display2.Range);
            Assert.False(display2.HasScript);
            Assert.Equal(0, display2.IndexInParent);
            Assert.Single(display2.Displays);

            var line2 = display2.Displays[0] as TextLineDisplay <TFont, TGlyph>;

            Assert.Single(line2.Atoms);
            Assert.Equal("2", line2.StringText());
            Assert.Equal(new PointF(), line2.Position);
            Assert.False(line2.HasScript);

            var display3 = display.Displays[2] as ListDisplay <TFont, TGlyph>;

            Assert.Equal(LinePosition.Subscript, display3.LinePosition);

            // Because both subscript and superscript are present, coords are
            // different from the subscript-only case.
            Assertions.ApproximatePoint(10, -6.12, display3.Position, 0.01);
            Assert.Equal(new Range(0, 1), display3.Range);
            Assert.False(display3.HasScript);
            Assert.Equal(0, display3.IndexInParent);
            Assert.Single(display3.Displays);

            var line3 = display3.Displays[0] as TextLineDisplay <TFont, TGlyph>;

            Assert.Single(line3.Atoms);
            Assert.Equal("1", line3.StringText());
            Assert.Equal(new PointF(), line3.Position);
            Assert.False(line3.HasScript);

            Assertions.ApproximatelyEqual(19.48, display.Ascent, 0.01);
            Assertions.ApproximatelyEqual(8.92, display.Descent, 0.01);
            Assertions.ApproximatelyEqual(17.32, display.Width, 0.01);
            Assertions.ApproximatelyEqual(display.Ascent, display2.Position.Y + line2.Ascent, 0.01);
            Assertions.ApproximatelyEqual(display.Descent, line3.Descent - display3.Position.Y, 0.01);
        }
コード例 #20
0
        public void TestInner()
        {
            var mathList = new MathList {
                new Inner {
                    InnerList = new MathList {
                        MathAtoms.ForCharacter('x'),
                    },
                    LeftBoundary  = MathAtoms.Create(MathAtomType.Boundary, '('),
                    RightBoundary = MathAtoms.Create(MathAtomType.Boundary, ')')
                }
            };

            var display = Typesetter <TFont, TGlyph> .CreateLine(mathList, _font, _context, LineStyle.Display);

            Assert.Equal(LinePosition.Regular, display.LinePosition);
            Assert.Equal(new Range(0, 1), display.Range);
            Assert.False(display.HasScript);
            Assert.Equal(Range.UndefinedInt, display.IndexInParent);
            Assert.Single(display.Displays);

            var display2 = display.Displays[0] as ListDisplay <TFont, TGlyph>;

            Assert.Equal(LinePosition.Regular, display2.LinePosition);
            Assert.Equal(new PointF(), display2.Position);
            Assert.Equal(new Range(0, 1), display2.Range);
            Assert.False(display2.HasScript);
            Assert.Equal(Range.UndefinedInt, display2.IndexInParent);
            Assert.Equal(3, display2.Displays.Count);

            var glyph = display2.Displays[0] as GlyphDisplay <TFont, TGlyph>;

            Assert.Equal(new PointF(), glyph.Position);
            Assert.Equal(Range.NotFound, glyph.Range);
            Assert.False(glyph.HasScript);

            var display3 = display2.Displays[1] as ListDisplay <TFont, TGlyph>;

            Assert.Equal(LinePosition.Regular, display3.LinePosition);
            Assertions.ApproximatePoint(10, 0, display3.Position, 0.01);
            Assert.Equal(new Range(0, 1), display3.Range);
            Assert.False(display3.HasScript);
            Assert.Equal(Range.UndefinedInt, display3.IndexInParent);
            Assert.Single(display3.Displays);

            var line = display3.Displays[0] as TextLineDisplay <TFont, TGlyph>;

            Assert.Single(line.Atoms);
            Assert.Equal("x", line.StringText());
            Assert.Equal(new PointF(), line.Position);
            Assert.False(line.HasScript);

            var glyph2 = display2.Displays[2] as GlyphDisplay <TFont, TGlyph>;

            Assertions.ApproximatePoint(20, 0, glyph2.Position, 0.01);
            Assert.Equal(Range.NotFound, glyph2.Range);
            Assert.False(glyph2.HasScript);

            Assert.Equal(display.Ascent, display2.Ascent);
            Assert.Equal(display.Descent, display2.Descent);
            Assert.Equal(display.Width, display2.Width);

            Assertions.ApproximatelyEqual(14, display.Ascent, 0.01);
            Assertions.ApproximatelyEqual(4, display.Descent, 0.01);
            Assertions.ApproximatelyEqual(30, display.Width, 0.01);
        }
コード例 #21
0
        public void TestAtop()
        {
            var mathList = new MathList {
                new Fraction(false)
                {
                    Numerator = new MathList {
                        MathAtoms.ForCharacter('1')
                    },
                    Denominator = new MathList {
                        MathAtoms.ForCharacter('3')
                    }
                }
            };

            var display = Typesetter <TFont, TGlyph> .CreateLine(mathList, _font, _context, LineStyle.Display);

            Assert.Equal(LinePosition.Regular, display.LinePosition);
            Assert.Equal(new PointF(), display.Position);
            Assert.Equal(new Range(0, 1), display.Range);
            Assert.False(display.HasScript);
            Assert.Equal(Range.UndefinedInt, display.IndexInParent);
            Assert.Single(display.Displays);

            var fraction = display.Displays[0] as FractionDisplay <TFont, TGlyph>;

            Assert.Equal(new Range(0, 1), fraction.Range);
            Assert.False(fraction.HasScript);
            Assert.Equal(new PointF(), fraction.Position);

            var numerator = fraction.Numerator as ListDisplay <TFont, TGlyph>;

            Assert.NotNull(numerator);
            Assert.Equal(LinePosition.Regular, numerator.LinePosition);
            Assert.False(numerator.HasScript);
            Assertions.ApproximatePoint(0, 13.54, numerator.Position, 0.01);
            Assert.Equal(new Range(0, 1), numerator.Range);
            Assert.Equal(Range.UndefinedInt, numerator.IndexInParent);
            Assert.Single(numerator.Displays);

            var subNumerator = numerator.Displays[0] as TextLineDisplay <TFont, TGlyph>;

            Assert.Single(subNumerator.Atoms);
            Assert.Equal("1", subNumerator.StringText());
            Assert.Equal(new PointF(), subNumerator.Position);
            Assert.Equal(new Range(0, 1), subNumerator.Range);
            Assert.False(subNumerator.HasScript);

            var denominator = fraction.Denominator as ListDisplay <TFont, TGlyph>;

            Assert.NotNull(denominator);
            Assert.Equal(LinePosition.Regular, denominator.LinePosition);
            Assertions.ApproximatePoint(0, -13.73, denominator.Position, 0.01);
            Assert.Equal(new Range(0, 1), denominator.Range);
            Assert.False(denominator.HasScript);
            Assert.Equal(Range.UndefinedInt, denominator.IndexInParent);
            Assert.Single(denominator.Displays);

            var subDenominator = denominator.Displays[0] as TextLineDisplay <TFont, TGlyph>;

            Assert.Single(subDenominator.Atoms);
            Assert.Equal("3", subDenominator.StringText());
            Assert.Equal(new PointF(), subDenominator.Position);
            Assert.Equal(new Range(0, 1), subDenominator.Range);
            Assert.False(subDenominator.HasScript);

            Assertions.ApproximatelyEqual(27.54, display.Ascent, 0.01);
            Assertions.ApproximatelyEqual(17.72, display.Descent, 0.01);
            Assertions.ApproximatelyEqual(10, display.Width, 0.01);
        }
コード例 #22
0
        public void TestBinomial()
        {
            var list     = new MathList();
            var fraction = new Fraction(false)
            {
                Numerator = new MathList {
                    MathAtoms.ForCharacter('1')
                },
                Denominator = new MathList {
                    MathAtoms.ForCharacter('3')
                },
                LeftDelimiter  = "(",
                RightDelimiter = ")"
            };

            list.Add(fraction);

            var display = Typesetter <TFont, TGlyph> .CreateLine(list, _font, _context, LineStyle.Display);

            Assert.Equal(LinePosition.Regular, display.LinePosition);
            Assert.Equal(new PointF(), display.Position);
            Assert.Equal(new Range(0, 1), display.Range);
            Assert.False(display.HasScript);
            Assert.Equal(Range.UndefinedInt, display.IndexInParent);
            Assert.Single(display.Displays);

            var display0 = display.Displays[0] as ListDisplay <TFont, TGlyph>;

            Assert.Equal(LinePosition.Regular, display0.LinePosition);
            Assert.Equal(new PointF(), display0.Position);
            Assert.Equal(new Range(0, 1), display.Range);
            Assert.False(display0.HasScript);
            Assert.Equal(Range.UndefinedInt, display0.IndexInParent);
            Assert.Equal(3, display0.Displays.Count);

            var glyph = display0.Displays[0] as GlyphDisplay <TFont, TGlyph>;

            Assert.Equal(new PointF(), glyph.Position);
            Assert.Equal(Range.NotFound, glyph.Range);
            Assert.False(glyph.HasScript);

            var subFraction = display0.Displays[1] as FractionDisplay <TFont, TGlyph>;

            Assert.Equal(new Range(0, 1), subFraction.Range);
            Assert.False(subFraction.HasScript);
            Assertions.ApproximatePoint(10, 0, subFraction.Position, 0.01);

            var numerator = subFraction.Numerator as ListDisplay <TFont, TGlyph>;

            Assert.NotNull(numerator);
            Assert.Equal(LinePosition.Regular, numerator.LinePosition);
            Assertions.ApproximatePoint(10, 13.54, numerator.Position, 0.01);
            Assert.Single(numerator.Displays);
            Assert.Equal(Range.UndefinedInt, numerator.IndexInParent);
            Assert.False(numerator.HasScript);

            var subNumerator = numerator.Displays[0] as TextLineDisplay <TFont, TGlyph>;

            Assert.Single(subNumerator.Atoms);
            Assert.Equal("1", subNumerator.StringText());
            Assert.Equal(new PointF(), subNumerator.Position);
            Assert.Equal(new Range(0, 1), subNumerator.Range);
            Assert.False(subNumerator.HasScript);

            var denominator = subFraction.Denominator as ListDisplay <TFont, TGlyph>;

            Assert.NotNull(denominator);
            Assert.Equal(LinePosition.Regular, denominator.LinePosition);
            Assertions.ApproximatePoint(10, -13.72, denominator.Position, 0.01);
            Assert.Equal(new Range(0, 1), denominator.Range);
            Assert.False(denominator.HasScript);
            Assert.Equal(Range.UndefinedInt, denominator.IndexInParent);
            Assert.Single(denominator.Displays);

            var subDenominator = denominator.Displays[0] as TextLineDisplay <TFont, TGlyph>;

            Assert.Single(subDenominator.Atoms);
            Assert.Equal("3", subDenominator.StringText());
            Assert.Equal(new PointF(), subDenominator.Position);
            Assert.Equal(new Range(0, 1), subDenominator.Range);
            Assert.False(subDenominator.HasScript);

            var subRight = display0.Displays[2] as GlyphDisplay <TFont, TGlyph>;

            Assert.False(subRight.HasScript);
            Assert.Equal(Range.NotFound, subRight.Range);
            Assertions.ApproximatePoint(20, 0, subRight.Position, 0.01);
            Assertions.ApproximatelyEqual(27.54, display.Ascent, 0.01);
            Assertions.ApproximatelyEqual(17.72, display.Descent, 0.01);
            Assertions.ApproximatelyEqual(30, display.Width, 0.01);
        }