OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2008, 2009, Google Inc. All rights reserved. | 2 * Copyright (c) 2008, 2009, Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 28 matching lines...) Expand all Loading... | |
39 namespace blink { | 39 namespace blink { |
40 | 40 |
41 // Number of bits in .ICO/.CUR used to store the directory and its entries, | 41 // Number of bits in .ICO/.CUR used to store the directory and its entries, |
42 // respectively (doesn't match sizeof values for member structs since we omit | 42 // respectively (doesn't match sizeof values for member structs since we omit |
43 // some fields). | 43 // some fields). |
44 static const size_t sizeOfDirectory = 6; | 44 static const size_t sizeOfDirectory = 6; |
45 static const size_t sizeOfDirEntry = 16; | 45 static const size_t sizeOfDirEntry = 16; |
46 | 46 |
47 ICOImageDecoder::ICOImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOp tion colorOptions, size_t maxDecodedBytes) | 47 ICOImageDecoder::ICOImageDecoder(AlphaOption alphaOption, GammaAndColorProfileOp tion colorOptions, size_t maxDecodedBytes) |
48 : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes) | 48 : ImageDecoder(alphaOption, colorOptions, maxDecodedBytes) |
49 , m_fastReader(nullptr) | |
49 , m_decodedOffset(0) | 50 , m_decodedOffset(0) |
50 { | 51 { |
51 } | 52 } |
52 | 53 |
53 ICOImageDecoder::~ICOImageDecoder() | 54 ICOImageDecoder::~ICOImageDecoder() |
54 { | 55 { |
55 } | 56 } |
56 | 57 |
57 void ICOImageDecoder::onSetData(SharedBuffer* data) | 58 void ICOImageDecoder::onSetData(SharedBuffer* data) |
58 { | 59 { |
60 m_fastReader.setData(data); | |
61 | |
59 for (BMPReaders::iterator i(m_bmpReaders.begin()); i != m_bmpReaders.end(); ++i) { | 62 for (BMPReaders::iterator i(m_bmpReaders.begin()); i != m_bmpReaders.end(); ++i) { |
60 if (*i) | 63 if (*i) |
61 (*i)->setData(data); | 64 (*i)->setData(data); |
62 } | 65 } |
63 for (size_t i = 0; i < m_pngDecoders.size(); ++i) | 66 for (size_t i = 0; i < m_pngDecoders.size(); ++i) |
64 setDataForPNGDecoderAtIndex(i); | 67 setDataForPNGDecoderAtIndex(i); |
65 } | 68 } |
66 | 69 |
67 IntSize ICOImageDecoder::size() const | 70 IntSize ICOImageDecoder::size() const |
68 { | 71 { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
119 { | 122 { |
120 decodeSize(); | 123 decodeSize(); |
121 return m_dirEntries.size(); | 124 return m_dirEntries.size(); |
122 } | 125 } |
123 | 126 |
124 void ICOImageDecoder::setDataForPNGDecoderAtIndex(size_t index) | 127 void ICOImageDecoder::setDataForPNGDecoderAtIndex(size_t index) |
125 { | 128 { |
126 if (!m_pngDecoders[index]) | 129 if (!m_pngDecoders[index]) |
127 return; | 130 return; |
128 | 131 |
129 const IconDirectoryEntry& dirEntry = m_dirEntries[index]; | 132 m_pngDecoders[index]->setData(m_data.get(), isAllDataReceived()); |
130 // Copy out PNG data to a separate vector and send to the PNG decoder. | |
131 // FIXME: Save this copy by making the PNG decoder able to take an | |
132 // optional offset. | |
133 RefPtr<SharedBuffer> pngData(SharedBuffer::create(&m_data->data()[dirEntry.m _imageOffset], m_data->size() - dirEntry.m_imageOffset)); | |
134 m_pngDecoders[index]->setData(pngData.get(), isAllDataReceived()); | |
135 } | 133 } |
136 | 134 |
137 void ICOImageDecoder::decode(size_t index, bool onlySize) | 135 void ICOImageDecoder::decode(size_t index, bool onlySize) |
138 { | 136 { |
139 if (failed()) | 137 if (failed()) |
140 return; | 138 return; |
141 | 139 |
142 // If we couldn't decode the image but we've received all the data, decoding | 140 // If we couldn't decode the image but we've received all the data, decoding |
143 // has failed. | 141 // has failed. |
144 if ((!decodeDirectory() || (!onlySize && !decodeAtIndex(index))) && isAllDat aReceived()) | 142 if ((!decodeDirectory() || (!onlySize && !decodeAtIndex(index))) && isAllDat aReceived()) |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
179 m_bmpReaders[index]->setData(m_data.get()); | 177 m_bmpReaders[index]->setData(m_data.get()); |
180 m_bmpReaders[index]->setBuffer(&m_frameBufferCache[index]); | 178 m_bmpReaders[index]->setBuffer(&m_frameBufferCache[index]); |
181 } | 179 } |
182 m_frameSize = dirEntry.m_size; | 180 m_frameSize = dirEntry.m_size; |
183 bool result = m_bmpReaders[index]->decodeBMP(false); | 181 bool result = m_bmpReaders[index]->decodeBMP(false); |
184 m_frameSize = IntSize(); | 182 m_frameSize = IntSize(); |
185 return result; | 183 return result; |
186 } | 184 } |
187 | 185 |
188 if (!m_pngDecoders[index]) { | 186 if (!m_pngDecoders[index]) { |
189 m_pngDecoders[index] = adoptPtr( | 187 AlphaOption alphaOption = m_premultiplyAlpha ? AlphaPremultiplied : Alph aNotPremultiplied; |
190 new PNGImageDecoder(m_premultiplyAlpha ? AlphaPremultiplied : AlphaN otPremultiplied, | 188 GammaAndColorProfileOption colorOptions = m_ignoreGammaAndColorProfile ? GammaAndColorProfileIgnored : GammaAndColorProfileApplied; |
Peter Kasting
2015/09/08 20:03:13
Nit: I'd name this "option" instead of "options" t
scroggo_chromium
2015/09/08 20:52:51
This name was suggested to me by noel@ a refactori
| |
191 m_ignoreGammaAndColorProfile ? GammaAndColorProfileIgnored : Gam maAndColorProfileApplied, m_maxDecodedBytes)); | 189 |
190 // dirEntry.m_imageOffset is known to be correct, since this function is never called unless decodeDirectory succeeds. | |
Peter Kasting
2015/09/08 20:03:13
Nit: This comment is probably unnecessary, we assu
scroggo_chromium
2015/09/08 20:52:51
Done.
| |
191 m_pngDecoders[index] = adoptPtr(new PNGImageDecoder(alphaOption, colorOp tions, m_maxDecodedBytes, dirEntry.m_imageOffset)); | |
192 | |
192 setDataForPNGDecoderAtIndex(index); | 193 setDataForPNGDecoderAtIndex(index); |
193 } | 194 } |
195 | |
194 // Fail if the size the PNGImageDecoder calculated does not match the size | 196 // Fail if the size the PNGImageDecoder calculated does not match the size |
195 // in the directory. | 197 // in the directory. |
196 if (m_pngDecoders[index]->isSizeAvailable() && (m_pngDecoders[index]->size() != dirEntry.m_size)) | 198 if (m_pngDecoders[index]->isSizeAvailable() && (m_pngDecoders[index]->size() != dirEntry.m_size)) |
197 return setFailed(); | 199 return setFailed(); |
198 m_frameBufferCache[index] = *m_pngDecoders[index]->frameBufferAtIndex(0); | 200 m_frameBufferCache[index] = *m_pngDecoders[index]->frameBufferAtIndex(0); |
199 m_frameBufferCache[index].setPremultiplyAlpha(m_premultiplyAlpha); | 201 m_frameBufferCache[index].setPremultiplyAlpha(m_premultiplyAlpha); |
200 return !m_pngDecoders[index]->failed() || setFailed(); | 202 return !m_pngDecoders[index]->failed() || setFailed(); |
201 } | 203 } |
202 | 204 |
203 bool ICOImageDecoder::processDirectory() | 205 bool ICOImageDecoder::processDirectory() |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
246 // The image size is the size of the largest entry. | 248 // The image size is the size of the largest entry. |
247 const IconDirectoryEntry& dirEntry = m_dirEntries.first(); | 249 const IconDirectoryEntry& dirEntry = m_dirEntries.first(); |
248 // Technically, this next call shouldn't be able to fail, since the width | 250 // Technically, this next call shouldn't be able to fail, since the width |
249 // and height here are each <= 256, and |m_frameSize| is empty. | 251 // and height here are each <= 256, and |m_frameSize| is empty. |
250 return setSize(dirEntry.m_size.width(), dirEntry.m_size.height()); | 252 return setSize(dirEntry.m_size.width(), dirEntry.m_size.height()); |
251 } | 253 } |
252 | 254 |
253 ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry() | 255 ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry() |
254 { | 256 { |
255 // Read icon data. | 257 // Read icon data. |
256 // The casts to uint8_t in the next few lines are because that's the on-disk | 258 // The following calls to readUint8 return an uint8_t, which is appropriate |
Peter Kasting
2015/09/08 20:03:13
Nit: "...readUint8() return a uint8_t..." (add par
scroggo_chromium
2015/09/08 20:52:51
Done.
| |
257 // type of the width and height values. Storing them in ints (instead of | 259 // because that's the on-disk type of the width and height values. Storing |
258 // matching uint8_ts) is so we can record dimensions of size 256 (which is | 260 // them in ints (instead of matching uint8_ts) is so we can record dimension s |
259 // what a zero byte really means). | 261 // of size 256 (which is what a zero byte really means). |
260 int width = static_cast<uint8_t>(m_data->data()[m_decodedOffset]); | 262 int width = readUint8(0); |
261 if (!width) | 263 if (!width) |
262 width = 256; | 264 width = 256; |
263 int height = static_cast<uint8_t>(m_data->data()[m_decodedOffset + 1]); | 265 int height = readUint8(1); |
264 if (!height) | 266 if (!height) |
265 height = 256; | 267 height = 256; |
266 IconDirectoryEntry entry; | 268 IconDirectoryEntry entry; |
267 entry.m_size = IntSize(width, height); | 269 entry.m_size = IntSize(width, height); |
268 if (m_fileType == CURSOR) { | 270 if (m_fileType == CURSOR) { |
269 entry.m_bitCount = 0; | 271 entry.m_bitCount = 0; |
270 entry.m_hotSpot = IntPoint(readUint16(4), readUint16(6)); | 272 entry.m_hotSpot = IntPoint(readUint16(4), readUint16(6)); |
271 } else { | 273 } else { |
272 entry.m_bitCount = readUint16(6); | 274 entry.m_bitCount = readUint16(6); |
273 entry.m_hotSpot = IntPoint(); | 275 entry.m_hotSpot = IntPoint(); |
274 } | 276 } |
275 entry.m_imageOffset = readUint32(12); | 277 entry.m_imageOffset = readUint32(12); |
276 | 278 |
277 // Some icons don't have a bit depth, only a color count. Convert the | 279 // Some icons don't have a bit depth, only a color count. Convert the |
278 // color count to the minimum necessary bit depth. It doesn't matter if | 280 // color count to the minimum necessary bit depth. It doesn't matter if |
279 // this isn't quite what the bitmap info header says later, as we only use | 281 // this isn't quite what the bitmap info header says later, as we only use |
280 // this value to determine which icon entry is best. | 282 // this value to determine which icon entry is best. |
281 if (!entry.m_bitCount) { | 283 if (!entry.m_bitCount) { |
282 int colorCount = static_cast<uint8_t>(m_data->data()[m_decodedOffset + 2 ]); | 284 int colorCount = readUint8(2); |
283 if (!colorCount) | 285 if (!colorCount) |
284 colorCount = 256; // Vague in the spec, needed by real-world icons. | 286 colorCount = 256; // Vague in the spec, needed by real-world icons. |
285 for (--colorCount; colorCount; colorCount >>= 1) | 287 for (--colorCount; colorCount; colorCount >>= 1) |
286 ++entry.m_bitCount; | 288 ++entry.m_bitCount; |
287 } | 289 } |
288 | 290 |
289 m_decodedOffset += sizeOfDirEntry; | 291 m_decodedOffset += sizeOfDirEntry; |
290 return entry; | 292 return entry; |
291 } | 293 } |
292 | 294 |
293 ICOImageDecoder::ImageType ICOImageDecoder::imageTypeAtIndex(size_t index) | 295 ICOImageDecoder::ImageType ICOImageDecoder::imageTypeAtIndex(size_t index) |
294 { | 296 { |
295 // Check if this entry is a BMP or a PNG; we need 4 bytes to check the magic | 297 // Check if this entry is a BMP or a PNG; we need 4 bytes to check the magic |
296 // number. | 298 // number. |
297 ASSERT_WITH_SECURITY_IMPLICATION(index < m_dirEntries.size()); | 299 ASSERT_WITH_SECURITY_IMPLICATION(index < m_dirEntries.size()); |
298 const uint32_t imageOffset = m_dirEntries[index].m_imageOffset; | 300 const uint32_t imageOffset = m_dirEntries[index].m_imageOffset; |
299 if ((imageOffset > m_data->size()) || ((m_data->size() - imageOffset) < 4)) | 301 if ((imageOffset > m_data->size()) || ((m_data->size() - imageOffset) < 4)) |
300 return Unknown; | 302 return Unknown; |
301 return strncmp(&m_data->data()[imageOffset], "\x89PNG", 4) ? BMP : PNG; | 303 char buffer[4]; |
304 const char* data = m_fastReader.getConsecutiveData(imageOffset, 4, buffer); | |
305 return strncmp(data, "\x89PNG", 4) ? BMP : PNG; | |
302 } | 306 } |
303 | 307 |
304 } | 308 } |
OLD | NEW |