Skip to content
Merged
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
24 changes: 24 additions & 0 deletions tests/layout/test_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -1096,3 +1096,27 @@ def test_page_break_child_margin_no_collapse():
body, = html.children
section, = body.children
div, = section.children


@assert_no_logs
def test_min_max_rtl():
page1, = render_pages('''
<style>
@page{ size: 10px }
</style>
<body style="direction: rtl">
<div style="height: 5px; width: 1px; max-height: 4px; min-width: 3px"></div>
<div style="height: 1px; width: 5px; min-height: 4px; max-width: 3px"></div>
</body>
''')
html, = page1.children
body, = html.children
div1, div2 = body.children
assert div1.position_x == 7
assert div1.position_y == 0
assert div1.height == 4
assert div1.width == 3
assert div2.position_x == 7
assert div2.position_y == 4
assert div2.height == 4
assert div2.width == 3
92 changes: 46 additions & 46 deletions weasyprint/layout/block.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Page breaking and layout for block-level and block-container boxes."""

from functools import partial
from math import inf

from ..formatting_structure import boxes
Expand All @@ -9,7 +10,6 @@
from .float import avoid_collisions, float_layout, get_clearance
from .grid import grid_layout
from .inline import iter_line_boxes
from .min_max import handle_min_max_width
from .percent import percentage, resolve_percentages, resolve_position_percentages
from .replaced import block_replaced_box_layout
from .table import table_layout, table_wrapper_width
Expand Down Expand Up @@ -141,8 +141,7 @@ def block_box_layout(context, box, bottom_space, skip_stack,
return result


@handle_min_max_width
def block_level_width(box, containing_block):
def block_level_width(box, containing_block, with_min_max=True):
"""Set the ``box`` width."""
# 'cb' stands for 'containing block'
if isinstance(containing_block, boxes.Box):
Expand All @@ -153,55 +152,56 @@ def block_level_width(box, containing_block):
# TODO: what is the real text direction?
direction = 'ltr'

# https://www.w3.org/TR/CSS21/visudet.html#blockwidth
padding_plus_border = (
box.padding_left + box.padding_right +
box.border_left_width + box.border_right_width)

# These names are waaay too long
margin_l = box.margin_left
margin_r = box.margin_right
padding_l = box.padding_left
padding_r = box.padding_right
border_l = box.border_left_width
border_r = box.border_right_width
width = box.width

# Only margin-left, margin-right and width can be 'auto'.
# See https://www.w3.org/TR/CSS21/visudet.html#blockwidth.
# Set width. Only margin-left, margin-right and width can be 'auto'.
# We want: width of containing block ==
# margin-left + border-left-width + padding-left + width
# + padding-right + border-right-width + margin-right

paddings_plus_borders = padding_l + padding_r + border_l + border_r
if box.width != 'auto':
total = paddings_plus_borders + width
if margin_l != 'auto':
total += margin_l
if margin_r != 'auto':
total += margin_r
if total > cb_width:
if margin_l == 'auto':
margin_l = box.margin_left = 0
if margin_r == 'auto':
margin_r = box.margin_right = 0
if width != 'auto' and margin_l != 'auto' and margin_r != 'auto':
# The equation is over-constrained.
if direction == 'rtl' and not box.is_column:
box.position_x += (
cb_width - paddings_plus_borders - width - margin_r - margin_l)
# Do nothing in ltr.
if width == 'auto':
if margin_l == 'auto':
margin_l = box.margin_left = 0
if margin_r == 'auto':
margin_r = box.margin_right = 0
width = box.width = cb_width - (
paddings_plus_borders + margin_l + margin_r)
margin_sum = cb_width - paddings_plus_borders - width
if margin_l == margin_r == 'auto':
if box.width == 'auto':
box.width = cb_width - padding_plus_border
if box.margin_left != 'auto':
box.width -= box.margin_left
if box.margin_right != 'auto':
box.width -= box.margin_right
if with_min_max:
box.width = max(box.min_width, min(box.max_width, box.width))

# Set auto margins to 0 for boxes larger than containing block.
margin_width = padding_plus_border + box.width
if box.margin_left != 'auto':
margin_width += box.margin_left
if box.margin_right != 'auto':
margin_width += box.margin_right
if margin_width > cb_width:
if box.margin_left == 'auto':
box.margin_left = 0
if box.margin_right == 'auto':
box.margin_right = 0

# Right-align right-to-left boxes.
if direction == 'rtl' and not box.is_column:
box.position_x += cb_width - padding_plus_border - box.width
if box.margin_left != 'auto':
box.position_x -= box.margin_left
if box.margin_right != 'auto':
box.position_x -= box.margin_right

# Set margins according to width.
margin_sum = cb_width - padding_plus_border - box.width
if box.margin_left == box.margin_right == 'auto':
box.margin_left = margin_sum / 2
box.margin_right = margin_sum / 2
elif margin_l == 'auto' and margin_r != 'auto':
box.margin_left = margin_sum - margin_r
elif margin_l != 'auto' and margin_r == 'auto':
box.margin_right = margin_sum - margin_l
elif box.margin_left == 'auto' and box.margin_right != 'auto':
box.margin_left = margin_sum - box.margin_right
elif box.margin_left != 'auto' and box.margin_right == 'auto':
box.margin_right = margin_sum - box.margin_left


block_level_width.without_min_max = partial(block_level_width, with_min_max=False)


def relative_positioning(box, containing_block):
Expand Down
6 changes: 0 additions & 6 deletions weasyprint/layout/min_max.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,12 @@ def handle_min_max_width(function):
"""Decorate a function setting used width, handling {min,max}-width."""
@functools.wraps(function)
def wrapper(box, *args):
computed_margins = box.margin_left, box.margin_right
result = function(box, *args)
if box.width > box.max_width:
box.width = box.max_width
box.margin_left, box.margin_right = computed_margins
result = function(box, *args)
if box.width < box.min_width:
box.width = box.min_width
box.margin_left, box.margin_right = computed_margins
result = function(box, *args)
return result
wrapper.without_min_max = function
Expand All @@ -26,15 +23,12 @@ def handle_min_max_height(function):
"""Decorate a function setting used height, handling {min,max}-height."""
@functools.wraps(function)
def wrapper(box, *args):
computed_margins = box.margin_top, box.margin_bottom
result = function(box, *args)
if box.height > box.max_height:
box.height = box.max_height
box.margin_top, box.margin_bottom = computed_margins
result = function(box, *args)
if box.height < box.min_height:
box.height = box.min_height
box.margin_top, box.margin_bottom = computed_margins
result = function(box, *args)
return result
wrapper.without_min_max = function
Expand Down
Loading