PageRenderTime 41ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/qt/qtwebkit/Tools/Scripts/webkitpy/w3c/test_converter.py

https://gitlab.com/x33n/phantomjs
Python | 193 lines | 146 code | 16 blank | 31 comment | 7 complexity | 81aa8df6fd3abcd5d7a3d150df185fdd MD5 | raw file
  1. #!/usr/bin/env python
  2. # Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
  3. #
  4. # Redistribution and use in source and binary forms, with or without
  5. # modification, are permitted provided that the following conditions
  6. # are met:
  7. #
  8. # 1. Redistributions of source code must retain the above
  9. # copyright notice, this list of conditions and the following
  10. # disclaimer.
  11. # 2. Redistributions in binary form must reproduce the above
  12. # copyright notice, this list of conditions and the following
  13. # disclaimer in the documentation and/or other materials
  14. # provided with the distribution.
  15. #
  16. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
  17. # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  18. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  19. # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
  20. # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
  21. # OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  22. # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  23. # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24. # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  25. # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  26. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. # SUCH DAMAGE.
  28. import logging
  29. import re
  30. from webkitpy.common.host import Host
  31. from webkitpy.common.webkit_finder import WebKitFinder
  32. from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup, Tag
  33. _log = logging.getLogger(__name__)
  34. class W3CTestConverter(object):
  35. def __init__(self):
  36. self._host = Host()
  37. self._filesystem = self._host.filesystem
  38. self._webkit_root = WebKitFinder(self._filesystem).webkit_base()
  39. # These settings might vary between WebKit and Blink
  40. self._css_property_file = self.path_from_webkit_root('Source', 'WebCore', 'css', 'CSSPropertyNames.in')
  41. self._css_property_split_string = '='
  42. self.prefixed_properties = self.read_webkit_prefixed_css_property_list()
  43. def path_from_webkit_root(self, *comps):
  44. return self._filesystem.abspath(self._filesystem.join(self._webkit_root, *comps))
  45. def read_webkit_prefixed_css_property_list(self):
  46. prefixed_properties = []
  47. contents = self._filesystem.read_text_file(self._css_property_file)
  48. for line in contents.splitlines():
  49. # Find lines starting with the -webkit- prefix.
  50. match = re.match('-webkit-[\w|-]*', line)
  51. if match:
  52. # Ignore lines where both the prefixed and non-prefixed property
  53. # are supported - denoted by -webkit-some-property = some-property.
  54. fields = line.split(self._css_property_split_string)
  55. if len(fields) == 2 and fields[1].strip() in fields[0].strip():
  56. continue
  57. prefixed_properties.append(match.group(0))
  58. return prefixed_properties
  59. def convert_for_webkit(self, new_path, filename):
  60. """ Converts a file's |contents| so it will function correctly in its |new_path| in Webkit.
  61. Returns the list of modified properties and the modified text if the file was modifed, None otherwise."""
  62. contents = self._filesystem.read_binary_file(filename)
  63. if filename.endswith('.css'):
  64. return self.convert_css(contents, filename)
  65. return self.convert_html(new_path, contents, filename)
  66. def convert_css(self, contents, filename):
  67. return self.add_webkit_prefix_to_unprefixed_properties(contents, filename)
  68. def convert_html(self, new_path, contents, filename):
  69. doc = BeautifulSoup(contents)
  70. did_modify_paths = self.convert_testharness_paths(doc, new_path, filename)
  71. converted_properties_and_content = self.convert_prefixed_properties(doc, filename)
  72. return converted_properties_and_content if (did_modify_paths or converted_properties_and_content[0]) else None
  73. def convert_testharness_paths(self, doc, new_path, filename):
  74. """ Update links to testharness.js in the BeautifulSoup |doc| to point to the copy in |new_path|.
  75. Returns whether the document was modified."""
  76. # Look for the W3C-style path to any testharness files - scripts (.js) or links (.css)
  77. pattern = re.compile('/resources/testharness')
  78. script_tags = doc.findAll(src=pattern)
  79. link_tags = doc.findAll(href=pattern)
  80. testharness_tags = script_tags + link_tags
  81. if not testharness_tags:
  82. return False
  83. resources_path = self.path_from_webkit_root('LayoutTests', 'resources')
  84. resources_relpath = self._filesystem.relpath(resources_path, new_path)
  85. for tag in testharness_tags:
  86. # FIXME: We need to handle img, audio, video tags also.
  87. attr = 'src'
  88. if tag.name != 'script':
  89. attr = 'href'
  90. if not attr in tag.attrMap:
  91. # FIXME: Figure out what to do w/ invalid tags. For now, we return False
  92. # and leave the document unmodified, which means that it'll probably fail to run.
  93. _log.error("Missing an attr in %s" % filename)
  94. return False
  95. old_path = tag[attr]
  96. new_tag = Tag(doc, tag.name, tag.attrs)
  97. new_tag[attr] = re.sub(pattern, resources_relpath + '/testharness', old_path)
  98. self.replace_tag(tag, new_tag)
  99. return True
  100. def convert_prefixed_properties(self, doc, filename):
  101. """ Searches a BeautifulSoup |doc| for any CSS properties requiring the -webkit- prefix and converts them.
  102. Returns the list of converted properties and the modified document as a string """
  103. converted_properties = []
  104. # Look for inline and document styles.
  105. inline_styles = doc.findAll(style=re.compile('.*'))
  106. style_tags = doc.findAll('style')
  107. all_styles = inline_styles + style_tags
  108. for tag in all_styles:
  109. # Get the text whether in a style tag or style attribute.
  110. style_text = ''
  111. if tag.name == 'style':
  112. if not tag.contents:
  113. continue
  114. style_text = tag.contents[0]
  115. else:
  116. style_text = tag['style']
  117. updated_style_text = self.add_webkit_prefix_to_unprefixed_properties(style_text, filename)
  118. # Rewrite tag only if changes were made.
  119. if updated_style_text[0]:
  120. converted_properties.extend(updated_style_text[0])
  121. new_tag = Tag(doc, tag.name, tag.attrs)
  122. new_tag.insert(0, updated_style_text[1])
  123. self.replace_tag(tag, new_tag)
  124. return (converted_properties, doc.prettify())
  125. def add_webkit_prefix_to_unprefixed_properties(self, text, filename):
  126. """ Searches |text| for instances of properties requiring the -webkit- prefix and adds the prefix to them.
  127. Returns the list of converted properties and the modified text."""
  128. converted_properties = []
  129. for prefixed_property in self.prefixed_properties:
  130. # FIXME: add in both the prefixed and unprefixed versions, rather than just replacing them?
  131. # That might allow the imported test to work in other browsers more easily.
  132. unprefixed_property = prefixed_property.replace('-webkit-', '')
  133. # Look for the various ways it might be in the CSS
  134. # Match the the property preceded by either whitespace or left curly brace
  135. # or at the beginning of the string (for inline style attribute)
  136. pattern = '([\s{]|^)' + unprefixed_property + '(\s+:|:)'
  137. if re.search(pattern, text):
  138. _log.info('converting %s -> %s' % (unprefixed_property, prefixed_property))
  139. converted_properties.append(prefixed_property)
  140. text = re.sub(pattern, prefixed_property + ':', text)
  141. # FIXME: Handle the JS versions of these properties and GetComputedStyle, too.
  142. return (converted_properties, text)
  143. def replace_tag(self, old_tag, new_tag):
  144. index = old_tag.parent.contents.index(old_tag)
  145. old_tag.parent.insert(index, new_tag)
  146. old_tag.extract()