def __init__(self, content): self.content = content self.attrs = {} for declaration in parse_declaration_list(content, skip_comments=True, skip_whitespace=True): if isinstance(declaration, ast.AtRule): if declaration.at_keyword == 'bottom-right': at_dec = Declarations(declaration.content) self.attrs['page_bottom_right_content'] = at_dec.attrs[ 'content'] else: raise NotImplementedError elif declaration.name == 'content': self.attrs[declaration.name.replace( '-', '_')] = parse_content_value(declaration.value) else: attr = declaration.name.replace('-', '_') value_parts = parse_value_parts(declaration.value) if declaration.name in ('color', 'background-color'): self.attrs[attr] = color3.parse_color(value_parts[0]) elif declaration.name in ('margin', 'padding'): apply_box_values(self.attrs, declaration.name + '_{}', list(map(convert, value_parts))) elif declaration.name == 'border-color': apply_box_values( self.attrs, 'border_{}_color', list(map(color3.parse_color, value_parts))) elif declaration.name == 'border-width': apply_box_values(self.attrs, 'border_{}_width', list(map(convert, value_parts))) elif declaration.name == 'border-collapse': self.attrs[attr] = getattr(BorderCollapse, value_parts[0].value) elif declaration.name == 'border-style': apply_box_values( self.attrs, 'border_{}_style', [getattr(BorderStyle, v.value) for v in value_parts]) elif declaration.name == 'border-spacing': if len(value_parts) == 1: self.attrs['border_spacing_horizontal'] = value_parts[ 0].value self.attrs['border_spacing_vertical'] = value_parts[ 0].value else: (self.attrs['border_spacing_horizontal'], self.attrs['border_spacing_vertical']) = value_parts elif declaration.name.startswith('border-'): if declaration.name.endswith('-style'): self.attrs[attr] = getattr(BorderStyle, value_parts[0].value) elif declaration.name.endswith('-color'): self.attrs[attr] = color3.parse_color(value_parts[0]) elif declaration.name.endswith('-width'): self.attrs[attr] = convert(value_parts[0]) elif isinstance(value_parts[0], ast.DimensionToken): self.attrs[attr] = convert(value_parts[0]) else: self.attrs[attr] = value_parts[0].value
def parse_color_stop(tokens): if len(tokens) == 1: color = parse_color(tokens[0]) if color is not None: return color, None elif len(tokens) == 2: color = parse_color(tokens[0]) position = get_length(tokens[1], negative=True, percentage=True) if color is not None and position is not None: return color, position raise InvalidValues
def parse_color_stop(tokens): if len(tokens) == 1: color = parse_color(tokens[0]) if color == 'currentColor': # TODO: return the current color instead return parse_color('black'), None if color is not None: return color, None elif len(tokens) == 2: color = parse_color(tokens[0]) position = get_length(tokens[1], negative=True, percentage=True) if color is not None and position is not None: return color, position raise InvalidValues
def color(token): """``*-color`` and ``color`` properties validation.""" result = parse_color(token) if result == 'currentColor': return 'inherit' else: return result
def grey_from_style_frag(frag): color = color3.parse_color(frag) if color is None: return frag else: grey = int(255 * color.red * 0.3 + 255 * color.green * 0.59 + 255 * color.blue * 0.11) return "rgb({g}, {g}, {g})".format(g=grey)
def test_color3_keywords(): for css, expected in load_json('color3_keywords.json'): result = parse_color(css) if result is not None: r, g, b, a = result result = [r * 255, g * 255, b * 255, a] assert result == expected
def expand_text_decoration(base_url, name, tokens): """Expand the ``text-decoration`` shorthand property.""" text_decoration_line = set() text_decoration_color = None text_decoration_style = None for token in tokens: keyword = get_keyword(token) if keyword in ('none', 'underline', 'overline', 'line-through', 'blink'): text_decoration_line.add(keyword) elif keyword in ('solid', 'double', 'dotted', 'dashed', 'wavy'): if text_decoration_style is not None: raise InvalidValues else: text_decoration_style = keyword else: color = parse_color(token) if color is None: raise InvalidValues elif text_decoration_color is not None: raise InvalidValues else: text_decoration_color = color if 'none' in text_decoration_line: if len(text_decoration_line) != 1: raise InvalidValues text_decoration_line = 'none' elif not text_decoration_line: text_decoration_line = 'none' yield 'text_decoration_line', text_decoration_line yield 'text_decoration_color', text_decoration_color or 'currentColor' yield 'text_decoration_style', text_decoration_style or 'solid'
def catColorAsRGBInt(category): if 'color' in category: rgb = parse_color(category['color']) if rgb is None: return None return (int(rgb.red * 255) << 16) + (int(rgb.green * 255) << 8) + int( rgb.blue * 255) return None
def is_valid_css_color(css_color: str) -> bool: """Determines whether css color is valid. :param css_color: css color :type css_color: str :return: whether css color is valid :rtype: bool """ return parse_color(css_color) is not None
def expand_border_side(name, tokens): """Expand the ``border-*`` shorthand properties. See http://www.w3.org/TR/CSS21/box.html#propdef-border-top """ for token in tokens: if parse_color(token) is not None: suffix = '-color' elif border_width([token]) is not None: suffix = '-width' elif border_style([token]) is not None: suffix = '-style' else: raise InvalidValues yield suffix, [token]
def compute_attr_function(computer, values): # TODO: use real token parsing instead of casting with Python types func_name, value = values assert func_name == 'attr()' attr_name, type_or_unit, fallback = value # computer.element sometimes is None # computer.element sometimes is a 'PageType' object without .get() # so wrapt the .get() into try and return None instead of crashing try: attr_value = computer.element.get(attr_name, fallback) if type_or_unit == 'string': pass # Keep the string elif type_or_unit == 'url': if attr_value.startswith('#'): attr_value = ('internal', unquote(attr_value[1:])) else: attr_value = ( 'external', safe_urljoin(computer.base_url, attr_value)) elif type_or_unit == 'color': attr_value = parse_color(attr_value.strip()) elif type_or_unit == 'integer': attr_value = int(attr_value.strip()) elif type_or_unit == 'number': attr_value = float(attr_value.strip()) elif type_or_unit == '%': attr_value = Dimension(float(attr_value.strip()), '%') type_or_unit = 'length' elif type_or_unit in LENGTH_UNITS: attr_value = Dimension(float(attr_value.strip()), type_or_unit) type_or_unit = 'length' elif type_or_unit in ANGLE_TO_RADIANS: attr_value = Dimension(float(attr_value.strip()), type_or_unit) type_or_unit = 'angle' except Exception: return return (type_or_unit, attr_value)
def compute_attr_function(computer, values): # TODO: use real token parsing instead of casting with Python types func_name, value = values assert func_name == 'attr()' attr_name, type_or_unit, fallback = value # computer['element'] sometimes is None # computer['element'] sometimes is a 'PageType' object without .get() # so wrapt the .get() into try and return None instead of crashing try: attr_value = computer['element'].get(attr_name, fallback) if type_or_unit == 'string': pass # Keep the string elif type_or_unit == 'url': if attr_value.startswith('#'): attr_value = ('internal', unquote(attr_value[1:])) else: attr_value = ('external', safe_urljoin(computer['base_url'], attr_value)) elif type_or_unit == 'color': attr_value = parse_color(attr_value.strip()) elif type_or_unit == 'integer': attr_value = int(attr_value.strip()) elif type_or_unit == 'number': attr_value = float(attr_value.strip()) elif type_or_unit == '%': attr_value = Dimension(float(attr_value.strip()), '%') type_or_unit = 'length' elif type_or_unit in LENGTH_UNITS: attr_value = Dimension(float(attr_value.strip()), type_or_unit) type_or_unit = 'length' elif type_or_unit in ANGLE_TO_RADIANS: attr_value = Dimension(float(attr_value.strip()), type_or_unit) type_or_unit = 'angle' except Exception: return return (type_or_unit, attr_value)
def test_color3_hsl(): for css, expected in load_json('color3_hsl.json'): assert to_json(parse_color(css)) == expected
def color(string): """Safely parse a color string and return a RGBA tuple.""" return parse_color(string or '') or (0, 0, 0, 1)
def other_colors(token): return parse_color(token)
def outline_color(token): if get_keyword(token) == 'invert': return 'currentColor' else: return parse_color(token)
from __future__ import division, unicode_literals import collections from tinycss2.color3 import parse_color Dimension = collections.namedtuple('Dimension', ['value', 'unit']) # See http://www.w3.org/TR/CSS21/propidx.html INITIAL_VALUES = { 'bottom': 'auto', 'caption_side': 'top', 'clear': 'none', 'clip': (), # computed value for 'auto' 'color': parse_color('black'), # chosen by the user agent 'content': 'normal', # Means 'none', but allow `display: list-item` to increment the # list-item counter. If we ever have a way for authors to query # computed values (JavaScript?), this value should serialize to 'none'. 'counter_increment': 'auto', 'counter_reset': (), # parsed value for 'none' # 'counter_set': (), # parsed value for 'none' 'direction': 'ltr', 'display': 'inline', 'empty_cells': 'show', 'float': 'none', 'height': 'auto', 'left': 'auto', 'line_height': 'normal', 'list_style_image': ('none', None),
""" import collections from tinycss2.color3 import parse_color Dimension = collections.namedtuple('Dimension', ['value', 'unit']) # See http://www.w3.org/TR/CSS21/propidx.html INITIAL_VALUES = { 'bottom': 'auto', 'caption_side': 'top', 'clear': 'none', 'clip': (), # computed value for 'auto' 'color': parse_color('black'), # chosen by the user agent # Means 'none', but allow `display: list-item` to increment the # list-item counter. If we ever have a way for authors to query # computed values (JavaScript?), this value should serialize to 'none'. 'counter_increment': 'auto', 'counter_reset': (), # parsed value for 'none' # 'counter_set': (), # parsed value for 'none' 'direction': 'ltr', 'display': 'inline', 'empty_cells': 'show', 'float': 'none', 'height': 'auto', 'left': 'auto', 'line_height': 'normal', 'list_style_image': ('none', None), 'list_style_position': 'outside',
def test_color3(input): return parse_color(input)
def test_parse_declaration_value_color(): source = 'color:#369' declaration = parse_one_declaration(source) (value_token,) = declaration.value assert parse_color(value_token) == (.2, .4, .6, 1) assert declaration.serialize() == source