Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(222)

Side by Side Diff: grit/gather/chrome_html.py

Issue 16539002: GRIT: Enable variable expansion in filenames during HTML inlining. (Closed) Base URL: https://chromium.googlesource.com/external/grit-i18n.git@master
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « grit/format/html_inline_unittest.py ('k') | grit/gather/chrome_html_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Prepares a Chrome HTML file by inlining resources and adding references to 6 """Prepares a Chrome HTML file by inlining resources and adding references to
7 high DPI resources and removing references to unsupported scale factors. 7 high DPI resources and removing references to unsupported scale factors.
8 8
9 This is a small gatherer that takes a HTML file, looks for src attributes 9 This is a small gatherer that takes a HTML file, looks for src attributes
10 and inlines the specified file, producing one HTML file with no external 10 and inlines the specified file, producing one HTML file with no external
(...skipping 30 matching lines...) Expand all
41 '([,\r\n ]*url\((?P<quote>"|\'|)[^"\'()]*(?P=quote)\)[ ]*[0-9.]*x)*)\)', 41 '([,\r\n ]*url\((?P<quote>"|\'|)[^"\'()]*(?P=quote)\)[ ]*[0-9.]*x)*)\)',
42 re.MULTILINE) 42 re.MULTILINE)
43 # Matches a single image in a CSS image set with the capture group scale. 43 # Matches a single image in a CSS image set with the capture group scale.
44 _CSS_IMAGE_SET_IMAGE = lazy_re.compile('[,\r\n ]*' + 44 _CSS_IMAGE_SET_IMAGE = lazy_re.compile('[,\r\n ]*' +
45 'url\((?P<quote>"|\'|)[^"\'()]*(?P=quote)\)[ ]*(?P<scale>[0-9.]*x)', 45 'url\((?P<quote>"|\'|)[^"\'()]*(?P=quote)\)[ ]*(?P<scale>[0-9.]*x)',
46 re.MULTILINE) 46 re.MULTILINE)
47 _HTML_IMAGE_SRC = lazy_re.compile( 47 _HTML_IMAGE_SRC = lazy_re.compile(
48 '<img[^>]+src=\"(?P<filename>[^">]*)\"[^>]*>') 48 '<img[^>]+src=\"(?P<filename>[^">]*)\"[^>]*>')
49 49
50 def GetImageList( 50 def GetImageList(
51 base_path, filename, scale_factors, distribution): 51 base_path, filename, scale_factors, distribution,
52 filename_expansion_function=None):
52 """Generate the list of images which match the provided scale factors. 53 """Generate the list of images which match the provided scale factors.
53 54
54 Takes an image filename and checks for files of the same name in folders 55 Takes an image filename and checks for files of the same name in folders
55 corresponding to the supported scale factors. If the file is from a 56 corresponding to the supported scale factors. If the file is from a
56 chrome://theme/ source, inserts supported @Nx scale factors as high DPI 57 chrome://theme/ source, inserts supported @Nx scale factors as high DPI
57 versions. 58 versions.
58 59
59 Args: 60 Args:
60 base_path: path to look for relative file paths in 61 base_path: path to look for relative file paths in
61 filename: name of the base image file 62 filename: name of the base image file
(...skipping 10 matching lines...) Expand all
72 images = [('1x', filename)] 73 images = [('1x', filename)]
73 for scale_factor in scale_factors: 74 for scale_factor in scale_factors:
74 images.append((scale_factor, "%s@%s" % (filename, scale_factor))) 75 images.append((scale_factor, "%s@%s" % (filename, scale_factor)))
75 return images 76 return images
76 77
77 if filename.find(':') != -1: 78 if filename.find(':') != -1:
78 # filename is probably a URL, only return filename itself. 79 # filename is probably a URL, only return filename itself.
79 return [('1x', filename)] 80 return [('1x', filename)]
80 81
81 filename = filename.replace(DIST_SUBSTR, distribution) 82 filename = filename.replace(DIST_SUBSTR, distribution)
83 if filename_expansion_function:
84 filename = filename_expansion_function(filename)
82 filepath = os.path.join(base_path, filename) 85 filepath = os.path.join(base_path, filename)
83 images = [('1x', filename)] 86 images = [('1x', filename)]
84 87
85 for scale_factor in scale_factors: 88 for scale_factor in scale_factors:
86 # Check for existence of file and add to image set. 89 # Check for existence of file and add to image set.
87 scale_path = os.path.split(os.path.join(base_path, filename)) 90 scale_path = os.path.split(os.path.join(base_path, filename))
88 scale_image_path = os.path.join(scale_path[0], scale_factor, scale_path[1]) 91 scale_image_path = os.path.join(scale_path[0], scale_factor, scale_path[1])
89 if os.path.isfile(scale_image_path): 92 if os.path.isfile(scale_image_path):
90 # HTML/CSS always uses forward slashed paths. 93 # HTML/CSS always uses forward slashed paths.
91 scale_image_name = re.sub('(?P<path>(.*/)?)(?P<file>[^/]*)', 94 scale_image_name = re.sub('(?P<path>(.*/)?)(?P<file>[^/]*)',
(...skipping 15 matching lines...) Expand all
107 string giving a -webkit-image-set rule referencing the provided images. 110 string giving a -webkit-image-set rule referencing the provided images.
108 (i.e. '-webkit-image-set(url('image.png') 1x, url('2x/image.png') 2x)') 111 (i.e. '-webkit-image-set(url('image.png') 1x, url('2x/image.png') 2x)')
109 """ 112 """
110 imageset = [] 113 imageset = []
111 for (scale_factor, filename) in images: 114 for (scale_factor, filename) in images:
112 imageset.append("url(%s%s%s) %s" % (quote, filename, quote, scale_factor)) 115 imageset.append("url(%s%s%s) %s" % (quote, filename, quote, scale_factor))
113 return "-webkit-image-set(%s)" % (', '.join(imageset)) 116 return "-webkit-image-set(%s)" % (', '.join(imageset))
114 117
115 118
116 def InsertImageSet( 119 def InsertImageSet(
117 src_match, base_path, scale_factors, distribution): 120 src_match, base_path, scale_factors, distribution,
121 filename_expansion_function=None):
118 """Regex replace function which inserts -webkit-image-set. 122 """Regex replace function which inserts -webkit-image-set.
119 123
120 Takes a regex match for url('path'). If the file is local, checks for 124 Takes a regex match for url('path'). If the file is local, checks for
121 files of the same name in folders corresponding to the supported scale 125 files of the same name in folders corresponding to the supported scale
122 factors. If the file is from a chrome://theme/ source, inserts the 126 factors. If the file is from a chrome://theme/ source, inserts the
123 supported @Nx scale factor request. In either case inserts a 127 supported @Nx scale factor request. In either case inserts a
124 -webkit-image-set rule to fetch the appropriate image for the current 128 -webkit-image-set rule to fetch the appropriate image for the current
125 scale factor. 129 scale factor.
126 130
127 Args: 131 Args:
128 src_match: regex match object from _CSS_IMAGE_URLS 132 src_match: regex match object from _CSS_IMAGE_URLS
129 base_path: path to look for relative file paths in 133 base_path: path to look for relative file paths in
130 scale_factors: a list of the supported scale factors (i.e. ['2x']) 134 scale_factors: a list of the supported scale factors (i.e. ['2x'])
131 distribution: string that should replace %DISTRIBUTION%. 135 distribution: string that should replace %DISTRIBUTION%.
132 136
133 Returns: 137 Returns:
134 string 138 string
135 """ 139 """
136 quote = src_match.group('quote') 140 quote = src_match.group('quote')
137 filename = src_match.group('filename') 141 filename = src_match.group('filename')
138 attr = src_match.group('attribute') 142 attr = src_match.group('attribute')
139 image_list = GetImageList(base_path, filename, scale_factors, distribution) 143 image_list = GetImageList(
144 base_path, filename, scale_factors, distribution,
145 filename_expansion_function=filename_expansion_function)
140 146
141 # Don't modify the source if there is only one image. 147 # Don't modify the source if there is only one image.
142 if len(image_list) == 1: 148 if len(image_list) == 1:
143 return src_match.group(0) 149 return src_match.group(0)
144 150
145 return "%s: %s" % (attr, GenerateImageSet(image_list, quote)[:-1]) 151 return "%s: %s" % (attr, GenerateImageSet(image_list, quote)[:-1])
146 152
147 153
148 def InsertImageStyle( 154 def InsertImageStyle(
149 src_match, base_path, scale_factors, distribution): 155 src_match, base_path, scale_factors, distribution,
156 filename_expansion_function=None):
150 """Regex replace function which adds a content style to an <img>. 157 """Regex replace function which adds a content style to an <img>.
151 158
152 Takes a regex match from _HTML_IMAGE_SRC and replaces the attribute with a CSS 159 Takes a regex match from _HTML_IMAGE_SRC and replaces the attribute with a CSS
153 style which defines the image set. 160 style which defines the image set.
154 """ 161 """
155 filename = src_match.group('filename') 162 filename = src_match.group('filename')
156 image_list = GetImageList(base_path, filename, scale_factors, distribution) 163 image_list = GetImageList(
164 base_path, filename, scale_factors, distribution,
165 filename_expansion_function=filename_expansion_function)
157 166
158 # Don't modify the source if there is only one image or image already defines 167 # Don't modify the source if there is only one image or image already defines
159 # a style. 168 # a style.
160 if src_match.group(0).find(" style=\"") != -1 or len(image_list) == 1: 169 if src_match.group(0).find(" style=\"") != -1 or len(image_list) == 1:
161 return src_match.group(0) 170 return src_match.group(0)
162 171
163 return "%s style=\"content: %s;\">" % (src_match.group(0)[:-1], 172 return "%s style=\"content: %s;\">" % (src_match.group(0)[:-1],
164 GenerateImageSet(image_list, "'")) 173 GenerateImageSet(image_list, "'"))
165 174
166 175
167 def InsertImageSets( 176 def InsertImageSets(
168 filepath, text, scale_factors, distribution): 177 filepath, text, scale_factors, distribution,
178 filename_expansion_function=None):
169 """Helper function that adds references to external images available in any of 179 """Helper function that adds references to external images available in any of
170 scale_factors in CSS backgrounds. 180 scale_factors in CSS backgrounds.
171 """ 181 """
172 # Add high DPI urls for css attributes: content, background, 182 # Add high DPI urls for css attributes: content, background,
173 # or *-image or <img src="foo">. 183 # or *-image or <img src="foo">.
174 return _CSS_IMAGE_URLS.sub( 184 return _CSS_IMAGE_URLS.sub(
175 lambda m: InsertImageSet(m, filepath, scale_factors, distribution), 185 lambda m: InsertImageSet(
186 m, filepath, scale_factors, distribution,
187 filename_expansion_function=filename_expansion_function),
176 _HTML_IMAGE_SRC.sub( 188 _HTML_IMAGE_SRC.sub(
177 lambda m: InsertImageStyle(m, filepath, scale_factors, distribution), 189 lambda m: InsertImageStyle(
190 m, filepath, scale_factors, distribution,
191 filename_expansion_function=filename_expansion_function),
178 text)).decode('utf-8').encode('utf-8') 192 text)).decode('utf-8').encode('utf-8')
179 193
180 194
181 def RemoveImagesNotIn(scale_factors, src_match): 195 def RemoveImagesNotIn(scale_factors, src_match):
182 """Regex replace function which removes images for scale factors not in 196 """Regex replace function which removes images for scale factors not in
183 scale_factors. 197 scale_factors.
184 198
185 Takes a regex match for _CSS_IMAGE_SETS. For each image in the group images, 199 Takes a regex match for _CSS_IMAGE_SETS. For each image in the group images,
186 checks if this scale factor is in scale_factors and if not, removes it. 200 checks if this scale factor is in scale_factors and if not, removes it.
187 201
(...skipping 13 matching lines...) Expand all
201 215
202 def RemoveImageSetImages(text, scale_factors): 216 def RemoveImageSetImages(text, scale_factors):
203 """Helper function which removes images in image sets not in the list of 217 """Helper function which removes images in image sets not in the list of
204 supported scale_factors. 218 supported scale_factors.
205 """ 219 """
206 return _CSS_IMAGE_SETS.sub( 220 return _CSS_IMAGE_SETS.sub(
207 lambda m: RemoveImagesNotIn(scale_factors, m), text) 221 lambda m: RemoveImagesNotIn(scale_factors, m), text)
208 222
209 223
210 def ProcessImageSets( 224 def ProcessImageSets(
211 filepath, text, scale_factors, distribution): 225 filepath, text, scale_factors, distribution,
226 filename_expansion_function=None):
212 """Helper function that adds references to external images available in other 227 """Helper function that adds references to external images available in other
213 scale_factors and removes images from image-sets in unsupported scale_factors. 228 scale_factors and removes images from image-sets in unsupported scale_factors.
214 """ 229 """
215 # Explicitly add 1x to supported scale factors so that it is not removed. 230 # Explicitly add 1x to supported scale factors so that it is not removed.
216 supported_scale_factors = ['1x'] 231 supported_scale_factors = ['1x']
217 supported_scale_factors.extend(scale_factors) 232 supported_scale_factors.extend(scale_factors)
218 return InsertImageSets(filepath, 233 return InsertImageSets(
219 RemoveImageSetImages(text, supported_scale_factors), 234 filepath,
220 scale_factors, 235 RemoveImageSetImages(text, supported_scale_factors),
221 distribution) 236 scale_factors,
237 distribution,
238 filename_expansion_function=filename_expansion_function)
222 239
223 240
224 class ChromeHtml(interface.GathererBase): 241 class ChromeHtml(interface.GathererBase):
225 """Represents an HTML document processed for Chrome WebUI. 242 """Represents an HTML document processed for Chrome WebUI.
226 243
227 HTML documents used in Chrome WebUI have local resources inlined and 244 HTML documents used in Chrome WebUI have local resources inlined and
228 automatically insert references to high DPI assets used in CSS properties 245 automatically insert references to high DPI assets used in CSS properties
229 with the use of the -webkit-image-set value. References to unsupported scale 246 with the use of the -webkit-image-set value. References to unsupported scale
230 factors in image sets are also removed. This does not generate any 247 factors in image sets are also removed. This does not generate any
231 translateable messages and instead generates a single DataPack resource. 248 translateable messages and instead generates a single DataPack resource.
232 """ 249 """
233 250
234 def __init__(self, *args, **kwargs): 251 def __init__(self, *args, **kwargs):
235 super(ChromeHtml, self).__init__(*args, **kwargs) 252 super(ChromeHtml, self).__init__(*args, **kwargs)
236 self.allow_external_script_ = False 253 self.allow_external_script_ = False
237 self.flatten_html_ = False 254 self.flatten_html_ = False
238 # 1x resources are implicitly already in the source and do not need to be 255 # 1x resources are implicitly already in the source and do not need to be
239 # added. 256 # added.
240 self.scale_factors_ = [] 257 self.scale_factors_ = []
258 self.filename_expansion_function = None
241 259
242 def SetAttributes(self, attrs): 260 def SetAttributes(self, attrs):
243 self.allow_external_script_ = ('allowexternalscript' in attrs and 261 self.allow_external_script_ = ('allowexternalscript' in attrs and
244 attrs['allowexternalscript'] == 'true') 262 attrs['allowexternalscript'] == 'true')
245 self.flatten_html_ = ('flattenhtml' in attrs and 263 self.flatten_html_ = ('flattenhtml' in attrs and
246 attrs['flattenhtml'] == 'true') 264 attrs['flattenhtml'] == 'true')
247 265
248 def SetDefines(self, defines): 266 def SetDefines(self, defines):
249 if 'scale_factors' in defines: 267 if 'scale_factors' in defines:
250 self.scale_factors_ = defines['scale_factors'].split(',') 268 self.scale_factors_ = defines['scale_factors'].split(',')
251 269
252 def GetText(self): 270 def GetText(self):
253 """Returns inlined text of the HTML document.""" 271 """Returns inlined text of the HTML document."""
254 return self.inlined_text_ 272 return self.inlined_text_
255 273
256 def GetTextualIds(self): 274 def GetTextualIds(self):
257 return [self.extkey] 275 return [self.extkey]
258 276
259 def GetData(self, lang, encoding): 277 def GetData(self, lang, encoding):
260 """Returns inlined text of the HTML document.""" 278 """Returns inlined text of the HTML document."""
261 return self.inlined_text_ 279 return self.inlined_text_
262 280
263 def GetHtmlResourceFilenames(self): 281 def GetHtmlResourceFilenames(self):
264 """Returns a set of all filenames inlined by this file.""" 282 """Returns a set of all filenames inlined by this file."""
265 if self.flatten_html_: 283 if self.flatten_html_:
266 return html_inline.GetResourceFilenames( 284 return html_inline.GetResourceFilenames(
267 self.grd_node.ToRealPath(self.GetInputPath()), 285 self.grd_node.ToRealPath(self.GetInputPath()),
268 allow_external_script=self.allow_external_script_, 286 allow_external_script=self.allow_external_script_,
269 rewrite_function=lambda fp, t, d: ProcessImageSets( 287 rewrite_function=lambda fp, t, d: ProcessImageSets(
270 fp, t, self.scale_factors_, d)) 288 fp, t, self.scale_factors_, d,
289 filename_expansion_function=self.filename_expansion_function),
290 filename_expansion_function=self.filename_expansion_function)
271 return [] 291 return []
272 292
273 def Translate(self, lang, pseudo_if_not_available=True, 293 def Translate(self, lang, pseudo_if_not_available=True,
274 skeleton_gatherer=None, fallback_to_english=False): 294 skeleton_gatherer=None, fallback_to_english=False):
275 """Returns this document translated.""" 295 """Returns this document translated."""
276 return self.inlined_text_ 296 return self.inlined_text_
277 297
298 def SetFilenameExpansionFunction(self, fn):
299 self.filename_expansion_function = fn
300
278 def Parse(self): 301 def Parse(self):
279 """Parses and inlines the represented file.""" 302 """Parses and inlines the represented file."""
280 303
281 filename = self.GetInputPath() 304 filename = self.GetInputPath()
305 if self.filename_expansion_function:
306 filename = self.filename_expansion_function(filename)
282 # Hack: some unit tests supply an absolute path and no root node. 307 # Hack: some unit tests supply an absolute path and no root node.
283 if not os.path.isabs(filename): 308 if not os.path.isabs(filename):
284 filename = self.grd_node.ToRealPath(filename) 309 filename = self.grd_node.ToRealPath(filename)
285 if self.flatten_html_: 310 if self.flatten_html_:
286 self.inlined_text_ = html_inline.InlineToString( 311 self.inlined_text_ = html_inline.InlineToString(
287 filename, 312 filename,
288 self.grd_node, 313 self.grd_node,
289 allow_external_script = self.allow_external_script_, 314 allow_external_script = self.allow_external_script_,
290 rewrite_function=lambda fp, t, d: ProcessImageSets( 315 rewrite_function=lambda fp, t, d: ProcessImageSets(
291 fp, t, self.scale_factors_, d)) 316 fp, t, self.scale_factors_, d,
317 filename_expansion_function=self.filename_expansion_function),
318 filename_expansion_function=self.filename_expansion_function)
292 else: 319 else:
293 distribution = html_inline.GetDistribution() 320 distribution = html_inline.GetDistribution()
294 self.inlined_text_ = ProcessImageSets( 321 self.inlined_text_ = ProcessImageSets(
295 os.path.dirname(filename), 322 os.path.dirname(filename),
296 util.ReadFile(filename, 'utf-8'), 323 util.ReadFile(filename, 'utf-8'),
297 self.scale_factors_, 324 self.scale_factors_,
298 distribution) 325 distribution,
326 filename_expansion_function=self.filename_expansion_function)
OLDNEW
« no previous file with comments | « grit/format/html_inline_unittest.py ('k') | grit/gather/chrome_html_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698