Resolve a percentage width on an image in a table cell against the cell (#223) - #505
Open
jakejackson1 wants to merge 2 commits into
Open
jakejackson1 wants to merge 2 commits into
jakejackson1 wants to merge 2 commits into
Conversation
…ll (mpdf#420) A percentage width, min-width or max-width on an <img> inside a table was converted against the block containing the table, since neither <table> nor <td> pushes a block level. The image came out wider than its column and, being the column's widest unbreakable content, widened the column past the width it was declared with. The image now carries such a percentage until the table is laid out, and _tableHeight() resolves it against the cell's content width. Until then a percentage width or max-width lets the cell narrow the picture, so it no longer raises the column's minimum. A table that has to be shrunk to fit its page is measured again with the pictures keeping their widths, so that a picture is scaled with the rest of the table instead of left in a cell with no room. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.
What was wrong
A percentage
width,min-widthormax-widthon an<img>in a table cell was resolved against the block containing the table, because neither<table>nor<td>pushes a block level. In a 60mm cell of a 180mm table,max-width: 20%came out as 36mm andmax-width: 100%never constrained anything. The image was then the widest unbreakable thing in its cell, soTableCheckMinWidth()made it the column's minimum and pulled the other columns off the widths they were declared with.The fix
Img::open()no longer converts such a percentage inside a table. It keeps it in the image'sobjattr(cell_sizing: the lengths it was given, its natural size and the percentages still to resolve) and sizes the image provisionally as though the percentage were absent. Once the column widths are known,_tableHeight()calls the newMpdf::sizeCellImages(), which resolves the percentages against the cell's content width and rewrites the object. Every later consumer (printbuffer,_tableWrite) sees the final size. The image is resized from what it was given each time, so the repeated layouts of the shrink/autosize loop give the same result. A percentageborder-radiuson such an image is resolved again against its final box.The sizing rules (default size, aspect ratio, min/max clamps, page fit) moved out of
ImgintoMpdf\Image\ImageSizing::fit(), so the tag and the table code use the same rules. The eight copies of "CSS value, else attribute, then convert" inImgbecame onelength()helper.Column minimums and shrink-to-fit
As in CSS (css-sizing-3 §5.2.2, compressible replaced elements), an image with a percentage
widthormax-widthno longer sets its column's minimum width. Its minimum is its absolutemin-width(if any) plus padding, border and margin. This is what keeps declared column widths intact.On its own, that would break tables too wide for the page. mPDF shrinks those as a whole (
shrin_k), columns go to their minimums, and a compressible image's column would collapse to almost nothing (0.1mm in a table of long URLs). So when the first measurement says the table must shrink ($check > 1) and it has such images, the table is measured again with the images keeping their provisional widths. The picture is then scaled with the rest of the table, as it was before this change. Nested tables work out both minimums when they close (nestedmiwandnestedmiw_kept), so this also covers an image inside a nested table of an overflowing table. Both extra measurements only run for tables that contain such images.Absolute lengths, images outside tables, and
height/min-height/max-heightbehave as before. No snapshot fixture changed.Decisions
width: 100%in an auto-width column takes its natural width as its max-content contribution, as browsers do. The column's width comes from that, and the picture then fills the column._tableColumnWidth(). Everything there that derives frommiw(colspans, percentage columns, the overflow check) would have needed a second copy, so I chose the re-measure, which runs only for affected tables.td img { … }never matching) is separate: no descendant rule under a table element matches anything inside a cell, not eventd spanortd p. It is a CSS cascade change with its own risk, so it has its own PR (Match descendant rules naming a table or cell against the content of the cell (#223) #507).Tests
tests/Mpdf/ImagePercentageInTableCellTest.phpcovers:max-width,width(CSS and attribute) andmin-widthpercentages resolving against the cell.The core cases fail on
gravitypdf.Part of #223; the descendant-selector half is #507, which closes it.
🤖 Generated with Claude Code