Index: grit/gather/chrome_scaled_image.py |
=================================================================== |
--- grit/gather/chrome_scaled_image.py (revision 202) |
+++ grit/gather/chrome_scaled_image.py (working copy) |
@@ -1,157 +0,0 @@ |
-#!/usr/bin/env python |
-# Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-# Use of this source code is governed by a BSD-style license that can be |
-# found in the LICENSE file. |
- |
-'''Gatherer for <structure type="chrome_scaled_image">. |
-''' |
- |
-import os |
-import struct |
- |
-from grit import exception |
-from grit import lazy_re |
-from grit import util |
-from grit.gather import interface |
- |
- |
-_PNG_SCALE_CHUNK = '\0\0\0\0csCl\xc1\x30\x60\x4d' |
- |
- |
-def _RescaleImage(data, from_scale, to_scale): |
- if from_scale != to_scale: |
- assert from_scale == 100 |
- # Rather than rescaling the image we add a custom chunk directing Chrome to |
- # rescale it on load. Just append it to the PNG data since |
- # _MoveSpecialChunksToFront will move it later anyway. |
- data += _PNG_SCALE_CHUNK |
- return data |
- |
- |
-_PNG_MAGIC = '\x89PNG\r\n\x1a\n' |
- |
-'''Mandatory first chunk in order for the png to be valid.''' |
-_FIRST_CHUNK = 'IHDR' |
- |
-'''Special chunks to move immediately after the IHDR chunk. (so that the PNG |
-remains valid.) |
-''' |
-_SPECIAL_CHUNKS = frozenset('csCl npTc'.split()) |
- |
-'''Any ancillary chunk not in this list is deleted from the PNG.''' |
-_ANCILLARY_CHUNKS_TO_LEAVE = frozenset( |
- 'bKGD cHRM gAMA iCCP pHYs sBIT sRGB tRNS'.split()) |
- |
- |
-def _MoveSpecialChunksToFront(data): |
- '''Move special chunks immediately after the IHDR chunk (so that the PNG |
- remains valid). Also delete ancillary chunks that are not on our whitelist. |
- ''' |
- first = [_PNG_MAGIC] |
- special_chunks = [] |
- rest = [] |
- for chunk in _ChunkifyPNG(data): |
- type = chunk[4:8] |
- critical = type < 'a' |
- if type == _FIRST_CHUNK: |
- first.append(chunk) |
- elif type in _SPECIAL_CHUNKS: |
- special_chunks.append(chunk) |
- elif critical or type in _ANCILLARY_CHUNKS_TO_LEAVE: |
- rest.append(chunk) |
- return ''.join(first + special_chunks + rest) |
- |
- |
-def _ChunkifyPNG(data): |
- '''Given a PNG image, yield its chunks in order.''' |
- assert data.startswith(_PNG_MAGIC) |
- pos = 8 |
- while pos != len(data): |
- length = 12 + struct.unpack_from('>I', data, pos)[0] |
- assert 12 <= length <= len(data) - pos |
- yield data[pos:pos+length] |
- pos += length |
- |
- |
-def _MakeBraceGlob(strings): |
- '''Given ['foo', 'bar'], return '{foo,bar}', for error reporting. |
- ''' |
- if len(strings) == 1: |
- return strings[0] |
- else: |
- return '{' + ','.join(strings) + '}' |
- |
- |
-class ChromeScaledImage(interface.GathererBase): |
- '''Represents an image that exists in multiple layout variants |
- (e.g. "default", "touch") and multiple scale variants |
- (e.g. "100_percent", "200_percent"). |
- ''' |
- |
- split_context_re_ = lazy_re.compile(r'(.+)_(\d+)_percent\Z') |
- |
- def _FindInputFile(self): |
- output_context = self.grd_node.GetRoot().output_context |
- match = self.split_context_re_.match(output_context) |
- if not match: |
- raise exception.MissingMandatoryAttribute( |
- 'All <output> nodes must have an appropriate context attribute' |
- ' (e.g. context="touch_200_percent")') |
- req_layout, req_scale = match.group(1), int(match.group(2)) |
- |
- layouts = [req_layout] |
- try_default_layout = self.grd_node.GetRoot().fallback_to_default_layout |
- if try_default_layout and 'default' not in layouts: |
- layouts.append('default') |
- |
- # TODO(tdanderson): Search in descending order of all image scales |
- # instead of immediately falling back to 100. |
- # See crbug.com/503643. |
- scales = [req_scale] |
- try_low_res = self.grd_node.FindBooleanAttribute( |
- 'fallback_to_low_resolution', default=False, skip_self=False) |
- if try_low_res and 100 not in scales: |
- scales.append(100) |
- |
- for layout in layouts: |
- for scale in scales: |
- dir = '%s_%s_percent' % (layout, scale) |
- path = os.path.join(dir, self.rc_file) |
- if os.path.exists(self.grd_node.ToRealPath(path)): |
- return path, scale, req_scale |
- |
- if not try_default_layout: |
- # The file was not found in the specified output context and it was |
- # explicitly indicated that the default context should not be searched |
- # as a fallback, so return an empty path. |
- return None, 100, req_scale |
- |
- # The file was found in neither the specified context nor the default |
- # context, so raise an exception. |
- dir = "%s_%s_percent" % (_MakeBraceGlob(layouts), |
- _MakeBraceGlob(map(str, scales))) |
- raise exception.FileNotFound( |
- 'Tried ' + self.grd_node.ToRealPath(os.path.join(dir, self.rc_file))) |
- |
- def GetInputPath(self): |
- path, scale, req_scale = self._FindInputFile() |
- return path |
- |
- def Parse(self): |
- pass |
- |
- def GetTextualIds(self): |
- return [self.extkey] |
- |
- def GetData(self, *args): |
- path, scale, req_scale = self._FindInputFile() |
- if path is None: |
- return None |
- |
- data = util.ReadFile(self.grd_node.ToRealPath(path), util.BINARY) |
- data = _RescaleImage(data, scale, req_scale) |
- data = _MoveSpecialChunksToFront(data) |
- return data |
- |
- def Translate(self, *args, **kwargs): |
- return self.GetData() |