|
@@ -8,31 +8,32 @@ namespace QuestPDF.Drawing.Proxy;
|
|
|
|
|
|
|
|
internal static class Helpers
|
|
internal static class Helpers
|
|
|
{
|
|
{
|
|
|
- internal static Size? TryMeasureWithOverflow(this Element element, Size availableSpace)
|
|
|
|
|
|
|
+ internal static SpacePlan TryMeasureWithOverflow(this Element element, Size availableSpace)
|
|
|
{
|
|
{
|
|
|
return TryVerticalOverflow()
|
|
return TryVerticalOverflow()
|
|
|
?? TryHorizontalOverflow()
|
|
?? TryHorizontalOverflow()
|
|
|
- ?? TryUnconstrainedOverflow();
|
|
|
|
|
|
|
+ ?? TryUnconstrainedOverflow()
|
|
|
|
|
+ ?? SpacePlan.Wrap();
|
|
|
|
|
|
|
|
- Size? TryOverflow(Size targetSpace)
|
|
|
|
|
|
|
+ SpacePlan? TryOverflow(Size targetSpace)
|
|
|
{
|
|
{
|
|
|
var contentSize = element.Measure(targetSpace);
|
|
var contentSize = element.Measure(targetSpace);
|
|
|
return contentSize.Type == SpacePlanType.Wrap ? null : contentSize;
|
|
return contentSize.Type == SpacePlanType.Wrap ? null : contentSize;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Size? TryVerticalOverflow()
|
|
|
|
|
|
|
+ SpacePlan? TryVerticalOverflow()
|
|
|
{
|
|
{
|
|
|
var overflowSpace = new Size(availableSpace.Width, Size.Infinity);
|
|
var overflowSpace = new Size(availableSpace.Width, Size.Infinity);
|
|
|
return TryOverflow(overflowSpace);
|
|
return TryOverflow(overflowSpace);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Size? TryHorizontalOverflow()
|
|
|
|
|
|
|
+ SpacePlan? TryHorizontalOverflow()
|
|
|
{
|
|
{
|
|
|
var overflowSpace = new Size(Size.Infinity, availableSpace.Height);
|
|
var overflowSpace = new Size(Size.Infinity, availableSpace.Height);
|
|
|
return TryOverflow(overflowSpace);
|
|
return TryOverflow(overflowSpace);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Size? TryUnconstrainedOverflow()
|
|
|
|
|
|
|
+ SpacePlan? TryUnconstrainedOverflow()
|
|
|
{
|
|
{
|
|
|
var overflowSpace = new Size(Size.Infinity, Size.Infinity);
|
|
var overflowSpace = new Size(Size.Infinity, Size.Infinity);
|
|
|
return TryOverflow(overflowSpace);
|
|
return TryOverflow(overflowSpace);
|
|
@@ -53,9 +54,23 @@ internal static class Helpers
|
|
|
|
|
|
|
|
void Traverse(TreeNode<OverflowDebuggingProxy> element)
|
|
void Traverse(TreeNode<OverflowDebuggingProxy> element)
|
|
|
{
|
|
{
|
|
|
- if (element.Value.SpacePlanType is null or SpacePlanType.FullRender)
|
|
|
|
|
|
|
+ // before assessing the element,
|
|
|
|
|
+ // reset layout state by measuring the element with original space
|
|
|
|
|
+ // in case when parent has altered the layout state with different overflow test
|
|
|
|
|
+ element.Value.Measure(element.Value.MeasurementSize);
|
|
|
|
|
+
|
|
|
|
|
+ // element was not part of the current layout measurement,
|
|
|
|
|
+ // it could not impact the process
|
|
|
|
|
+ if (element.Value.SpacePlanType is null)
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ // element renders fully,
|
|
|
|
|
+ // it could not impact the process
|
|
|
|
|
+ if (element.Value.SpacePlanType is SpacePlanType.FullRender)
|
|
|
return;
|
|
return;
|
|
|
|
|
|
|
|
|
|
+ // when element is partially rendering, it likely has no issues,
|
|
|
|
|
+ // however, in certain cases, it may contain a child that is a root cause
|
|
|
if (element.Value.SpacePlanType is SpacePlanType.PartialRender)
|
|
if (element.Value.SpacePlanType is SpacePlanType.PartialRender)
|
|
|
{
|
|
{
|
|
|
foreach (var child in element.Children)
|
|
foreach (var child in element.Children)
|
|
@@ -64,36 +79,54 @@ internal static class Helpers
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // strategy: element wrap can be caused by any child that returned wrap
|
|
|
|
|
- if (element.Children.Any(x => x.Value.SpacePlanType == SpacePlanType.Wrap))
|
|
|
|
|
- {
|
|
|
|
|
- if (TryFixChildrenOfType(SpacePlanType.Wrap))
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // strategy: there could be more complex inner/hidden layout constraint issue,
|
|
|
|
|
- // if element cannot be successfully drawn on infinite canvas
|
|
|
|
|
- if (element.Value.TryMeasureWithOverflow(element.Value.MeasurementSize) == null)
|
|
|
|
|
|
|
+ // all of the code below relates to element that is wrapping,
|
|
|
|
|
+ // it could be root cause, or contain a child (even deeply nested) that is the root cause
|
|
|
|
|
+
|
|
|
|
|
+ // strategy
|
|
|
|
|
+ // element does not contain any wrapping elements, no obvious root causes,
|
|
|
|
|
+ // if it renders fully with extended space, it is a layout root cause
|
|
|
|
|
+ if (element.Children.All(x => x.Value.SpacePlanType is not SpacePlanType.Wrap) && MeasureElementWithExtendedSpace() is SpacePlanType.FullRender)
|
|
|
{
|
|
{
|
|
|
- if (TryFixChildrenOfType(SpacePlanType.PartialRender))
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ // so apply the layout overflow proxy
|
|
|
|
|
+ element.Value.CreateProxy(x => new LayoutOverflowVisualization { Child = x });
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // fixing children does not help, fix the element itself
|
|
|
|
|
- element.Value.RemoveExistingProxies();
|
|
|
|
|
- element.Value.CreateProxy(x => new LayoutOverflowVisualization { Child = x });
|
|
|
|
|
|
|
|
|
|
- bool TryFixChildrenOfType(SpacePlanType spacePlanType)
|
|
|
|
|
- {
|
|
|
|
|
- var suspectedChildren = element.Children.Where(x => x.Value.SpacePlanType == spacePlanType);
|
|
|
|
|
-
|
|
|
|
|
- if (!suspectedChildren.Any())
|
|
|
|
|
- return false;
|
|
|
|
|
|
|
+ // every time a measurement is made, the layout state is mutated
|
|
|
|
|
+ // the previous strategy could modify the layout state
|
|
|
|
|
+ // reset layout state by measuring the element with original space
|
|
|
|
|
+ element.Value.Measure(element.Value.MeasurementSize);
|
|
|
|
|
+
|
|
|
|
|
+ // strategy:
|
|
|
|
|
+ // element contains wrapping children, they are likely the root cause,
|
|
|
|
|
+ // traverse them and attempt to fix them
|
|
|
|
|
+ foreach (var child in element.Children.Where(x => x.Value.SpacePlanType is SpacePlanType.Wrap))
|
|
|
|
|
+ Traverse(child);
|
|
|
|
|
+
|
|
|
|
|
+ // check if fixing wrapping children helped
|
|
|
|
|
+ if (MeasureElementWithExtendedSpace() is not SpacePlanType.Wrap)
|
|
|
|
|
+ return;
|
|
|
|
|
|
|
|
- foreach (var child in suspectedChildren)
|
|
|
|
|
- Traverse(child);
|
|
|
|
|
|
|
+ // reset layout state by measuring the element with original space
|
|
|
|
|
+ element.Value.Measure(element.Value.MeasurementSize); // reset state
|
|
|
|
|
+
|
|
|
|
|
+ // strategy:
|
|
|
|
|
+ // element has layout issues but no obvious/trivial root causes
|
|
|
|
|
+ // possibly the problem is in nested children of partial rendering children
|
|
|
|
|
+ foreach (var child in element.Children.Where(x => x.Value.SpacePlanType is SpacePlanType.PartialRender))
|
|
|
|
|
+ Traverse(child);
|
|
|
|
|
+
|
|
|
|
|
+ // check if fixing partial children helped
|
|
|
|
|
+ if (MeasureElementWithExtendedSpace() is not SpacePlanType.Wrap)
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ // none of the attempts above have fixed the layout issue
|
|
|
|
|
+ // the element itself is the root cause
|
|
|
|
|
+ element.Value.CreateProxy(x => new LayoutOverflowVisualization { Child = x });
|
|
|
|
|
|
|
|
- return element.Value.TryMeasureWithOverflow(element.Value.MeasurementSize).HasValue;
|
|
|
|
|
|
|
+ SpacePlanType MeasureElementWithExtendedSpace()
|
|
|
|
|
+ {
|
|
|
|
|
+ return element.Value.TryMeasureWithOverflow(element.Value.MeasurementSize).Type;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|