Skip to content

Commit 4cfdf87

Browse files
authored
Merge pull request #17 from alfattack/page-break-inside
Re-perform layout on page break avoid
2 parents 2da1da5 + 179da6a commit 4cfdf87

File tree

3 files changed

+36
-16
lines changed

3 files changed

+36
-16
lines changed

Source/Demos/HtmlRenderer.Demo.Common/TestSamples/37. Breaking Pages 4 - Divs.htm

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@
1515
<div style="page-break-inside: avoid; height: 1500px; background-color: blue; padding: 10px;">
1616
This is on page 4.
1717

18-
<div style="height: 500px; background-color: yellow;">
18+
<div style="height: 200px; background-color: yellow;">
1919
This is also on page 4
2020
</div>
21-
<div style="height: 100px; background-color: brown; page-break-inside: avoid;">
22-
This is also on page 4.
23-
</div>
2421

25-
<div style="height: 700px; background-color: aqua; page-break-inside: avoid;">
22+
<div style="height: 300px; background-color: aqua; page-break-inside: avoid;">
23+
This is on page 4
24+
</div>
25+
<div style="height:400px; background-color: orangered; page-break-inside: avoid;">
2626
This is on page 5
2727
</div>
2828
</div>

Source/Demos/HtmlRenderer.Demo.Console/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
foreach (var htmlSample in samples)
2525
{
2626
////Just doing one test here. Comment this for all of them.
27-
if (!htmlSample.FullName.Contains("37")) continue;
27+
if (!htmlSample.FullName.Contains("37") && !htmlSample.FullName.Contains("34")) continue;
2828

2929
//await skia.GenerateSampleAsync(htmlSample);
3030
//await svgSkia.GenerateSampleAsync(htmlSample);

Source/HtmlRenderer/Core/Dom/CssBox.cs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ internal class CssBox : CssBoxProperties, IDisposable
7070
/// Flag that indicates that CssTable algorithm already made fixes on it.
7171
/// </remarks>
7272
internal bool _tableFixed;
73+
74+
/// <summary>
75+
/// Flag indicating that we're on a second pass for laying out the element after
76+
/// avoiding a page break.
77+
/// </summary>
78+
internal bool _pageBreakAvoided;
7379

7480
protected bool _wordsSizeMeasured;
7581
private CssBox _listItemBox;
@@ -651,7 +657,9 @@ protected virtual async Task PerformLayoutImpAsync(RGraphics g)
651657
Size = new RSize(width - ActualMarginLeft - ActualMarginRight, Size.Height);
652658
}
653659

654-
if (Display != CssConstants.TableCell)
660+
// Don't recalculate the element's position if we're
661+
// on our second pass after avoiding a page break.
662+
if (Display != CssConstants.TableCell && !_pageBreakAvoided)
655663
{
656664
double left;
657665
double top;
@@ -700,15 +708,6 @@ protected virtual async Task PerformLayoutImpAsync(RGraphics g)
700708
{
701709
this.BreakPage(true);
702710
}
703-
else if (this.PageBreakInside == CssConstants.Avoid && prevSibling != null)
704-
{
705-
// handle page break avoiding.
706-
var pageLocationY = Location.Y % HtmlContainer.PageSize.Height;
707-
if (ActualHeight + pageLocationY > HtmlContainer.PageSize.Height)
708-
{
709-
this.BreakPage(true);
710-
}
711-
}
712711

713712
//Start with the assumption this is zero height.
714713
ActualBottom = Location.Y;
@@ -754,6 +753,27 @@ protected virtual async Task PerformLayoutImpAsync(RGraphics g)
754753

755754
if (!IsFixed && !IsAbsolute)
756755
{
756+
if (PageBreakInside == CssConstants.Avoid
757+
&& prevSibling != null
758+
&& Display != CssConstants.TableCell
759+
&& !_pageBreakAvoided)
760+
{
761+
// handle page break avoiding.
762+
var pageLocationY = Location.Y % HtmlContainer.PageSize.Height;
763+
if (Size.Height + pageLocationY > HtmlContainer.PageSize.Height)
764+
{
765+
// if we break page, we'll do another pass at PerformLayoutAsync
766+
// so that child elements are re-positioned correctly.
767+
BreakPage(true);
768+
_pageBreakAvoided = true;
769+
await this.PerformLayoutAsync(g);
770+
771+
// We'll set this flag back to false as this element
772+
// might need re-positioning by its parent.
773+
_pageBreakAvoided = false;
774+
}
775+
}
776+
757777
var actualWidth = Math.Max(GetMinimumWidth() + GetWidthMarginDeep(this), Size.Width < 90999 ? ActualRight - HtmlContainer.Root.Location.X : 0);
758778
HtmlContainer.ActualSize = CommonUtils.Max(HtmlContainer.ActualSize, new RSize(actualWidth, ActualBottom - HtmlContainer.Root.Location.Y));
759779
}

0 commit comments

Comments
 (0)