1
1
mirror of https://github.com/Kozea/WeasyPrint.git synced 2024-10-05 00:21:15 +03:00

Make changes more generic

This commit is contained in:
Mike Voets 2020-07-20 12:25:53 +12:00
parent d08c5b4fd6
commit db3944c1d9
5 changed files with 72 additions and 43 deletions

View File

@ -176,26 +176,11 @@ def register_computer(name):
return decorator
def compute(element, pseudo_type, specified, computed, parent_style,
root_style, base_url, target_collector):
"""Create a dict of computed values.
:param element: The HTML element these style apply to
:param pseudo_type: The type of pseudo-element, eg 'before', None
:param specified: A dict of specified values. Should contain
values for all properties.
:param computed: A dict of already known computed values.
Only contains some properties (or none).
:param parent_style: A dict of computed values of the parent
element (should contain values for all properties),
or ``None`` if ``element`` is the root element.
:param base_url: The base URL used to resolve relative URLs.
:param target_collector: A target collector used to get computed targets.
"""
def compute_variable(value, name, computed, base_url, parent_style):
from .validation.properties import PROPERTIES
already_computed_value = False
def resolve_var(value, name, computed):
if value and isinstance(value, tuple) and value[0] == 'var()':
variable_name, default = value[1]
computed_value = _resolve_var(computed, variable_name, default)
if computed_value is None:
@ -220,11 +205,34 @@ def compute(element, pseudo_type, specified, computed, parent_style,
variable_name.replace('_', '-'), name.replace('_', '-'))
if name in INHERITED and parent_style:
already_computed_value = True
return parent_style[name], already_computed_value
value = parent_style[name]
else:
already_computed_value = name not in INITIAL_NOT_COMPUTED
return INITIAL_VALUES[name], already_computed_value
return new_value, False
value = INITIAL_VALUES[name]
elif isinstance(new_value, list):
value, = new_value
else:
value = new_value
return value, already_computed_value
def compute(element, pseudo_type, specified, computed, parent_style,
root_style, base_url, target_collector):
"""Create a dict of computed values.
:param element: The HTML element these style apply to
:param pseudo_type: The type of pseudo-element, eg 'before', None
:param specified: A dict of specified values. Should contain
values for all properties.
:param computed: A dict of already known computed values.
Only contains some properties (or none).
:param parent_style: A dict of computed values of the parent
element (should contain values for all properties),
or ``None`` if ``element`` is the root element.
:param base_url: The base URL used to resolve relative URLs.
:param target_collector: A target collector used to get computed targets.
"""
computer = {
'is_root_element': parent_style is None,
@ -249,21 +257,20 @@ def compute(element, pseudo_type, specified, computed, parent_style,
function = getter(name)
already_computed_value = False
if value and isinstance(value, list):
for i, val in enumerate(value):
if not isinstance(val, tuple) or val[0] != 'var()':
continue
new_value, already_computed_value = \
resolve_var(val, name, computed)
if name == 'content':
new_value = new_value[0]
value[i] = new_value
elif value and isinstance(value, tuple) and value[0] == 'var()':
new_value, already_computed_value = \
resolve_var(value, name, computed)
if name == 'content':
new_value = new_value[0]
value = new_value
if value:
converted_to_list = False
if not isinstance(value, list):
converted_to_list = True
value = [value]
for i, v in enumerate(value):
value[i], already_computed_value = \
compute_variable(v, name, computed, base_url, parent_style)
if converted_to_list:
value, = value
if function is not None and not already_computed_value:
value = function(computer, name, value)

View File

@ -700,9 +700,9 @@ def get_content_list_token(token, base_url):
return string
# <var>
var_function = check_var_function(token)
if var_function is not None:
return var_function
var = check_var_function(token)
if var is not None:
return var
# contents
if get_keyword(token) == 'contents':

View File

@ -21,6 +21,7 @@ from ..utils import (
PREFIX = '-weasy-'
PROPRIETARY = set()
UNSTABLE = set()
MULTIVAL_PROPERTIES = set()
# Yes/no validators for non-shorthand properties
# Maps property names to functions taking a property name and a value list,
@ -33,7 +34,7 @@ PROPERTIES = {}
# Validators
def property(property_name=None, proprietary=False, unstable=False,
wants_base_url=False):
multiple_values=False, wants_base_url=False):
"""Decorator adding a function to the ``PROPERTIES``.
The name of the property covered by the decorated function is set to
@ -69,6 +70,8 @@ def property(property_name=None, proprietary=False, unstable=False,
PROPRIETARY.add(name)
if unstable:
UNSTABLE.add(name)
if multiple_values:
MULTIVAL_PROPERTIES.add(name)
return function
return decorator
@ -89,7 +92,7 @@ def validate_non_shorthand(base_url, name, tokens, required=False):
if not required and name not in PROPERTIES:
raise InvalidValues('property not supported yet')
if name != 'content':
if name not in MULTIVAL_PROPERTIES:
for token in tokens:
var_function = check_var_function(token)
if var_function:
@ -455,7 +458,7 @@ def clip(token):
return ()
@property(wants_base_url=True)
@property(multiple_values=True, wants_base_url=True)
def content(tokens, base_url):
"""``content`` property validation."""
# See https://www.w3.org/TR/css-content-3/#content-property

View File

@ -98,7 +98,7 @@ def assert_tree(box, expected):
assert isinstance(box, boxes.BlockBox)
assert box.element_tag == 'body'
assert serialize(box.children) == expected
assert serialize(box.children) == expected, '%s != %s' % (serialize(box.children), expected,)
def _sanity_checks(box):

View File

@ -11,6 +11,8 @@ import pytest
from ..css.properties import KNOWN_PROPERTIES
from .test_boxes import render_pages as parse
SIDES = ('top', 'right', 'bottom', 'left')
def test_variable_simple():
page, = parse('''
@ -83,6 +85,23 @@ def test_variable_chain():
assert paragraph.width == 10
def test_variable_partial_1():
page, = parse('''
<style>
html { --var: 10px }
div { margin: 0 0 0 var(--var) }
</style>
<div></div>
''')
html, = page.children
body, = html.children
div, = body.children
assert div.margin_top == 0
assert div.margin_right == 0
assert div.margin_bottom == 0
assert div.margin_left == 10
def test_variable_initial():
page, = parse('''
<style>