-
-
Notifications
You must be signed in to change notification settings - Fork 686
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Propose fix for issue #1278 #1884
Conversation
Hi! Thanks a lot for your proposal. 💜
That’s something I would really like to avoid 😢. Adding "ghost" style properties is a workaround that often leads to other problems in the future, and even whet it seems harmless it’s often a trap set for future developers. As explained in this comment and the next one, the solution is to keep the real style and to change both the Would you be interested in trying to find such a solution? |
I am aware of the technical debt and the reason I only propose this PR rather than submit it. Since I've created the test case to simulate the issue, the "ghost" style properties workaround was used to pass the test until a proper solution can be implemented.
I would be interested to try but this library is still new to me and I am still unclear of its inner workings. |
Do you mean that these lines should be removed: WeasyPrint/weasyprint/formatting_structure/build.py Lines 979 to 981 in 0381529
and the Then, I think the Line 816 in 0381529
WeasyPrint/weasyprint/layout/table.py Line 67 in 0381529
and for test cases: WeasyPrint/tests/test_boxes.py Line 22 in 0381529
If the structure of Line 862 in 0381529
Line 884 in 0381529
|
Yes, exactly.
Yes.
That would be great! More changes are probably required for the layout than for the drawing, because the drawing part is already different for collapsed and separate cells. |
Please take a look at the latest changes that omitted At this point is it safe to assume only the change of From your #1278 (comment):
I think the right value will be:
If the FAILED tests/layout/test_table.py::test_layout_table_fixed_5 - assert 10.0 == 5
FAILED tests/layout/test_table.py::test_layout_table_auto_17 - assert 10.0 == 5 due to: > assert table.border_left_width == 5 # half of the collapsed 10px border
E assert 10.0 == 5
E + where 10.0 = <TableBox table>.border_left_width Can you point out where |
Thanks a lot for your work on this topic.
Damn, you’re right! Border style and color are not useful for the layout, and they’re never used during the drawing (as we draw collapsed borders instead). There’s probably no need at all to change them in the style, and
Yes, it is.
These attributes are used values. For border width, it’s set by The specification explains that the collapsed border width values should be set as used values. So, the solution is to change these attributes instead of the style dictionary (that are computed values), and check that everything else works well (ie. that the whole table layout code uses the used values, and not the computed values for example). |
WeasyPrint/docs/going_further.rst Lines 225 to 226 in 0381529
Based on the above, is the following correct?
At the following point? WeasyPrint/weasyprint/layout/table.py Line 807 in 0381529
meaning:
should instead be: setattr(box, f'border_{side}_width', twice_width / 2) |
Yes, it is.
That’s the idea, but it may not be that simple. The current bad solution replaces the style during the build step (that builds the boxes), so that the layout step (that sets the position and the size of each box) is sure to use the values that result from the collapsing algorithm. Now, we have to set the used values during the layout step. We have to set the collapsed values after almost each Here’s what you can try:
If some tests don’t pass after this, it probably means that we use computed values instead of used values somewhere during the layout. But maybe you’ll be lucky and everything will work as expected! |
The problem encountered with "experiment" using used values over computed values for ================================================================ short test summary info ================================================================
FAILED tests/layout/test_table.py::test_layout_table_fixed_5 - assert 32.0 == 34
=========================================================== 1 failed, 112 deselected in 2.01s =========================================================== at WeasyPrint/tests/layout/test_table.py Line 239 in 21810ba
for HTML: WeasyPrint/tests/layout/test_table.py Lines 206 to 223 in 21810ba
Tracing the source code for the failed test, I think:
Any pointers? |
…resolve_percentages
…ollapsed-borders mode
This code is not so straightforward to remove as the WeasyPrint/weasyprint/layout/preferred.py Lines 150 to 153 in 21810ba
Thus, I've made "smaller" modifications first until I can better understand the logic:
I believe used values will not be available yet when |
Continuing from the latest commit, which have passed all tests, if I naively change if left:
width += box.border_left_width
if right:
width += box.border_right_width the result for ================================================================ short test summary info ================================================================
FAILED tests/layout/test_table.py::test_layout_table_fixed_5 - AttributeError: 'TableColumnBox' object has no attribute 'border_left_width'. Did you mean: 'border_width'? with the relevant stack trace: ...
weasyprint/layout/table.py:712: in auto_table_layout
table_and_columns_preferred_widths(context, box, outer=False)
weasyprint/layout/preferred.py:448: in table_and_columns_preferred_widths
min_content_width(context, groups[i]))
weasyprint/layout/preferred.py:47: in min_content_width
return block_min_content_width(context, box, outer)
weasyprint/layout/preferred.py:180: in block_min_content_width
return _block_content_width(
weasyprint/layout/preferred.py:104: in _block_content_width
return adjust(box, outer, width)
weasyprint/layout/preferred.py:173: in adjust
return margin_width(box, fixed, left, right)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
box = <TableColumnBox col>, width = 30.0, left = True, right = True
def margin_width(box, width, left=True, right=True):
"""Add box paddings, borders and margins to ``width``."""
percentages = 0
for value in (
(['margin_left', 'padding_left'] if left else []) +
(['margin_right', 'padding_right'] if right else [])
):
style_value = box.style[value]
if style_value != 'auto':
if style_value.unit == 'px':
width += style_value.value
else:
assert style_value.unit == '%'
percentages += style_value.value
collapse = box.style['border_collapse'] == 'collapse'
if left:
> width += box.border_left_width
E AttributeError: 'TableColumnBox' object has no attribute 'border_left_width'. Did you mean: 'border_width'? From the stack trace, it's obvious that If we were to stick to just used values for |
Please review the latest commit:
While I think the code can be refactored further, I will appreciate if you can merge this fix for the next release. |
@liZe please review the latest commit:
I hope this fix can be merged while we continue improving the maintainability of border collapse codes. |
Sorry for the delay, we’re currently quite busy with other projects! We’ll review and hopefully merge this PR as soon as possible. |
To summarize the key areas of the fix: The original WeasyPrint/weasyprint/formatting_structure/build.py Lines 1100 to 1103 in 4e9ad95
so that WeasyPrint/weasyprint/layout/preferred.py Lines 150 to 153 in 4e9ad95
and later store as used values in WeasyPrint/weasyprint/layout/percent.py Lines 95 to 98 in 4e9ad95
This fix stores the collapsed border width in used values: WeasyPrint/weasyprint/layout/table.py Lines 1082 to 1084 in af141ba
and modifies WeasyPrint/weasyprint/layout/preferred.py Lines 154 to 171 in af141ba
and skip storing as used values again in WeasyPrint/weasyprint/layout/percent.py Lines 95 to 102 in af141ba
|
It was failing with previous version too.
Hi! Thanks for your work on this issue 💜. I’ve changed the tests to use drawing, as it’s easier to debug, and to be sure that the rendering is what we actually expect from the layout. (Images are generated in It looks like there are differences between what we have and what we expect:
So, what’s important is to find where this space comes from, other bugs can be fixed later. I’ll check the PR in details when these two bugs pass. |
….build.wrap_table function
The space arises from moving the collapsed-borders conflict resolution from WeasyPrint/weasyprint/formatting_structure/build.py Lines 979 to 981 in 9e59b20
to WeasyPrint/weasyprint/layout/table.py Lines 812 to 817 in 2a3747a
The used border-width values of the cell (half the winning border-width) is used by WeasyPrint/weasyprint/layout/page.py Lines 445 to 447 in ce46dbe
through WeasyPrint/weasyprint/layout/preferred.py Lines 154 to 171 in ce46dbe
Restoring the collapsed-borders conflict resolution to its original place seems to fix the two bugs. |
tests/layout/test_table.py
Outdated
dashed_blue_5 = ('dashed', 5, blue) | ||
|
||
|
||
@assert_no_logs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please consider preserving these test cases (originally in test_boxes.py) as unit test on conflict resolution logic for collapsed borders.
Explained in #1884 (comment) and fix has been pushed
Appears to be a "repeat" of issue #1278 but for margins and the "ugly fix" to keep the original margins style: diff --git a/weasyprint/formatting_structure/build.py b/weasyprint/formatting_structure/build.py
index b247eb19..6663214c 100644
--- a/weasyprint/formatting_structure/build.py
+++ b/weasyprint/formatting_structure/build.py
@@ -994,6 +994,13 @@ def wrap_table(box, children):
# of the wrapper and the table. The other get the initial value.
# TODO: put this in a method of the table object
for name in properties.TABLE_WRAPPER_BOX_PROPERTIES:
+ if name in ['margin_left', 'margin_right', 'margin_top', 'margin_bottom']:
+ if f'*-{name}' in table.style:
+ # restore original style
+ table.style[name] = table.style[f'*-{name}']
+ else:
+ # backup original style
+ table.style[f'*-{name}'] = table.style[name]
wrapper.style[name] = table.style[name]
table.style[name] = properties.INITIAL_VALUES[name] |
To recap, the root cause of issues (#1278 and #2013 (comment)) boils down to computed values in running tables are being overwritten, WeasyPrint/weasyprint/formatting_structure/build.py Lines 1094 to 1100 in e018bf3
and WeasyPrint/weasyprint/formatting_structure/build.py Lines 988 to 993 in e018bf3
|
@kygoh Thanks a lot 💜 |
Before these properties are overwritten in the
set_transparent_border
function:border_{side}_style
border_{side}_width
border_{side}_color
a copy of the original value is stored in the
style
dictionary using property name prefixed with double underscore__
:__border_{side}_style
__border_{side}_width
__border_{side}_color
When
collapse_table_border
is called each time the boxes of the table are built, the original property values are restored first, if exists.