This commit is contained in:
Kovid Goyal 2016-04-11 17:57:52 +05:30
parent dc1cb09bbb
commit 4998b3922f

View File

@ -63,7 +63,7 @@ def iterrules(container, rules, sheet_name, media_rule_ok=media_allowed, rule_in
num = next(rule_index_counter)
yield rule, sheet_name, num
StyleDeclaration = namedtuple('StyleDeclaration', 'index sheet_name declaration pseudo_element')
StyleDeclaration = namedtuple('StyleDeclaration', 'index declaration pseudo_element')
Specificity = namedtuple('Specificity', 'is_style num_id num_class num_elem rule_index')
def specificity(rule_index, selector, is_style=0):
@ -78,29 +78,39 @@ def iterdeclaration(decl):
else:
for k, v in n(p.name, p.propertyValue).iteritems():
yield Property(k, v, p.literalpriority)
class Values(tuple):
def normalize_style_declaration(decl):
''' A tuple of `cssutils.css.Value ` (and its subclasses) objects. Also has a
`sheet_name` attribute that is the canonical name relative to which URLs
for this property should be resolved. '''
def __new__(typ, pv, sheet_name=None, priority=''):
ans = tuple.__new__(typ, pv)
ans.sheet_name = sheet_name
ans.is_important = priority == 'important'
return ans
def normalize_style_declaration(decl, sheet_name):
ans = {}
for prop in iterdeclaration(decl):
ans[prop.name] = (prop.propertyValue, prop.priority)
ans[prop.name] = Values(prop.propertyValue, sheet_name, prop.priority)
return ans
def resolve_declarations(decls):
property_names = set()
for decl in decls:
property_names |= set(decl)
for d in decls:
property_names |= set(d.declaration)
ans = {}
for name in property_names:
first_val = None
for decl in decls:
x = decl.get(name)
x = decl.declaration.get(name)
if x is not None:
val, priority = x
if priority == 'important':
first_val = val
if x.is_important:
first_val = x
break
if first_val is None:
first_val = val
first_val = x
ans[name] = first_val
return ans
@ -122,13 +132,13 @@ def resolve_styles(container, name):
container.log.error('Ignoring CSS rule with invalid selector: %r (%s)' % (text, as_unicode(err)))
continue
m = pseudo_pat.search(text)
style = normalize_style_declaration(rule.style)
style = normalize_style_declaration(rule.style, sheet_name)
if m is None:
for elem in matches:
style_map[elem].append(StyleDeclaration(specificity(rule_index, selector), sheet_name, style, None))
style_map[elem].append(StyleDeclaration(specificity(rule_index, selector), style, None))
else:
for elem in matches:
pseudo_style_map[elem].append(StyleDeclaration(specificity(rule_index, selector), sheet_name, style, m.group(1)))
pseudo_style_map[elem].append(StyleDeclaration(specificity(rule_index, selector), style, m.group(1)))
process_sheet(html_css_stylesheet(), 'user-agent.css')
@ -158,7 +168,7 @@ def resolve_styles(container, name):
text = elem.get('style')
if text:
style = container.parse_css(text, is_declaration=True)
style_map[elem].append(StyleDeclaration(Specificity(1, 0, 0, 0, 0), name, normalize_style_declaration(style), None))
style_map[elem].append(StyleDeclaration(Specificity(1, 0, 0, 0, 0), normalize_style_declaration(style, name), None))
for l in (style_map, pseudo_style_map):
for x in l.itervalues():
@ -175,14 +185,14 @@ def defvals():
global _defvals
if _defvals is None:
u = type('')
_defvals = {k:Property(k, u(val)).propertyValue for k, val in DEFAULTS.iteritems()}
_defvals = {k:Values(Property(k, u(val)).propertyValue) for k, val in DEFAULTS.iteritems()}
return _defvals
def get_resolved_property(elem, name, style_map):
''' Given a `style_map` previously generated by :func:`resolve_styles()` and
a property `name`, returns the effective value of that property for the
specified element. Handles inheritance and CSS cascading rules. Returns
an instance of `cssutils.css.PropertyValue`. If the property was never set and
an instance of :class:`Values`. If the property was never set and
is not a known property, then it will return None. '''
inheritable = name in INHERITED