Conversion: Fix normalization of CSS shorthand font property not working when multiple font families are specified in the same shorthand property

This commit is contained in:
Kovid Goyal 2014-06-10 21:25:56 +05:30
parent 8440f1603b
commit 97c59cc1ec

View File

@ -113,7 +113,7 @@ def normalize_simple_composition(name, cssvalue, composition, check_inherit=True
font_composition = ('font-style', 'font-variant', 'font-weight', 'font-size', 'line-height', 'font-family') font_composition = ('font-style', 'font-variant', 'font-weight', 'font-size', 'line-height', 'font-family')
def normalize_font(name, cssvalue): def normalize_font(cssvalue, font_family_as_list=False):
# See https://developer.mozilla.org/en-US/docs/Web/CSS/font # See https://developer.mozilla.org/en-US/docs/Web/CSS/font
composition = font_composition composition = font_composition
val = cssvalue.cssText val = cssvalue.cssText
@ -121,28 +121,44 @@ def normalize_font(name, cssvalue):
return {k:'inherit' for k in composition} return {k:'inherit' for k in composition}
if val in {'caption', 'icon', 'menu', 'message-box', 'small-caption', 'status-bar'}: if val in {'caption', 'icon', 'menu', 'message-box', 'small-caption', 'status-bar'}:
return {k:DEFAULTS[k] for k in composition} return {k:DEFAULTS[k] for k in composition}
try: if getattr(cssvalue, 'length', 1) < 2:
primitives = list(v.cssText for v in cssvalue)
except TypeError:
primitives = [cssvalue.cssText]
if len(primitives) < 2:
return {} # Mandatory to define both font size and font family return {} # Mandatory to define both font size and font family
style = {k:DEFAULTS[k] for k in composition} style = {k:DEFAULTS[k] for k in composition}
style['font-family'] = primitives.pop() families = []
if len(primitives) > 1 and cssprofiles.validate('line-height', primitives[-1]) and cssprofiles.validate('font-size', primitives[-2]): vals = [x.cssText for x in cssvalue]
style['line-height'], style['font-size'] = primitives.pop(), primitives.pop() found_font_size = False
else: while vals:
val = primitives.pop() text = vals.pop()
if not cssprofiles.validate('font-size', val): if not families and text == 'inherit':
return {} families.append(text)
style['font-size'] = val continue
composition = composition[:3] if cssprofiles.validate('font-size', text):
while primitives: style['font-size'] = text
value = primitives.pop() found_font_size = True
for key in composition: break
if cssprofiles.validate(key, value): if cssprofiles.validate('line-height', text):
style[key] = value style['line-height'] = text
if not vals or not cssprofiles.validate('font-size', vals[-1]):
return {} # must have font-size here
style['font-size'] = vals.pop()
found_font_size = True
break
if families == ['inherit']:
return {} # Cannot have multiple font-families if the last one if inherit
families.insert(0, text)
if not families or not found_font_size:
return {} # font-family required
style['font-family'] = families if font_family_as_list else ', '.join(families)
props = ['font-style', 'font-variant', 'font-weight']
while vals:
for i, prop in enumerate(tuple(props)):
if cssprofiles.validate(prop, vals[0]):
props.pop(i)
style[prop] = vals.pop(0)
break break
else:
return {} # unrecognized value
return style return style
def normalize_border(name, cssvalue): def normalize_border(name, cssvalue):
@ -154,7 +170,7 @@ def normalize_border(name, cssvalue):
normalizers = { normalizers = {
'list-style': simple_normalizer('list-style', ('type', 'position', 'image')), 'list-style': simple_normalizer('list-style', ('type', 'position', 'image')),
'font': normalize_font, 'font': lambda prop, v: normalize_font(v),
'border': normalize_border, 'border': normalize_border,
} }
@ -268,7 +284,7 @@ def test_normalization(): # {{{
def test_font_normalization(self): def test_font_normalization(self):
def font_dict(expected): def font_dict(expected):
ans = {k:DEFAULTS[k] for k in font_composition} ans = {k:DEFAULTS[k] for k in font_composition} if expected else {}
ans.update(expected) ans.update(expected)
return ans return ans
@ -276,6 +292,7 @@ def test_normalization(): # {{{
'some_font': {}, 'none': {}, 'inherit':{k:'inherit' for k in font_composition}, 'some_font': {}, 'none': {}, 'inherit':{k:'inherit' for k in font_composition},
'1.2pt/1.4 A_Font': {'font-family':'A_Font', 'font-size':'1.2pt', 'line-height':'1.4'}, '1.2pt/1.4 A_Font': {'font-family':'A_Font', 'font-size':'1.2pt', 'line-height':'1.4'},
'bad font': {}, '10% serif': {'font-family':'serif', 'font-size':'10%'}, 'bad font': {}, '10% serif': {'font-family':'serif', 'font-size':'10%'},
'12px "My Font", serif': {'font-family':'"My Font", serif', 'font-size': '12px'},
'bold italic large serif': {'font-family':'serif', 'font-weight':'bold', 'font-style':'italic', 'font-size':'large'}, 'bold italic large serif': {'font-family':'serif', 'font-weight':'bold', 'font-style':'italic', 'font-size':'large'},
'bold italic small-caps larger/normal serif': 'bold italic small-caps larger/normal serif':
{'font-family':'serif', 'font-weight':'bold', 'font-style':'italic', 'font-size':'larger', {'font-family':'serif', 'font-weight':'bold', 'font-style':'italic', 'font-size':'larger',
@ -283,10 +300,7 @@ def test_normalization(): # {{{
}.iteritems(): }.iteritems():
val = tuple(parseStyle('font: %s' % raw, validate=False))[0].cssValue val = tuple(parseStyle('font: %s' % raw, validate=False))[0].cssValue
style = normalizers['font']('font', val) style = normalizers['font']('font', val)
if expected: self.assertDictEqual(font_dict(expected), style, raw)
self.assertDictEqual(font_dict(expected), style)
else:
self.assertDictEqual(expected, style)
def test_border_normalization(self): def test_border_normalization(self):
def border_edge_dict(expected, edge='right'): def border_edge_dict(expected, edge='right'):