| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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) |
| OLD | NEW |