3
3
"""
4
4
5
5
import re
6
- from typing import Optional
6
+ from typing import Dict , Optional
7
7
import warnings
8
8
9
9
@@ -12,8 +12,6 @@ class CSSWarning(UserWarning):
12
12
This CSS syntax cannot currently be parsed.
13
13
"""
14
14
15
- pass
16
-
17
15
18
16
def _side_expander (prop_fmt : str ):
19
17
def expand (self , prop , value : str ):
@@ -34,7 +32,64 @@ class CSSResolver:
34
32
A callable for parsing and resolving CSS to atomic properties.
35
33
"""
36
34
37
- def __call__ (self , declarations_str , inherited = None ):
35
+ UNIT_RATIOS = {
36
+ "rem" : ("pt" , 12 ),
37
+ "ex" : ("em" , 0.5 ),
38
+ # 'ch':
39
+ "px" : ("pt" , 0.75 ),
40
+ "pc" : ("pt" , 12 ),
41
+ "in" : ("pt" , 72 ),
42
+ "cm" : ("in" , 1 / 2.54 ),
43
+ "mm" : ("in" , 1 / 25.4 ),
44
+ "q" : ("mm" , 0.25 ),
45
+ "!!default" : ("em" , 0 ),
46
+ }
47
+
48
+ FONT_SIZE_RATIOS = UNIT_RATIOS .copy ()
49
+ FONT_SIZE_RATIOS .update (
50
+ {
51
+ "%" : ("em" , 0.01 ),
52
+ "xx-small" : ("rem" , 0.5 ),
53
+ "x-small" : ("rem" , 0.625 ),
54
+ "small" : ("rem" , 0.8 ),
55
+ "medium" : ("rem" , 1 ),
56
+ "large" : ("rem" , 1.125 ),
57
+ "x-large" : ("rem" , 1.5 ),
58
+ "xx-large" : ("rem" , 2 ),
59
+ "smaller" : ("em" , 1 / 1.2 ),
60
+ "larger" : ("em" , 1.2 ),
61
+ "!!default" : ("em" , 1 ),
62
+ }
63
+ )
64
+
65
+ MARGIN_RATIOS = UNIT_RATIOS .copy ()
66
+ MARGIN_RATIOS .update ({"none" : ("pt" , 0 )})
67
+
68
+ BORDER_WIDTH_RATIOS = UNIT_RATIOS .copy ()
69
+ BORDER_WIDTH_RATIOS .update (
70
+ {
71
+ "none" : ("pt" , 0 ),
72
+ "thick" : ("px" , 4 ),
73
+ "medium" : ("px" , 2 ),
74
+ "thin" : ("px" , 1 ),
75
+ # Default: medium only if solid
76
+ }
77
+ )
78
+
79
+ SIDE_SHORTHANDS = {
80
+ 1 : [0 , 0 , 0 , 0 ],
81
+ 2 : [0 , 1 , 0 , 1 ],
82
+ 3 : [0 , 1 , 2 , 1 ],
83
+ 4 : [0 , 1 , 2 , 3 ],
84
+ }
85
+
86
+ SIDES = ("top" , "right" , "bottom" , "left" )
87
+
88
+ def __call__ (
89
+ self ,
90
+ declarations_str : str ,
91
+ inherited : Optional [Dict [str , str ]] = None ,
92
+ ) -> Dict [str , str ]:
38
93
"""
39
94
The given declarations to atomic properties.
40
95
@@ -76,100 +131,78 @@ def __call__(self, declarations_str, inherited=None):
76
131
if inherited is None :
77
132
inherited = {}
78
133
134
+ props = self ._update_initial (props , inherited )
135
+ props = self ._update_font_size (props , inherited )
136
+ return self ._update_other_units (props )
137
+
138
+ def _update_initial (
139
+ self ,
140
+ props : Dict [str , str ],
141
+ inherited : Dict [str , str ],
142
+ ) -> Dict [str , str ]:
79
143
# 1. resolve inherited, initial
80
144
for prop , val in inherited .items ():
81
145
if prop not in props :
82
146
props [prop ] = val
83
147
84
- for prop , val in list (props .items ()):
148
+ new_props = props .copy ()
149
+ for prop , val in props .items ():
85
150
if val == "inherit" :
86
151
val = inherited .get (prop , "initial" )
87
- if val == "initial" :
88
- val = None
89
152
90
- if val is None :
153
+ if val in ( "initial" , None ) :
91
154
# we do not define a complete initial stylesheet
92
- del props [prop ]
155
+ del new_props [prop ]
93
156
else :
94
- props [prop ] = val
95
-
157
+ new_props [prop ] = val
158
+ return new_props
159
+
160
+ def _update_font_size (
161
+ self ,
162
+ props : Dict [str , str ],
163
+ inherited : Dict [str , str ],
164
+ ) -> Dict [str , str ]:
96
165
# 2. resolve relative font size
97
- font_size : Optional [float ]
98
166
if props .get ("font-size" ):
99
- if "font-size" in inherited :
100
- em_pt = inherited ["font-size" ]
101
- assert em_pt [- 2 :] == "pt"
102
- em_pt = float (em_pt [:- 2 ])
103
- else :
104
- em_pt = None
105
167
props ["font-size" ] = self .size_to_pt (
106
- props ["font-size" ], em_pt , conversions = self .FONT_SIZE_RATIOS
168
+ props ["font-size" ],
169
+ self ._get_font_size (inherited ),
170
+ conversions = self .FONT_SIZE_RATIOS ,
107
171
)
172
+ return props
108
173
109
- font_size = float (props ["font-size" ][:- 2 ])
110
- else :
111
- font_size = None
174
+ def _get_font_size (self , props : Dict [str , str ]) -> Optional [float ]:
175
+ if props .get ("font-size" ):
176
+ font_size_string = props ["font-size" ]
177
+ return self ._get_float_font_size_from_pt (font_size_string )
178
+ return None
179
+
180
+ def _get_float_font_size_from_pt (self , font_size_string : str ) -> float :
181
+ assert font_size_string .endswith ("pt" )
182
+ return float (font_size_string .rstrip ("pt" ))
112
183
184
+ def _update_other_units (self , props : Dict [str , str ]) -> Dict [str , str ]:
185
+ font_size = self ._get_font_size (props )
113
186
# 3. TODO: resolve other font-relative units
114
187
for side in self .SIDES :
115
188
prop = f"border-{ side } -width"
116
189
if prop in props :
117
190
props [prop ] = self .size_to_pt (
118
- props [prop ], em_pt = font_size , conversions = self .BORDER_WIDTH_RATIOS
191
+ props [prop ],
192
+ em_pt = font_size ,
193
+ conversions = self .BORDER_WIDTH_RATIOS ,
119
194
)
195
+
120
196
for prop in [f"margin-{ side } " , f"padding-{ side } " ]:
121
197
if prop in props :
122
198
# TODO: support %
123
199
props [prop ] = self .size_to_pt (
124
- props [prop ], em_pt = font_size , conversions = self .MARGIN_RATIOS
200
+ props [prop ],
201
+ em_pt = font_size ,
202
+ conversions = self .MARGIN_RATIOS ,
125
203
)
126
-
127
204
return props
128
205
129
- UNIT_RATIOS = {
130
- "rem" : ("pt" , 12 ),
131
- "ex" : ("em" , 0.5 ),
132
- # 'ch':
133
- "px" : ("pt" , 0.75 ),
134
- "pc" : ("pt" , 12 ),
135
- "in" : ("pt" , 72 ),
136
- "cm" : ("in" , 1 / 2.54 ),
137
- "mm" : ("in" , 1 / 25.4 ),
138
- "q" : ("mm" , 0.25 ),
139
- "!!default" : ("em" , 0 ),
140
- }
141
-
142
- FONT_SIZE_RATIOS = UNIT_RATIOS .copy ()
143
- FONT_SIZE_RATIOS .update (
144
- {
145
- "%" : ("em" , 0.01 ),
146
- "xx-small" : ("rem" , 0.5 ),
147
- "x-small" : ("rem" , 0.625 ),
148
- "small" : ("rem" , 0.8 ),
149
- "medium" : ("rem" , 1 ),
150
- "large" : ("rem" , 1.125 ),
151
- "x-large" : ("rem" , 1.5 ),
152
- "xx-large" : ("rem" , 2 ),
153
- "smaller" : ("em" , 1 / 1.2 ),
154
- "larger" : ("em" , 1.2 ),
155
- "!!default" : ("em" , 1 ),
156
- }
157
- )
158
-
159
- MARGIN_RATIOS = UNIT_RATIOS .copy ()
160
- MARGIN_RATIOS .update ({"none" : ("pt" , 0 )})
161
-
162
- BORDER_WIDTH_RATIOS = UNIT_RATIOS .copy ()
163
- BORDER_WIDTH_RATIOS .update (
164
- {
165
- "none" : ("pt" , 0 ),
166
- "thick" : ("px" , 4 ),
167
- "medium" : ("px" , 2 ),
168
- "thin" : ("px" , 1 ),
169
- # Default: medium only if solid
170
- }
171
- )
172
-
173
206
def size_to_pt (self , in_val , em_pt = None , conversions = UNIT_RATIOS ):
174
207
def _error ():
175
208
warnings .warn (f"Unhandled size: { repr (in_val )} " , CSSWarning )
@@ -222,14 +255,6 @@ def atomize(self, declarations):
222
255
for prop , value in expand (prop , value ):
223
256
yield prop , value
224
257
225
- SIDE_SHORTHANDS = {
226
- 1 : [0 , 0 , 0 , 0 ],
227
- 2 : [0 , 1 , 0 , 1 ],
228
- 3 : [0 , 1 , 2 , 1 ],
229
- 4 : [0 , 1 , 2 , 3 ],
230
- }
231
- SIDES = ("top" , "right" , "bottom" , "left" )
232
-
233
258
expand_border_color = _side_expander ("border-{:s}-color" )
234
259
expand_border_style = _side_expander ("border-{:s}-style" )
235
260
expand_border_width = _side_expander ("border-{:s}-width" )
0 commit comments