Browse Source

2021.2.0 Internal links, external links, dynamic images, font weights

Marcin Ziąbek 4 years ago
parent
commit
35214892ef
41 changed files with 512 additions and 322 deletions
  1. 2 2
      QuestPDF.ReportSample/Layouts/SectionTemplate.cs
  2. 6 3
      QuestPDF.ReportSample/Layouts/StandardReport.cs
  3. 51 0
      QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs
  4. 1 1
      QuestPDF.ReportSample/Typography.cs
  5. 1 1
      QuestPDF.UnitTests/AlignmentTests.cs
  6. 1 1
      QuestPDF.UnitTests/AspectRatioTests.cs
  7. 1 1
      QuestPDF.UnitTests/BackgroundTests.cs
  8. 1 1
      QuestPDF.UnitTests/BorderTests.cs
  9. 1 1
      QuestPDF.UnitTests/ConstrainedTests.cs
  10. 1 1
      QuestPDF.UnitTests/DebugTests.cs
  11. 1 1
      QuestPDF.UnitTests/ExtendTests.cs
  12. 2 2
      QuestPDF.UnitTests/Helpers.cs
  13. 1 1
      QuestPDF.UnitTests/PaddingTests.cs
  14. 1 1
      QuestPDF.UnitTests/ShowOnceTest.cs
  15. 4 1
      QuestPDF.UnitTests/StackTests.cs
  16. 43 0
      QuestPDF.UnitTests/TestEngine/CanvasMock.cs
  17. 16 0
      QuestPDF.UnitTests/TestEngine/ElementMock.cs
  18. 7 0
      QuestPDF.UnitTests/TestEngine/OperationBase.cs
  19. 16 0
      QuestPDF.UnitTests/TestEngine/Operations/CanvasDrawImageOperation.cs
  20. 18 0
      QuestPDF.UnitTests/TestEngine/Operations/CanvasDrawRectangleOperation.cs
  21. 18 0
      QuestPDF.UnitTests/TestEngine/Operations/CanvasDrawTextOperation.cs
  22. 14 0
      QuestPDF.UnitTests/TestEngine/Operations/CanvasTranslateOperation.cs
  23. 16 0
      QuestPDF.UnitTests/TestEngine/Operations/ChildDrawOperation.cs
  24. 19 0
      QuestPDF.UnitTests/TestEngine/Operations/ChildMeasureOperation.cs
  25. 12 0
      QuestPDF.UnitTests/TestEngine/Operations/ElementMeasureOperation.cs
  26. 31 0
      QuestPDF.UnitTests/TestEngine/SingleChildTests.cs
  27. 19 209
      QuestPDF.UnitTests/TestEngine/TestPlan.cs
  28. 11 1
      QuestPDF/Drawing/Canvas.cs
  29. 5 3
      QuestPDF/Drawing/CanvasCache.cs
  30. 0 1
      QuestPDF/Drawing/DocumentGenerator.cs
  31. 21 0
      QuestPDF/Elements/ExternalLink.cs
  32. 21 0
      QuestPDF/Elements/InternalLink.cs
  33. 17 0
      QuestPDF/Elements/InternalLocation.cs
  34. 5 12
      QuestPDF/Elements/Stack.cs
  35. 0 62
      QuestPDF/Elements/Watermark.cs
  36. 27 3
      QuestPDF/Fluent/ElementExtensions.cs
  37. 71 3
      QuestPDF/Fluent/TextStyleExtensions.cs
  38. 16 0
      QuestPDF/Infrastructure/FontWeight.cs
  39. 3 1
      QuestPDF/Infrastructure/ICanvas.cs
  40. 9 7
      QuestPDF/Infrastructure/TextStyle.cs
  41. 2 2
      QuestPDF/QuestPDF.csproj

+ 2 - 2
QuestPDF.ReportSample/Layouts/SectionTemplate.cs

@@ -25,11 +25,11 @@ namespace QuestPDF.ReportSample.Layouts
                         .PaddingBottom(5)
                         .PaddingBottom(5)
                         .Text(Model.Title, Typography.Headline);
                         .Text(Model.Title, Typography.Headline);
 
 
-                    section.Content().PageableStack(column =>
+                    section.Content().PageableStack(stack =>
                     {
                     {
                         foreach (var part in Model.Parts)
                         foreach (var part in Model.Parts)
                         {
                         {
-                            column.Element().Row(row =>
+                            stack.Element().Row(row =>
                             {
                             {
                                 row.ConstantColumn(150).DarkCell().Text(part.Label, Typography.Normal);
                                 row.ConstantColumn(150).DarkCell().Text(part.Label, Typography.Normal);
                                 var frame = row.RelativeColumn().LightCell();
                                 var frame = row.RelativeColumn().LightCell();

+ 6 - 3
QuestPDF.ReportSample/Layouts/StandardReport.cs

@@ -71,7 +71,7 @@ namespace QuestPDF.ReportSample.Layouts
 
 
                 });
                 });
                 
                 
-                row.ConstantColumn(150).Image(Model.LogoData);
+                row.ConstantColumn(150).ExternalLink("https://www.questpdf.com").Image(Model.LogoData);
             });
             });
         }
         }
 
 
@@ -81,11 +81,14 @@ namespace QuestPDF.ReportSample.Layouts
             {
             {
                 stack.Spacing(20);
                 stack.Spacing(20);
 
 
+                stack.Element().Component(new TableOfContentsTemplate(Model.Sections));
+                
                 foreach (var section in Model.Sections)
                 foreach (var section in Model.Sections)
-                    stack.Element().Component(new SectionTemplate(section));
+                    stack.Element().Location(section.Title).Component(new SectionTemplate(section));
 
 
                 stack.Element().PageBreak();
                 stack.Element().PageBreak();
-
+                stack.Element().Location("Photos");
+                
                 foreach (var photo in Model.Photos)
                 foreach (var photo in Model.Photos)
                     stack.Element().Component(new PhotoTemplate(photo));
                     stack.Element().Component(new PhotoTemplate(photo));
             });
             });

+ 51 - 0
QuestPDF.ReportSample/Layouts/TableOfContentsTemplate.cs

@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using QuestPDF.Fluent;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.ReportSample.Layouts
+{
+    public class TableOfContentsTemplate : IComponent
+    {
+        private List<ReportSection> Sections { get; }
+
+        public TableOfContentsTemplate(List<ReportSection> sections)
+        {
+            Sections = sections;
+        }
+        
+        public void Compose(IContainer container)
+        {
+            container
+                .Section(section =>
+                {
+                    section
+                        .Header()
+                        .PaddingBottom(5)
+                        .Text("Table of contents", Typography.Headline);
+
+                    section.Content().PageableStack(stack =>
+                    {
+                        stack.Spacing(5);
+                        
+                        for (var i = 0; i < Sections.Count; i++)
+                            stack.Element(c => DrawLink(c, i+1, Sections[i].Title));
+
+                        stack.Element(c => DrawLink(c, Sections.Count+1, "Photos"));
+                    });
+                });
+        }
+
+        private void DrawLink(IContainer container, int number, string locationName)
+        {
+            container
+                .InternalLink(locationName)
+                .Row(row =>
+                {
+                    row.ConstantColumn(25).Text($"{number}.", Typography.Normal);
+                    row.RelativeColumn().Text(locationName, Typography.Normal);
+                });
+        }
+    }
+}

+ 1 - 1
QuestPDF.ReportSample/Typography.cs

@@ -5,7 +5,7 @@ namespace QuestPDF.ReportSample
 {
 {
     public static class Typography
     public static class Typography
     {
     {
-        public static TextStyle Title => TextStyle.Default.FontType("Helvetica").Color("#000000").Size(20);
+        public static TextStyle Title => TextStyle.Default.FontType("Helvetica").Color("#000000").Size(20).Bold();
         public static TextStyle Headline => TextStyle.Default.FontType("Helvetica").Color("#047AED").Size(14);
         public static TextStyle Headline => TextStyle.Default.FontType("Helvetica").Color("#047AED").Size(14);
         public static TextStyle Normal => TextStyle.Default.FontType("Helvetica").Color("#000000").Size(10).LineHeight(1.25f).AlignLeft();
         public static TextStyle Normal => TextStyle.Default.FontType("Helvetica").Color("#000000").Size(10).LineHeight(1.25f).AlignLeft();
     }
     }

+ 1 - 1
QuestPDF.UnitTests/AlignmentTests.cs

@@ -2,7 +2,7 @@
 using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Elements;
 using QuestPDF.Elements;
 using QuestPDF.Infrastructure;
 using QuestPDF.Infrastructure;
-using QuestPDF.UnitTests.MeasureTest;
+using QuestPDF.UnitTests.TestEngine;
 
 
 namespace QuestPDF.UnitTests
 namespace QuestPDF.UnitTests
 {
 {

+ 1 - 1
QuestPDF.UnitTests/AspectRatioTests.cs

@@ -3,7 +3,7 @@ using NUnit.Framework;
 using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Elements;
 using QuestPDF.Elements;
 using QuestPDF.Infrastructure;
 using QuestPDF.Infrastructure;
-using QuestPDF.UnitTests.MeasureTest;
+using QuestPDF.UnitTests.TestEngine;
 
 
 namespace QuestPDF.UnitTests
 namespace QuestPDF.UnitTests
 {
 {

+ 1 - 1
QuestPDF.UnitTests/BackgroundTests.cs

@@ -1,7 +1,7 @@
 using NUnit.Framework;
 using NUnit.Framework;
 using QuestPDF.Elements;
 using QuestPDF.Elements;
 using QuestPDF.Infrastructure;
 using QuestPDF.Infrastructure;
-using QuestPDF.UnitTests.MeasureTest;
+using QuestPDF.UnitTests.TestEngine;
 
 
 namespace QuestPDF.UnitTests
 namespace QuestPDF.UnitTests
 {
 {

+ 1 - 1
QuestPDF.UnitTests/BorderTests.cs

@@ -2,7 +2,7 @@
 using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Elements;
 using QuestPDF.Elements;
 using QuestPDF.Infrastructure;
 using QuestPDF.Infrastructure;
-using QuestPDF.UnitTests.MeasureTest;
+using QuestPDF.UnitTests.TestEngine;
 
 
 namespace QuestPDF.UnitTests
 namespace QuestPDF.UnitTests
 {
 {

+ 1 - 1
QuestPDF.UnitTests/ConstrainedTests.cs

@@ -2,7 +2,7 @@
 using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Elements;
 using QuestPDF.Elements;
 using QuestPDF.Infrastructure;
 using QuestPDF.Infrastructure;
-using QuestPDF.UnitTests.MeasureTest;
+using QuestPDF.UnitTests.TestEngine;
 
 
 namespace QuestPDF.UnitTests
 namespace QuestPDF.UnitTests
 {
 {

+ 1 - 1
QuestPDF.UnitTests/DebugTests.cs

@@ -1,6 +1,6 @@
 using NUnit.Framework;
 using NUnit.Framework;
 using QuestPDF.Elements;
 using QuestPDF.Elements;
-using QuestPDF.UnitTests.MeasureTest;
+using QuestPDF.UnitTests.TestEngine;
 
 
 namespace QuestPDF.UnitTests
 namespace QuestPDF.UnitTests
 {
 {

+ 1 - 1
QuestPDF.UnitTests/ExtendTests.cs

@@ -1,6 +1,6 @@
 using NUnit.Framework;
 using NUnit.Framework;
 using QuestPDF.Elements;
 using QuestPDF.Elements;
-using QuestPDF.UnitTests.MeasureTest;
+using QuestPDF.UnitTests.TestEngine;
 
 
 namespace QuestPDF.UnitTests
 namespace QuestPDF.UnitTests
 {
 {

+ 2 - 2
QuestPDF.UnitTests/Helpers.cs

@@ -3,7 +3,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using FluentAssertions;
 using FluentAssertions;
 using QuestPDF.Infrastructure;
 using QuestPDF.Infrastructure;
-using QuestPDF.UnitTests.MeasureTest;
+using QuestPDF.UnitTests.TestEngine;
 
 
 namespace QuestPDF.UnitTests
 namespace QuestPDF.UnitTests
 {
 {
@@ -13,7 +13,7 @@ namespace QuestPDF.UnitTests
         
         
         public static Size RandomSize => new Size(Random.Next(200, 400), Random.Next(100, 200));
         public static Size RandomSize => new Size(Random.Next(200, 400), Random.Next(100, 200));
 
 
-        public static void ShouldEqual(this IEnumerable<Operation> commands, IEnumerable<Operation> expected)
+        public static void ShouldEqual(this IEnumerable<OperationBase> commands, IEnumerable<OperationBase> expected)
         {
         {
             commands.Should().HaveSameCount(expected);
             commands.Should().HaveSameCount(expected);
             
             

+ 1 - 1
QuestPDF.UnitTests/PaddingTests.cs

@@ -4,7 +4,7 @@ using NUnit.Framework;
 using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Elements;
 using QuestPDF.Elements;
 using QuestPDF.Infrastructure;
 using QuestPDF.Infrastructure;
-using QuestPDF.UnitTests.MeasureTest;
+using QuestPDF.UnitTests.TestEngine;
 
 
 namespace QuestPDF.UnitTests
 namespace QuestPDF.UnitTests
 {
 {

+ 1 - 1
QuestPDF.UnitTests/ShowOnceTest.cs

@@ -3,7 +3,7 @@ using NUnit.Framework;
 using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Elements;
 using QuestPDF.Elements;
 using QuestPDF.Infrastructure;
 using QuestPDF.Infrastructure;
-using QuestPDF.UnitTests.MeasureTest;
+using QuestPDF.UnitTests.TestEngine;
 
 
 namespace QuestPDF.UnitTests
 namespace QuestPDF.UnitTests
 {
 {

+ 4 - 1
QuestPDF.UnitTests/StackTests.cs

@@ -2,7 +2,7 @@
 using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Elements;
 using QuestPDF.Elements;
 using QuestPDF.Infrastructure;
 using QuestPDF.Infrastructure;
-using QuestPDF.UnitTests.MeasureTest;
+using QuestPDF.UnitTests.TestEngine;
 
 
 namespace QuestPDF.UnitTests
 namespace QuestPDF.UnitTests
 {
 {
@@ -220,6 +220,9 @@ namespace QuestPDF.UnitTests
                 .ExpectCanvasTranslate(0, -250)
                 .ExpectCanvasTranslate(0, -250)
 
 
                 .ExpectChildMeasure("c", expectedInput: new Size(500, 400), returns: new FullRender(Size.Zero))
                 .ExpectChildMeasure("c", expectedInput: new Size(500, 400), returns: new FullRender(Size.Zero))
+                .ExpectCanvasTranslate(0, 600)
+                .ExpectChildDraw("c", new Size(500, 0))
+                .ExpectCanvasTranslate(0, -600)
 
 
                 .ExpectChildMeasure("d", expectedInput: new Size(500, 400), returns: new FullRender(200, 400))
                 .ExpectChildMeasure("d", expectedInput: new Size(500, 400), returns: new FullRender(200, 400))
                 .ExpectCanvasTranslate(0, 600)
                 .ExpectCanvasTranslate(0, 600)

+ 43 - 0
QuestPDF.UnitTests/TestEngine/CanvasMock.cs

@@ -0,0 +1,43 @@
+using System;
+using QuestPDF.Infrastructure;
+using SkiaSharp;
+
+namespace QuestPDF.UnitTests.TestEngine
+{
+    internal class CanvasMock : ICanvas
+    {
+        public Action<Position> TranslateFunc { get; set; }
+        public Action<SKImage, Position, Size> DrawImageFunc { get; set; }
+        public Action<string, Position, TextStyle> DrawTextFunc { get; set; }
+        public Action<Position, Size, string> DrawRectFunc { get; set; }
+        
+        public void Translate(Position vector) => TranslateFunc(vector);
+        public void DrawRectangle(Position vector, Size size, string color) => DrawRectFunc(vector, size, color);
+        public void DrawText(string text, Position position, TextStyle style) => DrawTextFunc(text, position, style);
+        public void DrawImage(SKImage image, Position position, Size size) => DrawImageFunc(image, position, size);
+        public void DrawExternalLink(string url, Size size)
+        {
+            throw new NotImplementedException();
+        }
+
+        public void DrawLocationLink(string locationName, Size size)
+        {
+            throw new NotImplementedException();
+        }
+
+        public void DrawLocation(string locationName)
+        {
+            throw new NotImplementedException();
+        }
+
+        public void DrawLink(string url, Size size)
+        {
+            throw new NotImplementedException();
+        }
+
+        public Size MeasureText(string text, TextStyle style)
+        {
+            return new Size(text.Length * style.Size, style.Size);
+        }
+    }
+}

+ 16 - 0
QuestPDF.UnitTests/TestEngine/ElementMock.cs

@@ -0,0 +1,16 @@
+using System;
+using QuestPDF.Drawing.SpacePlan;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.UnitTests.TestEngine
+{
+    internal class ElementMock : Element
+    {
+        public string Id { get; set; }
+        public Func<Size, ISpacePlan> MeasureFunc { get; set; }
+        public Action<Size> DrawFunc { get; set; }
+
+        internal override ISpacePlan Measure(Size availableSpace) => MeasureFunc(availableSpace);
+        internal override void Draw(ICanvas canvas, Size availableSpace) => DrawFunc(availableSpace);
+    }
+}

+ 7 - 0
QuestPDF.UnitTests/TestEngine/OperationBase.cs

@@ -0,0 +1,7 @@
+namespace QuestPDF.UnitTests.TestEngine
+{
+    public abstract class OperationBase
+    {
+        
+    }
+}

+ 16 - 0
QuestPDF.UnitTests/TestEngine/Operations/CanvasDrawImageOperation.cs

@@ -0,0 +1,16 @@
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.UnitTests.TestEngine.Operations
+{
+    internal class CanvasDrawImageOperationBase : OperationBase
+    {
+        public Position Position { get; }
+        public Size Size { get; }
+
+        public CanvasDrawImageOperationBase(Position position, Size size)
+        {
+            Position = position;
+            Size = size;
+        }
+    }
+}

+ 18 - 0
QuestPDF.UnitTests/TestEngine/Operations/CanvasDrawRectangleOperation.cs

@@ -0,0 +1,18 @@
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.UnitTests.TestEngine.Operations
+{
+    internal class CanvasDrawRectangleOperationBase : OperationBase
+    {
+        public Position Position { get; } 
+        public Size Size { get; }
+        public string Color { get; }
+
+        public CanvasDrawRectangleOperationBase(Position position, Size size, string color)
+        {
+            Position = position;
+            Size = size;
+            Color = color;
+        }
+    }
+}

+ 18 - 0
QuestPDF.UnitTests/TestEngine/Operations/CanvasDrawTextOperation.cs

@@ -0,0 +1,18 @@
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.UnitTests.TestEngine.Operations
+{
+    internal class CanvasDrawTextOperationBase : OperationBase
+    {
+        public string Text { get; }
+        public Position Position { get; }
+        public TextStyle Style { get; }
+
+        public CanvasDrawTextOperationBase(string text, Position position, TextStyle style)
+        {
+            Text = text;
+            Position = position;
+            Style = style;
+        }
+    }
+}

+ 14 - 0
QuestPDF.UnitTests/TestEngine/Operations/CanvasTranslateOperation.cs

@@ -0,0 +1,14 @@
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.UnitTests.TestEngine.Operations
+{
+    internal class CanvasTranslateOperationBase : OperationBase
+    {
+        public Position Position { get; }
+
+        public CanvasTranslateOperationBase(Position position)
+        {
+            Position = position;
+        }
+    }
+}

+ 16 - 0
QuestPDF.UnitTests/TestEngine/Operations/ChildDrawOperation.cs

@@ -0,0 +1,16 @@
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.UnitTests.TestEngine.Operations
+{
+    public class ChildDrawOperationBase : OperationBase
+    {
+        public string ChildId { get; }
+        public Size Input { get; }
+
+        public ChildDrawOperationBase(string childId, Size input)
+        {
+            ChildId = childId;
+            Input = input;
+        }
+    }
+}

+ 19 - 0
QuestPDF.UnitTests/TestEngine/Operations/ChildMeasureOperation.cs

@@ -0,0 +1,19 @@
+using QuestPDF.Drawing.SpacePlan;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.UnitTests.TestEngine.Operations
+{
+    internal class ChildMeasureOperationBase : OperationBase
+    {
+        public string ChildId { get; }
+        public Size Input { get; }
+        public ISpacePlan Output { get; }
+
+        public ChildMeasureOperationBase(string childId, Size input, ISpacePlan output)
+        {
+            ChildId = childId;
+            Input = input;
+            Output = output;
+        }
+    }
+}

+ 12 - 0
QuestPDF.UnitTests/TestEngine/Operations/ElementMeasureOperation.cs

@@ -0,0 +1,12 @@
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.UnitTests.TestEngine.Operations
+{
+    public class ElementMeasureOperationBase : OperationBase
+    {
+        public ElementMeasureOperationBase(Size input)
+        {
+            
+        }
+    }
+}

+ 31 - 0
QuestPDF.UnitTests/TestEngine/SingleChildTests.cs

@@ -0,0 +1,31 @@
+using FluentAssertions;
+using NUnit.Framework;
+using QuestPDF.Drawing.SpacePlan;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.UnitTests.TestEngine
+{
+    public static class SingleChildTests
+    {
+        internal static void MeasureWithoutChild<T>(this T element) where T : ContainerElement
+        {
+            element.Child = null;
+            element.Measure(Size.Zero).Should().BeEquivalentTo(new FullRender(Size.Zero));
+        }
+        
+        internal static void DrawWithoutChild<T>(this T element) where T : ContainerElement
+        {
+            // component does not throw an exception when called with null child
+            Assert.DoesNotThrow(() =>
+            {
+                element.Child = null;
+                
+                // component does not perform any canvas operation when called with null child
+                TestPlan
+                    .For(x => element)
+                    .DrawElement(new Size(200, 100))
+                    .CheckDrawResult();
+            });
+        }
+    }
+}

+ 19 - 209
QuestPDF.UnitTests/MeasureTest/MeasureTestMock.cs → QuestPDF.UnitTests/TestEngine/TestPlan.cs

@@ -1,144 +1,20 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Text.Json;
 using System.Text.Json;
-using FluentAssertions;
 using NUnit.Framework;
 using NUnit.Framework;
 using QuestPDF.Drawing.SpacePlan;
 using QuestPDF.Drawing.SpacePlan;
-using QuestPDF.Elements;
 using QuestPDF.Infrastructure;
 using QuestPDF.Infrastructure;
-using SkiaSharp;
+using QuestPDF.UnitTests.TestEngine.Operations;
 
 
-namespace QuestPDF.UnitTests.MeasureTest
+namespace QuestPDF.UnitTests.TestEngine
 {
 {
-    public abstract class Operation
-    {
-        
-    }
-
-    public class ElementMeasureOperation : Operation
-    {
-        public ElementMeasureOperation(Size input)
-        {
-            
-        }
-    }
-    
-    internal class ChildMeasureOperation : Operation
-    {
-        public string ChildId { get; }
-        public Size Input { get; }
-        public ISpacePlan Output { get; }
-
-        public ChildMeasureOperation(string childId, Size input, ISpacePlan output)
-        {
-            ChildId = childId;
-            Input = input;
-            Output = output;
-        }
-    }
-
-    public class ChildDrawOperation : Operation
-    {
-        public string ChildId { get; }
-        public Size Input { get; }
-
-        public ChildDrawOperation(string childId, Size input)
-        {
-            ChildId = childId;
-            Input = input;
-        }
-    }
-    
-    internal class CanvasTranslateOperation : Operation
-    {
-        public Position Position { get; }
-
-        public CanvasTranslateOperation(Position position)
-        {
-            Position = position;
-        }
-    }
-    
-    internal class CanvasDrawRectangleOperation : Operation
-    {
-        public Position Position { get; } 
-        public Size Size { get; }
-        public string Color { get; }
-
-        public CanvasDrawRectangleOperation(Position position, Size size, string color)
-        {
-            Position = position;
-            Size = size;
-            Color = color;
-        }
-    }
-    
-    internal class CanvasDrawTextOperation : Operation
-    {
-        public string Text { get; }
-        public Position Position { get; }
-        public TextStyle Style { get; }
-
-        public CanvasDrawTextOperation(string text, Position position, TextStyle style)
-        {
-            Text = text;
-            Position = position;
-            Style = style;
-        }
-    }
-    
-    internal class CanvasDrawImageOperation : Operation
-    {
-        public Position Position { get; }
-        public Size Size { get; }
-
-        public CanvasDrawImageOperation(Position position, Size size)
-        {
-            Position = position;
-            Size = size;
-        }
-    }
-    
-    internal class ElementMock : Element
-    {
-        public string Id { get; set; }
-        public Func<Size, ISpacePlan> MeasureFunc { get; set; }
-        public Action<Size> DrawFunc { get; set; }
-
-        internal override ISpacePlan Measure(Size availableSpace) => MeasureFunc(availableSpace);
-        internal override void Draw(ICanvas canvas, Size availableSpace) => DrawFunc(availableSpace);
-    }
-
-    internal class CanvasMock : ICanvas
-    {
-        public Action<Position> TranslateFunc { get; set; }
-        public Action<SKImage, Position, Size> DrawImageFunc { get; set; }
-        public Action<string, Position, TextStyle> DrawTextFunc { get; set; }
-        public Action<Position, Size, string> DrawRectFunc { get; set; }
-        
-        public void Translate(Position vector) => TranslateFunc(vector);
-        public void DrawRectangle(Position vector, Size size, string color) => DrawRectFunc(vector, size, color);
-        public void DrawText(string text, Position position, TextStyle style) => DrawTextFunc(text, position, style);
-        public void DrawImage(SKImage image, Position position, Size size) => DrawImageFunc(image, position, size);
-        
-        public void DrawLink(string url, Size size)
-        {
-            throw new NotImplementedException();
-        }
-
-        public Size MeasureText(string text, TextStyle style)
-        {
-            return new Size(text.Length * style.Size, style.Size);
-        }
-    }
-    
     internal class TestPlan
     internal class TestPlan
     {
     {
         private Element Element { get; set; }
         private Element Element { get; set; }
         private ICanvas Canvas { get; }
         private ICanvas Canvas { get; }
         
         
         private Size OperationInput { get; set; }
         private Size OperationInput { get; set; }
-        private Queue<Operation> Operations { get; } = new Queue<Operation>();
+        private Queue<OperationBase> Operations { get; } = new Queue<OperationBase>();
 
 
         public TestPlan()
         public TestPlan()
         {
         {
@@ -153,7 +29,7 @@ namespace QuestPDF.UnitTests.MeasureTest
             return plan;
             return plan;
         }
         }
 
 
-        private T GetExpected<T>() where T : Operation
+        private T GetExpected<T>() where T : OperationBase
         {
         {
             if (Operations.TryDequeue(out var value) && value is T result)
             if (Operations.TryDequeue(out var value) && value is T result)
                 return result;
                 return result;
@@ -169,7 +45,7 @@ namespace QuestPDF.UnitTests.MeasureTest
             {
             {
                 TranslateFunc = position =>
                 TranslateFunc = position =>
                 {
                 {
-                    var expected = GetExpected<CanvasTranslateOperation>();
+                    var expected = GetExpected<CanvasTranslateOperationBase>();
                     
                     
                     Assert.AreEqual(expected.Position.X, position.X);
                     Assert.AreEqual(expected.Position.X, position.X);
                     Assert.AreEqual(expected.Position.Y, position.Y);
                     Assert.AreEqual(expected.Position.Y, position.Y);
@@ -178,7 +54,7 @@ namespace QuestPDF.UnitTests.MeasureTest
                 },
                 },
                 DrawRectFunc = (position, size, color) =>
                 DrawRectFunc = (position, size, color) =>
                 {
                 {
-                    var expected = GetExpected<CanvasDrawRectangleOperation>();
+                    var expected = GetExpected<CanvasDrawRectangleOperationBase>();
                     
                     
                     Assert.AreEqual(expected.Position.X, position.X);
                     Assert.AreEqual(expected.Position.X, position.X);
                     Assert.AreEqual(expected.Position.Y, position.Y);
                     Assert.AreEqual(expected.Position.Y, position.Y);
@@ -194,7 +70,7 @@ namespace QuestPDF.UnitTests.MeasureTest
                 },
                 },
                 DrawTextFunc = (text, position, style) => 
                 DrawTextFunc = (text, position, style) => 
                 {
                 {
-                    var expected = GetExpected<CanvasDrawTextOperation>();
+                    var expected = GetExpected<CanvasDrawTextOperationBase>();
                     
                     
                     Assert.AreEqual(expected.Text, text);
                     Assert.AreEqual(expected.Text, text);
                     
                     
@@ -211,7 +87,7 @@ namespace QuestPDF.UnitTests.MeasureTest
                 },
                 },
                 DrawImageFunc = (image, position, size) =>
                 DrawImageFunc = (image, position, size) =>
                 {
                 {
-                    var expected = GetExpected<CanvasDrawImageOperation>();
+                    var expected = GetExpected<CanvasDrawImageOperationBase>();
                     
                     
                     Assert.AreEqual(expected.Position.X, position.X);
                     Assert.AreEqual(expected.Position.X, position.X);
                     Assert.AreEqual(expected.Position.Y, position.Y);
                     Assert.AreEqual(expected.Position.Y, position.Y);
@@ -232,7 +108,7 @@ namespace QuestPDF.UnitTests.MeasureTest
                 Id = id,
                 Id = id,
                 MeasureFunc = availableSpace =>
                 MeasureFunc = availableSpace =>
                 {
                 {
-                    var expected = GetExpected<ChildMeasureOperation>();
+                    var expected = GetExpected<ChildMeasureOperationBase>();
 
 
                     Assert.AreEqual(expected.ChildId, id);
                     Assert.AreEqual(expected.ChildId, id);
                     
                     
@@ -246,7 +122,7 @@ namespace QuestPDF.UnitTests.MeasureTest
                 },
                 },
                 DrawFunc = availableSpace =>
                 DrawFunc = availableSpace =>
                 {
                 {
-                    var expected = GetExpected<ChildDrawOperation>();
+                    var expected = GetExpected<ChildDrawOperationBase>();
 
 
                     Assert.AreEqual(expected.ChildId, id);
                     Assert.AreEqual(expected.ChildId, id);
                     
                     
@@ -271,45 +147,45 @@ namespace QuestPDF.UnitTests.MeasureTest
             return this;
             return this;
         }
         }
 
 
-        private TestPlan AddOperation(Operation operation)
+        private TestPlan AddOperation(OperationBase operationBase)
         {
         {
-            Operations.Enqueue(operation);
+            Operations.Enqueue(operationBase);
             return this;
             return this;
         }
         }
         
         
         public TestPlan ExpectChildMeasure(string child, Size expectedInput, ISpacePlan returns)
         public TestPlan ExpectChildMeasure(string child, Size expectedInput, ISpacePlan returns)
         {
         {
-            return AddOperation(new ChildMeasureOperation(child, expectedInput, returns));
+            return AddOperation(new ChildMeasureOperationBase(child, expectedInput, returns));
         }
         }
         
         
         public TestPlan ExpectChildDraw(string child, Size expectedInput)
         public TestPlan ExpectChildDraw(string child, Size expectedInput)
         {
         {
-            return AddOperation(new ChildDrawOperation(child, expectedInput));
+            return AddOperation(new ChildDrawOperationBase(child, expectedInput));
         }
         }
 
 
         public TestPlan ExpectCanvasTranslate(Position position)
         public TestPlan ExpectCanvasTranslate(Position position)
         {
         {
-            return AddOperation(new CanvasTranslateOperation(position));
+            return AddOperation(new CanvasTranslateOperationBase(position));
         }
         }
         
         
         public TestPlan ExpectCanvasTranslate(float left, float top)
         public TestPlan ExpectCanvasTranslate(float left, float top)
         {
         {
-            return AddOperation(new CanvasTranslateOperation(new Position(left, top)));
+            return AddOperation(new CanvasTranslateOperationBase(new Position(left, top)));
         }
         }
 
 
         public TestPlan ExpectCanvasDrawRectangle(Position position, Size size, string color)
         public TestPlan ExpectCanvasDrawRectangle(Position position, Size size, string color)
         {
         {
-            return AddOperation(new CanvasDrawRectangleOperation(position, size, color));
+            return AddOperation(new CanvasDrawRectangleOperationBase(position, size, color));
         }
         }
         
         
         public TestPlan ExpectCanvasDrawText(string text, Position position, TextStyle style)
         public TestPlan ExpectCanvasDrawText(string text, Position position, TextStyle style)
         {
         {
-            return AddOperation(new CanvasDrawTextOperation(text, position, style));
+            return AddOperation(new CanvasDrawTextOperationBase(text, position, style));
         }
         }
         
         
         public TestPlan ExpectCanvasDrawImage(Position position, Size size)
         public TestPlan ExpectCanvasDrawImage(Position position, Size size)
         {
         {
-            return AddOperation(new CanvasDrawImageOperation(position, size));
+            return AddOperation(new CanvasDrawImageOperationBase(position, size));
         }
         }
         
         
         public TestPlan CheckMeasureResult(ISpacePlan expected)
         public TestPlan CheckMeasureResult(ISpacePlan expected)
@@ -336,70 +212,4 @@ namespace QuestPDF.UnitTests.MeasureTest
             return this;
             return this;
         }
         }
     }
     }
-
-    public static class SingleChildTests
-    {
-        internal static void MeasureWithoutChild<T>(this T element) where T : ContainerElement
-        {
-            element.Child = null;
-            element.Measure(Size.Zero).Should().BeEquivalentTo(new FullRender(Size.Zero));
-        }
-        
-        internal static void DrawWithoutChild<T>(this T element) where T : ContainerElement
-        {
-            // component does not throw an exception when called with null child
-            Assert.DoesNotThrow(() =>
-            {
-                element.Child = null;
-                
-                // component does not perform any canvas operation when called with null child
-                TestPlan
-                    .For(x => element)
-                    .DrawElement(new Size(200, 100))
-                    .CheckDrawResult();
-            });
-        }
-    }
-
-    [TestFixture]
-    public class LetsTest
-    {
-        [Test]
-        public void TestExample()
-        {
-            TestPlan
-                .For(x => new Padding
-                {
-                    Top = 5,
-                    Right = 10,
-                    Bottom = 15,
-                    Left = 20, 
-                    
-                    Child = x.CreateChild("child")
-                })
-                .MeasureElement(new Size(200, 100))
-                .ExpectChildMeasure("child", expectedInput: new Size(170, 80), returns: new FullRender(new Size(100, 50)))
-                .CheckMeasureResult(new FullRender(130, 70));
-        }
-        
-        [Test]
-        public void TestExample2()
-        {
-            TestPlan
-                .For(x => new Padding
-                { 
-                    Top = 5,
-                    Right = 10,
-                    Bottom = 15,
-                    Left = 20, 
-                    
-                    Child = x.CreateChild("child")
-                })
-                .DrawElement(new Size(200, 100))
-                .ExpectCanvasTranslate(new Position(20, 5))
-                .ExpectChildDraw("child", expectedInput: new Size(170, 80))
-                .ExpectCanvasTranslate(new Position(-20, -5))
-                .CheckDrawResult();
-        }
-    }
 }
 }

+ 11 - 1
QuestPDF/Drawing/Canvas.cs

@@ -41,9 +41,19 @@ namespace QuestPDF.Drawing
             SkiaCanvas.DrawImage(image, new SKRect(vector.X, vector.Y, size.Width, size.Height));
             SkiaCanvas.DrawImage(image, new SKRect(vector.X, vector.Y, size.Width, size.Height));
         }
         }
 
 
-        public void DrawLink(string url, Size size)
+        public void DrawExternalLink(string url, Size size)
         {
         {
             SkiaCanvas.DrawUrlAnnotation(new SKRect(0, 0, size.Width, size.Height), url);
             SkiaCanvas.DrawUrlAnnotation(new SKRect(0, 0, size.Width, size.Height), url);
         }
         }
+        
+        public void DrawLocationLink(string locationName, Size size)
+        {
+            SkiaCanvas.DrawLinkDestinationAnnotation(new SKRect(0, 0, size.Width, size.Height), locationName);
+        }
+
+        public void DrawLocation(string locationName)
+        {
+            SkiaCanvas.DrawNamedDestinationAnnotation(new SKPoint(0, 0), locationName);
+        }
     }
     }
 }
 }

+ 5 - 3
QuestPDF/Drawing/CanvasCache.cs

@@ -30,13 +30,15 @@ namespace QuestPDF.Drawing
             
             
             static SKPaint Convert(TextStyle style)
             static SKPaint Convert(TextStyle style)
             {
             {
+                var slant = style.IsItalic ? SKFontStyleSlant.Italic : SKFontStyleSlant.Upright;
+                
                 return new SKPaint
                 return new SKPaint
                 {
                 {
                     Color = SKColor.Parse(style.Color),
                     Color = SKColor.Parse(style.Color),
-                    Typeface = Fonts.GetOrAdd(style.FontType, SKTypeface.FromFamilyName),
+                    Typeface = SKTypeface.FromFamilyName(style.FontType, (int)style.FontWeight, (int)SKFontStyleWidth.Normal, slant),
                     TextSize = style.Size,
                     TextSize = style.Size,
-                    IsLinearText = true,
-                
+                    TextEncoding = SKTextEncoding.Utf32,
+                    
                     TextAlign = style.Alignment switch
                     TextAlign = style.Alignment switch
                     {
                     {
                         HorizontalAlignment.Left => SKTextAlign.Left,
                         HorizontalAlignment.Left => SKTextAlign.Left,

+ 0 - 1
QuestPDF/Drawing/DocumentGenerator.cs

@@ -12,7 +12,6 @@ namespace QuestPDF.Drawing
     static class DocumentGenerator
     static class DocumentGenerator
     {
     {
         const int DocumentLayoutExceptionThreshold = 250;
         const int DocumentLayoutExceptionThreshold = 250;
-        private static readonly Watermark Watermark = new Watermark();
 
 
         internal static void Generate(Stream stream, IDocument document)
         internal static void Generate(Stream stream, IDocument document)
         {
         {

+ 21 - 0
QuestPDF/Elements/ExternalLink.cs

@@ -0,0 +1,21 @@
+using QuestPDF.Drawing.SpacePlan;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.Elements
+{
+    internal class ExternalLink : ContainerElement
+    {
+        public string Url { get; set; } = "https://www.questpdf.com";
+        
+        internal override void Draw(ICanvas canvas, Size availableSpace)
+        {
+            var targetSize = Child?.Measure(availableSpace) as Size;
+
+            if (targetSize == null)
+                return;
+
+            canvas.DrawExternalLink(Url, targetSize);
+            Child?.Draw(canvas, availableSpace);
+        }
+    }
+}

+ 21 - 0
QuestPDF/Elements/InternalLink.cs

@@ -0,0 +1,21 @@
+using QuestPDF.Drawing.SpacePlan;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.Elements
+{
+    internal class InternalLink : ContainerElement
+    {
+        public string LocationName { get; set; }
+        
+        internal override void Draw(ICanvas canvas, Size availableSpace)
+        {
+            var targetSize = Child?.Measure(availableSpace) as Size;
+
+            if (targetSize == null)
+                return;
+
+            canvas.DrawLocationLink(LocationName, targetSize);
+            Child?.Draw(canvas, availableSpace);
+        }
+    }
+}

+ 17 - 0
QuestPDF/Elements/InternalLocation.cs

@@ -0,0 +1,17 @@
+using System;
+using QuestPDF.Drawing.SpacePlan;
+using QuestPDF.Infrastructure;
+
+namespace QuestPDF.Elements
+{
+    internal class InternalLocation : ContainerElement
+    {
+        public string LocationName { get; set; }
+        
+        internal override void Draw(ICanvas canvas, Size availableSpace)
+        {
+            canvas.DrawLocation(LocationName);
+            Child?.Draw(canvas, availableSpace);
+        }
+    }
+}

+ 5 - 12
QuestPDF/Elements/Stack.cs

@@ -47,10 +47,8 @@ namespace QuestPDF.Elements
 
 
                 var size = space as Size;
                 var size = space as Size;
                 
                 
-                if (size.Height < Size.Epsilon)
-                    continue;
-
-                heightOnCurrentPage += size.Height + Spacing;
+                if (size.Height > Size.Epsilon)
+                    heightOnCurrentPage += size.Height + Spacing;
 
 
                 if (space is PartialRender)
                 if (space is PartialRender)
                 {
                 {
@@ -81,18 +79,13 @@ namespace QuestPDF.Elements
                     break;
                     break;
 
 
                 var size = space as Size;
                 var size = space as Size;
-
-                if (size.Height < Size.Epsilon)
-                {
-                    ChildrenQueue.Dequeue();
-                    continue;
-                }
-
+                
                 canvas.Translate(new Position(0, topOffset));
                 canvas.Translate(new Position(0, topOffset));
                 child.Draw(canvas, new Size(availableSpace.Width, size.Height));
                 child.Draw(canvas, new Size(availableSpace.Width, size.Height));
                 canvas.Translate(new Position(0, -topOffset));
                 canvas.Translate(new Position(0, -topOffset));
                 
                 
-                topOffset += size.Height + Spacing;
+                if (size.Height > Size.Epsilon)
+                    topOffset += size.Height + Spacing;
 
 
                 if (space is PartialRender)
                 if (space is PartialRender)
                     break;
                     break;

+ 0 - 62
QuestPDF/Elements/Watermark.cs

@@ -1,62 +0,0 @@
-using QuestPDF.Drawing.SpacePlan;
-using QuestPDF.Infrastructure;
-
-namespace QuestPDF.Elements
-{
-    internal class Watermark : Element
-    {
-        private Position Offset { get; set; } = new Position(36, 36);
-        private const float ImageHeight = 28;
-        private const string TargetUrl = "https://www.questpdf.com";
-        
-        private Image Image { get; set; }
-        private static readonly byte[] ImageData;
-
-        static Watermark()
-        {
-            ImageData = Helpers.Helpers.LoadEmbeddedResource("QuestPDF.Resources.Watermark.png");
-        }
-        
-        public Watermark()
-        {
-            Image = new Image()
-            {
-                Data = ImageData
-            };
-        }
-
-        internal void AdjustPosition(Element? element)
-        {
-            while (element != null)
-            {
-                if (element is Padding padding)
-                {
-                    if (padding.Left > 0 && padding.Bottom > 0)
-                        Offset = new Position(padding.Left, padding.Bottom);
-                    
-                    return;
-                }
-
-                element = (element as ContainerElement)?.Child;
-            }
-        }
-
-        internal override ISpacePlan Measure(Size availableSpace)
-        {
-            return Image.Measure(availableSpace);
-        }
-
-        internal override void Draw(ICanvas canvas, Size availableSpace)
-        {
-            var offset = new Position(Offset.X, availableSpace.Height - Offset.Y - ImageHeight);
-            canvas.Translate(offset);
-
-            availableSpace = new Size(availableSpace.Width, ImageHeight);
-            var targetSize = Image.Measure(availableSpace) as FullRender;
-            Image.Draw(canvas, targetSize);
-            canvas.DrawLink(TargetUrl, targetSize);
-            
-            canvas.Translate(offset.Reverse());
-        }
-    }
-}

+ 27 - 3
QuestPDF/Fluent/ElementExtensions.cs

@@ -66,6 +66,14 @@ namespace QuestPDF.Fluent
             });
             });
         }
         }
         
         
+        public static void DynamicImage(this IContainer element, Func<Size, byte[]> imageSource)
+        {
+            element.Element(new DynamicImage
+            {
+                Source = imageSource
+            });
+        }
+        
         public static void PageNumber(this IContainer element, string textFormat = "{number}", TextStyle? style = null)
         public static void PageNumber(this IContainer element, string textFormat = "{number}", TextStyle? style = null)
         {
         {
             element.Element(new PageNumber
             element.Element(new PageNumber
@@ -127,11 +135,27 @@ namespace QuestPDF.Fluent
             return element.Element(new Container());
             return element.Element(new Container());
         }
         }
         
         
-        private static void DynamicImage(this IContainer element, Func<Size, byte[]> handler)
+        public static IContainer ExternalLink(this IContainer element, string url)
+        {
+            return element.Element(new ExternalLink
+            {
+                Url = url
+            });
+        }
+        
+        public static IContainer Location(this IContainer element, string locationName)
+        {
+            return element.Element(new InternalLocation
+            {
+                LocationName = locationName
+            });
+        }
+        
+        public static IContainer InternalLink(this IContainer element, string locationName)
         {
         {
-            element.Element(new DynamicImage()
+            return element.Element(new InternalLink
             {
             {
-                Source = handler
+                LocationName = locationName
             });
             });
         }
         }
     }
     }

+ 71 - 3
QuestPDF/Fluent/TextStyleExtensions.cs

@@ -31,6 +31,13 @@ namespace QuestPDF.Fluent
             return style.Mutate(x => x.LineHeight = value);
             return style.Mutate(x => x.LineHeight = value);
         }
         }
         
         
+        public static TextStyle Italic(this TextStyle style, bool value = true)
+        {
+            return style.Mutate(x => x.IsItalic = value);
+        }
+
+        #region Alignmnet
+        
         public static TextStyle Alignment(this TextStyle style, HorizontalAlignment value)
         public static TextStyle Alignment(this TextStyle style, HorizontalAlignment value)
         {
         {
             return style.Mutate(x => x.Alignment = value);
             return style.Mutate(x => x.Alignment = value);
@@ -38,17 +45,78 @@ namespace QuestPDF.Fluent
         
         
         public static TextStyle AlignLeft(this TextStyle style)
         public static TextStyle AlignLeft(this TextStyle style)
         {
         {
-            return style.Mutate(x => x.Alignment = HorizontalAlignment.Left);
+            return style.Alignment(HorizontalAlignment.Left);
         }
         }
         
         
         public static TextStyle AlignCenter(this TextStyle style)
         public static TextStyle AlignCenter(this TextStyle style)
         {
         {
-            return style.Mutate(x => x.Alignment = HorizontalAlignment.Center);
+            return style.Alignment(HorizontalAlignment.Center);
         }
         }
         
         
         public static TextStyle AlignRight(this TextStyle style)
         public static TextStyle AlignRight(this TextStyle style)
         {
         {
-            return style.Mutate(x => x.Alignment = HorizontalAlignment.Right);
+            return style.Alignment(HorizontalAlignment.Right);
+        }
+        
+        #endregion
+        
+        #region Weight
+        
+        public static TextStyle Weight(this TextStyle style, FontWeight weight)
+        {
+            return style.Mutate(x => x.FontWeight = weight);
+        }
+        
+        public static TextStyle Thin(this TextStyle style)
+        {
+            return style.Weight(FontWeight.Thin);
+        }
+        
+        public static TextStyle ExtraLight(this TextStyle style)
+        {
+            return style.Weight(FontWeight.ExtraLight);
+        }
+        
+        public static TextStyle Light(this TextStyle style)
+        {
+            return style.Weight(FontWeight.Light);
+        }
+        
+        public static TextStyle NormalWeight(this TextStyle style)
+        {
+            return style.Weight(FontWeight.Normal);
+        }
+        
+        public static TextStyle Medium(this TextStyle style)
+        {
+            return style.Weight(FontWeight.Medium);
+        }
+        
+        public static TextStyle SemiBold(this TextStyle style)
+        {
+            return style.Weight(FontWeight.SemiBold);
+        }
+        
+        public static TextStyle Bold(this TextStyle style)
+        {
+            return style.Weight(FontWeight.Bold);
         }
         }
+        
+        public static TextStyle ExtraBold(this TextStyle style)
+        {
+            return style.Weight(FontWeight.ExtraBold);
+        }
+        
+        public static TextStyle Black(this TextStyle style)
+        {
+            return style.Weight(FontWeight.Black);
+        }
+        
+        public static TextStyle ExtraBlack(this TextStyle style)
+        {
+            return style.Weight(FontWeight.ExtraBlack);
+        }
+        
+        #endregion
     }
     }
 }
 }

+ 16 - 0
QuestPDF/Infrastructure/FontWeight.cs

@@ -0,0 +1,16 @@
+namespace QuestPDF.Infrastructure
+{
+    public enum FontWeight
+    {
+        Thin = 100,
+        ExtraLight = 200,
+        Light = 300,
+        Normal = 400,
+        Medium = 500,
+        SemiBold = 600,
+        Bold = 700,
+        ExtraBold = 800,
+        Black = 900,
+        ExtraBlack = 1000
+    }
+}

+ 3 - 1
QuestPDF/Infrastructure/ICanvas.cs

@@ -10,6 +10,8 @@ namespace QuestPDF.Infrastructure
         void DrawText(string text, Position position, TextStyle style);
         void DrawText(string text, Position position, TextStyle style);
         void DrawImage(SKImage image, Position position, Size size);
         void DrawImage(SKImage image, Position position, Size size);
 
 
-        void DrawLink(string url, Size size);
+        void DrawExternalLink(string url, Size size);
+        void DrawLocationLink(string locationName, Size size);
+        void DrawLocation(string locationName);
     }
     }
 }
 }

+ 9 - 7
QuestPDF/Infrastructure/TextStyle.cs

@@ -2,17 +2,19 @@
 {
 {
     public class TextStyle
     public class TextStyle
     {
     {
-        public string Color { get; set; } = "#000000";
-        public string FontType { get; set; } = "Helvetica";
-        public float Size { get; set; } = 12;
-        public float LineHeight { get; set; } = 1.2f;
-        public HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left;
-        
+        internal string Color { get; set; } = "#000000";
+        internal string FontType { get; set; } = "Helvetica";
+        internal float Size { get; set; } = 12;
+        internal float LineHeight { get; set; } = 1.2f;
+        internal HorizontalAlignment Alignment { get; set; } = HorizontalAlignment.Left;
+        internal FontWeight FontWeight { get; set; } = FontWeight.Normal;
+        internal bool IsItalic { get; set; } = false;
+
         public static TextStyle Default => new TextStyle();
         public static TextStyle Default => new TextStyle();
         
         
         public override string ToString()
         public override string ToString()
         {
         {
-            return $"{Color}|{FontType}|{Size}|{LineHeight}|{Alignment}";
+            return $"{Color}|{FontType}|{Size}|{LineHeight}|{Alignment}|{FontWeight}|{IsItalic}";
         }
         }
     }
     }
 }
 }

+ 2 - 2
QuestPDF/QuestPDF.csproj

@@ -4,9 +4,9 @@
         <Authors>MarcinZiabek</Authors>
         <Authors>MarcinZiabek</Authors>
         <Company>CodeFlint</Company>
         <Company>CodeFlint</Company>
         <PackageId>QuestPDF</PackageId>
         <PackageId>QuestPDF</PackageId>
-        <Version>2021.1.0</Version>
+        <Version>2021.2.0</Version>
         <PackageDescription>QuestPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API.</PackageDescription>
         <PackageDescription>QuestPDF is an open-source, modern and battle-tested library that can help you with generating PDF documents by offering friendly, discoverable and predictable C# fluent API.</PackageDescription>
-        <PackageReleaseNotes>The library is open-source and totally free now. Removed watermak.</PackageReleaseNotes>
+        <PackageReleaseNotes>2021.2.0 Internal links, external links, dynamic images, font weights</PackageReleaseNotes>
         <LangVersion>8</LangVersion>
         <LangVersion>8</LangVersion>
         <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
         <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
         <PackageIcon>Logo.png</PackageIcon>
         <PackageIcon>Logo.png</PackageIcon>