Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(141)

Side by Side Diff: grit/gather/chrome_scaled_image.py

Issue 1442863002: Remove contents of grit's SVN repository. (Closed) Base URL: http://grit-i18n.googlecode.com/svn/trunk/
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « grit/gather/chrome_html_unittest.py ('k') | grit/gather/chrome_scaled_image_unittest.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 '''Gatherer for <structure type="chrome_scaled_image">.
7 '''
8
9 import os
10 import struct
11
12 from grit import exception
13 from grit import lazy_re
14 from grit import util
15 from grit.gather import interface
16
17
18 _PNG_SCALE_CHUNK = '\0\0\0\0csCl\xc1\x30\x60\x4d'
19
20
21 def _RescaleImage(data, from_scale, to_scale):
22 if from_scale != to_scale:
23 assert from_scale == 100
24 # Rather than rescaling the image we add a custom chunk directing Chrome to
25 # rescale it on load. Just append it to the PNG data since
26 # _MoveSpecialChunksToFront will move it later anyway.
27 data += _PNG_SCALE_CHUNK
28 return data
29
30
31 _PNG_MAGIC = '\x89PNG\r\n\x1a\n'
32
33 '''Mandatory first chunk in order for the png to be valid.'''
34 _FIRST_CHUNK = 'IHDR'
35
36 '''Special chunks to move immediately after the IHDR chunk. (so that the PNG
37 remains valid.)
38 '''
39 _SPECIAL_CHUNKS = frozenset('csCl npTc'.split())
40
41 '''Any ancillary chunk not in this list is deleted from the PNG.'''
42 _ANCILLARY_CHUNKS_TO_LEAVE = frozenset(
43 'bKGD cHRM gAMA iCCP pHYs sBIT sRGB tRNS'.split())
44
45
46 def _MoveSpecialChunksToFront(data):
47 '''Move special chunks immediately after the IHDR chunk (so that the PNG
48 remains valid). Also delete ancillary chunks that are not on our whitelist.
49 '''
50 first = [_PNG_MAGIC]
51 special_chunks = []
52 rest = []
53 for chunk in _ChunkifyPNG(data):
54 type = chunk[4:8]
55 critical = type < 'a'
56 if type == _FIRST_CHUNK:
57 first.append(chunk)
58 elif type in _SPECIAL_CHUNKS:
59 special_chunks.append(chunk)
60 elif critical or type in _ANCILLARY_CHUNKS_TO_LEAVE:
61 rest.append(chunk)
62 return ''.join(first + special_chunks + rest)
63
64
65 def _ChunkifyPNG(data):
66 '''Given a PNG image, yield its chunks in order.'''
67 assert data.startswith(_PNG_MAGIC)
68 pos = 8
69 while pos != len(data):
70 length = 12 + struct.unpack_from('>I', data, pos)[0]
71 assert 12 <= length <= len(data) - pos
72 yield data[pos:pos+length]
73 pos += length
74
75
76 def _MakeBraceGlob(strings):
77 '''Given ['foo', 'bar'], return '{foo,bar}', for error reporting.
78 '''
79 if len(strings) == 1:
80 return strings[0]
81 else:
82 return '{' + ','.join(strings) + '}'
83
84
85 class ChromeScaledImage(interface.GathererBase):
86 '''Represents an image that exists in multiple layout variants
87 (e.g. "default", "touch") and multiple scale variants
88 (e.g. "100_percent", "200_percent").
89 '''
90
91 split_context_re_ = lazy_re.compile(r'(.+)_(\d+)_percent\Z')
92
93 def _FindInputFile(self):
94 output_context = self.grd_node.GetRoot().output_context
95 match = self.split_context_re_.match(output_context)
96 if not match:
97 raise exception.MissingMandatoryAttribute(
98 'All <output> nodes must have an appropriate context attribute'
99 ' (e.g. context="touch_200_percent")')
100 req_layout, req_scale = match.group(1), int(match.group(2))
101
102 layouts = [req_layout]
103 try_default_layout = self.grd_node.GetRoot().fallback_to_default_layout
104 if try_default_layout and 'default' not in layouts:
105 layouts.append('default')
106
107 # TODO(tdanderson): Search in descending order of all image scales
108 # instead of immediately falling back to 100.
109 # See crbug.com/503643.
110 scales = [req_scale]
111 try_low_res = self.grd_node.FindBooleanAttribute(
112 'fallback_to_low_resolution', default=False, skip_self=False)
113 if try_low_res and 100 not in scales:
114 scales.append(100)
115
116 for layout in layouts:
117 for scale in scales:
118 dir = '%s_%s_percent' % (layout, scale)
119 path = os.path.join(dir, self.rc_file)
120 if os.path.exists(self.grd_node.ToRealPath(path)):
121 return path, scale, req_scale
122
123 if not try_default_layout:
124 # The file was not found in the specified output context and it was
125 # explicitly indicated that the default context should not be searched
126 # as a fallback, so return an empty path.
127 return None, 100, req_scale
128
129 # The file was found in neither the specified context nor the default
130 # context, so raise an exception.
131 dir = "%s_%s_percent" % (_MakeBraceGlob(layouts),
132 _MakeBraceGlob(map(str, scales)))
133 raise exception.FileNotFound(
134 'Tried ' + self.grd_node.ToRealPath(os.path.join(dir, self.rc_file)))
135
136 def GetInputPath(self):
137 path, scale, req_scale = self._FindInputFile()
138 return path
139
140 def Parse(self):
141 pass
142
143 def GetTextualIds(self):
144 return [self.extkey]
145
146 def GetData(self, *args):
147 path, scale, req_scale = self._FindInputFile()
148 if path is None:
149 return None
150
151 data = util.ReadFile(self.grd_node.ToRealPath(path), util.BINARY)
152 data = _RescaleImage(data, scale, req_scale)
153 data = _MoveSpecialChunksToFront(data)
154 return data
155
156 def Translate(self, *args, **kwargs):
157 return self.GetData()
OLDNEW
« no previous file with comments | « grit/gather/chrome_html_unittest.py ('k') | grit/gather/chrome_scaled_image_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698