Example #1
0
        public void BasicLatinTest()
        {
            var lineBreaker = new LineBreaker();

            lineBreaker.Reset("Hello World\r\nThis is a test.");

            LineBreak b;

            Assert.True(lineBreaker.NextBreak(out b));
            Assert.Equal(6, b.PositionWrap);
            Assert.False(b.Required);

            Assert.True(lineBreaker.NextBreak(out b));
            Assert.Equal(13, b.PositionWrap);
            Assert.True(b.Required);

            Assert.True(lineBreaker.NextBreak(out b));
            Assert.Equal(18, b.PositionWrap);
            Assert.False(b.Required);

            Assert.True(lineBreaker.NextBreak(out b));
            Assert.Equal(21, b.PositionWrap);
            Assert.False(b.Required);

            Assert.True(lineBreaker.NextBreak(out b));
            Assert.Equal(23, b.PositionWrap);
            Assert.False(b.Required);

            Assert.True(lineBreaker.NextBreak(out b));
            Assert.Equal(28, b.PositionWrap);
            Assert.False(b.Required);

            Assert.False(lineBreaker.NextBreak(out b));
        }
            internal float MeasureTextBoxHeight(Microsoft.ReportingServices.Rendering.RichText.TextBox textBox, FlowContext flowContext)
            {
                if (m_bitsGraphics == null)
                {
                    CreateGraphics();
                }
                float height = 0f;

                LineBreaker.Flow(textBox, m_bitsGraphics, FontCache, flowContext, keepLines: false, out height);
                return(height);
            }
            public float MeasureTextBoxHeight(AspNetCore.ReportingServices.Rendering.RichText.TextBox textBox, FlowContext flowContext)
            {
                if (this.m_bitsGraphics == null)
                {
                    this.CreateGraphics();
                }
                float result = 0f;

                LineBreaker.Flow(textBox, this.m_bitsGraphics, this.FontCache, flowContext, false, out result);
                return(result);
            }
Example #4
0
        public static void ReadingFile(string fileName)
        {
            string str;

            using (StreamReader sr = new StreamReader(fileName))
            {
                while ((str = sr.ReadLine()) != null)
                {
                    string[] words = LineBreaker.ReturnWordArr('|', str, 0);
                    Greeting.ListOfBooks.Add(new Book(words[0], words[1], words[2], words[3], words[4], words[5]));
                }
            }
        }
Example #5
0
        void ForwardTest()
        {
            var lineBreaker = new LineBreaker();

            lineBreaker.Reset("Apples Pears Bananas");
            var positionsF = lineBreaker.GetBreaks().ToList();

            Assert.Equal(7, positionsF[0].PositionWrap);
            Assert.Equal(6, positionsF[0].PositionMeasure);
            Assert.Equal(13, positionsF[1].PositionWrap);
            Assert.Equal(12, positionsF[1].PositionMeasure);
            Assert.Equal(20, positionsF[2].PositionWrap);
            Assert.Equal(20, positionsF[2].PositionMeasure);
        }
Example #6
0
        void ForwardTextWithOuterWhitespace()
        {
            var lineBreaker = new LineBreaker();

            lineBreaker.Reset(" Apples Pears Bananas   ");
            var positionsF = lineBreaker.GetBreaks().ToList();

            Assert.Equal(1, positionsF[0].PositionWrap);
            Assert.Equal(0, positionsF[0].PositionMeasure);
            Assert.Equal(8, positionsF[1].PositionWrap);
            Assert.Equal(7, positionsF[1].PositionMeasure);
            Assert.Equal(14, positionsF[2].PositionWrap);
            Assert.Equal(13, positionsF[2].PositionMeasure);
            Assert.Equal(24, positionsF[3].PositionWrap);
            Assert.Equal(21, positionsF[3].PositionMeasure);
        }
Example #7
0
        public TextLayout(string text, TextFont font, BoxAlignment alignment, StringTrimming trimming, Vector2 maxSize)
        {
            textLines = LineBreaker.Split(text, (int)Math.Ceiling(maxSize.X), c => font.GetGlyph(c).Width);

            var glyphIndex = 0;
            var width      = 0.0f;
            var height     = 0.0f;

            foreach (var textLine in textLines)
            {
                var line = new TextLayoutLine(this, height, alignment, lines.Count == 0);
                foreach (var c in textLine)
                {
                    line.Add(font.GetGlyph(c), glyphIndex++);
                }

                // trimming != StringTrimming.None &&
                //if (maxSize.Y > 0 && height + line.Height > maxSize.Y)
                //    break;

                lines.Add(line);
                width   = Math.Max(width, line.Width);
                height += line.Height;
            }

            if (lines.Count == 0)
            {
                lines.Add(new TextLayoutLine(this, 0, alignment, true));
            }
            var lastLine = lines[lines.Count - 1];

            if (lastLine.GlyphCount == 0)
            {
                height += font.LineHeight;
            }
            lastLine.Add(new FontGlyph(null, 0, font.LineHeight), glyphIndex++);

            size = new Vector2(width, height);
        }
Example #8
0
        /// <summary>
        /// Generates the layout.
        /// </summary>
        /// <param name="text">The text.</param>
        /// <param name="options">The style.</param>
        /// <returns>A collection of layout that describe all thats needed to measure or render a series of glyphs.</returns>
        public IReadOnlyList <GlyphLayout> GenerateLayout(ReadOnlySpan <char> text, RendererOptions options)
        {
            if (text.IsEmpty)
            {
                return(Array.Empty <GlyphLayout>());
            }

            var     dpi    = new Vector2(options.DpiX, options.DpiY);
            Vector2 origin = options.Origin / dpi;

            float maxWidth = float.MaxValue;
            float originX  = 0;

            if (options.WrappingWidth > 0)
            {
                // trim trailing white spaces from the text
                text     = text.TrimEnd(null);
                maxWidth = options.WrappingWidth / options.DpiX;
            }

            // lets convert the text into codepoints
            Memory <int> codePointsMemory = LineBreaker.ToUtf32(text);

            if (codePointsMemory.IsEmpty)
            {
                return(Array.Empty <GlyphLayout>());
            }

            Span <int> codepoints  = codePointsMemory.Span;
            var        lineBreaker = new LineBreaker();

            lineBreaker.Reset(codePointsMemory);

            AppliedFontStyle spanStyle = options.GetStyle(0, codepoints.Length);
            var layout = new List <GlyphLayout>(codepoints.Length);

            float   unscaledLineHeight       = 0f;
            float   lineHeight               = 0f;
            float   unscaledLineMaxAscender  = 0f;
            float   unscaledLineMaxDescender = 0f;
            float   lineMaxAscender          = 0f;
            float   lineMaxDescender         = 0f;
            Vector2 location = Vector2.Zero;
            float   lineHeightOfFirstLine = 0;

            // Remember where the top of the layouted text is for accurate vertical alignment.
            // This is important because there is considerable space between the lineHeight at the glyph's ascender.
            float top = 0;

            bool          firstLine             = true;
            GlyphInstance?previousGlyph         = null;
            float         scale                 = 0;
            int           lastWrappableLocation = -1;
            int           nextWrappableLocation = codepoints.Length;
            bool          nextWrappableRequired = false;
            bool          startOfLine           = true;
            float         totalHeight           = 0;
            int           graphemeIndex         = 0;

            if (lineBreaker.TryGetNextBreak(out LineBreak b))
            {
                nextWrappableLocation = b.PositionWrap - 1;
                nextWrappableRequired = b.Required;
            }

            for (int i = 0; i < codepoints.Length; i++)
            {
                if (spanStyle.End < i)
                {
                    spanStyle     = options.GetStyle(i, codepoints.Length);
                    previousGlyph = null;
                }

                int codePoint = codepoints[i];

                GlyphInstance[] glyphs = spanStyle.GetGlyphLayers(codePoint, options.ColorFontSupport);
                if (glyphs.Length == 0)
                {
                    return(FontsThrowHelper.ThrowGlyphMissingException <IReadOnlyList <GlyphLayout> >(codePoint));
                }

                GlyphInstance?glyph      = glyphs[0];
                float         fontHeight = glyph.Font.LineHeight * options.LineSpacing;
                if (fontHeight > unscaledLineHeight)
                {
                    // get the larget lineheight thus far
                    unscaledLineHeight = fontHeight;
                    scale      = glyph.Font.EmSize * 72;
                    lineHeight = unscaledLineHeight * spanStyle.PointSize / scale;
                }

                if (glyph.Font.Ascender > unscaledLineMaxAscender)
                {
                    unscaledLineMaxAscender = glyph.Font.Ascender;
                    scale           = glyph.Font.EmSize * 72;
                    lineMaxAscender = unscaledLineMaxAscender * spanStyle.PointSize / scale;
                }

                if (Math.Abs(glyph.Font.Descender) > unscaledLineMaxDescender)
                {
                    unscaledLineMaxDescender = Math.Abs(glyph.Font.Descender);
                    scale            = glyph.Font.EmSize * 72;
                    lineMaxDescender = unscaledLineMaxDescender * spanStyle.PointSize / scale;
                }

                if (firstLine)
                {
                    // Reset the line height for the first line to prevent initial lead.
                    float unspacedLineHeight = lineHeight / options.LineSpacing;
                    if (unspacedLineHeight > lineHeightOfFirstLine)
                    {
                        lineHeightOfFirstLine = unspacedLineHeight;
                    }

                    switch (options.VerticalAlignment)
                    {
                    case VerticalAlignment.Top:
                        top = lineMaxAscender;
                        break;

                    case VerticalAlignment.Center:
                        top = (lineMaxAscender / 2F) - (lineMaxDescender / 2F);
                        break;

                    case VerticalAlignment.Bottom:
                        top = -lineMaxDescender;
                        break;
                    }
                }

                if ((options.WrappingWidth > 0 && nextWrappableLocation == i) || nextWrappableRequired)
                {
                    // keep a record of where to wrap text and ensure that no line starts with white space
                    for (int j = layout.Count - 1; j >= 0; j--)
                    {
                        if (!layout[j].IsWhiteSpace)
                        {
                            lastWrappableLocation = j + 1;
                            break;
                        }
                    }
                }

                if (nextWrappableLocation == i)
                {
                    if (lineBreaker.TryGetNextBreak(out b))
                    {
                        nextWrappableLocation = b.PositionWrap - 1;
                        nextWrappableRequired = b.Required;
                    }
                }

                float glyphWidth  = glyph.AdvanceWidth * spanStyle.PointSize / scale;
                float glyphHeight = glyph.Height * spanStyle.PointSize / scale;

                if (codepoints[i] != '\r' && codepoints[i] != '\n' && codepoints[i] != '\t' && codepoints[i] != ' ')
                {
                    Vector2 glyphLocation = location;
                    if (spanStyle.ApplyKerning && previousGlyph != null)
                    {
                        // if there is special instructions for this glyph pair use that width
                        Vector2 scaledOffset = spanStyle.GetOffset(glyph, previousGlyph) * spanStyle.PointSize / scale;

                        glyphLocation += scaledOffset;

                        // only fix the 'X' of the current tracked location but use the actual 'X'/'Y' of the offset
                        location.X = glyphLocation.X;
                    }

                    foreach (GlyphInstance?g in glyphs)
                    {
                        float w = g.AdvanceWidth * spanStyle.PointSize / scale;
                        float h = g.Height * spanStyle.PointSize / scale;
                        layout.Add(new GlyphLayout(graphemeIndex, codePoint, new Glyph(g, spanStyle.PointSize), glyphLocation, w, h, lineHeight, startOfLine, false, false));

                        if (w > glyphWidth)
                        {
                            glyphWidth = w;
                        }
                    }

                    // Increment the index to signify we have moved on the a new cluster.
                    graphemeIndex++;
                    startOfLine = false;

                    // move forward the actual width of the glyph, we are retaining the baseline
                    location.X += glyphWidth;

                    // if the word extended pass the end of the box, wrap it
                    if (location.X >= maxWidth && lastWrappableLocation > 0)
                    {
                        if (lastWrappableLocation < layout.Count)
                        {
                            float wrappingOffset = layout[lastWrappableLocation].Location.X;
                            startOfLine = true;

                            // move the characters to the next line
                            for (int j = lastWrappableLocation; j < layout.Count; j++)
                            {
                                if (layout[j].IsWhiteSpace)
                                {
                                    wrappingOffset += layout[j].Width;
                                    layout.RemoveAt(j);
                                    j--;
                                    continue;
                                }

                                Vector2 current = layout[j].Location;
                                layout[j]   = new GlyphLayout(layout[j].GraphemeIndex, layout[j].CodePoint, layout[j].Glyph, new Vector2(current.X - wrappingOffset, current.Y + lineHeight), layout[j].Width, layout[j].Height, layout[j].LineHeight, startOfLine, layout[j].IsWhiteSpace, layout[j].IsControlCharacter);
                                startOfLine = false;

                                location.X = layout[j].Location.X + layout[j].Width;
                            }

                            location.Y           += lineHeight;
                            totalHeight          += lineHeight;
                            firstLine             = false;
                            lastWrappableLocation = -1;
                        }
                    }

                    previousGlyph = glyph;
                }
                else if (codepoints[i] == '\r')
                {
                    // carriage return resets the XX coordinate to 0
                    location.X    = 0;
                    previousGlyph = null;
                    startOfLine   = true;

                    layout.Add(new GlyphLayout(-1, codePoint, new Glyph(glyph, spanStyle.PointSize), location, 0, glyphHeight, lineHeight, startOfLine, true, true));
                    startOfLine = false;
                }
                else if (codepoints[i] == '\n')
                {
                    // carriage return resets the XX coordinate to 0
                    layout.Add(new GlyphLayout(-1, codePoint, new Glyph(glyph, spanStyle.PointSize), location, 0, glyphHeight, lineHeight, startOfLine, true, true));
                    location.X              = 0;
                    location.Y             += lineHeight;
                    totalHeight            += lineHeight;
                    unscaledLineHeight      = 0;
                    unscaledLineMaxAscender = 0;
                    previousGlyph           = null;
                    firstLine             = false;
                    lastWrappableLocation = -1;
                    startOfLine           = true;
                }
                else if (codepoints[i] == '\t')
                {
                    float tabStop    = glyphWidth * spanStyle.TabWidth;
                    float finalWidth = 0;

                    if (tabStop > 0)
                    {
                        finalWidth = tabStop - (location.X % tabStop);
                    }

                    if (finalWidth < glyphWidth)
                    {
                        // if we are not going to tab atleast a glyph width add another tabstop to it ???
                        // should I be doing this?
                        finalWidth += tabStop;
                    }

                    layout.Add(new GlyphLayout(-1, codePoint, new Glyph(glyph, spanStyle.PointSize), location, finalWidth, glyphHeight, lineHeight, startOfLine, true, false));
                    startOfLine = false;

                    // advance to a position > width away that
                    location.X   += finalWidth;
                    previousGlyph = null;
                }
                else if (codepoints[i] == ' ')
                {
                    layout.Add(new GlyphLayout(-1, codePoint, new Glyph(glyph, spanStyle.PointSize), location, glyphWidth, glyphHeight, lineHeight, startOfLine, true, false));
                    startOfLine   = false;
                    location.X   += glyphWidth;
                    previousGlyph = null;
                }
            }

            var offsetY = new Vector2(0, top);

            switch (options.VerticalAlignment)
            {
            case VerticalAlignment.Center:
                offsetY += new Vector2(0, -(totalHeight / 2F));
                break;

            case VerticalAlignment.Bottom:
                offsetY += new Vector2(0, -totalHeight);
                break;
            }

            Vector2 offsetX = Vector2.Zero;

            for (int i = 0; i < layout.Count; i++)
            {
                GlyphLayout glyphLayout = layout[i];
                graphemeIndex = glyphLayout.GraphemeIndex;

                // Scan ahead getting the width.
                if (glyphLayout.StartOfLine)
                {
                    float width = 0;
                    for (int j = i; j < layout.Count; j++)
                    {
                        GlyphLayout current = layout[j];
                        int         currentGraphemeIndex = current.GraphemeIndex;
                        if (current.StartOfLine && (currentGraphemeIndex != graphemeIndex))
                        {
                            // Leading graphemes are made up of multiple glyphs all marked as 'StartOfLine so we only
                            // break when we are sure we have entered a new cluster or previously defined break.
                            break;
                        }

                        width = current.Location.X + current.Width;
                    }

                    switch (options.HorizontalAlignment)
                    {
                    case HorizontalAlignment.Left:
                        offsetX = new Vector2(originX, 0) + offsetY;
                        break;

                    case HorizontalAlignment.Right:
                        offsetX = new Vector2(originX - width, 0) + offsetY;
                        break;

                    case HorizontalAlignment.Center:
                        offsetX = new Vector2(originX - (width / 2F), 0) + offsetY;
                        break;
                    }
                }

                // TODO calculate an offset from the 'origin' based on TextAlignment for each line
                layout[i] = new GlyphLayout(
                    glyphLayout.GraphemeIndex,
                    glyphLayout.CodePoint,
                    glyphLayout.Glyph,
                    glyphLayout.Location + offsetX + origin,
                    glyphLayout.Width,
                    glyphLayout.Height,
                    glyphLayout.LineHeight,
                    glyphLayout.StartOfLine,
                    glyphLayout.IsWhiteSpace,
                    glyphLayout.IsControlCharacter);
            }

            return(layout);
        }
Example #9
0
        public void Test()
        {
            // Read the test file
            var location = System.IO.Path.GetDirectoryName(typeof(LineBreakTests).Assembly.Location);
            var lines    = System.IO.File.ReadAllLines(System.IO.Path.Combine(location, "LineBreakTest.txt"));

            // Process each line
            int lineNumber = 0;

            foreach (var line in lines)
            {
                // Ignore deliberately skipped test?
                if (_skipLines.Contains(lineNumber))
                {
                    continue;
                }
                lineNumber++;

                // Split the line
                var parts = line.Split("#");
                var test  = parts[0].Trim();

                // Ignore blank/comment only lines
                if (string.IsNullOrWhiteSpace(test))
                {
                    continue;
                }

                // Parse the test
                var        p           = 0;
                List <int> codePoints  = new List <int>();
                List <int> breakPoints = new List <int>();
                while (p < test.Length)
                {
                    // Ignore white space
                    if (char.IsWhiteSpace(test[p]))
                    {
                        p++;
                        continue;
                    }

                    if (test[p] == '×')
                    {
                        p++;
                        continue;
                    }

                    if (test[p] == '÷')
                    {
                        breakPoints.Add(codePoints.Count);
                        p++;
                        continue;
                    }

                    int codePointPos = p;
                    while (p < test.Length && IsHexDigit(test[p]))
                    {
                        p++;
                    }

                    var codePointStr = test.Substring(codePointPos, p - codePointPos);
                    var codePoint    = Convert.ToInt32(codePointStr, 16);
                    codePoints.Add(codePoint);
                }

                // Run the line breaker and build a list of break points
                List <int> foundBreaks = new List <int>();
                var        lineBreaker = new LineBreaker();
                lineBreaker.Reset(new Slice <int>(codePoints.ToArray()));
                while (lineBreaker.NextBreak(out var b))
                {
                    foundBreaks.Add(b.PositionWrap);
                }

                // Check the same
                Assert.Equal(breakPoints, foundBreaks);
            }
        }
Example #10
0
        public void LineBreakerTest(string text, LineBreak[] expectedLineBreaks)
        {
            var lb = new LineBreaker(text);

            Assert.Equal(expectedLineBreaks, lb.ToArray());
        }
        internal override void DrawContent(GdiContext context)
        {
            RPLTextBoxPropsDef rPLTextBoxPropsDef = DefinitionProperties as RPLTextBoxPropsDef;
            RPLTextBoxProps    rPLTextBoxProps    = InstanceProperties as RPLTextBoxProps;

            if (rPLTextBoxProps.IsToggleParent)
            {
                GetToggleImage(context.GdiWriter, out Bitmap image);
                if (m_toggleRectangleMM.Width > 0f)
                {
                    DrawResourceImage(imageRectanglePX: new RectangleF(0f, 0f, image.Width, image.Height), context: context, image: image, itemRectangleMM: m_toggleRectangleMM);
                }
            }
            if (rPLTextBoxPropsDef.CanSort)
            {
                GetSortImage(context.GdiWriter, out Bitmap image2, out SortOrder _);
                if (m_sortRectangleMM.Width > 0f)
                {
                    DrawResourceImage(imageRectanglePX: new RectangleF(0f, 0f, image2.Width, image2.Height), context: context, image: image2, itemRectangleMM: m_sortRectangleMM);
                }
            }
            if (TextPosition.Width <= 0f || TextPosition.Height <= 0f)
            {
                return;
            }
            RPLFormat.WritingModes writingMode = WritingMode;
            float contentHeight  = 0f;
            float contentHeight2 = 0f;

            if (writingMode == RPLFormat.WritingModes.Horizontal)
            {
                contentHeight = rPLTextBoxProps.ContentHeight;
            }
            else
            {
                contentHeight2 = rPLTextBoxProps.ContentHeight;
            }
            List <Paragraph>            list  = null;
            List <RTSelectionHighlight> list2 = null;
            FlowContext flowContext           = new FlowContext(TextPosition.Width, TextPosition.Height);
            bool        flag = !rPLTextBoxPropsDef.CanGrow && !rPLTextBoxPropsDef.CanShrink;

            if (flag)
            {
                m_richTextBox.Paragraphs = new List <Paragraph>(m_paragraphs.Count);
                for (int i = 0; i < m_paragraphs.Count; i++)
                {
                    RTSelectionHighlight searchHit = m_paragraphs[i].GetSearchHit(context);
                    if (searchHit != null)
                    {
                        context.TextRunIndexHitStart = searchHit.SelectionStart.TextRunIndex;
                        context.TextRunIndexHitEnd   = searchHit.SelectionEnd.TextRunIndex;
                    }
                    m_paragraphs[i].DrawContent(context);
                    m_richTextBox.Paragraphs.Add(m_paragraphs[i].RichParagraph);
                    context.TextRunIndexHitStart = -1;
                    context.TextRunIndexHitEnd   = -1;
                }
                m_richTextBox.ScriptItemize();
                if (writingMode == RPLFormat.WritingModes.Horizontal)
                {
                    TextBox.MeasureFullHeight(m_richTextBox, context.Graphics, context.FontCache, flowContext, out contentHeight);
                }
                else
                {
                    TextBox.MeasureFullHeight(m_richTextBox, context.Graphics, context.FontCache, flowContext, out contentHeight2);
                }
                list = m_richTextBox.Paragraphs;
                m_richTextBox.Paragraphs = null;
            }
            if (writingMode == RPLFormat.WritingModes.Horizontal)
            {
                if (contentHeight + 0.001f > TextPosition.Height)
                {
                    flowContext.LineLimit = false;
                }
            }
            else if (contentHeight2 + 0.001f > TextPosition.Width)
            {
                flowContext.LineLimit = false;
            }
            m_richTextBox.Paragraphs = new List <Paragraph>(1);
            bool  flag2 = true;
            float num   = 0f;
            float num2  = 0f;

            for (int j = 0; j < m_paragraphs.Count; j++)
            {
                if (writingMode == RPLFormat.WritingModes.Horizontal)
                {
                    if (num > 0f)
                    {
                        if (num >= TextPosition.Height)
                        {
                            break;
                        }
                        flowContext.Height = TextPosition.Height - num;
                    }
                }
                else if (num2 > 0f)
                {
                    if (num2 >= TextPosition.Width)
                    {
                        break;
                    }
                    flowContext.Width = TextPosition.Width - num2;
                }
                RTSelectionHighlight searchHit2 = m_paragraphs[j].GetSearchHit(context);
                if (!flag)
                {
                    if (searchHit2 != null)
                    {
                        context.TextRunIndexHitStart = searchHit2.SelectionStart.TextRunIndex;
                        context.TextRunIndexHitEnd   = searchHit2.SelectionEnd.TextRunIndex;
                    }
                    m_paragraphs[j].DrawContent(context);
                    m_richTextBox.Paragraphs.Add(m_paragraphs[j].RichParagraph);
                    context.TextRunIndexHitStart = -1;
                    context.TextRunIndexHitEnd   = -1;
                    m_richTextBox.ScriptItemize();
                }
                else
                {
                    m_richTextBox.Paragraphs.Add(list[0]);
                }
                if (searchHit2 != null)
                {
                    searchHit2.SelectionStart.ParagraphIndex = 0;
                    searchHit2.SelectionEnd.ParagraphIndex   = 0;
                    list2 = new List <RTSelectionHighlight>(0);
                    list2.Add(searchHit2);
                }
                float            height          = 0f;
                List <Paragraph> rTParagraphs    = LineBreaker.Flow(m_richTextBox, context.Graphics, context.FontCache, flowContext, keepLines: true, out height);
                RectangleF       layoutParagraph = RectangleF.Empty;
                PointF           offset          = PointF.Empty;
                float            delta           = 0f;
                if (writingMode == RPLFormat.WritingModes.Horizontal)
                {
                    AdjustParagraphLayout(contentHeight, height, num, flag2, writingMode, ref delta, ref layoutParagraph, ref offset);
                }
                else
                {
                    AdjustParagraphLayout(contentHeight2, height, num2, flag2, writingMode, ref delta, ref layoutParagraph, ref offset);
                }
                m_context = context;
                m_paragraphs[j].TextPosition = layoutParagraph;
                RichTextRenderer richTextRenderer = new RichTextRenderer();
                try
                {
                    richTextRenderer.SetTextbox(m_richTextBox);
                    richTextRenderer.RTParagraphs = rTParagraphs;
                    richTextRenderer.FontCache    = context.FontCache;
                    if (writingMode == RPLFormat.WritingModes.Horizontal)
                    {
                        RenderRichText(richTextRenderer, context.Graphics, TextPosition, offset, list2);
                    }
                    else
                    {
                        RenderRichText(richTextRenderer, context.Graphics, layoutParagraph, offset, list2);
                    }
                    richTextRenderer.FontCache = null;
                }
                finally
                {
                    if (richTextRenderer != null)
                    {
                        richTextRenderer.Dispose();
                        richTextRenderer = null;
                    }
                }
                m_context = null;
                flowContext.Reset();
                if (writingMode == RPLFormat.WritingModes.Horizontal)
                {
                    if (flag2)
                    {
                        num  += delta;
                        flag2 = false;
                    }
                    num += height;
                }
                else
                {
                    if (flag2)
                    {
                        num2 += delta;
                        flag2 = false;
                    }
                    num2 += height;
                }
                if (searchHit2 != null)
                {
                    searchHit2.SelectionStart.ParagraphIndex = j;
                    searchHit2.SelectionEnd.ParagraphIndex   = j;
                }
                m_richTextBox.Paragraphs.RemoveAt(0);
                if (!flag)
                {
                    m_paragraphs[j].RichParagraph = null;
                }
                else
                {
                    list.RemoveAt(0);
                }
            }
            if (list != null && list.Count > 0)
            {
                list.Clear();
            }
            list = null;
        }
Example #12
0
        public static bool Run()
        {
            Console.WriteLine("Grapheme Cluster Tests");
            Console.WriteLine("----------------------");
            Console.WriteLine();

            // Read the test file
            var location = System.IO.Path.GetDirectoryName(typeof(LineBreakTests).Assembly.Location);
            var lines    = System.IO.File.ReadAllLines(System.IO.Path.Combine(location, Path.Combine("TestData", "GraphemeBreakTest.txt")));

            // Process each line
            var tests = new List <Test>();

            for (int lineNumber = 1; lineNumber < lines.Length + 1; lineNumber++)
            {
                // Get the line, remove comments
                var line = lines[lineNumber - 1].Split('#')[0].Trim();

                // Ignore blank/comment only lines
                if (string.IsNullOrWhiteSpace(line))
                {
                    continue;
                }

                var codePoints  = new List <int>();
                var breakPoints = new List <int>();

                // Parse the test
                var p = 0;
                while (p < line.Length)
                {
                    // Ignore white space
                    if (char.IsWhiteSpace(line[p]))
                    {
                        p++;
                        continue;
                    }

                    if (line[p] == '×')
                    {
                        p++;
                        continue;
                    }

                    if (line[p] == '÷')
                    {
                        breakPoints.Add(codePoints.Count);
                        p++;
                        continue;
                    }

                    int codePointPos = p;
                    while (p < line.Length && IsHexDigit(line[p]))
                    {
                        p++;
                    }

                    var codePointStr = line.Substring(codePointPos, p - codePointPos);
                    var codePoint    = Convert.ToInt32(codePointStr, 16);
                    codePoints.Add(codePoint);
                }

                // Create test
                var test = new Test()
                {
                    LineNumber  = lineNumber,
                    CodePoints  = codePoints.ToArray(),
                    BreakPoints = breakPoints.ToArray(),
                };
                tests.Add(test);
            }

            // Preload
            GraphemeClusterAlgorithm.IsBoundary(new Slice <int>(new int[10]), 0);

            var lineBreaker = new LineBreaker();
            var tr          = new TestResults();

            var foundBreaks = new List <int>();

            foundBreaks.Capacity = 100;

            for (int testNumber = 0; testNumber < tests.Count; testNumber++)
            {
                var t = tests[testNumber];

                foundBreaks.Clear();

                var codePointsSlice = new Slice <int>(t.CodePoints.ToArray());

                tr.EnterTest();

                // Run the algorithm
                for (int i = 0; i < codePointsSlice.Length + 1; i++)
                {
                    if (GraphemeClusterAlgorithm.IsBoundary(codePointsSlice, i))
                    {
                        foundBreaks.Add(i);
                    }
                }

                tr.LeaveTest();

                // Check the same
                bool pass = true;
                if (foundBreaks.Count != t.BreakPoints.Length)
                {
                    pass = false;
                }
                else
                {
                    for (int i = 0; i < foundBreaks.Count; i++)
                    {
                        if (foundBreaks[i] != t.BreakPoints[i])
                        {
                            pass = false;
                        }
                    }
                }

                if (!pass)
                {
                    Console.WriteLine($"Failed test on line {t.LineNumber}");
                    Console.WriteLine();
                    Console.WriteLine($"    Code Points: {string.Join(" ", t.CodePoints)}");
                    Console.WriteLine($"Expected Breaks: {string.Join(" ", t.BreakPoints)}");
                    Console.WriteLine($"  Actual Breaks: {string.Join(" ", foundBreaks)}");
                    Console.WriteLine($"     Char Props: {string.Join(" ", t.CodePoints.Select(x => UnicodeClasses.GraphemeClusterClass(x)))}");
                    Console.WriteLine();
                    return(false);
                }

                // Record it
                tr.TestPassed(pass);
            }

            tr.Dump();

            return(tr.AllPassed);
        }
Example #13
0
        public void NegativeTest()
        {
            LineBreaker breaker = new LineBreaker("");

            Assert.Throws <ArgumentOutOfRangeException>(() => breaker.Break(-1));
        }
Example #14
0
        public void SpecialPostiveTests(string input, int columns, string expectedOutput)
        {
            LineBreaker breaker = new LineBreaker(input);

            Assert.Equal(expectedOutput, breaker.Break(columns));
        }