fix: broken, infinitely looping minPresenceAhead calculation#2400
Merged
diegomura merged 7 commits intodiegomura:masterfrom Jan 15, 2024
Merged
fix: broken, infinitely looping minPresenceAhead calculation#2400diegomura merged 7 commits intodiegomura:masterfrom
diegomura merged 7 commits intodiegomura:masterfrom
Conversation
The old minPresenceAhead had some major issues, among others because vertical margins were completely ignored in the presence calculations.
🦋 Changeset detectedLatest commit: ff69234 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
28d35e3 to
ff69234
Compare
carlobeltrame
added a commit
to carlobeltrame/ecamp3
that referenced
this pull request
Sep 29, 2023
Until diegomura/react-pdf#2400 is merged, react-pdf can sometimes fall into an infinite loop during layouting, when a min-presence-ahead element has a following sibling with vertical margins. This caused our Star Wars example camp to be unprintable. The bug does not happen with vertical padding, so this workaround will fix the problem for now.
This was referenced Oct 6, 2023
|
Great work! That fixed a bunch of issues I was having with my layout! |
Collaborator
Author
Great to hear someone other than me was finally able to test this! |
diegomura
approved these changes
Jan 15, 2024
Owner
diegomura
left a comment
There was a problem hiding this comment.
tACK
Amazing. Thanks so much!
mskec
pushed a commit
to mskec/react-pdf
that referenced
this pull request
Feb 26, 2024
…ra#2400) * Rework breaking logic and add tests to fix minPresenceAhead The old minPresenceAhead had some major issues, among others because vertical margins were completely ignored in the presence calculations. * Add changeset * Add regression tests * Ignore fixed elements when calculating page breaks * Do not break before a wrapping element * Rename variable to make it easier to understand * Refactor for better readability
Ceereals
pushed a commit
to Ceereals/react-pdf
that referenced
this pull request
Mar 9, 2025
…ra#2400) * Rework breaking logic and add tests to fix minPresenceAhead The old minPresenceAhead had some major issues, among others because vertical margins were completely ignored in the presence calculations. * Add changeset * Add regression tests * Ignore fixed elements when calculating page breaks * Do not break before a wrapping element * Rename variable to make it easier to understand * Refactor for better readability
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2303, where sometimes react-pdf could be caught in an infinite loop during rendering!
Fixes #2238
I debugged the existing
shouldBreaklogic which was introduced for react-pdf v2, and found some major flaws in the logic. At first I tried to just fix the logic, but I noticed it could be done more efficiently and cleanly, so I went ahead and rewrote part of the logic.Problem 1: When calculating the "presence" of the sibling nodes following the child in question, vertical margin was completely ignored so far. I agree to ignore the bottom margin of the bottom-most node, but all other margins must be taken into account.
In this picture,
shouldBreak(child, futureElements, ...)returnedfalseso far because the height alone offutureElements[0]was not enough to exceed the page height. The marginTop o futureElements[0] was completely ignored in the old logic. The new logic correctly returnstruein this case, because it searches for the last box end in allfutureElements.Problem 2: The previous logic would ignore the minPresenceAhead value, if the heights of the nodes following the child didn't add up to at least minPresenceAhead.
In this picture, the two futureElements have a height total of 80, or 90 if one includes the vertical margins except the last bottom margin, which is less than the 100 minPresenceAhead. The old logic would completely ignore the minPresenceAhead, when the futureElements aren't at least this high. The new logic correctly outputs
trueforshouldBreak(child, futureElements, ...)in this case.Problem 3: The previous logic would in certain scenarios output
trueforshouldBreak(child, futureElements, ...)even when the child is already at the top of the page. Breaking the child over to the next page wouldn't improve the situation at all, because the breaking conditions would then be met again on the next page, and on the next, and so on, leading to an infinite loop. The new logic prevents this by detecting whether the child is already at the top of the page.Problem 4: The previous logic would incorrectly take fixed futureElements into account. The new logic correctly ignores fixed elements, because they do not have any influence on the page flow.
Notes
shouldBreak, had no tests, was implemented in an overly specific way for just this one use case, and was not necessary anymore after my rewrite.presenceAheadfunction as a prop on any element. This was undocumented, I didn't find any internal uses and it did not seem very helpful to me in the current form (at least, the function would requireelementas an argument to be useful, likedefaultPresenceAheadreceives it).