TextJustifyRules.cs
//
// This code is part of Document Solutions for Imaging demos.
// Copyright (c) MESCIUS inc. All rights reserved.
//
using System;
using System.Drawing;
using System.IO;
using GrapeCity.Documents.Text;
using GCTEXT = GrapeCity.Documents.Text;
using GCDRAW = GrapeCity.Documents.Drawing;
using GrapeCity.Documents.Imaging;

namespace DsImagingWeb.Demos
{
    // This sample demonstrates how LineBreakingRules and TextExtensionStrategy affect automatic
    // line wrapping and distributed justification.
    // LineBreakingRules.Unicode and .Simplified may break inside a run of non-whitespace
    // characters (e.g. between a Latin/digit run and an adjacent CJK run) to pack a line tighter;
    // LineBreakingRules.WhiteSpace only wraps at whitespace, keeping such runs (hyphenated
    // identifiers, codes, product names, file names, URLs) intact on one line instead.
    public class TextJustifyRules
    {
        public GcBitmap GenerateImage(Size pixelSize, float dpi, bool opaque, string[] _ = null)
        {
            var regular = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "NotoSansJP-Regular.ttf"));
            var bold = GCTEXT.Font.FromFile(Path.Combine("Resources", "Fonts", "NotoSerif-Bold.ttf"));

            var bmp = new GcBitmap(pixelSize.Width, pixelSize.Height, opaque, dpi, dpi);

            using var g = bmp.CreateGraphics(Color.White);

            var tl = g.CreateTextLayout();
            tl.TextAlignment = TextAlignment.Distributed;
            tl.JustifiedSpaceExtension = 0f;
            tl.JustifiedTextExtension = 20f;

            var tf = new TextFormat { FontSize = 14f, Font = regular };
            var tfInfo = new TextFormat { FontSize = 9f, Font = bold };

            float marginx = 372, marginy = 28;
            tl.MaxWidth = pixelSize.Width - marginx * 2;
            var text = "1234567890-890-9876-54321-123986321 10abc9876 56A-345本列島で使われ456";

            float DrawText(TextLayout tl, float y)
            {
                var pt = new PointF(marginx, y + 12);
                tl.Append(text, tf);
                tl.PerformLayout(true);
                var rc = new RectangleF(pt, new SizeF(tl.ContentWidth, tl.ContentHeight));
                g.FillRectangle(rc, Color.PaleGoldenrod);
                g.DrawString($"LineBreakingRules.{tl.LineBreakingRules}, TextExtensionStrategy.{tl.TextExtensionStrategy}:",
                    tfInfo, new PointF(marginx / 2f, y));
                g.DrawTextLayout(tl, pt);
                tl.Clear();
                return rc.Bottom + 8;
            }

            float y = marginy;
            y = DrawText(tl, y);
            tl.TextExtensionStrategy = TextExtensionStrategy.EastAsianExcel;
            y = DrawText(tl, y);
            tl.TextExtensionStrategy = TextExtensionStrategy.Excel;
            y = DrawText(tl, y);
            tl.LineBreakingRules = LineBreakingRules.Simplified;
            tl.WordBoundaryRules = WordBoundaryRules.Simplified;
            tl.TextExtensionStrategy = TextExtensionStrategy.Default;
            y = DrawText(tl, y);
            tl.TextExtensionStrategy = TextExtensionStrategy.EastAsianExcel;
            y = DrawText(tl, y);
            tl.TextExtensionStrategy = TextExtensionStrategy.Excel;
            y = DrawText(tl, y);
            tl.LineBreakingRules = LineBreakingRules.WhiteSpace;
            tl.WordBoundaryRules = WordBoundaryRules.Unicode; // WordBoundaryRules has no WhiteSpace value - it only affects word-boundary lookups, not wrapping
            tl.TextExtensionStrategy = TextExtensionStrategy.Default;
            y = DrawText(tl, y);
            tl.TextExtensionStrategy = TextExtensionStrategy.EastAsianExcel;
            y = DrawText(tl, y);
            tl.TextExtensionStrategy = TextExtensionStrategy.Excel;
            y = DrawText(tl, y);

            return bmp;
        }
    }
}