css_generator.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. # Copyright 2019 The Chromium Authors. All rights reserved.
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. from style_variable_generator.base_generator import Color, BaseGenerator
  5. from style_variable_generator.model import Modes, VariableType
  6. import collections
  7. class CSSStyleGenerator(BaseGenerator):
  8. '''Generator for CSS Variables'''
  9. @staticmethod
  10. def GetName():
  11. return 'CSS'
  12. def Render(self):
  13. return self.ApplyTemplate(self, 'templates/css_generator.tmpl',
  14. self.GetParameters())
  15. def GetParameters(self):
  16. if self.generate_single_mode:
  17. resolved_colors = self.model.colors.Flatten(resolve_missing=True)
  18. resolved_opacities = self.model.opacities.Flatten(
  19. resolve_missing=True)
  20. colors = {
  21. Modes.DEFAULT: resolved_colors[self.generate_single_mode]
  22. }
  23. opacities = {
  24. Modes.DEFAULT: resolved_opacities[self.generate_single_mode]
  25. }
  26. else:
  27. colors = self.model.colors.Flatten()
  28. opacities = self.model.opacities.Flatten()
  29. return {
  30. 'opacities': opacities,
  31. 'colors': colors,
  32. 'typefaces': self.model.typefaces,
  33. 'font_families': self.model.font_families,
  34. 'untyped_css': self.model.untyped_css,
  35. }
  36. def GetFilters(self):
  37. return {
  38. 'to_css_var_name': self.ToCSSVarName,
  39. 'css_color': self._CSSColor,
  40. 'css_opacity': self._CSSOpacity,
  41. 'css_color_rgb': self.CSSColorRGB,
  42. 'process_simple_ref': self.ProcessSimpleRef,
  43. }
  44. def GetGlobals(self):
  45. return {
  46. 'css_color_var':
  47. self.CSSColorVar,
  48. 'in_files':
  49. self.GetInputFiles(),
  50. 'dark_mode_selector':
  51. self.generator_options.get('dark_mode_selector', None),
  52. 'suppress_sources_comment':
  53. self.generator_options.get('suppress_sources_comment', False),
  54. 'Modes':
  55. Modes,
  56. }
  57. def AddGeneratedVars(self, var_names, variable):
  58. def AddVarNames(name, variations):
  59. for v in variations:
  60. var_name = v.replace('$css_name', self.ToCSSVarName(name))
  61. if var_name in var_names:
  62. raise ValueError(name + " is defined multiple times")
  63. var_names[var_name] = name
  64. variable_type = variable.variable_type
  65. if variable_type == VariableType.OPACITY:
  66. AddVarNames(variable.name, ['$css_name'])
  67. elif variable_type == VariableType.COLOR:
  68. AddVarNames(variable.name, ['$css_name', '$css_name-rgb'])
  69. elif variable_type == VariableType.UNTYPED_CSS:
  70. AddVarNames(variable.name, ['$css_name'])
  71. elif variable_type == VariableType.FONT_FAMILY:
  72. AddVarNames(variable.name, ['$css_name'])
  73. elif variable_type == VariableType.TYPEFACE:
  74. AddVarNames(variable.name, [
  75. '$css_name-font',
  76. '$css_name-font-family',
  77. '$css_name-font-size',
  78. '$css_name-font-weight',
  79. '$css_name-line-height',
  80. ])
  81. else:
  82. raise ValueError("GetGeneratedVars() for '%s' not implemented")
  83. def GetCSSVarNames(self):
  84. '''Returns a map of all generated names to the model names that
  85. generated them.
  86. '''
  87. var_names = dict()
  88. for variable in self.model.variable_map.values():
  89. self.AddGeneratedVars(var_names, variable)
  90. return var_names
  91. def ProcessSimpleRef(self, value):
  92. '''If |value| is a simple '$other_variable' reference, returns a
  93. CSS variable that points to '$other_variable'.'''
  94. if value.startswith('$'):
  95. ref_name = value[1:]
  96. assert ref_name in self.model.variable_map
  97. value = 'var({0})'.format(self.ToCSSVarName(ref_name))
  98. return value
  99. def _GetCSSVarPrefix(self, name):
  100. prefix = self.model.variable_map[name].context.get(
  101. CSSStyleGenerator.GetName(), {}).get('prefix')
  102. return prefix + '-' if prefix else ''
  103. def ToCSSVarName(self, name):
  104. # This handles old_semantic_names as well as new.token-names.
  105. var_name = name.translate(str.maketrans('-_.', '_--'))
  106. return '--%s%s' % (self._GetCSSVarPrefix(name), var_name)
  107. def _CSSOpacity(self, opacity):
  108. if opacity.var:
  109. return 'var(%s)' % self.ToCSSVarName(opacity.var)
  110. return ('%f' % opacity.a).rstrip('0').rstrip('.')
  111. def _CSSColor(self, c):
  112. '''Returns the CSS color representation of |c|'''
  113. assert (isinstance(c, Color))
  114. if c.var:
  115. return 'var(%s)' % self.ToCSSVarName(c.var)
  116. if c.rgb_var:
  117. if c.opacity.a != 1:
  118. return 'rgba(var(%s-rgb), %g)' % (self.ToCSSVarName(
  119. c.RGBVarToVar()), self._CSSOpacity(c.opacity))
  120. else:
  121. return 'rgb(var(%s-rgb))' % self.ToCSSVarName(c.RGBVarToVar())
  122. elif c.a != 1:
  123. return 'rgba(%d, %d, %d, %g)' % (c.r, c.g, c.b,
  124. self._CSSOpacity(c.opacity))
  125. else:
  126. return 'rgb(%d, %d, %d)' % (c.r, c.g, c.b)
  127. def CSSColorRGB(self, c):
  128. '''Returns the CSS rgb representation of |c|'''
  129. if c.var:
  130. return 'var(%s-rgb)' % self.ToCSSVarName(c.var)
  131. if c.rgb_var:
  132. return 'var(%s-rgb)' % self.ToCSSVarName(c.RGBVarToVar())
  133. return '%d, %d, %d' % (c.r, c.g, c.b)
  134. def CSSColorVar(self, name, color):
  135. '''Returns the CSS color representation given a color name and color'''
  136. if color.var:
  137. return 'var(%s)' % self.ToCSSVarName(color.var)
  138. if color.opacity and color.opacity.a != 1:
  139. return 'rgba(var(%s-rgb), %s)' % (self.ToCSSVarName(name),
  140. self._CSSOpacity(color.opacity))
  141. else:
  142. return 'rgb(var(%s-rgb))' % self.ToCSSVarName(name)