# Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import base64 import os import re class Image(object): def __init__(self, resource): self.resource = resource self.aliases = [] @property def relative_path(self): return self.resource.relative_path @property def absolute_path(self): return self.resource.absolute_path @property def contents(self): return self.resource.contents class ParsedStyleSheet(object): def __init__(self, loader, containing_dirname, contents): self.loader = loader self.contents = contents self._images = None self._Load(containing_dirname) @property def images(self): return self._images def AppendDirectlyDependentFilenamesTo(self, dependent_filenames): for i in self.images: dependent_filenames.append(i.resource.absolute_path) @property def contents_with_inlined_images(self): images_by_url = {} for i in self.images: for a in i.aliases: images_by_url[a] = i def InlineUrl(m): url = m.group('url') image = images_by_url[url] ext = os.path.splitext(image.absolute_path)[1] data = base64.standard_b64encode(image.contents) return 'url(data:image/%s;base64,%s)' % (ext[1:], data) # I'm assuming we only have url()'s associated with images return re.sub('url\((?P"|\'|)(?P[^"\'()]*)(?P=quote)\)', InlineUrl, self.contents) def AppendDirectlyDependentFilenamesTo(self, dependent_filenames): for i in self.images: dependent_filenames.append(i.resource.absolute_path) def _Load(self, containing_dirname): if self.contents.find('@import') != -1: raise Exception('@imports are not supported') matches = re.findall( 'url\((?:["|\']?)([^"\'()]*)(?:["|\']?)\)', self.contents) def resolve_url(url): if os.path.isabs(url): # FIXME: module is used here, but py_vulcanize.module is never imported. # However, py_vulcanize.module cannot be imported since py_vulcanize.module may import # style_sheet, leading to an import loop. raise module.DepsException('URL references must be relative') # URLS are relative to this module's directory abs_path = os.path.abspath(os.path.join(containing_dirname, url)) image = self.loader.LoadImage(abs_path) image.aliases.append(url) return image self._images = [resolve_url(x) for x in matches] class StyleSheet(object): """Represents a stylesheet resource referenced by a module via the base.requireStylesheet(xxx) directive.""" def __init__(self, loader, name, resource): self.loader = loader self.name = name self.resource = resource self._parsed_style_sheet = None @property def filename(self): return self.resource.absolute_path @property def contents(self): return self.resource.contents def __repr__(self): return 'StyleSheet(%s)' % self.name @property def images(self): self._InitParsedStyleSheetIfNeeded() return self._parsed_style_sheet.images def AppendDirectlyDependentFilenamesTo(self, dependent_filenames): self._InitParsedStyleSheetIfNeeded() dependent_filenames.append(self.resource.absolute_path) self._parsed_style_sheet.AppendDirectlyDependentFilenamesTo( dependent_filenames) @property def contents_with_inlined_images(self): self._InitParsedStyleSheetIfNeeded() return self._parsed_style_sheet.contents_with_inlined_images def load(self): self._InitParsedStyleSheetIfNeeded() def _InitParsedStyleSheetIfNeeded(self): if self._parsed_style_sheet: return module_dirname = os.path.dirname(self.resource.absolute_path) self._parsed_style_sheet = ParsedStyleSheet( self.loader, module_dirname, self.contents)