Fixed: AspectRatio behaviour does not take into account child measurement. Added tests for AspectRatio, Image and DynamicImage elements. Small TestPlan framework improvements.

This commit is contained in:
MarcinZiabek 2021-03-23 18:05:39 +01:00
Родитель 08126b2fa4
Коммит c5cb588857
19 изменённых файлов: 464 добавлений и 152 удалений

Просмотреть файл

@ -13,7 +13,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\QuestPDF.InvoiceSample\QuestPDF.InvoiceSample.csproj" />
<ProjectReference Include="..\QuestPDF\QuestPDF.csproj" /> <ProjectReference Include="..\QuestPDF\QuestPDF.csproj" />
</ItemGroup> </ItemGroup>

Просмотреть файл

@ -21,10 +21,10 @@ namespace QuestPDF.UnitTests
TestPlan TestPlan
.For(x => new Alignment .For(x => new Alignment
{ {
Child = x.CreateChild("child") Child = x.CreateChild()
}) })
.MeasureElement(new Size(1000, 500)) .MeasureElement(new Size(1000, 500))
.ExpectChildMeasure("child", expectedInput: new Size(1000, 500), returns: new Wrap()) .ExpectChildMeasure(expectedInput: new Size(1000, 500), returns: new Wrap())
.CheckMeasureResult(new Wrap()); .CheckMeasureResult(new Wrap());
} }
@ -37,12 +37,12 @@ namespace QuestPDF.UnitTests
Horizontal = HorizontalAlignment.Center, Horizontal = HorizontalAlignment.Center,
Vertical = VerticalAlignment.Middle, Vertical = VerticalAlignment.Middle,
Child = x.CreateChild("child") Child = x.CreateChild()
}) })
.DrawElement(new Size(1000, 500)) .DrawElement(new Size(1000, 500))
.ExpectChildMeasure("child", expectedInput: new Size(1000, 500), returns: new PartialRender(new Size(400, 200))) .ExpectChildMeasure(expectedInput: new Size(1000, 500), returns: new PartialRender(new Size(400, 200)))
.ExpectCanvasTranslate(new Position(300, 150)) .ExpectCanvasTranslate(new Position(300, 150))
.ExpectChildDraw("child", new Size(400, 200)) .ExpectChildDraw(new Size(400, 200))
.ExpectCanvasTranslate(new Position(-300, -150)) .ExpectCanvasTranslate(new Position(-300, -150))
.CheckDrawResult(); .CheckDrawResult();
} }
@ -56,12 +56,12 @@ namespace QuestPDF.UnitTests
Horizontal = HorizontalAlignment.Left, Horizontal = HorizontalAlignment.Left,
Vertical = VerticalAlignment.Middle, Vertical = VerticalAlignment.Middle,
Child = x.CreateChild("child") Child = x.CreateChild()
}) })
.DrawElement(new Size(400, 300)) .DrawElement(new Size(400, 300))
.ExpectChildMeasure("child", expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50))) .ExpectChildMeasure(expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
.ExpectCanvasTranslate(new Position(0, 125)) .ExpectCanvasTranslate(new Position(0, 125))
.ExpectChildDraw("child", new Size(100, 50)) .ExpectChildDraw(new Size(100, 50))
.ExpectCanvasTranslate(new Position(0, -125)) .ExpectCanvasTranslate(new Position(0, -125))
.CheckDrawResult(); .CheckDrawResult();
} }
@ -75,12 +75,12 @@ namespace QuestPDF.UnitTests
Horizontal = HorizontalAlignment.Center, Horizontal = HorizontalAlignment.Center,
Vertical = VerticalAlignment.Bottom, Vertical = VerticalAlignment.Bottom,
Child = x.CreateChild("child") Child = x.CreateChild()
}) })
.DrawElement(new Size(400, 300)) .DrawElement(new Size(400, 300))
.ExpectChildMeasure("child", expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50))) .ExpectChildMeasure(expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
.ExpectCanvasTranslate(new Position(150, 250)) .ExpectCanvasTranslate(new Position(150, 250))
.ExpectChildDraw("child", new Size(100, 50)) .ExpectChildDraw(new Size(100, 50))
.ExpectCanvasTranslate(new Position(-150, -250)) .ExpectCanvasTranslate(new Position(-150, -250))
.CheckDrawResult(); .CheckDrawResult();
} }
@ -94,12 +94,12 @@ namespace QuestPDF.UnitTests
Horizontal = HorizontalAlignment.Right, Horizontal = HorizontalAlignment.Right,
Vertical = VerticalAlignment.Top, Vertical = VerticalAlignment.Top,
Child = x.CreateChild("child") Child = x.CreateChild()
}) })
.DrawElement(new Size(400, 300)) .DrawElement(new Size(400, 300))
.ExpectChildMeasure("child", expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50))) .ExpectChildMeasure(expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
.ExpectCanvasTranslate(new Position(300, 0)) .ExpectCanvasTranslate(new Position(300, 0))
.ExpectChildDraw("child", new Size(100, 50)) .ExpectChildDraw(new Size(100, 50))
.ExpectCanvasTranslate(new Position(-300, 0)) .ExpectCanvasTranslate(new Position(-300, 0))
.CheckDrawResult(); .CheckDrawResult();
} }

Просмотреть файл

@ -15,5 +15,168 @@ namespace QuestPDF.UnitTests
[Test] [Test]
public void Draw_ShouldHandleNullChild() => new AspectRatio().DrawWithoutChild(); public void Draw_ShouldHandleNullChild() => new AspectRatio().DrawWithoutChild();
[Test]
public void Measure_FitWidth_EnoughSpace_FullRender()
{
TestPlan
.For(x => new AspectRatio
{
Child = x.CreateChild(),
Option = AspectRatioOption.FitArea,
Ratio = 2f
})
.MeasureElement(new Size(400, 201))
.ExpectChildMeasure(new Size(400, 200), new FullRender(100, 50))
.CheckMeasureResult(new FullRender(400, 200));
}
[Test]
public void Measure_FitWidth_EnoughSpace_PartialRender()
{
TestPlan
.For(x => new AspectRatio
{
Child = x.CreateChild(),
Option = AspectRatioOption.FitArea,
Ratio = 2f
})
.MeasureElement(new Size(400, 201))
.ExpectChildMeasure(new Size(400, 200), new PartialRender(100, 50))
.CheckMeasureResult(new PartialRender(400, 200));
}
[Test]
public void Measure_FitWidth_EnoughSpace_Wrap()
{
TestPlan
.For(x => new AspectRatio
{
Child = x.CreateChild(),
Option = AspectRatioOption.FitArea,
Ratio = 2f
})
.MeasureElement(new Size(400, 201))
.ExpectChildMeasure(new Size(400, 200), new Wrap())
.CheckMeasureResult(new Wrap());
}
[Test]
public void Measure_FitWidth_EnoughSpace()
{
TestPlan
.For(x => new AspectRatio
{
Child = x.CreateChild(),
Option = AspectRatioOption.FitWidth,
Ratio = 2f
})
.MeasureElement(new Size(400, 201))
.ExpectChildMeasure(new Size(400, 200), new FullRender(100, 50))
.CheckMeasureResult(new FullRender(400, 200));
}
[Test]
public void Measure_FitWidth_NotEnoughSpace()
{
TestPlan
.For(x => new AspectRatio
{
Child = x.CreateChild(),
Option = AspectRatioOption.FitWidth,
Ratio = 2f
})
.MeasureElement(new Size(400, 199))
.CheckMeasureResult(new Wrap());
}
[Test]
public void Measure_FitHeight_EnoughSpace()
{
TestPlan
.For(x => new AspectRatio
{
Child = x.CreateChild(),
Option = AspectRatioOption.FitHeight,
Ratio = 2f
})
.MeasureElement(new Size(401, 200))
.ExpectChildMeasure(new Size(400, 200), new FullRender(100, 50))
.CheckMeasureResult(new FullRender(400, 200));
}
[Test]
public void Measure_FitHeight_NotEnoughSpace()
{
TestPlan
.For(x => new AspectRatio
{
Child = x.CreateChild(),
Option = AspectRatioOption.FitHeight,
Ratio = 2f
})
.MeasureElement(new Size(399, 200))
.CheckMeasureResult(new Wrap());
}
[Test]
public void Measure_FitArea_ToWidth()
{
TestPlan
.For(x => new AspectRatio
{
Child = x.CreateChild(),
Option = AspectRatioOption.FitArea,
Ratio = 2f
})
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure(new Size(400, 200), new FullRender(100, 50))
.CheckMeasureResult(new FullRender(400, 200));
}
[Test]
public void Measure_FitArea_ToHeight()
{
TestPlan
.For(x => new AspectRatio
{
Child = x.CreateChild(),
Option = AspectRatioOption.FitArea,
Ratio = 2f
})
.MeasureElement(new Size(500, 200))
.ExpectChildMeasure(new Size(400, 200), new FullRender(100, 50))
.CheckMeasureResult(new FullRender(400, 200));
}
[Test]
public void DrawChild_PerWidth()
{
TestPlan
.For(x => new AspectRatio
{
Child = x.CreateChild(),
Option = AspectRatioOption.FitArea,
Ratio = 2f
})
.DrawElement(new Size(500, 200))
.ExpectChildDraw(new Size(400, 200))
.CheckDrawResult();
}
[Test]
public void DrawChild_PerHeight()
{
TestPlan
.For(x => new AspectRatio
{
Child = x.CreateChild(),
Option = AspectRatioOption.FitArea,
Ratio = 2f
})
.DrawElement(new Size(400, 300))
.ExpectChildDraw(new Size(400, 200))
.CheckDrawResult();
}
} }
} }

Просмотреть файл

@ -31,11 +31,11 @@ namespace QuestPDF.UnitTests
.For(x => new Background .For(x => new Background
{ {
Color = "#F00", Color = "#F00",
Child = x.CreateChild("a") Child = x.CreateChild()
}) })
.DrawElement(new Size(400, 300)) .DrawElement(new Size(400, 300))
.ExpectCanvasDrawRectangle(new Position(0, 0), new Size(400, 300), "#F00") .ExpectCanvasDrawRectangle(new Position(0, 0), new Size(400, 300), "#F00")
.ExpectChildDraw("a", new Size(400, 300)) .ExpectChildDraw(new Size(400, 300))
.CheckDrawResult(); .CheckDrawResult();
} }
} }

Просмотреть файл

@ -23,10 +23,10 @@ namespace QuestPDF.UnitTests
Bottom = 30, Bottom = 30,
Left = 40, Left = 40,
Child = x.CreateChild("child") Child = x.CreateChild()
}) })
.MeasureElement(new Size(400, 300)) .MeasureElement(new Size(400, 300))
.ExpectChildMeasure("child", expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50))) .ExpectChildMeasure(expectedInput: new Size(400, 300), returns: new FullRender(new Size(100, 50)))
.CheckMeasureResult( new FullRender(new Size(100, 50))); .CheckMeasureResult( new FullRender(new Size(100, 50)));
} }
@ -43,15 +43,15 @@ namespace QuestPDF.UnitTests
Color = "#FF0000", Color = "#FF0000",
Child = x.CreateChild("child") Child = x.CreateChild()
}) })
.DrawElement(new Size(400, 300)) .DrawElement(new Size(400, 300))
.ExpectChildDraw("child", new Size(400, 300)) .ExpectChildDraw(new Size(400, 300))
.ExpectCanvasDrawRectangle(new Position(-20, -5), new Size(430, 10), "#FF0000") // top .ExpectCanvasDrawRectangle(new Position(-20, -5), new Size(430, 10), "#FF0000") // top
.ExpectCanvasDrawRectangle(new Position(-20, -5), new Size(40, 320), "#FF0000") // left .ExpectCanvasDrawRectangle(new Position(-20, -5), new Size(40, 320), "#FF0000") // left
.ExpectCanvasDrawRectangle(new Position(-20, 285), new Size(430, 30), "#FF0000") // bottom .ExpectCanvasDrawRectangle(new Position(-20, 285), new Size(430, 30), "#FF0000") // bottom
.ExpectCanvasDrawRectangle(new Position(390, -5), new Size(20, 320), "#FF0000") // right .ExpectCanvasDrawRectangle(new Position(390, -5), new Size(20, 320), "#FF0000") // right
.ExpectChildDraw("child", new Size(400, 300)) .ExpectChildDraw(new Size(400, 300))
.CheckDrawResult(); .CheckDrawResult();
} }
} }

Просмотреть файл

@ -34,10 +34,10 @@ namespace QuestPDF.UnitTests
.For(x => new Constrained .For(x => new Constrained
{ {
MinHeight = 100, MinHeight = 100,
Child = x.CreateChild("a") Child = x.CreateChild()
}) })
.MeasureElement(new Size(400, 200)) .MeasureElement(new Size(400, 200))
.ExpectChildMeasure("a", new Size(400, 200), new FullRender(400, 50)) .ExpectChildMeasure(new Size(400, 200), new FullRender(400, 50))
.CheckMeasureResult(new FullRender(400, 100)); .CheckMeasureResult(new FullRender(400, 100));
} }
@ -48,10 +48,10 @@ namespace QuestPDF.UnitTests
.For(x => new Constrained .For(x => new Constrained
{ {
MinHeight = 100, MinHeight = 100,
Child = x.CreateChild("a") Child = x.CreateChild()
}) })
.MeasureElement(new Size(400, 200)) .MeasureElement(new Size(400, 200))
.ExpectChildMeasure("a", new Size(400, 200), new FullRender(400, 150)) .ExpectChildMeasure(new Size(400, 200), new FullRender(400, 150))
.CheckMeasureResult(new FullRender(400, 150)); .CheckMeasureResult(new FullRender(400, 150));
} }
@ -74,10 +74,10 @@ namespace QuestPDF.UnitTests
.For(x => new Constrained .For(x => new Constrained
{ {
MaxHeight = 100, MaxHeight = 100,
Child = x.CreateChild("a") Child = x.CreateChild()
}) })
.MeasureElement(new Size(400, 200)) .MeasureElement(new Size(400, 200))
.ExpectChildMeasure("a", new Size(400, 100), new PartialRender(400, 75)) .ExpectChildMeasure(new Size(400, 100), new PartialRender(400, 75))
.CheckMeasureResult(new PartialRender(400, 75)); .CheckMeasureResult(new PartialRender(400, 75));
} }
@ -88,10 +88,10 @@ namespace QuestPDF.UnitTests
.For(x => new Constrained .For(x => new Constrained
{ {
MaxHeight = 100, MaxHeight = 100,
Child = x.CreateChild("a") Child = x.CreateChild()
}) })
.MeasureElement(new Size(400, 200)) .MeasureElement(new Size(400, 200))
.ExpectChildMeasure("a", new Size(400, 100), new Wrap()) .ExpectChildMeasure(new Size(400, 100), new Wrap())
.CheckMeasureResult(new Wrap()); .CheckMeasureResult(new Wrap());
} }
} }

Просмотреть файл

@ -1,10 +1,86 @@
using NUnit.Framework; using System;
using FluentAssertions;
using NUnit.Framework;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Elements;
using QuestPDF.Infrastructure;
using QuestPDF.UnitTests.TestEngine;
using SkiaSharp;
namespace QuestPDF.UnitTests namespace QuestPDF.UnitTests
{ {
[TestFixture] [TestFixture]
public class DynamicImageTests public class DynamicImageTests
{ {
[Test]
public void Measure_TakesAvailableSpaceRegardlessOfSize()
{
TestPlan
.For(x => new DynamicImage
{
Source = GenerateImage
})
.MeasureElement(new Size(300, 200))
.CheckMeasureResult(new FullRender(300, 200));
}
[Test]
public void Draw_HandlesNull()
{
TestPlan
.For(x => new DynamicImage
{
Source = size => null
})
.DrawElement(new Size(300, 200))
.CheckDrawResult();
}
[Test]
public void Draw_PreservesSize()
{
TestPlan
.For(x => new DynamicImage
{
Source = GenerateImage
})
.DrawElement(new Size(300, 200))
.ExpectCanvasDrawImage(Position.Zero, new Size(300, 200))
.CheckDrawResult();
}
[Test]
public void Draw_PassesCorrectSizeToSource()
{
Size passedSize = null;
TestPlan
.For(x => new DynamicImage
{
Source = size =>
{
passedSize = size;
return GenerateImage(size);
}
})
.DrawElement(new Size(400, 300))
.ExpectCanvasDrawImage(Position.Zero, new Size(400, 300))
.CheckDrawResult();
passedSize.Should().Be(new Size(400, 300));
}
byte[] GenerateImage(Size size)
{
var image = GenerateImage((int) size.Width, (int) size.Height);
return image.Encode(SKEncodedImageFormat.Png, 100).ToArray();
}
SKImage GenerateImage(int width, int height)
{
var imageInfo = new SKImageInfo(width, height);
using var surface = SKSurface.Create(imageInfo);
return surface.Snapshot();
}
} }
} }

Просмотреть файл

@ -1,10 +0,0 @@
using NUnit.Framework;
namespace QuestPDF.UnitTests
{
[TestFixture]
public class EmptyTests
{
}
}

Просмотреть файл

@ -1,7 +1,12 @@
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using QuestPDF.Drawing;
using QuestPDF.Drawing.SpacePlan;
using QuestPDF.Elements; using QuestPDF.Elements;
using QuestPDF.Fluent;
using QuestPDF.Infrastructure; using QuestPDF.Infrastructure;
using QuestPDF.UnitTests.TestEngine;
using SkiaSharp;
namespace QuestPDF.UnitTests namespace QuestPDF.UnitTests
{ {
@ -9,17 +14,57 @@ namespace QuestPDF.UnitTests
public class ImageTests public class ImageTests
{ {
[Test] [Test]
public void Draw_ShouldHandleNullChild() public void Measure_ShouldHandleNullChild() => new AspectRatio().MeasureWithoutChild();
[Test]
public void Draw_ShouldHandleNullChild() => new AspectRatio().DrawWithoutChild();
[Test]
public void Measure_TakesAvailableSpaceRegardlessOfSize()
{ {
Assert.DoesNotThrow(() => TestPlan
{ .For(x => new Image
var image = new Image()
{ {
InternalImage = null InternalImage = GenerateImage(400, 300)
}; })
.MeasureElement(new Size(300, 200))
image.Draw(It.IsAny<ICanvas>(), Size.Zero); .CheckMeasureResult(new FullRender(300, 200));
}); }
[Test]
public void Draw_TakesAvailableSpaceRegardlessOfSize()
{
TestPlan
.For(x => new Image
{
InternalImage = GenerateImage(400, 300)
})
.DrawElement(new Size(300, 200))
.ExpectCanvasDrawImage(new Position(0, 0), new Size(300, 200))
.CheckDrawResult();
}
[Test]
public void Fluent_RecognizesImageProportions()
{
var image = GenerateImage(600, 200).Encode(SKEncodedImageFormat.Png, 100).ToArray();
TestPlan
.For(x =>
{
var container = new Container();
container.Image(image);
return container;
})
.MeasureElement(new Size(300, 200))
.CheckMeasureResult(new FullRender(300, 100));;
}
SKImage GenerateImage(int width, int height)
{
var imageInfo = new SKImageInfo(width, height);
using var surface = SKSurface.Create(imageInfo);
return surface.Snapshot();
} }
} }
} }

Просмотреть файл

@ -17,62 +17,77 @@ namespace QuestPDF.UnitTests
[Test] [Test]
public void Draw_ShouldHandleNullChild() => new Padding().DrawWithoutChild(); public void Draw_ShouldHandleNullChild() => new Padding().DrawWithoutChild();
private Padding GetPadding(Element child) private Padding GetPadding(TestPlan plan)
{ {
return new Padding() return new Padding()
{ {
Top = 5, Top = 10,
Right = 10, Right = 20,
Bottom = 15, Bottom = 30,
Left = 20, Left = 40,
Child = child Child = plan.CreateChild()
}; };
} }
[Test] [Test]
public void Measure_WhenChildReturnsWrap_ReturnsWrap() public void Measure_General_EnoughSpace()
{ {
var child = new Mock<Element>(); TestPlan
.For(GetPadding)
child .MeasureElement(new Size(400, 300))
.Setup(x => x.Measure(It.IsAny<Size>())) .ExpectChildMeasure(new Size(340, 260), new FullRender(140, 60))
.Returns(() => new Wrap()); .CheckMeasureResult(new FullRender(200, 100));
}
GetPadding(child.Object)
.Measure(Size.Zero) [Test]
.Should() public void Measure_NotEnoughWidth()
.BeOfType<Wrap>(); {
TestPlan
.For(GetPadding)
.MeasureElement(new Size(50, 300))
.CheckMeasureResult(new Wrap());
} }
[Test] [Test]
public void Measure_WhenChildReturnsFullRender_ReturnsFullRender() public void Measure_NotEnoughHeight()
{ {
var child = new Mock<Element>(); TestPlan
.For(GetPadding)
child .MeasureElement(new Size(20, 300))
.Setup(x => x.Measure(It.IsAny<Size>())) .CheckMeasureResult(new Wrap());
.Returns(() => new FullRender(Size.Zero));
GetPadding(child.Object)
.Measure(Size.Zero)
.Should()
.BeOfType<FullRender>();
} }
[Test] [Test]
public void Measure_WhenChildReturnsPartialRender_ReturnsPartialRender() public void Measure_AcceptsPartialRender()
{ {
var child = new Mock<Element>(); TestPlan
.For(GetPadding)
child .MeasureElement(new Size(400, 300))
.Setup(x => x.Measure(It.IsAny<Size>())) .ExpectChildMeasure(new Size(340, 260), new PartialRender(40, 160))
.Returns(() => new PartialRender(Size.Zero)); .CheckMeasureResult(new PartialRender(100, 200));
}
GetPadding(child.Object)
.Measure(Size.Zero) [Test]
.Should() public void Measure_AcceptsWrap()
.BeOfType<PartialRender>(); {
TestPlan
.For(GetPadding)
.MeasureElement(new Size(400, 300))
.ExpectChildMeasure(new Size(340, 260), new Wrap())
.CheckMeasureResult(new Wrap());
}
[Test]
public void Draw_General()
{
TestPlan
.For(GetPadding)
.DrawElement(new Size(400, 300))
.ExpectCanvasTranslate(new Position(40, 10))
.ExpectChildDraw(new Size(340, 260))
.ExpectCanvasTranslate(new Position(-40, -10))
.CheckDrawResult();
} }
} }
} }

Просмотреть файл

@ -1,10 +0,0 @@
using NUnit.Framework;
namespace QuestPDF.UnitTests
{
[TestFixture]
public class PlaceholderTests
{
}
}

Просмотреть файл

@ -42,7 +42,7 @@ namespace QuestPDF.UnitTests
TestPlan TestPlan
.For(x => new ShowOnce() .For(x => new ShowOnce()
{ {
Child = x.CreateChild("child") Child = x.CreateChild()
}) })
// Measure the element and return result // Measure the element and return result
@ -52,21 +52,21 @@ namespace QuestPDF.UnitTests
// Draw element partially // Draw element partially
.DrawElement(new Size(200, 200)) .DrawElement(new Size(200, 200))
.ExpectChildMeasure("child", new Size(200, 200), new PartialRender(new Size(200, 200))) .ExpectChildMeasure(new Size(200, 200), new PartialRender(new Size(200, 200)))
.ExpectChildDraw("child", new Size(200, 200)) .ExpectChildDraw(new Size(200, 200))
.CheckDrawResult() .CheckDrawResult()
// Element was not fully drawn // Element was not fully drawn
// It should be measured again for rendering on next page // It should be measured again for rendering on next page
.MeasureElement(new Size(800, 200)) .MeasureElement(new Size(800, 200))
.ExpectChildMeasure("child", new Size(800, 200), new FullRender(new Size(400, 200))) .ExpectChildMeasure(new Size(800, 200), new FullRender(new Size(400, 200)))
.CheckMeasureResult(new FullRender(new Size(400, 200))) .CheckMeasureResult(new FullRender(new Size(400, 200)))
// Draw element on next page // Draw element on next page
// Element was fully drawn at this point // Element was fully drawn at this point
.DrawElement(new Size(400, 200)) .DrawElement(new Size(400, 200))
.ExpectChildMeasure("child", new Size(400, 200), new FullRender(new Size(400, 200))) .ExpectChildMeasure(new Size(400, 200), new FullRender(new Size(400, 200)))
.ExpectChildDraw("child", new Size(400, 200)) .ExpectChildDraw(new Size(400, 200))
.CheckDrawResult() .CheckDrawResult()
// In the next attempt of measuring element, it should behave like empty parent. // In the next attempt of measuring element, it should behave like empty parent.

Просмотреть файл

@ -10,6 +10,8 @@ namespace QuestPDF.UnitTests.TestEngine
{ {
internal class TestPlan internal class TestPlan
{ {
private const string DefaultChildName = "child";
private Element Element { get; set; } private Element Element { get; set; }
private ICanvas Canvas { get; } private ICanvas Canvas { get; }
@ -100,6 +102,8 @@ namespace QuestPDF.UnitTests.TestEngine
} }
}; };
} }
public Element CreateChild() => CreateChild(DefaultChildName);
public Element CreateChild(string id) public Element CreateChild(string id)
{ {
@ -153,11 +157,21 @@ namespace QuestPDF.UnitTests.TestEngine
return this; return this;
} }
public TestPlan ExpectChildMeasure(Size expectedInput, ISpacePlan returns)
{
return ExpectChildMeasure(DefaultChildName, expectedInput, returns);
}
public TestPlan ExpectChildMeasure(string child, Size expectedInput, ISpacePlan returns) public TestPlan ExpectChildMeasure(string child, Size expectedInput, ISpacePlan returns)
{ {
return AddOperation(new ChildMeasureOperationBase(child, expectedInput, returns)); return AddOperation(new ChildMeasureOperationBase(child, expectedInput, returns));
} }
public TestPlan ExpectChildDraw(Size expectedInput)
{
return ExpectChildDraw(DefaultChildName, expectedInput);
}
public TestPlan ExpectChildDraw(string child, Size expectedInput) public TestPlan ExpectChildDraw(string child, Size expectedInput)
{ {
return AddOperation(new ChildDrawOperationBase(child, expectedInput)); return AddOperation(new ChildDrawOperationBase(child, expectedInput));

Просмотреть файл

@ -14,15 +14,26 @@ namespace QuestPDF.Elements
if(Child == null) if(Child == null)
return new FullRender(Size.Zero); return new FullRender(Size.Zero);
var size = GetTargetSize(availableSpace); var targetSize = GetTargetSize(availableSpace);
if (size.Height > availableSpace.Height + Size.Epsilon) if (targetSize.Height > availableSpace.Height + Size.Epsilon)
return new Wrap(); return new Wrap();
if (size.Width > availableSpace.Width + Size.Epsilon) if (targetSize.Width > availableSpace.Width + Size.Epsilon)
return new Wrap(); return new Wrap();
var childSize = Child.Measure(targetSize);
if (childSize is Wrap)
return new Wrap();
if (childSize is PartialRender)
return new PartialRender(targetSize);
if (childSize is FullRender)
return new FullRender(targetSize);
return new FullRender(size); throw new NotSupportedException();
} }
internal override void Draw(ICanvas canvas, Size availableSpace) internal override void Draw(ICanvas canvas, Size availableSpace)

Просмотреть файл

@ -11,9 +11,6 @@ namespace QuestPDF.Elements
internal override ISpacePlan Measure(Size availableSpace) internal override ISpacePlan Measure(Size availableSpace)
{ {
if (availableSpace.Width < 0 || availableSpace.Height < 0)
return new Wrap();
return new FullRender(availableSpace.Width, availableSpace.Height); return new FullRender(availableSpace.Width, availableSpace.Height);
} }

Просмотреть файл

@ -17,6 +17,10 @@ namespace QuestPDF.Elements
return new FullRender(Size.Zero); return new FullRender(Size.Zero);
var internalSpace = InternalSpace(availableSpace); var internalSpace = InternalSpace(availableSpace);
if (internalSpace.Width <= 0 || internalSpace.Height <= 0)
return new Wrap();
var measure = Child.Measure(internalSpace) as Size; var measure = Child.Measure(internalSpace) as Size;
if (measure == null) if (measure == null)

Просмотреть файл

@ -14,8 +14,6 @@ namespace QuestPDF.Elements
public void Compose(IContainer container) public void Compose(IContainer container)
{ {
// TODO: consider moving this element into fluent API
container container
.Background("CCC") .Background("CCC")
.AlignMiddle() .AlignMiddle()

Просмотреть файл

@ -48,45 +48,7 @@ namespace QuestPDF.Fluent
{ {
return parent.Element(new Debug()); return parent.Element(new Debug());
} }
public static void Image(this IContainer parent, byte[] data, ImageScaling scaling = ImageScaling.FitWidth)
{
if (data == null)
return;
var image = SKImage.FromEncodedData(data);
var aspectRatio = image.Width / (float)image.Height;
var imageElement = new Image
{
InternalImage = image
};
if (scaling != ImageScaling.Resize)
parent = parent.AspectRatio(aspectRatio, Map(scaling));
parent.Element(imageElement);
static AspectRatioOption Map(ImageScaling scaling)
{
return scaling switch
{
ImageScaling.FitWidth => AspectRatioOption.FitWidth,
ImageScaling.FitHeight => AspectRatioOption.FitHeight,
ImageScaling.FitArea => AspectRatioOption.FitArea,
_ => throw new ArgumentOutOfRangeException()
};
}
}
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

Просмотреть файл

@ -0,0 +1,48 @@
using System;
using QuestPDF.Elements;
using QuestPDF.Infrastructure;
using SkiaSharp;
namespace QuestPDF.Fluent
{
public static class ImageExtensions
{
public static void Image(this IContainer parent, byte[] data, ImageScaling scaling = ImageScaling.FitWidth)
{
if (data == null)
return;
var image = SKImage.FromEncodedData(data);
var aspectRatio = image.Width / (float)image.Height;
var imageElement = new Image
{
InternalImage = image
};
if (scaling != ImageScaling.Resize)
parent = parent.AspectRatio(aspectRatio, Map(scaling));
parent.Element(imageElement);
static AspectRatioOption Map(ImageScaling scaling)
{
return scaling switch
{
ImageScaling.FitWidth => AspectRatioOption.FitWidth,
ImageScaling.FitHeight => AspectRatioOption.FitHeight,
ImageScaling.FitArea => AspectRatioOption.FitArea,
_ => throw new ArgumentOutOfRangeException()
};
}
}
public static void DynamicImage(this IContainer element, Func<Size, byte[]> imageSource)
{
element.Element(new DynamicImage
{
Source = imageSource
});
}
}
}