Skip to content

Commit 7a4d6f8

Browse files
committed
Support larger and smaller values for font-size
1 parent a0ccc8d commit 7a4d6f8

File tree

3 files changed

+59
-8
lines changed

3 files changed

+59
-8
lines changed

weasyprint/css/computed_values.py

+20-5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
1111
"""
1212

13+
from collections import OrderedDict
1314
from urllib.parse import unquote
1415

1516
from tinycss2.color3 import parse_color
@@ -28,8 +29,7 @@
2829
# Value in pixels of font-size for <absolute-size> keywords: 12pt (16px) for
2930
# medium, and scaling factors given in CSS3 for others:
3031
# http://www.w3.org/TR/css3-fonts/#font-size-prop
31-
# TODO: this will need to be ordered to implement 'smaller' and 'larger'
32-
FONT_SIZE_KEYWORDS = dict(
32+
FONT_SIZE_KEYWORDS = OrderedDict(
3333
# medium is 16px, others are a ratio of medium
3434
(name, INITIAL_VALUES['font_size'] * a / b)
3535
for name, a, b in (
@@ -592,14 +592,29 @@ def font_size(computer, name, value):
592592
"""Compute the ``font-size`` property."""
593593
if value in FONT_SIZE_KEYWORDS:
594594
return FONT_SIZE_KEYWORDS[value]
595-
# TODO: support 'larger' and 'smaller'
596595

596+
keyword_values = list(FONT_SIZE_KEYWORDS.values())
597597
parent_font_size = computer['parent_style']['font_size']
598+
599+
if value == 'larger':
600+
if parent_font_size >= keyword_values[-1]:
601+
return parent_font_size * 1.2
602+
for i, keyword_value in enumerate(keyword_values):
603+
if keyword_value > parent_font_size:
604+
return keyword_values[i]
605+
elif value == 'smaller':
606+
if parent_font_size <= keyword_values[0]:
607+
return parent_font_size * 0.8
608+
for i, keyword_value in enumerate(keyword_values[::-1]):
609+
if keyword_value < parent_font_size:
610+
return keyword_values[-i - 1]
611+
598612
if value.unit == '%':
599613
return value.value * parent_font_size / 100.
600614
else:
601-
return length(computer, name, value, pixels_only=True,
602-
font_size=parent_font_size)
615+
return length(
616+
computer, name, value, pixels_only=True,
617+
font_size=parent_font_size)
603618

604619

605620
@register_computer('font-weight')

weasyprint/css/validation/properties.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -784,9 +784,8 @@ def font_size(token):
784784
return length
785785
font_size_keyword = get_keyword(token)
786786
if font_size_keyword in ('smaller', 'larger'):
787-
raise InvalidValues('value not supported yet')
787+
return font_size_keyword
788788
if font_size_keyword in computed_values.FONT_SIZE_KEYWORDS:
789-
# or keyword in ('smaller', 'larger')
790789
return font_size_keyword
791790

792791

weasyprint/tests/test_css.py

+38-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
1010
"""
1111

12+
from math import isclose
13+
1214
import pytest
1315
import tinycss2
1416

@@ -83,7 +85,7 @@ def test_annotate_document():
8385
style_for = get_all_computed_styles(
8486
document, user_stylesheets=[CSS(resource_filename('user.css'))])
8587

86-
# Element objects behave a lists of their children
88+
# Element objects behave as lists of their children
8789
_head, body = document.etree_element
8890
h1, p, ul, div = body
8991
li_0, _li_1 = ul
@@ -451,3 +453,38 @@ def test_units(value, width):
451453
body, = html.children
452454
p, = body.children
453455
assert p.margin_left == width
456+
457+
458+
@assert_no_logs
459+
@pytest.mark.parametrize('parent_css, parent_size, child_css, child_size', (
460+
('10px', 10, '10px', 10),
461+
('x-small', 12, 'xx-large', 32),
462+
('x-large', 24, '2em', 48),
463+
('1em', 16, '1em', 16),
464+
('1em', 16, 'larger', 6 / 5 * 16),
465+
('medium', 16, 'larger', 6 / 5 * 16),
466+
('x-large', 24, 'larger', 32),
467+
('xx-large', 32, 'larger', 1.2 * 32),
468+
('1px', 1, 'larger', 3 / 5 * 16),
469+
('28px', 28, 'larger', 32),
470+
('100px', 100, 'larger', 120),
471+
('xx-small', 3 / 5 * 16, 'larger', 12),
472+
('1em', 16, 'smaller', 8 / 9 * 16),
473+
('medium', 16, 'smaller', 8 / 9 * 16),
474+
('x-large', 24, 'smaller', 6 / 5 * 16),
475+
('xx-large', 32, 'smaller', 24),
476+
('xx-small', 3 / 5 * 16, 'smaller', 0.8 * 3 / 5 * 16),
477+
('1px', 1, 'smaller', 0.8),
478+
('28px', 28, 'smaller', 24),
479+
('100px', 100, 'smaller', 32),
480+
))
481+
def test_font_size(parent_css, parent_size, child_css, child_size):
482+
document = FakeHTML(string='<p>a<span>b')
483+
style_for = get_all_computed_styles(document, user_stylesheets=[CSS(
484+
string='p{font-size:%s}span{font-size:%s}' % (parent_css, child_css))])
485+
486+
_head, body = document.etree_element
487+
p, = body
488+
span, = p
489+
assert isclose(style_for(p)['font_size'], parent_size)
490+
assert isclose(style_for(span)['font_size'], child_size)

0 commit comments

Comments
 (0)