Skip to content

Commit 82f4eb6

Browse files
authored
Added font features (FontMap, et.al.) to Pango (#58)
* FontMap and FontFamily added * Demo with Pango and recording surface (it just works :-)) * FontListDemo that prints a line for each font in the default font map * FontFace added * Naming of type with Pango prefix to avoid clashes with cairo names * Fixed font size in SetFontDescription * Fixed enumerator in PangoFontFace and PangoFontFamily * Fixed xml doc comments * Fixed Pango demo to run on Linux too * More default fonts for CairoSharp.Extensions
1 parent b7e3758 commit 82f4eb6

28 files changed

+1082
-67
lines changed

demos/FreeTypeDemo/Program.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,15 @@ static void Core(string fileName, string[] fontNames, Func<string, FreeTypeFont>
150150
{
151151
yield return (DefaultFonts.SansSerif , "Helvetica");
152152
yield return (DefaultFonts.SansSerifBold , "Helvetica (bold)");
153+
yield return (DefaultFonts.SansSerifItalic , "Helvetica (italic)");
153154
yield return (DefaultFonts.SansSerifBoldItalic, "Helvetica (bold, italic)");
155+
yield return (DefaultFonts.Serif , "DejaVu Serif");
156+
yield return (DefaultFonts.SerifBold , "DejaVu Serif (bold)");
157+
yield return (DefaultFonts.SerifItalic , "DejaVu Serif (italic)");
158+
yield return (DefaultFonts.SerifBoldItalic , "DejaVu Serif (bold, italic)");
154159
yield return (DefaultFonts.MonoSpace , "Source Code Pro (monospace)");
155160
yield return (DefaultFonts.MonoSpaceBold , "Source Code Pro (monospace, bold)");
161+
yield return (DefaultFonts.MonoSpaceItalic , "Source Code Pro (monospace, italic)");
156162
yield return (DefaultFonts.MonoSpaceBoldItalic, "Source Code Pro (monospace, bold, italic)");
157163
}
158164
}

demos/PangoDemo/PangoDemo.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@
88
<ProjectReference Include="..\..\source\CairoSharp.Extensions\CairoSharp.Extensions.csproj" />
99
</ItemGroup>
1010

11+
<ItemGroup>
12+
<Content Include="..\FreeTypeDemo\fonts\SanRemo.ttf" Link="fonts\SanRemo.ttf" CopyToOutputDirectory="PreserveNewest" />
13+
</ItemGroup>
14+
1115
</Project>

demos/PangoDemo/Program.cs

Lines changed: 273 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Cairo.Extensions.Pango;
99
using Cairo.Fonts;
1010
using Cairo.Surfaces.PDF;
11+
using Cairo.Surfaces.Recording;
1112
using Cairo.Surfaces.SVG;
1213
using Cairo.Surfaces.Tee;
1314
using IOPath = System.IO.Path;
@@ -21,6 +22,7 @@
2122
PangoNative.LibPangoName => IOPath.Combine(@"C:\Program Files\msys64\ucrt64\bin", "libpango-1.0-0.dll"),
2223
PangoNative.LibPangoCairoName => IOPath.Combine(@"C:\Program Files\msys64\ucrt64\bin", "libpangocairo-1.0-0.dll"),
2324
PangoNative.LibGObjectName => IOPath.Combine(@"C:\Program Files\msys64\ucrt64\bin", "libgobject-2.0-0.dll"),
25+
PangoNative.LibGLibName => IOPath.Combine(@"C:\Program Files\msys64\ucrt64\bin", "libglib-2.0-0.dll"),
2426
_ => null
2527
};
2628

@@ -37,11 +39,15 @@
3739
Directory.CreateDirectory("output");
3840
Environment.CurrentDirectory = IOPath.Combine(Environment.CurrentDirectory, "output");
3941

40-
DemoComparisonWithCairoText();
41-
DemoFromPangoDocsWithTextAroundCircle();
42-
DemoPangoFeatures();
42+
ComparisonWithCairoTextDemo();
43+
FontSelectionDemo();
44+
PangoDocsDemoWithTextAroundCircle();
45+
PangoFeaturesDemo();
46+
FontMapDemo();
47+
RecordingSurfaceDemo();
48+
FontListDemo();
4349
//-----------------------------------------------------------------------------
44-
static void DemoComparisonWithCairoText()
50+
static void ComparisonWithCairoTextDemo()
4551
{
4652
const int Width = 600;
4753
const int Height = 150;
@@ -103,7 +109,60 @@ static void DemoComparisonWithCairoText()
103109
tee.WriteToPng("cairo_comparison.png");
104110
}
105111
//-----------------------------------------------------------------------------
106-
static void DemoFromPangoDocsWithTextAroundCircle()
112+
static void FontSelectionDemo()
113+
{
114+
const int Width = 800;
115+
const int Height = 100;
116+
const string Text = "Hello from CairoSharp, w/o any AV and VA";
117+
118+
using SvgSurface svg = new("font-selection.svg", Width, Height);
119+
using PdfSurface pdf = new("font-selection.pdf", Width, Height);
120+
using TeeSurface tee = new(svg);
121+
using CairoContext cr = new(tee);
122+
tee.Add(pdf);
123+
124+
cr.Color = KnownColors.White;
125+
cr.Paint();
126+
cr.LineWidth = 6;
127+
cr.Color = Color.Default;
128+
cr.Rectangle(0, 0, Width, Height);
129+
cr.Stroke();
130+
cr.LineWidth = 1;
131+
132+
double curY = 10;
133+
using PangoLayout pangoLayout = new(cr);
134+
135+
cr.MoveTo(10, curY);
136+
pangoLayout.SetText($"{Text} (Pango font from string)");
137+
string? fontDescriptionAsString = pangoLayout.SetFontDescriptionFromString("DejaVu Serif, Normal 22");
138+
Console.WriteLine(fontDescriptionAsString);
139+
pangoLayout.ShowLayout();
140+
pangoLayout.GetSize(out double width, out double height);
141+
142+
curY += height;
143+
cr.MoveTo(10, curY);
144+
using PangoFontMap fontMap = PangoFontMap.CairoFontMapGetDefault();
145+
using PangoFontFamily fontFamily = fontMap.GetFamily("DejaVu Serif");
146+
using PangoFontFace? fontFace = fontFamily.GetFace(null);
147+
Debug.Assert(fontFace is not null);
148+
pangoLayout.SetText($"{Text} (Pango font selected)");
149+
fontDescriptionAsString = pangoLayout.SetFontDescription(fontFace, size: 22);
150+
Console.WriteLine(fontDescriptionAsString);
151+
pangoLayout.ShowLayout();
152+
pangoLayout.GetSize(out width, out height);
153+
curY += height;
154+
155+
cr.SelectFontFace("DejaVu Serif");
156+
cr.SetFontSize(22);
157+
cr.FontExtents(out FontExtents fontExtents);
158+
curY += fontExtents.Ascent;
159+
cr.MoveTo(10, curY);
160+
cr.ShowText($"{Text} (cairo)");
161+
162+
tee.WriteToPng("font-selection.png");
163+
}
164+
//-----------------------------------------------------------------------------
165+
static void PangoDocsDemoWithTextAroundCircle()
107166
{
108167
// Demo from https://docs.gtk.org/PangoCairo/pango_cairo.html
109168

@@ -161,7 +220,7 @@ static void DemoFromPangoDocsWithTextAroundCircle()
161220
tee.WriteToPng("sample_from_docs.png");
162221
}
163222
//-----------------------------------------------------------------------------
164-
static void DemoPangoFeatures()
223+
static void PangoFeaturesDemo()
165224
{
166225
const int Width = 600;
167226
const int Height = 620;
@@ -278,7 +337,7 @@ static void DemoPangoFeatures()
278337
{
279338
cr.Color = KnownColors.DeepSkyBlue;
280339
cr.MoveTo(10, curY);
281-
pangoLayout.SetText("Another long text, to showcase how justify works. And as we get on at least one more line, we can test next how JustifyLastLine works.");
340+
pangoLayout.SetMarkup("Another long text, to showcase how <tt>Justify</tt> works. And as we get on at least one more line, we can test next how <tt>JustifyLastLine</tt> works."u8);
282341
pangoLayout.ShowLayout();
283342

284343
pangoLayout.GetSize(out width, out height);
@@ -347,3 +406,210 @@ static void DemoPangoFeatures()
347406

348407
tee.WriteToPng("features.png");
349408
}
409+
//-----------------------------------------------------------------------------
410+
static void FontMapDemo()
411+
{
412+
Console.WriteLine();
413+
using StreamWriter sw = File.CreateText("font-families.csv");
414+
sw.WriteLine("Name;IsMonospace;IsVariable");
415+
416+
using PangoFontMap fontMap = PangoFontMap.CairoFontMapGetDefault();
417+
fontMap.AddFontFile(IOPath.Combine(AppContext.BaseDirectory, "fonts", "SanRemo.ttf"));
418+
419+
List<PangoFontFamily> families = [];
420+
foreach (PangoFontFamily fontFamily in fontMap.ListFamilies())
421+
{
422+
families.Add(fontFamily);
423+
}
424+
425+
string fontFamilyName = "";
426+
foreach (PangoFontFamily fontFamily in families.OrderBy(f => f.Name))
427+
{
428+
fontFamilyName = fontFamily.Name;
429+
430+
sw.WriteLine($"{fontFamilyName};{fontFamily.IsMonospace};{fontFamily.IsVariable}");
431+
Console.WriteLine(fontFamily);
432+
Console.WriteLine("Faces:");
433+
434+
foreach (PangoFontFace fontFace in fontFamily.ListFaces())
435+
{
436+
Console.WriteLine($"\t{fontFace.Name}\tsynthesized: {fontFace.IsSynthesized}");
437+
Console.WriteLine("\tSizes:");
438+
439+
foreach (double size in fontFace.ListSizes())
440+
{
441+
Console.WriteLine($"\t\t{size}");
442+
}
443+
}
444+
445+
Console.WriteLine();
446+
}
447+
448+
const int Width = 600;
449+
const int Height = 120;
450+
451+
using SvgSurface svg = new("font-map.svg", Width, Height);
452+
using PdfSurface pdf = new("font-map.pdf", Width, Height);
453+
using TeeSurface tee = new(svg);
454+
using CairoContext cr = new(tee);
455+
tee.Add(pdf);
456+
457+
using PangoLayout pangoLayout = new(cr);
458+
double curY = 10;
459+
460+
cr.MoveTo(10, curY);
461+
pangoLayout.SetFontDescriptionFromString($"{fontFamilyName} Normal 22");
462+
pangoLayout.SetText($"Font: {fontFamilyName}");
463+
pangoLayout.ShowLayout();
464+
pangoLayout.GetSize(out double width, out double height);
465+
curY += height;
466+
467+
cr.MoveTo(10, curY);
468+
pangoLayout.SetFontDescriptionFromString("Viner Hand ITC, Normal 22");
469+
pangoLayout.SetText("Font: Viner Hand ITC");
470+
pangoLayout.ShowLayout();
471+
pangoLayout.GetSize(out width, out height);
472+
curY += height;
473+
474+
cr.MoveTo(10, curY);
475+
pangoLayout.SetFontDescriptionFromString("San Remo, Normal 22");
476+
pangoLayout.SetText("Font: San Remo");
477+
pangoLayout.ShowLayout();
478+
pangoLayout.GetSize(out width, out height);
479+
curY += height;
480+
481+
tee.WriteToPng("font-map.png");
482+
483+
families.ForEach(f => f.Dispose());
484+
}
485+
//-----------------------------------------------------------------------------
486+
static void RecordingSurfaceDemo()
487+
{
488+
using PangoFontMap fontMap = PangoFontMap.CairoFontMapGetDefault();
489+
fontMap.AddFontFile(IOPath.Combine(AppContext.BaseDirectory, "fonts", "SanRemo.ttf"));
490+
491+
List<PangoFontFamily> families = [];
492+
foreach (PangoFontFamily fontFamily in fontMap.ListFamilies())
493+
{
494+
families.Add(fontFamily);
495+
}
496+
497+
string fontFamilyName = "";
498+
foreach (PangoFontFamily fontFamily in families.OrderBy(f => f.Name))
499+
{
500+
fontFamilyName = fontFamily.Name;
501+
}
502+
503+
using RecordingSurface surface = new();
504+
using (CairoContext cr = new(surface))
505+
{
506+
using PangoLayout pangoLayout = new(cr);
507+
double curY = 10;
508+
509+
cr.MoveTo(10, curY);
510+
pangoLayout.SetFontDescriptionFromString($"{fontFamilyName} Normal 22");
511+
pangoLayout.SetText($"Font: {fontFamilyName}");
512+
pangoLayout.ShowLayout();
513+
pangoLayout.GetSize(out double width, out double height);
514+
curY += height;
515+
516+
cr.MoveTo(10, curY);
517+
pangoLayout.SetFontDescriptionFromString("Viner Hand ITC, Normal 22");
518+
pangoLayout.SetText("Font: Viner Hand ITC");
519+
pangoLayout.ShowLayout();
520+
pangoLayout.GetSize(out width, out height);
521+
curY += height;
522+
523+
cr.MoveTo(10, curY);
524+
pangoLayout.SetFontDescriptionFromString("San Remo, Normal 22");
525+
pangoLayout.SetText("Font: San Remo");
526+
pangoLayout.ShowLayout();
527+
pangoLayout.GetSize(out width, out height);
528+
curY += height;
529+
}
530+
531+
Rectangle recordingExtents = surface.GetInkExtents();
532+
const int Padding = 10;
533+
534+
using SvgSurface svg = new("recording.svg", recordingExtents.Width + 2 * Padding, recordingExtents.Height + 2 * Padding);
535+
using PdfSurface pdf = new("recording.pdf", recordingExtents.Width + 2 * Padding, recordingExtents.Height + 2 * Padding);
536+
using TeeSurface tee = new(svg);
537+
using (CairoContext cr = new(tee))
538+
{
539+
tee.Add(pdf);
540+
541+
cr.SetSourceSurface(surface, Padding - recordingExtents.X, Padding - recordingExtents.Y);
542+
cr.Paint();
543+
}
544+
545+
tee.WriteToPng("recording.png");
546+
547+
families.ForEach(f => f.Dispose());
548+
}
549+
//-----------------------------------------------------------------------------
550+
static void FontListDemo()
551+
{
552+
using PangoFontMap fontMap = PangoFontMap.CairoFontMapGetDefault();
553+
fontMap.AddFontFile(IOPath.Combine(AppContext.BaseDirectory, "fonts", "SanRemo.ttf"));
554+
555+
List<PangoFontFamily> families = [];
556+
foreach (PangoFontFamily fontFamily in fontMap.ListFamilies())
557+
{
558+
families.Add(fontFamily);
559+
}
560+
families = [.. families
561+
.OrderBy(f => f.IsMonospace)
562+
.ThenBy (f => f.Name)
563+
];
564+
565+
using RecordingSurface surface = new();
566+
using (CairoContext cr = new(surface))
567+
{
568+
using PangoLayout pangoLayout = new(cr);
569+
double curY = 10;
570+
571+
foreach (PangoFontFamily fontFamily in families)
572+
{
573+
using PangoFontFace? fontFace = fontFamily.GetFace(null);
574+
575+
if (fontFace is null)
576+
{
577+
continue;
578+
}
579+
580+
cr.MoveTo(10, curY);
581+
pangoLayout.SetText($"Font: {fontFamily.Name} {fontFace.Name}; AV and VA to see kerning or not");
582+
pangoLayout.SetFontDescription(fontFace, size: 22);
583+
pangoLayout.ShowLayout();
584+
pangoLayout.GetSize(out double width, out double height);
585+
curY += height;
586+
}
587+
}
588+
589+
Rectangle recordingExtents = surface.GetInkExtents();
590+
const int Padding = 10;
591+
double surfaceWidth = recordingExtents.Width + 2 * Padding;
592+
double surfaceHeight = recordingExtents.Height + 2 * Padding;
593+
594+
using SvgSurface svg = new("font-list.svg", surfaceWidth, surfaceHeight);
595+
using PdfSurface pdf = new("font-list.pdf", surfaceWidth, surfaceHeight);
596+
using TeeSurface tee = new(svg);
597+
using (CairoContext cr = new(tee))
598+
{
599+
tee.Add(pdf);
600+
601+
cr.Color = KnownColors.White;
602+
cr.Paint();
603+
cr.Color = Color.Default;
604+
cr.LineWidth = 4;
605+
cr.Rectangle(0, 0, surfaceWidth, surfaceHeight);
606+
cr.Stroke();
607+
608+
cr.SetSourceSurface(surface, Padding - recordingExtents.X, Padding - recordingExtents.Y);
609+
cr.Paint();
610+
}
611+
612+
tee.WriteToPng("font-list.png");
613+
614+
families.ForEach(f => f.Dispose());
615+
}

0 commit comments

Comments
 (0)