diff --git a/src/Engine/Draw/Layout/SkiaLayout.ColumnRow.cs b/src/Engine/Draw/Layout/SkiaLayout.ColumnRow.cs
index 666e1a45..2c6e4b23 100644
--- a/src/Engine/Draw/Layout/SkiaLayout.ColumnRow.cs
+++ b/src/Engine/Draw/Layout/SkiaLayout.ColumnRow.cs
@@ -49,6 +49,7 @@ void LayoutCell(ScaledSize measured, ControlInStack cell, SkiaControl child, flo
{
if (!measured.IsEmpty)
{
+
child.Arrange(cell.Area, measured.Units.Width, measured.Units.Height, scale);
var maybeArranged = child.Destination;
@@ -73,7 +74,13 @@ void LayoutCell(ScaledSize measured, ControlInStack cell, SkiaControl child, flo
}
}
-
+ ///
+ /// Cell.Area contains the area for layout
+ ///
+ ///
+ ///
+ ///
+ public record SecondPassArrange(ControlInStack Cell, SkiaControl Child, float Scale);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected float GetSpacingForIndex(int forIndex, float scale)
@@ -291,6 +298,10 @@ public virtual ScaledSize MeasureStack(SKRect rectForChildrenPixels, float scale
template = ChildrenFactory.GetTemplateInstance();
}
+ var maybeSecondPass = Type == LayoutType.Row &&
+ (float.IsInfinity(rectForChild.Bottom) || float.IsInfinity(rectForChild.Top));
+ List listSecondPass = new();
+
//measure
//left to right, top to bottom
for (var row = 0; row < layoutStructure.MaxRows; row++)
@@ -380,6 +391,18 @@ public virtual ScaledSize MeasureStack(SKRect rectForChildrenPixels, float scale
else
{
measured = MeasureAndArrangeCell(rectFitChild, cell, child, scale);
+ if (maybeSecondPass) //has infinity in destination
+ {
+ if (Type == LayoutType.Column && child.HorizontalOptions != LayoutOptions.Start)
+ {
+ listSecondPass.Add(new(cell, child, scale));
+ }
+ else
+ if (Type == LayoutType.Row && child.VerticalOptions != LayoutOptions.Start)
+ {
+ listSecondPass.Add(new(cell, child, scale));
+ }
+ }
}
if (!measured.IsEmpty)
@@ -412,6 +435,33 @@ public virtual ScaledSize MeasureStack(SKRect rectForChildrenPixels, float scale
}//end of iterate rows
+ //second layout pass for if we had infinity
+ foreach (var secondPass in listSecondPass)
+ {
+ if (float.IsInfinity(secondPass.Cell.Area.Bottom))
+ {
+ secondPass.Cell.Area = new(secondPass.Cell.Area.Left, secondPass.Cell.Area.Top, secondPass.Cell.Area.Right, secondPass.Cell.Area.Top + stackHeight);
+ }
+ else
+ if (float.IsInfinity(secondPass.Cell.Area.Top))
+ {
+ secondPass.Cell.Area = new(secondPass.Cell.Area.Left, secondPass.Cell.Area.Bottom - stackHeight, secondPass.Cell.Area.Right, secondPass.Cell.Area.Bottom);
+ }
+
+ if (float.IsInfinity(secondPass.Cell.Area.Right))
+ {
+ secondPass.Cell.Area = new(secondPass.Cell.Area.Left, secondPass.Cell.Area.Top, secondPass.Cell.Area.Left + stackWidth, secondPass.Cell.Area.Bottom);
+ }
+ else
+ if (float.IsInfinity(secondPass.Cell.Area.Left))
+ {
+ secondPass.Cell.Area = new(secondPass.Cell.Area.Right - stackWidth, secondPass.Cell.Area.Top, secondPass.Cell.Area.Right, secondPass.Cell.Area.Bottom);
+ }
+
+ LayoutCell(secondPass.Child.MeasuredSize, secondPass.Cell, secondPass.Child, secondPass.Scale);
+ }
+
+
if (IsTemplated && useOneTemplate)
{
ChildrenFactory.ReleaseView(template);
@@ -529,325 +579,6 @@ bool ProcessStructure(int i, SkiaControl control)
return structure;
}
- //2 passes for FILL LAYOUT OPTIONS
- //not using this as fps drops
- /*
- case LayoutType.Column:
- case LayoutType.Row:
-
- if (ViewsMaster.GetChildrenCount() > 0)
- {
- float AddSpacing(int pos)
- {
- var spacing = 0.0f;
- if (pos > 0)
- {
- spacing = (float)(Spacing * scale);
- }
- return spacing;
- }
-
- SKRect rectForChild = rectForChildrenPixels.Clone();
-
- var column = 0;
- var row = 0;
- var rows = new List>();
- var columns = new List();
- int maxColumns = MaxColumns; // New MaxColumns property
- int maxRows = MaxRows; // New MaxRows property
-
- for (int index = 0; index < ViewsMaster.GetChildrenCount(); index++)
- {
- // vertical stack or if maxColumns is exceeded
- if (Type == LayoutType.Column && maxColumns < 1 || (maxColumns > 0 && column >= maxColumns) || LineBreaks.Contains(index))
- {
- if (index > 0)
- {
- //insert a vbreak between all children
- rows.Add(columns);
- columns = new();
- column = 0;
- row++;
- }
- }
-
- // If maxRows is reached and exceeded, break the loop
- if (maxRows > 0 && row >= maxRows)
- {
- break;
- }
-
- columns.Add(new ControlInStack { ControlIndex = index });
- column++;
- }
-
- rows.Add(columns);
- StackStructure = rows;
-
- SkiaControl template = null;
- if (IsTemplated)
- {
- template = ViewsMaster.GetTemplateInstance();
- }
-
- var stackHeight = 0.0f;
- var stackWidth = 0.0f;
- var maxHeight = 0.0f;
- var maxWidth = 0.0f;
- bool hasFills = false;
-
- var takenHeight = 0f;
- var takenWidth = 0f;
-
- //PASS 1
- for (row = 0; row < rows.Count; row++)
- {
- maxHeight = 0.0f; //max row height
- rectForChild.Top += AddSpacing(row);
-
- stackWidth = 0.0f;
- var columnsCount = rows[row].Count;
-
- if (!DynamicColumns && columnsCount < maxColumns)
- {
- columnsCount = Math.Min(1, MaxColumns);
- }
-
- var widthPerColumn = (float)(columnsCount > 1 ?
- (rectForChildrenPixels.Width - (columnsCount - 1) * Spacing * scale) / columnsCount :
- rectForChildrenPixels.Width);
-
- for (column = 0; column < columnsCount; column++)
- {
- rectForChild.Left += AddSpacing(column);
-
- var rectFitChild = new SKRect(rectForChild.Left, rectForChild.Top, rectForChild.Left + widthPerColumn, rectForChild.Bottom);
-
- var cell = rows[row][column];
-
- var child = ViewsMaster.GetChildAt(cell.ControlIndex, template);
-
- //Trace.WriteLine($"[PASS 1] LAYOUT - {child.Tag}");
-
- if (child == null)
- {
- ContentSize = ScaledSize.FromPixels(rectForChildrenPixels.Width, rectForChildrenPixels.Height, scale);
- widthConstraint = AdaptWidthContraintToContentRequest(widthConstraint, ContentSize, constraintLeft + constraintRight);
- heightConstraint = AdaptHeightContraintToContentRequest(heightConstraint, ContentSize, constraintTop + constraintBottom);
- return SetMeasured(widthConstraint, heightConstraint, scale);
- }
- else
- {
- //reset calculated stuff as this might be a template being reused
- if (child is SkiaControl control)
- {
- control.InvalidateInternal();
- }
- }
-
- if (
- (Type == LayoutType.Row && child.HorizontalOptions.Alignment == LayoutAlignment.Fill && child.WidthRequest < 0)
- ||
- (Type == LayoutType.Column && child.VerticalOptions.Alignment == LayoutAlignment.Fill && child.HeightRequest < 0)
- )
- {
- hasFills = true;
- cell.Tmp = rectFitChild;
- cell.Expands = true;
- continue;
- }
-
- cell.Expands = false;
-
- var measured = MeasureChild(child,
- rectFitChild.Width, rectFitChild.Height,
- scale);
-
- cell.Measured = ScaledSize.FromPixels(measured, scale);
-
- if (measured != SKSize.Empty)
- {
- child.Arrange(rectFitChild, measured.Width, measured.Height, scale);
-
- var maybeArranged = child.Destination;
-
- var arranged = new SKRect(rectFitChild.Left, rectFitChild.Top,
- rectFitChild.Left + cell.Measured.Pixels.Width,
- rectFitChild.Top + cell.Measured.Pixels.Height);
-
- if (float.IsNormal(maybeArranged.Height))
- {
- arranged.Top = maybeArranged.Top;
- arranged.Bottom = maybeArranged.Bottom;
- }
- if (float.IsNormal(maybeArranged.Width))
- {
- arranged.Left = maybeArranged.Left;
- arranged.Right = maybeArranged.Right;
- }
-
- cell.Destination = arranged;
-
- var width = measured.Width;
- var height = measured.Height;
-
- stackWidth += width + AddSpacing(column);
-
- if (measured.Height > maxHeight)
- maxHeight = height;
-
- //offset -->
- rectForChild.Left += (float)(width);
- }
-
- }//end of iterate columns
-
- if (stackWidth > maxWidth)
- maxWidth = stackWidth;
-
- stackHeight += maxHeight + AddSpacing(row);
- rectForChild.Top += (float)(maxHeight);
-
- rectForChild.Left = 0; //reset to start
-
- }//end of iterate rows
-
- //PASS 2
- if (hasFills)
- {
- rectForChild = rectForChildrenPixels.Clone();
-
- var offsetMoveY = 0f;
-
- for (row = 0; row < rows.Count; row++)
- {
- var offsetMoveX = 0f;
-
- rectForChild.Top += AddSpacing(row);
- stackWidth = 0.0f;
- maxHeight = 0.0f;
-
- var columnsCount = rows[row].Count;
-
- if (!DynamicColumns && columnsCount < maxColumns)
- {
- columnsCount = Math.Min(1, MaxColumns);
- }
-
- var widthPerColumn = (float)(columnsCount > 1 ?
- (rectForChildrenPixels.Width - (columnsCount - 1) * Spacing * scale) / columnsCount :
- rectForChildrenPixels.Width);
-
- for (column = 0; column < columnsCount; column++)
- {
-
- var cell = rows[row][column];
-
- var child = ViewsMaster.GetChildAt(cell.ControlIndex, template);
-
- if (!cell.Expands)
- {
- if (offsetMoveY > 0 || offsetMoveX > 0)
- {
- //newly filled made us move
- var itBecaime = new SKRect(cell.Destination.Left + offsetMoveX, cell.Destination.Top + offsetMoveY,
- cell.Destination.Right + offsetMoveX, cell.Destination.Bottom + offsetMoveY);
- cell.Destination = itBecaime;
- }
- rectForChild.Left += cell.Measured.Pixels.Width + AddSpacing(column);
-
- //usual end of row
- stackWidth += cell.Measured.Pixels.Width + AddSpacing(column);
- maxHeight = cell.Measured.Pixels.Height;
- continue;
- }
-
- var availableWidth = rectForChildrenPixels.Width -
- (rectForChild.Left - rectForChildrenPixels.Left)
- - CalculateTakenWidthRight(row, column, (float)(Spacing * scale));
-
- var availableHeight = rectForChildrenPixels.Height -
- (rectForChild.Top - rectForChildrenPixels.Top)
- - CalculateTakenHeightBelow(row, (float)(Spacing * scale));
-
- //Trace.WriteLine($"[PASS 2] LAYOUT - {child.Tag}");
-
- var measured = MeasureChild(child,
- availableWidth, availableHeight, scale);
-
- cell.Measured = ScaledSize.FromPixels(measured, scale);
-
- if (measured != SKSize.Empty)
- {
- //child.InvalidateChildren();
- child.Arrange(new SKRect(rectForChild.Left, rectForChild.Top, rectForChild.Left + availableWidth, rectForChild.Top + availableHeight),
- measured.Width, measured.Height, scale);
-
- //child.InvalidateChildren();
-
- var maybeArranged = child.Destination;
-
- var arranged = new SKRect(cell.Tmp.Left, cell.Tmp.Top,
- cell.Tmp.Left + cell.Measured.Pixels.Width,
- cell.Tmp.Top + cell.Measured.Pixels.Height);
-
- if (float.IsNormal(maybeArranged.Height))
- {
- arranged.Top = maybeArranged.Top;
- arranged.Bottom = maybeArranged.Bottom;
- }
- if (float.IsNormal(maybeArranged.Width))
- {
- arranged.Left = maybeArranged.Left;
- arranged.Right = maybeArranged.Right;
- }
-
- cell.Destination = arranged;
-
- var width = measured.Width;
- var height = measured.Height;
-
- offsetMoveY += height;
- offsetMoveX += width;
-
- stackWidth += width + AddSpacing(column);
-
- if (measured.Height > maxHeight)
- maxHeight = height;
-
- //offset -->
- rectForChild.Left += (float)(width);
- }
- }//end of iterate columns
-
- if (stackWidth > maxWidth)
- maxWidth = stackWidth;
-
- stackHeight += maxHeight + AddSpacing(row);
- rectForChild.Top += (float)(maxHeight);
- rectForChild.Left = 0; //reset to start
-
- }//end of iterate rows
-
- }
-
- if (IsTemplated)
- {
- ViewsMaster.ReleaseView(template);
- }
-
- ContentSize = ScaledSize.FromPixels(maxWidth, stackHeight, scale);
-
- widthConstraint = AdaptWidthContraintToContentRequest(widthConstraint, ContentSize, constraintLeft + constraintRight);
- heightConstraint = AdaptHeightContraintToContentRequest(heightConstraint, ContentSize, constraintBottom + constraintTop);
-
- childrenmeasured = true;
- }
-
- break;
- */
-
-
#endregion
}
diff --git a/src/Engine/Draw/SkiaControl.cs b/src/Engine/Draw/SkiaControl.cs
index 2cd60e0e..71c86cf9 100644
--- a/src/Engine/Draw/SkiaControl.cs
+++ b/src/Engine/Draw/SkiaControl.cs
@@ -4731,7 +4731,8 @@ public CachedObject RenderObjectPrevious
{
var kill = _renderObjectPrevious;
_renderObjectPrevious = value;
- kill?.Dispose();
+ if (kill != null && UsingCacheType != SkiaCacheType.Image && UsingCacheType == SkiaCacheType.ImageComposite)
+ DisposeObject(kill);
}
}
}
@@ -5009,9 +5010,17 @@ protected virtual bool UseRenderingObject(SkiaDrawingContext context, SKRect rec
if (RenderObjectPrevious != null && RenderObjectPreviousNeedsUpdate)
{
- DisposeObject(RenderObjectPrevious);
+ var kill = RenderObjectPrevious;
RenderObjectPrevious = null;
RenderObjectPreviousNeedsUpdate = false;
+ if (kill != null)
+ {
+
+ Tasks.StartDelayed(TimeSpan.FromSeconds(3.5), () =>
+ {
+ kill.Dispose();
+ });
+ }
}
if (cache != null)
@@ -5555,7 +5564,10 @@ protected void CreateRenderingObjectAndPaint(
}
if (usingCacheType != SkiaCacheType.ImageDoubleBuffered && usingCacheType != SkiaCacheType.ImageComposite)
{
- oldObject.Dispose();
+ Tasks.StartDelayed(TimeSpan.FromSeconds(3.5), () =>
+ {
+ oldObject.Dispose();
+ });
}
}
diff --git a/src/Engine/Draw/Text/SkiaLabel.cs b/src/Engine/Draw/Text/SkiaLabel.cs
index 10d73f11..14d714a5 100644
--- a/src/Engine/Draw/Text/SkiaLabel.cs
+++ b/src/Engine/Draw/Text/SkiaLabel.cs
@@ -454,34 +454,34 @@ public override ScaledSize Measure(float widthConstraint, float heightConstraint
if (IsDisposed || IsDisposing)
return ScaledSize.Default;
- ReplaceFont();
-
//background measuring or invisible or self measure from draw because layout will never pass -1
if (IsMeasuring || !CanDraw || (widthConstraint < 0 || heightConstraint < 0))
{
return MeasuredSize;
}
- var request = CreateMeasureRequest(widthConstraint, heightConstraint, scale);
- if (request.IsSame)
+ IsMeasuring = true;
+
+ try
{
- return MeasuredSize;
- }
+ var request = CreateMeasureRequest(widthConstraint, heightConstraint, scale);
+ if (request.IsSame)
+ {
+ return MeasuredSize;
+ }
- SetupDefaultPaint(scale);
+ ReplaceFont();
- if (PaintDefault.Typeface == null)
- {
- UpdateFont();
- return MeasuredSize;
- }
+ SetupDefaultPaint(scale);
- var constraints = GetMeasuringConstraints(request);
+ if (PaintDefault.Typeface == null)
+ {
+ UpdateFont();
+ return MeasuredSize;
+ }
- IsMeasuring = true;
+ var constraints = GetMeasuringConstraints(request);
- try
- {
var textWidthPixels = 0f;
var textHeightPixels = 0f;
@@ -745,13 +745,13 @@ public override void OnDisposing()
_spans.CollectionChanged -= OnCollectionChanged;
- PaintDefault.Typeface = null; //preserve cached font from disposing
+ PaintDefault.Typeface = SKTypeface.Default; //preserve cached font from disposing
PaintDefault.Dispose();
- PaintStroke.Typeface = null; //preserve cached font from disposing
+ PaintStroke.Typeface = SKTypeface.Default; //preserve cached font from disposing
PaintStroke.Dispose();
- PaintShadow.Typeface = null; //preserve cached font from disposing
+ PaintShadow.Typeface = SKTypeface.Default; //preserve cached font from disposing
PaintShadow.Dispose();
PaintDeco.Dispose();
@@ -1458,9 +1458,10 @@ protected virtual async void UpdateFont()
protected void ReplaceFont()
{
- if (_replaceFont != null)
+ var newFont = _replaceFont;
+ if (newFont != null)
{
- TypeFace = _replaceFont;
+ TypeFace = newFont;
_replaceFont = null;
OnFontUpdated();
}
@@ -1811,12 +1812,14 @@ public static SKShaper.Result GetShapedText(SKShaper shaper, string text, float
if (paint == null)
throw new ArgumentNullException(nameof(paint));
- using var font = paint.ToFont();
+ var font = paint.ToFont();
+
if (font != null && shaper.Typeface != null)
{
font.Typeface = shaper.Typeface;
// shape the text
var result = shaper.Shape(text, x, y, paint);
+
return result;
}
@@ -1883,7 +1886,7 @@ public static bool IsGlyphAlwaysAvailable(string glyphText)
if (needsShaping)
{
- using var shaper = new SKShaper(paint.Typeface);
+ var shaper = new SKShaper(paint.Typeface);
var result = GetShapedText(shaper, text, 0, 0, paint);
if (result == null)
{
@@ -2747,7 +2750,7 @@ public int FontWeight
nameof(TypeFace),
typeof(SKTypeface),
typeof(SkiaLabel),
- defaultValue: null,
+ defaultValue: SKTypeface.Default,
propertyChanged: NeedUpdateFont);
public SKTypeface TypeFace
diff --git a/src/Engine/Draw/Text/TextSpan.cs b/src/Engine/Draw/Text/TextSpan.cs
index 7041d385..df823ec5 100644
--- a/src/Engine/Draw/Text/TextSpan.cs
+++ b/src/Engine/Draw/Text/TextSpan.cs
@@ -109,11 +109,21 @@ public SKPaint SetupPaint(double scale, SKPaint defaultPaint)
if (HasSetFont || AutoFindFont || defaultPaint == null)
{
- Paint.Typeface = TypeFace;
+ if (TypeFace != null)
+ {
+ Paint.Typeface = TypeFace;
+ }
+ else
+ {
+ Paint.Typeface = SKTypeface.Default;
+ }
}
else
{
- Paint.Typeface = defaultPaint.Typeface;
+ if (defaultPaint.Typeface != null)
+ Paint.Typeface = defaultPaint.Typeface;
+ else
+ Paint.Typeface = SKTypeface.Default;
}
if (defaultPaint != null)
@@ -326,7 +336,7 @@ public virtual void Dispose()
if (Paint != null)
{
- Paint.Typeface = null; //do not sipose typeface that can be cached and reused
+ Paint.Typeface = SKTypeface.Default; //do not sipose typeface that can be cached and reused
Paint.Dispose();
}
@@ -466,7 +476,7 @@ void Invalidate()
private Color _backgroundColor = Colors.Transparent;
private Color _paragraphColor = Colors.Transparent;
private bool _autoFindFont;
- private SKTypeface _typeFace;
+ private SKTypeface _typeFace = SKTypeface.Default;
private bool _needShape;
public string FontFamily
diff --git a/src/Engine/Features/Fonts/SkiaFontManager.cs b/src/Engine/Features/Fonts/SkiaFontManager.cs
index ebadb8d6..a6e0c443 100644
--- a/src/Engine/Features/Fonts/SkiaFontManager.cs
+++ b/src/Engine/Features/Fonts/SkiaFontManager.cs
@@ -314,7 +314,7 @@ public SKTypeface GetEmbeededFont(string filename, Assembly assembly, string ali
{
if (stream == null)
- return null;
+ return SKTypeface.Default;
font = SKTypeface.FromStream(stream);
if (font != null)
@@ -326,6 +326,9 @@ public SKTypeface GetEmbeededFont(string filename, Assembly assembly, string ali
}
+ if (font == null)
+ font = SKTypeface.Default;
+
return font;
}