Skip to content

Commit

Permalink
Unprefix paged media, transforms, and SVG properties
Browse files Browse the repository at this point in the history
The image-rendering, transform, transform-origin and size
properties are now unprefixed.

The prefixed form (eg. -weasy-size) is ignored but gives
a specific warning.
  • Loading branch information
SimonSapin committed Jul 4, 2012
1 parent 1cdb625 commit 279386b
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 167 deletions.
43 changes: 32 additions & 11 deletions weasyprint/css/validation.py
Expand Up @@ -61,7 +61,7 @@
EXPANDERS = {}

PREFIXED = set()
# The same replacement was done on property names:
UNPREFIXED = set()
PREFIX = '-weasy-'


Expand All @@ -71,14 +71,28 @@ class InvalidValues(ValueError):

# Validators

def validator(property_name=None, prefixed=False, wants_base_url=False):
def validator(property_name=None, prefixed=False, unprefixed=False,
wants_base_url=False):
"""Decorator adding a function to the ``VALIDATORS``.
The name of the property covered by the decorated function is set to
``property_name`` if given, or is inferred from the function name
(replacing underscores by hyphens).
:param prefixed:
Vendor-specific (non-standard) and experimental properties are
prefixed: stylesheets need to use eg. ``-weasy-bookmark-level: 2``
instead of ``bookmark-level: 2``.
See http://wiki.csswg.org/spec/vendor-prefixes
:param unprefixed:
Mark properties that used to be prefixed. When used with the prefix,
they will be ignored be give a specific warning.
:param wants_base_url:
The function takes the stylesheet’s base URL as an additional
parameter.
"""
assert not (prefixed and unprefixed)
def decorator(function):
"""Add ``function`` to the ``VALIDATORS``."""
if property_name is None:
Expand All @@ -92,6 +106,8 @@ def decorator(function):
VALIDATORS[name] = function
if prefixed:
PREFIXED.add(name)
if unprefixed:
UNPREFIXED.add(name)
return function
return decorator

Expand Down Expand Up @@ -202,7 +218,7 @@ def image(token, base_url):
return safe_urljoin(base_url, token.value)


@validator('transform-origin', prefixed=True) # Not in CR yet
@validator('transform-origin', unprefixed=True)
@validator()
def background_position(tokens):
"""``background-position`` property validation.
Expand Down Expand Up @@ -791,14 +807,14 @@ def white_space(keyword):
return keyword in ('normal', 'pre', 'nowrap', 'pre-wrap', 'pre-line')


@validator(prefixed=True) # Taken from SVG
@validator(unprefixed=True)
@single_keyword
def image_rendering(keyword):
"""Validation for ``image-rendering``."""
return keyword in ('auto', 'optimizespeed', 'optimizequality')


@validator(prefixed=True) # Not in CR yet
@validator(unprefixed=True)
def size(tokens):
"""``size`` property validation.
Expand Down Expand Up @@ -838,7 +854,7 @@ def size(tokens):
return width, height


@validator(prefixed=True) # Proprietary
@validator(prefixed=True) # Non-standard
@single_token
def anchor(token):
"""Validation for ``anchor``."""
Expand All @@ -853,7 +869,7 @@ def anchor(token):
return (name, args[0])


@validator(prefixed=True, wants_base_url=True) # Proprietary
@validator(prefixed=True, wants_base_url=True) # Non-standard
@single_token
def link(token, base_url):
"""Validation for ``link``."""
Expand All @@ -873,7 +889,7 @@ def link(token, base_url):
return (name, args[0])


@validator(prefixed=True) # CSS3 GCPM
@validator(prefixed=True) # CSS3 GCPM, experimental
@single_token
def bookmark_label(token):
"""Validation for ``bookmark-label``."""
Expand All @@ -885,7 +901,7 @@ def bookmark_label(token):
return ('string', token.value)


@validator(prefixed=True) # CSS3 GCPM
@validator(prefixed=True) # CSS3 GCPM, experimental
@single_token
def bookmark_level(token):
"""Validation for ``bookmark-level``."""
Expand All @@ -897,7 +913,7 @@ def bookmark_level(token):
return 'none'


@validator(prefixed=True) # Not in CR yet
@validator(unprefixed=True)
def transform(tokens):
if get_single_keyword(tokens) == 'none':
return []
Expand Down Expand Up @@ -1268,7 +1284,8 @@ def validation_error(level, reason):

if name in PREFIXED and not name.startswith(PREFIX):
validation_error('warn',
'the property is experimental, use ' + PREFIX + name)
'the property is experimental or non-standard, use '
+ PREFIX + name)
continue

if name in NOT_PRINT_MEDIA:
Expand All @@ -1278,6 +1295,10 @@ def validation_error(level, reason):

if name.startswith(PREFIX):
unprefixed_name = name[len(PREFIX):]
if unprefixed_name in UNPREFIXED:
validation_error('warn',
'the property was unprefixed, use ' + unprefixed_name)
continue
if unprefixed_name in PREFIXED:
name = unprefixed_name

Expand Down
8 changes: 4 additions & 4 deletions weasyprint/tests/test_api.py
Expand Up @@ -200,9 +200,9 @@ def test_python_render():
html = TestHTML(string='<body><img src=pattern.png>',
base_url=resource_filename('dummy.html'))
css = CSS(string='''
@page { margin: 2px; -weasy-size: 8px; background: #fff }
@page { margin: 2px; size: 8px; background: #fff }
body { margin: 0; font-size: 0 }
img { -weasy-image-rendering: optimizeSpeed }
img { image-rendering: optimizeSpeed }
''')

png_bytes = html.write_png(stylesheets=[css])
Expand Down Expand Up @@ -257,7 +257,7 @@ def getvalue(self):
def test_command_line_render():
"""Test rendering with the command-line API."""
css = b'''
@page { margin: 2px; -weasy-size: 8px; background: #fff }
@page { margin: 2px; size: 8px; background: #fff }
body { margin: 0; font-size: 0 }
'''
html = b'<body><img src=pattern.png>'
Expand Down Expand Up @@ -337,7 +337,7 @@ def test_unicode_filenames():
# Replicate pattern.png in CSS so that base_url does not matter.
html = b'''
<style>
@page { margin: 2px; -weasy-size: 8px; background: #fff }
@page { margin: 2px; size: 8px; background: #fff }
html { background: #00f; }
body { background: #f00; width: 1px; height: 1px; }
</style>
Expand Down
4 changes: 2 additions & 2 deletions weasyprint/tests/test_boxes.py
Expand Up @@ -1183,7 +1183,7 @@ def test_margin_boxes():
@page {
/* Make the page content area only 10px high and wide,
so every word in <p> end up on a page of its own. */
-weasy-size: 30px;
size: 30px;
margin: 10px;
@top-center { content: "Title" }
}
Expand Down Expand Up @@ -1218,7 +1218,7 @@ def test_page_counters():
@page {
/* Make the page content area only 10px high and wide,
so every word in <p> end up on a page of its own. */
-weasy-size: 30px;
size: 30px;
margin: 10px;
@bottom-center {
content: "Page " counter(page) " of " counter(pages) ".";
Expand Down
52 changes: 26 additions & 26 deletions weasyprint/tests/test_css_validation.py
Expand Up @@ -99,52 +99,52 @@ def test_decoration():

@assert_no_logs
def test_size():
assert expand_to_dict('-weasy-size: 200px') == {
assert expand_to_dict('size: 200px') == {
'size': ((200, 'px'), (200, 'px'))}
assert expand_to_dict('-weasy-size: 200px 300pt') == {
assert expand_to_dict('size: 200px 300pt') == {
'size': ((200, 'px'), (300, 'pt'))}
assert expand_to_dict('-weasy-size: auto') == {
assert expand_to_dict('size: auto') == {
'size': ((210, 'mm'), (297, 'mm'))}
assert expand_to_dict('-weasy-size: portrait') == {
assert expand_to_dict('size: portrait') == {
'size': ((210, 'mm'), (297, 'mm'))}
assert expand_to_dict('-weasy-size: landscape') == {
assert expand_to_dict('size: landscape') == {
'size': ((297, 'mm'), (210, 'mm'))}
assert expand_to_dict('-weasy-size: A3 portrait') == {
assert expand_to_dict('size: A3 portrait') == {
'size': ((297, 'mm'), (420, 'mm'))}
assert expand_to_dict('-weasy-size: A3 landscape') == {
assert expand_to_dict('size: A3 landscape') == {
'size': ((420, 'mm'), (297, 'mm'))}
assert expand_to_dict('-weasy-size: portrait A3') == {
assert expand_to_dict('size: portrait A3') == {
'size': ((297, 'mm'), (420, 'mm'))}
assert expand_to_dict('-weasy-size: landscape A3') == {
assert expand_to_dict('size: landscape A3') == {
'size': ((420, 'mm'), (297, 'mm'))}
assert expand_to_dict('-weasy-size: A3 landscape A3', 'invalid') == {}
assert expand_to_dict('-weasy-size: A9', 'invalid') == {}
assert expand_to_dict('-weasy-size: foo', 'invalid') == {}
assert expand_to_dict('-weasy-size: foo bar', 'invalid') == {}
assert expand_to_dict('-weasy-size: 20%', 'invalid') == {}
assert expand_to_dict('size: A3 landscape A3', 'invalid') == {}
assert expand_to_dict('size: A9', 'invalid') == {}
assert expand_to_dict('size: foo', 'invalid') == {}
assert expand_to_dict('size: foo bar', 'invalid') == {}
assert expand_to_dict('size: 20%', 'invalid') == {}


@assert_no_logs
def test_transforms():
assert expand_to_dict('-weasy-transform: none') == {
assert expand_to_dict('transform: none') == {
'transform': []}
assert expand_to_dict('-weasy-transform: translate(6px) rotate(90deg)'
assert expand_to_dict('transform: translate(6px) rotate(90deg)'
) == {'transform': [('translate', ((6, 'px'), (0, 'px'))),
('rotate', (90, 'deg'))]}
assert expand_to_dict('-weasy-transform: translate(-4px, 0)'
assert expand_to_dict('transform: translate(-4px, 0)'
) == {'transform': [('translate', ((-4, 'px'), (0, None)))]}
assert expand_to_dict('-weasy-transform: translate(6px, 20%)'
assert expand_to_dict('transform: translate(6px, 20%)'
) == {'transform': [('translate', ((6, 'px'), (20, '%')))]}
assert expand_to_dict('-weasy-transform: scale(2)'
assert expand_to_dict('transform: scale(2)'
) == {'transform': [('scale', (2, 2))]}
assert expand_to_dict('-weasy-transform: translate(6px 20%)',
assert expand_to_dict('transform: translate(6px 20%)',
'invalid') == {} # missing comma
assert expand_to_dict('-weasy-transform: lipsumize(6px)', 'invalid') == {}
assert expand_to_dict('-weasy-transform: foo', 'invalid') == {}
assert expand_to_dict('-weasy-transform: scale(2) foo', 'invalid') == {}
assert expand_to_dict('-weasy-transform: 6px', 'invalid') == {}
assert expand_to_dict('transform: none',
'the property is experimental, use -weasy-transform') == {}
assert expand_to_dict('transform: lipsumize(6px)', 'invalid') == {}
assert expand_to_dict('transform: foo', 'invalid') == {}
assert expand_to_dict('transform: scale(2) foo', 'invalid') == {}
assert expand_to_dict('transform: 6px', 'invalid') == {}
assert expand_to_dict('-weasy-transform: none',
'the property was unprefixed, use transform') == {}


@assert_no_logs
Expand Down

0 comments on commit 279386b

Please sign in to comment.