| OLD | NEW |
| (Empty) |
| 1 # Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. | |
| 2 # | |
| 3 # Redistribution and use in source and binary forms, with or without | |
| 4 # modification, are permitted provided that the following conditions | |
| 5 # are met: | |
| 6 # | |
| 7 # 1. Redistributions of source code must retain the above | |
| 8 # copyright notice, this list of conditions and the following | |
| 9 # disclaimer. | |
| 10 # 2. Redistributions in binary form must reproduce the above | |
| 11 # copyright notice, this list of conditions and the following | |
| 12 # disclaimer in the documentation and/or other materials | |
| 13 # provided with the distribution. | |
| 14 # | |
| 15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY | |
| 16 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 17 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
| 18 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE | |
| 19 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, | |
| 20 # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| 21 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| 22 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | |
| 24 # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF | |
| 25 # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 26 # SUCH DAMAGE. | |
| 27 | |
| 28 import logging | |
| 29 import re | |
| 30 | |
| 31 from webkitpy.common.host import Host | |
| 32 from webkitpy.common.webkit_finder import WebKitFinder | |
| 33 from HTMLParser import HTMLParser | |
| 34 | |
| 35 | |
| 36 _log = logging.getLogger(__name__) | |
| 37 | |
| 38 | |
| 39 def convert_for_webkit(new_path, filename, reference_support_info, host=Host()): | |
| 40 """Converts a file's contents so the Blink layout test runner can run it. | |
| 41 | |
| 42 Args: | |
| 43 new_path: Absolute path where file will be copied to in the Chromium rep
o. | |
| 44 filename: Absolute path to where the file is. | |
| 45 reference_support_info: Dict of information about a related reference HT
ML, if any. | |
| 46 | |
| 47 Returns: | |
| 48 A pair of (list of modified CSS properties, modified text). | |
| 49 """ | |
| 50 # Conversion is not necessary for any tests in wpt now; see http://crbug.com
/654081. | |
| 51 contents = host.filesystem.read_binary_file(filename) | |
| 52 try: | |
| 53 contents = contents.decode('utf-8') | |
| 54 except UnicodeDecodeError: | |
| 55 contents = contents.decode('utf-16') | |
| 56 | |
| 57 converter = _W3CTestConverter(new_path, filename, reference_support_info, ho
st) | |
| 58 if filename.endswith('.css'): | |
| 59 return converter.add_webkit_prefix_to_unprefixed_properties(contents) | |
| 60 converter.feed(contents) | |
| 61 converter.close() | |
| 62 return converter.output() | |
| 63 | |
| 64 | |
| 65 class _W3CTestConverter(HTMLParser): | |
| 66 """A HTMLParser subclass which converts a HTML file as it is parsed. | |
| 67 | |
| 68 After the feed() method is called, the converted document will be stored | |
| 69 in converted_data, and can be retrieved with the output() method. | |
| 70 """ | |
| 71 | |
| 72 def __init__(self, new_path, filename, reference_support_info, host=Host()): | |
| 73 HTMLParser.__init__(self) | |
| 74 | |
| 75 self._host = host | |
| 76 self._filesystem = self._host.filesystem | |
| 77 self._webkit_root = WebKitFinder(self._filesystem).webkit_base() | |
| 78 | |
| 79 self.converted_data = [] | |
| 80 self.converted_properties = [] | |
| 81 self.in_style_tag = False | |
| 82 self.style_data = [] | |
| 83 self.filename = filename | |
| 84 self.reference_support_info = reference_support_info | |
| 85 resources_path = self.path_from_webkit_root('LayoutTests', 'resources') | |
| 86 resources_relpath = self._filesystem.relpath(resources_path, new_path) | |
| 87 self.resources_relpath = resources_relpath | |
| 88 | |
| 89 # These settings might vary between WebKit and Blink. | |
| 90 # Only -webkit-text-emphasis is currently needed. See: | |
| 91 # https://bugs.chromium.org/p/chromium/issues/detail?id=614955#c1 | |
| 92 self.prefixed_properties = [ | |
| 93 '-webkit-text-emphasis', | |
| 94 '-webkit-text-emphasis-color', | |
| 95 '-webkit-text-emphasis-position', | |
| 96 '-webkit-text-emphasis-style', | |
| 97 ] | |
| 98 prop_regex = r'([\s{]|^)(' + '|'.join( | |
| 99 prop.replace('-webkit-', '') for prop in self.prefixed_properties) +
r')(\s+:|:)' | |
| 100 self.prop_re = re.compile(prop_regex) | |
| 101 | |
| 102 def output(self): | |
| 103 return (self.converted_properties, ''.join(self.converted_data)) | |
| 104 | |
| 105 def path_from_webkit_root(self, *comps): | |
| 106 return self._filesystem.abspath(self._filesystem.join(self._webkit_root,
*comps)) | |
| 107 | |
| 108 def add_webkit_prefix_to_unprefixed_properties(self, text): | |
| 109 """Searches |text| for instances of properties requiring the -webkit- pr
efix and adds the prefix to them. | |
| 110 | |
| 111 Returns the list of converted properties and the modified text. | |
| 112 """ | |
| 113 converted_properties = set() | |
| 114 text_chunks = [] | |
| 115 cur_pos = 0 | |
| 116 for match in self.prop_re.finditer(text): | |
| 117 text_chunks.extend([ | |
| 118 text[cur_pos:match.start()], | |
| 119 match.group(1), '-webkit-', | |
| 120 match.group(2), | |
| 121 match.group(3) | |
| 122 ]) | |
| 123 converted_properties.add(match.group(2)) | |
| 124 cur_pos = match.end() | |
| 125 text_chunks.append(text[cur_pos:]) | |
| 126 | |
| 127 for prop in converted_properties: | |
| 128 _log.info(' converting %s', prop) | |
| 129 | |
| 130 # FIXME: Handle the JS versions of these properties and GetComputedStyle
, too. | |
| 131 return (converted_properties, ''.join(text_chunks)) | |
| 132 | |
| 133 def convert_reference_relpaths(self, text): | |
| 134 """Converts reference file paths found in the given text. | |
| 135 | |
| 136 Searches |text| for instances of files in |self.reference_support_info|
and | |
| 137 updates the relative path to be correct for the new ref file location. | |
| 138 """ | |
| 139 converted = text | |
| 140 for path in self.reference_support_info['files']: | |
| 141 if path in text: | |
| 142 # FIXME: This doesn't handle an edge case where simply removing
the relative path doesn't work. | |
| 143 # See crbug.com/421584 for details. | |
| 144 new_path = re.sub(self.reference_support_info['reference_relpath
'], '', path, 1) | |
| 145 converted = re.sub(path, new_path, text) | |
| 146 | |
| 147 return converted | |
| 148 | |
| 149 def convert_style_data(self, data): | |
| 150 converted = self.add_webkit_prefix_to_unprefixed_properties(data) | |
| 151 if converted[0]: | |
| 152 self.converted_properties.extend(list(converted[0])) | |
| 153 | |
| 154 if self.reference_support_info is None or self.reference_support_info ==
{}: | |
| 155 return converted[1] | |
| 156 | |
| 157 return self.convert_reference_relpaths(converted[1]) | |
| 158 | |
| 159 def convert_attributes_if_needed(self, tag, attrs): | |
| 160 """Converts attributes in a start tag in HTML. | |
| 161 | |
| 162 The converted tag text is appended to |self.converted_data|. | |
| 163 """ | |
| 164 converted = self.get_starttag_text() | |
| 165 for attr_name, attr_value in attrs: | |
| 166 if attr_name == 'style': | |
| 167 new_style = self.convert_style_data(attr_value) | |
| 168 converted = re.sub(re.escape(attr_value), new_style, converted) | |
| 169 | |
| 170 src_tags = ('script', 'img', 'style', 'frame', 'iframe', 'input', 'layer
', 'textarea', 'video', 'audio') | |
| 171 if tag in src_tags and self.reference_support_info is not None and self.
reference_support_info != {}: | |
| 172 for attr_name, attr_value in attrs: | |
| 173 if attr_name == 'src': | |
| 174 new_path = self.convert_reference_relpaths(attr_value) | |
| 175 converted = re.sub(re.escape(attr_value), new_path, converte
d) | |
| 176 | |
| 177 self.converted_data.append(converted) | |
| 178 | |
| 179 def parse_endtag(self, i): | |
| 180 # parse_endtag is being overridden here instead of handle_endtag | |
| 181 # so we can get the original end tag text with the original | |
| 182 # capitalization | |
| 183 endpos = HTMLParser.parse_endtag(self, i) | |
| 184 self.converted_data.extend([self.rawdata[i:endpos]]) | |
| 185 return endpos | |
| 186 | |
| 187 def handle_starttag(self, tag, attrs): | |
| 188 if tag == 'style': | |
| 189 self.in_style_tag = True | |
| 190 self.convert_attributes_if_needed(tag, attrs) | |
| 191 | |
| 192 def handle_endtag(self, tag): | |
| 193 if tag == 'style': | |
| 194 self.converted_data.append(self.convert_style_data(''.join(self.styl
e_data))) | |
| 195 self.in_style_tag = False | |
| 196 self.style_data = [] | |
| 197 | |
| 198 def handle_startendtag(self, tag, attrs): | |
| 199 self.convert_attributes_if_needed(tag, attrs) | |
| 200 | |
| 201 def handle_data(self, data): | |
| 202 if self.in_style_tag: | |
| 203 self.style_data.append(data) | |
| 204 else: | |
| 205 self.converted_data.append(data) | |
| 206 | |
| 207 def handle_entityref(self, name): | |
| 208 self.converted_data.extend(['&', name, ';']) | |
| 209 | |
| 210 def handle_charref(self, name): | |
| 211 self.converted_data.extend(['&#', name, ';']) | |
| 212 | |
| 213 def handle_comment(self, data): | |
| 214 self.converted_data.extend(['<!--', data, '-->']) | |
| 215 | |
| 216 def handle_decl(self, decl): | |
| 217 self.converted_data.extend(['<!', decl, '>']) | |
| 218 | |
| 219 def handle_pi(self, data): | |
| 220 self.converted_data.extend(['<?', data, '>']) | |
| OLD | NEW |