Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Source/HtmlRenderer/Core/Dom/CssBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,7 @@ protected virtual void PerformLayoutImp(RGraphics g)
// Shrink-to-fit, CSS 2.1 §10.3.5 and §10.3.7. GetMinMaxWidth already includes the
// padding and border.
double minWidth, maxWidth;
MeasureDescendantWordsSize(g);
GetMinMaxWidth(out minWidth, out maxWidth);
width = Math.Min(Math.Max(minWidth, width), maxWidth);
}
Expand Down Expand Up @@ -1111,6 +1112,18 @@ internal virtual void MeasureWordsSize(RGraphics g)
}
}

/// <summary>
/// Measures the words of all descendants, which <see cref="GetMinMaxWidth"/> needs before their own layout ran.
/// </summary>
internal void MeasureDescendantWordsSize(RGraphics g)
{
foreach (var childBox in Boxes)
{
childBox.MeasureWordsSize(g);
childBox.MeasureDescendantWordsSize(g);
}
}

/// <summary>
/// Get the parent of this css properties instance.
/// </summary>
Expand Down
19 changes: 1 addition & 18 deletions Source/HtmlRenderer/Core/Dom/CssLayoutEngineTable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public static void PerformLayout(RGraphics g, CssBox tableBox)
/// </summary>
private void Layout(RGraphics g)
{
MeasureWords(_tableBox, g);
_tableBox.MeasureDescendantWordsSize(g);

// get the table boxes into the proper fields
AssignBoxKinds();
Expand Down Expand Up @@ -890,23 +890,6 @@ private static bool RowHasCellSpanningIntoSubsequentRow(CssBox row, int currentr
return false;
}

/// <summary>
/// Recursively measures words inside the box
/// </summary>
/// <param name="box">the box to measure</param>
/// <param name="g">Device to use</param>
private static void MeasureWords(CssBox box, RGraphics g)
{
if (box != null)
{
foreach (var childBox in box.Boxes)
{
childBox.MeasureWordsSize(g);
MeasureWords(childBox, g);
}
}
}

/// <summary>
/// Tells if the columns widths can be reduced,
/// by checking the minimum widths of all cells
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,6 @@ public void Float_WithAutoMargins_HasZeroMargins()
Assert.AreEqual(50, f.Size.Width, Delta);
}

[Ignore("Gap, see Spec/css21.yml")]
[TestMethod]
[Spec("css21", "visudet.html#float-width")]
[Spec("css-sizing-3", "#intrinsic-sizes")]
Expand All @@ -210,6 +209,29 @@ public void AutoWidthFloat_ShrinksToFitItsContent()
Assert.AreEqual(words[0].Top, words[^1].Top, Delta);
}

[TestMethod]
[Spec("css21", "visudet.html#float-width")]
public void AutoWidthFloat_IsSizedByTheFirstLayout()
{
var (root, container) = LayoutHarness.Layout(LayoutHarness.Wrap(
"<div style='overflow:hidden;border:1px solid blue'>" +
"<div id='f' style='float:left;font-size:56px;margin-right:24px'>8.6</div>" +
"<p id='p'>line one</p><p>line two</p></div>"), maxWidth: 400);
var f = Box(root, "f");
var words = LayoutHarness.Descendants(f).SelectMany(b => b.Words).ToList();
var size = container.ActualSize;

Assert.AreEqual(words[^1].Right - words[0].Left, f.Size.Width, 1);
Assert.AreEqual(1, f.Location.X, Delta);
Assert.AreEqual(f.ActualRight + 24, FirstWord(Box(root, "p"))!.Left, 1);

// Another layout pass must not change anything
LayoutHarness.PerformLayout(container);

Assert.AreEqual(size.Width, container.ActualSize.Width, Delta);
Assert.AreEqual(size.Height, container.ActualSize.Height, Delta);
}

[TestMethod]
[Spec("css21", "visudet.html#float-replaced-width")]
public void FloatedImage_KeepsItsIntrinsicWidth()
Expand Down Expand Up @@ -255,7 +277,6 @@ public void Absolute_WithLeftAndRight_StretchesTheAutoWidth()
Assert.AreEqual(160, a.Size.Width, Delta);
}

[Ignore("Gap, see Spec/css21.yml")]
[TestMethod]
[Spec("css21", "visudet.html#abs-non-replaced-width")]
[Spec("css-position-3", "#abs-non-replaced-width")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,22 @@ internal static (CssBox Root, HtmlContainerInt Container) Layout(
prepare(container.Root!);
}

using var bitmap = new Bitmap(1, 1, PixelFormat.Format32bppArgb);
using var g = Graphics.FromImage(bitmap);
using var graphics = new GraphicsAdapter(g, false);
container.PerformLayout(graphics);
PerformLayout(container);

Assert.IsNotNull(container.Root);

return (container.Root!, container);
}

/// <summary>Runs one layout pass of <paramref name="container"/>, e.g. a second one after <see cref="Layout"/>.</summary>
internal static void PerformLayout(HtmlContainerInt container)
{
using var bitmap = new Bitmap(1, 1, PixelFormat.Format32bppArgb);
using var g = Graphics.FromImage(bitmap);
using var graphics = new GraphicsAdapter(g, false);
container.PerformLayout(graphics);
}

/// <summary>Wraps a body fragment in a minimal document, so a test can state only the markup it cares about.</summary>
internal static string Wrap(string body) => $"<html><head></head><body style='margin:0'>{body}</body></html>";

Expand Down
1 change: 0 additions & 1 deletion Spec/css-position-3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ sections:
status: partial
gaps:
- With both insets set, an auto size is its content size instead of the stretch-fit size
- The fit-content width is computed before the content is measured, see CSS 2.1 10.3.7
'#abspos-margins':
title: 4.2 Auto Margins of Absolutely-Positioned Boxes
status: partial
Expand Down
1 change: 0 additions & 1 deletion Spec/css-sizing-3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ sections:
title: 5.1 Intrinsic Sizes
status: partial
gaps:
- The fit-content width of an auto width float is computed before its content is measured, see CSS 2.1 10.3.5
- An auto width inline-block wider than the line wraps across lines instead of shrinking, see CSS 2.1 10.3.9
'#intrinsic-contribution':
title: 5.2 Intrinsic Contributions
Expand Down
2 changes: 1 addition & 1 deletion Spec/css-sizing-4.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ sections:
title: 5.1 Intrinsic Sizes
status: partial
gaps:
- Floats and inline-blocks aren't sized to their content as specified, see css-sizing-3 5.1
- Inline-blocks aren't sized to their content as specified, see css-sizing-3 5.1
'#intrinsic-size-override':
title: '5.2 Overriding Contained Intrinsic Sizes: the contain-intrinsic-* properties'
status: parsed-only
Expand Down
5 changes: 1 addition & 4 deletions Spec/css21.yml
Original file line number Diff line number Diff line change
Expand Up @@ -503,9 +503,7 @@ sections:
- Auto margins compute to 0, a block image is never centered by them
visudet.html#float-width:
title: 10.3.5 Floating, non-replaced elements
status: partial
gaps:
- The shrink-to-fit width of an auto width float is computed before its content is measured, on the first layout it's 0 or NaN and the text wraps after every word
status: supported
visudet.html#float-replaced-width:
title: 10.3.6 Floating, replaced elements
status: supported
Expand All @@ -514,7 +512,6 @@ sections:
status: partial
gaps:
- With 'left' and 'right' set, an auto width is 0 instead of filling the space between them
- The shrink-to-fit width of an auto width box is computed before its content is measured, on the first layout it's 0 or NaN
- With 'left', 'right' and 'width' set, auto margins compute to 0 instead of centering the box
- With 'left' and 'right' auto, the box is placed at the containing block's content edge instead of its static position
visudet.html#abs-replaced-width:
Expand Down
Loading