OLD | NEW |
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Presubmit script for Chromium browser resources. | 5 """Presubmit script for Chromium browser resources. |
6 | 6 |
7 See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts | 7 See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts |
8 for more details about the presubmit API built into gcl/git cl, and see | 8 for more details about the presubmit API built into gcl/git cl, and see |
9 http://www.chromium.org/developers/web-development-style-guide for the rules | 9 http://www.chromium.org/developers/web-development-style-guide for the rules |
10 we're checking against here. | 10 we're checking against here. |
11 """ | 11 """ |
12 | 12 |
13 | 13 |
14 import os | 14 import os |
15 import struct | 15 import struct |
16 | 16 |
17 | 17 |
| 18 class InvalidPNGException(Exception): |
| 19 pass |
| 20 |
| 21 |
18 class ResourceScaleFactors(object): | 22 class ResourceScaleFactors(object): |
19 """Verifier of image dimensions for Chromium resources. | 23 """Verifier of image dimensions for Chromium resources. |
20 | 24 |
21 This class verifies the image dimensions of resources in the various | 25 This class verifies the image dimensions of resources in the various |
22 resource subdirectories. | 26 resource subdirectories. |
23 | 27 |
24 Attributes: | 28 Attributes: |
25 paths: An array of tuples giving the folders to check and their | 29 paths: An array of tuples giving the folders to check and their |
26 relevant scale factors. For example: | 30 relevant scale factors. For example: |
27 | 31 |
28 [(100, 'default_100_percent'), (200, 'default_200_percent')] | 32 [(100, 'default_100_percent'), (200, 'default_200_percent')] |
29 """ | 33 """ |
30 | 34 |
31 def __init__(self, input_api, output_api, paths): | 35 def __init__(self, input_api, output_api, paths): |
32 """ Initializes ResourceScaleFactors with paths.""" | 36 """ Initializes ResourceScaleFactors with paths.""" |
33 self.input_api = input_api | 37 self.input_api = input_api |
34 self.output_api = output_api | 38 self.output_api = output_api |
35 self.paths = paths | 39 self.paths = paths |
36 | 40 |
37 def RunChecks(self): | 41 def RunChecks(self): |
38 """Verifies the scale factors of resources being added or modified. | 42 """Verifies the scale factors of resources being added or modified. |
39 | 43 |
40 Returns: | 44 Returns: |
41 An array of presubmit errors if any images were detected not | 45 An array of presubmit errors if any images were detected not |
42 having the correct dimensions. | 46 having the correct dimensions. |
43 """ | 47 """ |
44 def ImageSize(filename): | 48 def ImageSize(filename): |
45 with open(filename, 'rb', buffering=0) as f: | 49 with open(filename, 'rb', buffering=0) as f: |
46 data = f.read(24) | 50 data = f.read(24) |
47 assert data[:8] == '\x89PNG\r\n\x1A\n' and data[12:16] == 'IHDR' | 51 if data[:8] != '\x89PNG\r\n\x1A\n' or data[12:16] != 'IHDR': |
| 52 raise InvalidPNGException |
48 return struct.unpack('>ii', data[16:24]) | 53 return struct.unpack('>ii', data[16:24]) |
49 | 54 |
50 # Returns a list of valid scaled image sizes. The valid sizes are the | 55 # Returns a list of valid scaled image sizes. The valid sizes are the |
51 # floor and ceiling of (base_size * scale_percent / 100). This is equivalent | 56 # floor and ceiling of (base_size * scale_percent / 100). This is equivalent |
52 # to requiring that the actual scaled size is less than one pixel away from | 57 # to requiring that the actual scaled size is less than one pixel away from |
53 # the exact scaled size. | 58 # the exact scaled size. |
54 def ValidSizes(base_size, scale_percent): | 59 def ValidSizes(base_size, scale_percent): |
55 return sorted(set([(base_size * scale_percent) / 100, | 60 return sorted(set([(base_size * scale_percent) / 100, |
56 (base_size * scale_percent + 99) / 100])) | 61 (base_size * scale_percent + 99) / 100])) |
57 | 62 |
(...skipping 10 matching lines...) Expand all Loading... |
68 path_root = self.input_api.os_path.join( | 73 path_root = self.input_api.os_path.join( |
69 repository_path, path_spec[1]) | 74 repository_path, path_spec[1]) |
70 if (f.LocalPath().endswith('.png') and | 75 if (f.LocalPath().endswith('.png') and |
71 f.LocalPath().startswith(path_root)): | 76 f.LocalPath().startswith(path_root)): |
72 # Only save the relative path from the resource directory. | 77 # Only save the relative path from the resource directory. |
73 relative_path = self.input_api.os_path.relpath(f.LocalPath(), | 78 relative_path = self.input_api.os_path.relpath(f.LocalPath(), |
74 path_root) | 79 path_root) |
75 if relative_path not in files: | 80 if relative_path not in files: |
76 files.append(relative_path) | 81 files.append(relative_path) |
77 | 82 |
| 83 corrupt_png_error = ('Corrupt PNG in file %s. Note that binaries are not ' |
| 84 'correctly uploaded to the code review tool and must be directly ' |
| 85 'submitted using the dcommit command.') |
78 for f in files: | 86 for f in files: |
79 base_image = self.input_api.os_path.join(self.paths[0][1], f) | 87 base_image = self.input_api.os_path.join(self.paths[0][1], f) |
80 if not os.path.exists(base_image): | 88 if not os.path.exists(base_image): |
81 results.append(self.output_api.PresubmitError( | 89 results.append(self.output_api.PresubmitError( |
82 'Base image %s does not exist' % self.input_api.os_path.join( | 90 'Base image %s does not exist' % self.input_api.os_path.join( |
83 repository_path, base_image))) | 91 repository_path, base_image))) |
84 continue | 92 continue |
85 base_dimensions = ImageSize(base_image) | 93 try: |
| 94 base_dimensions = ImageSize(base_image) |
| 95 except InvalidPNGException: |
| 96 results.append(self.output_api.PresubmitError(corrupt_png_error % |
| 97 self.input_api.os_path.join(repository_path, base_image))) |
| 98 continue |
86 # Find all scaled versions of the base image and verify their sizes. | 99 # Find all scaled versions of the base image and verify their sizes. |
87 for i in range(1, len(self.paths)): | 100 for i in range(1, len(self.paths)): |
88 image_path = self.input_api.os_path.join(self.paths[i][1], f) | 101 image_path = self.input_api.os_path.join(self.paths[i][1], f) |
89 if not os.path.exists(image_path): | 102 if not os.path.exists(image_path): |
90 continue | 103 continue |
91 # Ensure that each image for a particular scale factor is the | 104 # Ensure that each image for a particular scale factor is the |
92 # correct scale of the base image. | 105 # correct scale of the base image. |
93 scaled_dimensions = ImageSize(image_path) | 106 try: |
| 107 scaled_dimensions = ImageSize(image_path) |
| 108 except InvalidPNGException: |
| 109 results.append(self.output_api.PresubmitError(corrupt_png_error % |
| 110 self.input_api.os_path.join(repository_path, image_path))) |
| 111 continue |
94 for dimension_name, base_size, scaled_size in zip( | 112 for dimension_name, base_size, scaled_size in zip( |
95 ('width', 'height'), base_dimensions, scaled_dimensions): | 113 ('width', 'height'), base_dimensions, scaled_dimensions): |
96 valid_sizes = ValidSizes(base_size, self.paths[i][0]) | 114 valid_sizes = ValidSizes(base_size, self.paths[i][0]) |
97 if scaled_size not in valid_sizes: | 115 if scaled_size not in valid_sizes: |
98 results.append(self.output_api.PresubmitError( | 116 results.append(self.output_api.PresubmitError( |
99 'Image %s has %s %d, expected to be %s' % ( | 117 'Image %s has %s %d, expected to be %s' % ( |
100 self.input_api.os_path.join(repository_path, image_path), | 118 self.input_api.os_path.join(repository_path, image_path), |
101 dimension_name, | 119 dimension_name, |
102 scaled_size, | 120 scaled_size, |
103 ' or '.join(map(str, valid_sizes))))) | 121 ' or '.join(map(str, valid_sizes))))) |
104 return results | 122 return results |
OLD | NEW |