Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Tools / Scripts / webkitpy / w3c / test_converter.py
1 #!/usr/bin/env python
2
3 # Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 #
9 # 1. Redistributions of source code must retain the above
10 #    copyright notice, this list of conditions and the following
11 #    disclaimer.
12 # 2. Redistributions in binary form must reproduce the above
13 #    copyright notice, this list of conditions and the following
14 #    disclaimer in the documentation and/or other materials
15 #    provided with the distribution.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
18 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
21 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22 # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26 # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27 # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 # SUCH DAMAGE.
29
30 import logging
31 import re
32
33 from webkitpy.common.host import Host
34 from webkitpy.common.webkit_finder import WebKitFinder
35 from HTMLParser import HTMLParser
36
37
38 _log = logging.getLogger(__name__)
39
40
41 def convert_for_webkit(new_path, filename, reference_support_info, host=Host()):
42     """ Converts a file's |contents| so it will function correctly in its |new_path| in Webkit.
43
44     Returns the list of modified properties and the modified text if the file was modifed, None otherwise."""
45     contents = host.filesystem.read_binary_file(filename)
46     converter = _W3CTestConverter(new_path, filename, reference_support_info, host)
47     if filename.endswith('.css'):
48         return converter.add_webkit_prefix_to_unprefixed_properties(contents)
49     else:
50         converter.feed(contents)
51         converter.close()
52         return converter.output()
53
54
55 class _W3CTestConverter(HTMLParser):
56     def __init__(self, new_path, filename, reference_support_info, host=Host()):
57         HTMLParser.__init__(self)
58
59         self._host = host
60         self._filesystem = self._host.filesystem
61         self._webkit_root = WebKitFinder(self._filesystem).webkit_base()
62
63         self.converted_data = []
64         self.converted_properties = []
65         self.in_style_tag = False
66         self.style_data = []
67         self.filename = filename
68         self.reference_support_info = reference_support_info
69
70         resources_path = self.path_from_webkit_root('LayoutTests', 'resources')
71         resources_relpath = self._filesystem.relpath(resources_path, new_path)
72         self.resources_relpath = resources_relpath
73
74         # These settings might vary between WebKit and Blink
75         self._css_property_file = self.path_from_webkit_root('Source', 'core', 'css', 'CSSProperties.in')
76
77         self.prefixed_properties = self.read_webkit_prefixed_css_property_list()
78
79         self.prefixed_properties = self.read_webkit_prefixed_css_property_list()
80         prop_regex = '([\s{]|^)(' + "|".join(prop.replace('-webkit-', '') for prop in self.prefixed_properties) + ')(\s+:|:)'
81         self.prop_re = re.compile(prop_regex)
82
83     def output(self):
84         return (self.converted_properties, ''.join(self.converted_data))
85
86     def path_from_webkit_root(self, *comps):
87         return self._filesystem.abspath(self._filesystem.join(self._webkit_root, *comps))
88
89     def read_webkit_prefixed_css_property_list(self):
90         prefixed_properties = []
91         unprefixed_properties = set()
92
93         contents = self._filesystem.read_text_file(self._css_property_file)
94         for line in contents.splitlines():
95             if re.match('^(#|//|$)', line):
96                 # skip comments and preprocessor directives
97                 continue
98             prop = line.split()[0]
99             # Find properties starting with the -webkit- prefix.
100             match = re.match('-webkit-([\w|-]*)', prop)
101             if match:
102                 prefixed_properties.append(match.group(1))
103             else:
104                 unprefixed_properties.add(prop.strip())
105
106         # Ignore any prefixed properties for which an unprefixed version is supported
107         return [prop for prop in prefixed_properties if prop not in unprefixed_properties]
108
109     def add_webkit_prefix_to_unprefixed_properties(self, text):
110         """ Searches |text| for instances of properties requiring the -webkit- prefix and adds the prefix to them.
111
112         Returns the list of converted properties and the modified text."""
113
114         converted_properties = set()
115         text_chunks = []
116         cur_pos = 0
117         for m in self.prop_re.finditer(text):
118             text_chunks.extend([text[cur_pos:m.start()], m.group(1), '-webkit-', m.group(2), m.group(3)])
119             converted_properties.add(m.group(2))
120             cur_pos = m.end()
121         text_chunks.append(text[cur_pos:])
122
123         for prop in converted_properties:
124             _log.info('  converting %s', prop)
125
126         # FIXME: Handle the JS versions of these properties and GetComputedStyle, too.
127         return (converted_properties, ''.join(text_chunks))
128
129     def convert_reference_relpaths(self, text):
130         """ Searches |text| for instances of files in reference_support_info and updates the relative path to be correct for the new ref file location"""
131
132         converted = text
133         for path in self.reference_support_info['files']:
134             if text.find(path) != -1:
135                 # FIXME: This doesn't handle an edge case where simply removing the relative path doesn't work.
136                 # See crbug.com/421584 for details.
137                 new_path = re.sub(self.reference_support_info['reference_relpath'], '', path, 1)
138                 converted = re.sub(path, new_path, text)
139
140         return converted
141
142     def convert_style_data(self, data):
143         converted = self.add_webkit_prefix_to_unprefixed_properties(data)
144         if converted[0]:
145             self.converted_properties.extend(list(converted[0]))
146
147         if self.reference_support_info is None or self.reference_support_info == {}:
148             return converted[1]
149
150         return self.convert_reference_relpaths(converted[1])
151
152     def convert_attributes_if_needed(self, tag, attrs):
153         converted = self.get_starttag_text()
154         if tag in ('script', 'link'):
155             target_attr = 'src'
156             if tag != 'script':
157                 target_attr = 'href'
158             for attr_name, attr_value in attrs:
159                 if attr_name == target_attr:
160                     new_path = re.sub('/resources/testharness',
161                                       self.resources_relpath + '/testharness',
162                                       attr_value)
163                     converted = re.sub(re.escape(attr_value), new_path, converted)
164                     new_path = re.sub('/common/vendor-prefix',
165                                       self.resources_relpath + '/vendor-prefix',
166                                       attr_value)
167                     converted = re.sub(re.escape(attr_value), new_path, converted)
168
169         for attr_name, attr_value in attrs:
170             if attr_name == 'style':
171                 new_style = self.convert_style_data(attr_value)
172                 converted = re.sub(re.escape(attr_value), new_style, converted)
173             if attr_name == 'class' and 'instructions' in attr_value:
174                 # Always hide instructions, they're for manual testers.
175                 converted = re.sub(' style=".*?"', '', converted)
176                 converted = re.sub('\>', ' style="display:none">', converted)
177
178         src_tags = ('script', 'img', 'style', 'frame', 'iframe', 'input', 'layer', 'textarea', 'video', 'audio')
179         if tag in src_tags and self.reference_support_info is not None and self.reference_support_info != {}:
180             for attr_name, attr_value in attrs:
181                 if attr_name == 'src':
182                     new_path = self.convert_reference_relpaths(attr_value)
183                     converted = re.sub(re.escape(attr_value), new_path, converted)
184
185         self.converted_data.append(converted)
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.style_data)))
195             self.in_style_tag = False
196             self.style_data = []
197         self.converted_data.extend(['</', tag, '>'])
198
199     def handle_startendtag(self, tag, attrs):
200         self.convert_attributes_if_needed(tag, attrs)
201
202     def handle_data(self, data):
203         if self.in_style_tag:
204             self.style_data.append(data)
205         else:
206             self.converted_data.append(data)
207
208     def handle_entityref(self, name):
209         self.converted_data.extend(['&', name, ';'])
210
211     def handle_charref(self, name):
212         self.converted_data.extend(['&#', name, ';'])
213
214     def handle_comment(self, data):
215         self.converted_data.extend(['<!-- ', data, ' -->'])
216
217     def handle_decl(self, decl):
218         self.converted_data.extend(['<!', decl, '>'])
219
220     def handle_pi(self, data):
221         self.converted_data.extend(['<?', data, '>'])