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 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
76 return (index && (index < m_dirEntries.size())) ? m_dirEntries[index].m_size : size(); | 76 return (index && (index < m_dirEntries.size())) ? m_dirEntries[index].m_size : size(); |
77 } | 77 } |
78 | 78 |
79 bool ICOImageDecoder::setSize(unsigned width, unsigned height) | 79 bool ICOImageDecoder::setSize(unsigned width, unsigned height) |
80 { | 80 { |
81 // The size calculated inside the BMPImageReader had better match the one in | 81 // The size calculated inside the BMPImageReader had better match the one in |
82 // the icon directory. | 82 // the icon directory. |
83 return m_frameSize.isEmpty() ? ImageDecoder::setSize(width, height) : ((IntS ize(width, height) == m_frameSize) || setFailed()); | 83 return m_frameSize.isEmpty() ? ImageDecoder::setSize(width, height) : ((IntS ize(width, height) == m_frameSize) || setFailed()); |
84 } | 84 } |
85 | 85 |
86 bool ICOImageDecoder::frameIsFullyReceivedAtIndex(size_t index) const | |
87 { | |
88 ASSERT(haveUpdatedFrameCount()); | |
89 if (index >= m_dirEntries.size()) | |
90 return ImageDecoder::frameIsFullyReceivedAtIndex(index); | |
91 const IconDirectoryEntry& dirEntry = m_dirEntries[index]; | |
92 return ((dirEntry.m_imageOffset + dirEntry.m_byteSize) <= m_data->size()) || ImageDecoder::frameIsFullyReceivedAtIndex(index); | |
93 } | |
94 | |
86 bool ICOImageDecoder::setFailed() | 95 bool ICOImageDecoder::setFailed() |
87 { | 96 { |
88 m_bmpReaders.clear(); | 97 m_bmpReaders.clear(); |
89 m_pngDecoders.clear(); | 98 m_pngDecoders.clear(); |
90 return ImageDecoder::setFailed(); | 99 return ImageDecoder::setFailed(); |
91 } | 100 } |
92 | 101 |
93 bool ICOImageDecoder::hotSpot(IntPoint& hotSpot) const | 102 bool ICOImageDecoder::hotSpot(IntPoint& hotSpot) const |
94 { | 103 { |
95 // When unspecified, the default frame is always frame 0. This is consistent with | 104 // When unspecified, the default frame is always frame 0. This is consistent with |
96 // BitmapImage where currentFrame() starts at 0 and only increases when anim ation is | 105 // BitmapImage where currentFrame() starts at 0 and only increases when anim ation is |
97 // requested. | 106 // requested. |
98 return hotSpotAtIndex(0, hotSpot); | 107 return hotSpotAtIndex(0, hotSpot); |
99 } | 108 } |
100 | 109 |
101 bool ICOImageDecoder::hotSpotAtIndex(size_t index, IntPoint& hotSpot) const | 110 bool ICOImageDecoder::hotSpotAtIndex(size_t index, IntPoint& hotSpot) const |
102 { | 111 { |
103 if (index >= m_dirEntries.size() || m_fileType != CURSOR) | 112 if (index >= m_dirEntries.size() || m_fileType != CURSOR) |
104 return false; | 113 return false; |
105 | 114 |
106 hotSpot = m_dirEntries[index].m_hotSpot; | 115 hotSpot = m_dirEntries[index].m_hotSpot; |
107 return true; | 116 return true; |
108 } | 117 } |
109 | 118 |
110 | |
111 // static | 119 // static |
112 bool ICOImageDecoder::compareEntries(const IconDirectoryEntry& a, const IconDire ctoryEntry& b) | 120 bool ICOImageDecoder::compareEntries(const IconDirectoryEntry& a, const IconDire ctoryEntry& b) |
113 { | 121 { |
114 // Larger icons are better. After that, higher bit-depth icons are better. | 122 // Larger icons are better. After that, higher bit-depth icons are better. |
115 const int aEntryArea = a.m_size.width() * a.m_size.height(); | 123 const int aEntryArea = a.m_size.width() * a.m_size.height(); |
116 const int bEntryArea = b.m_size.width() * b.m_size.height(); | 124 const int bEntryArea = b.m_size.width() * b.m_size.height(); |
117 return (aEntryArea == bEntryArea) ? (a.m_bitCount > b.m_bitCount) : (aEntryA rea > bEntryArea); | 125 return (aEntryArea == bEntryArea) ? (a.m_bitCount > b.m_bitCount) : (aEntryA rea > bEntryArea); |
118 } | 126 } |
119 | 127 |
120 size_t ICOImageDecoder::decodeFrameCount() | 128 size_t ICOImageDecoder::decodeFrameCount() |
121 { | 129 { |
122 decodeSize(); | 130 decodeSize(); |
131 | |
132 for (size_t i = 0; i < m_dirEntries.size(); ++i) { | |
133 const IconDirectoryEntry& dirEntry = m_dirEntries[i]; | |
134 if ((dirEntry.m_imageOffset + dirEntry.m_byteSize) > m_data->size()) | |
aleksandar.stojiljkovic
2016/06/06 14:26:39
frameCount should include only fully received fram
| |
135 return i + 1; | |
136 } | |
123 return m_dirEntries.size(); | 137 return m_dirEntries.size(); |
124 } | 138 } |
125 | 139 |
126 void ICOImageDecoder::setDataForPNGDecoderAtIndex(size_t index) | 140 void ICOImageDecoder::setDataForPNGDecoderAtIndex(size_t index) |
127 { | 141 { |
128 if (!m_pngDecoders[index]) | 142 if (!m_pngDecoders[index]) |
129 return; | 143 return; |
130 | 144 |
131 m_pngDecoders[index]->setData(m_data.get(), isAllDataReceived()); | 145 m_pngDecoders[index]->setData(m_data.get(), isAllDataReceived()); |
132 } | 146 } |
133 | 147 |
134 void ICOImageDecoder::decode(size_t index, bool onlySize) | 148 void ICOImageDecoder::decode(size_t index, bool onlySize) |
135 { | 149 { |
136 if (failed()) | 150 if (failed()) |
137 return; | 151 return; |
138 | 152 |
139 // Defensively clear the FastSharedBufferReader's cache, as another caller | 153 // Defensively clear the FastSharedBufferReader's cache, as another caller |
140 // may have called SharedBuffer::mergeSegmentsIntoBuffer(). | 154 // may have called SharedBuffer::mergeSegmentsIntoBuffer(). |
141 m_fastReader.clearCache(); | 155 m_fastReader.clearCache(); |
142 | 156 |
143 // If we couldn't decode the image but we've received all the data, decoding | 157 // If we couldn't decode the image but we've received all the data, decoding |
144 // has failed. | 158 // has failed. |
145 if ((!decodeDirectory() || (!onlySize && !decodeAtIndex(index))) && isAllDat aReceived()) { | 159 if ((!decodeDirectory() || (!onlySize && !decodeAtIndex(index))) && isAllDat aReceived()) { |
146 setFailed(); | 160 setFailed(); |
147 // If we're done decoding this frame, we don't need the BMPImageReader or | 161 // If we're done decoding this frame, we don't need the BMPImageReader or |
148 // PNGImageDecoder anymore. (If we failed, these have already been | 162 // PNGImageDecoder anymore. (If we failed, these have already been |
149 // cleared.) | 163 // cleared.) |
150 } else if ((m_frameBufferCache.size() > index) && (m_frameBufferCache[index] .getStatus() == ImageFrame::FrameComplete)) { | 164 } else if (frameIsCompleteAtIndex(index)) { |
151 m_bmpReaders[index].clear(); | 165 m_bmpReaders[index].clear(); |
152 m_pngDecoders[index].clear(); | 166 m_pngDecoders[index].clear(); |
153 } | 167 } |
154 } | 168 } |
155 | 169 |
156 bool ICOImageDecoder::decodeDirectory() | 170 bool ICOImageDecoder::decodeDirectory() |
157 { | 171 { |
158 // Read and process directory. | 172 // Read and process directory. |
159 if ((m_decodedOffset < sizeOfDirectory) && !processDirectory()) | 173 if ((m_decodedOffset < sizeOfDirectory) && !processDirectory()) |
160 return false; | 174 return false; |
161 | 175 |
162 // Read and process directory entries. | 176 // Read and process directory entries. |
163 return (m_decodedOffset >= (sizeOfDirectory + (m_dirEntries.size() * sizeOfD irEntry))) || processDirectoryEntries(); | 177 return (m_decodedOffset >= (sizeOfDirectory + (m_dirEntries.size() * sizeOfD irEntry))) || processDirectoryEntries(); |
164 } | 178 } |
165 | 179 |
166 bool ICOImageDecoder::decodeAtIndex(size_t index) | 180 bool ICOImageDecoder::decodeAtIndex(size_t index) |
167 { | 181 { |
168 ASSERT_WITH_SECURITY_IMPLICATION(index < m_dirEntries.size()); | 182 ASSERT_WITH_SECURITY_IMPLICATION(index < m_dirEntries.size()); |
169 const IconDirectoryEntry& dirEntry = m_dirEntries[index]; | 183 const IconDirectoryEntry& dirEntry = m_dirEntries[index]; |
170 const ImageType imageType = imageTypeAtIndex(index); | 184 const ImageType imageType = imageTypeAtIndex(index); |
171 if (imageType == Unknown) | 185 if (imageType == Unknown) |
172 return false; // Not enough data to determine image type yet. | 186 return false; // Not enough data to determine image type yet. |
173 | 187 |
188 ASSERT(m_frameBufferCache.size() == decodeFrameCount()); | |
aleksandar.stojiljkovic
2016/06/06 14:26:39
this assert is copied from previous code but is no
| |
174 if (imageType == BMP) { | 189 if (imageType == BMP) { |
175 if (!m_bmpReaders[index]) { | 190 if (!m_bmpReaders[index]) { |
176 // We need to have already sized m_frameBufferCache before this, and | |
177 // we must not resize it again later (see caution in frameCount()). | |
178 ASSERT(m_frameBufferCache.size() == m_dirEntries.size()); | |
179 m_bmpReaders[index] = adoptPtr(new BMPImageReader(this, dirEntry.m_i mageOffset, 0, true)); | 191 m_bmpReaders[index] = adoptPtr(new BMPImageReader(this, dirEntry.m_i mageOffset, 0, true)); |
180 m_bmpReaders[index]->setData(m_data.get()); | 192 m_bmpReaders[index]->setData(m_data.get()); |
181 m_bmpReaders[index]->setBuffer(&m_frameBufferCache[index]); | |
182 } | 193 } |
194 // Update the pointer to the buffer as it could change after | |
195 // m_frameBufferCache.resize(). | |
196 m_bmpReaders[index]->setBuffer(&m_frameBufferCache[index]); | |
183 m_frameSize = dirEntry.m_size; | 197 m_frameSize = dirEntry.m_size; |
184 bool result = m_bmpReaders[index]->decodeBMP(false); | 198 bool result = m_bmpReaders[index]->decodeBMP(false); |
185 m_frameSize = IntSize(); | 199 m_frameSize = IntSize(); |
186 return result; | 200 return result; |
187 } | 201 } |
188 | 202 |
189 if (!m_pngDecoders[index]) { | 203 if (!m_pngDecoders[index]) { |
190 AlphaOption alphaOption = m_premultiplyAlpha ? AlphaPremultiplied : Alph aNotPremultiplied; | 204 AlphaOption alphaOption = m_premultiplyAlpha ? AlphaPremultiplied : Alph aNotPremultiplied; |
191 GammaAndColorProfileOption colorOptions = m_ignoreGammaAndColorProfile ? GammaAndColorProfileIgnored : GammaAndColorProfileApplied; | 205 GammaAndColorProfileOption colorOptions = m_ignoreGammaAndColorProfile ? GammaAndColorProfileIgnored : GammaAndColorProfileApplied; |
192 m_pngDecoders[index] = adoptPtr(new PNGImageDecoder(alphaOption, colorOp tions, m_maxDecodedBytes, dirEntry.m_imageOffset)); | 206 m_pngDecoders[index] = adoptPtr(new PNGImageDecoder(alphaOption, colorOp tions, m_maxDecodedBytes, dirEntry.m_imageOffset)); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
266 height = 256; | 280 height = 256; |
267 IconDirectoryEntry entry; | 281 IconDirectoryEntry entry; |
268 entry.m_size = IntSize(width, height); | 282 entry.m_size = IntSize(width, height); |
269 if (m_fileType == CURSOR) { | 283 if (m_fileType == CURSOR) { |
270 entry.m_bitCount = 0; | 284 entry.m_bitCount = 0; |
271 entry.m_hotSpot = IntPoint(readUint16(4), readUint16(6)); | 285 entry.m_hotSpot = IntPoint(readUint16(4), readUint16(6)); |
272 } else { | 286 } else { |
273 entry.m_bitCount = readUint16(6); | 287 entry.m_bitCount = readUint16(6); |
274 entry.m_hotSpot = IntPoint(); | 288 entry.m_hotSpot = IntPoint(); |
275 } | 289 } |
290 entry.m_byteSize = readUint32(8); | |
276 entry.m_imageOffset = readUint32(12); | 291 entry.m_imageOffset = readUint32(12); |
277 | 292 |
278 // Some icons don't have a bit depth, only a color count. Convert the | 293 // Some icons don't have a bit depth, only a color count. Convert the |
279 // color count to the minimum necessary bit depth. It doesn't matter if | 294 // color count to the minimum necessary bit depth. It doesn't matter if |
280 // this isn't quite what the bitmap info header says later, as we only use | 295 // this isn't quite what the bitmap info header says later, as we only use |
281 // this value to determine which icon entry is best. | 296 // this value to determine which icon entry is best. |
282 if (!entry.m_bitCount) { | 297 if (!entry.m_bitCount) { |
283 int colorCount = readUint8(2); | 298 int colorCount = readUint8(2); |
284 if (!colorCount) | 299 if (!colorCount) |
285 colorCount = 256; // Vague in the spec, needed by real-world icons. | 300 colorCount = 256; // Vague in the spec, needed by real-world icons. |
(...skipping 12 matching lines...) Expand all Loading... | |
298 ASSERT_WITH_SECURITY_IMPLICATION(index < m_dirEntries.size()); | 313 ASSERT_WITH_SECURITY_IMPLICATION(index < m_dirEntries.size()); |
299 const uint32_t imageOffset = m_dirEntries[index].m_imageOffset; | 314 const uint32_t imageOffset = m_dirEntries[index].m_imageOffset; |
300 if ((imageOffset > m_data->size()) || ((m_data->size() - imageOffset) < 4)) | 315 if ((imageOffset > m_data->size()) || ((m_data->size() - imageOffset) < 4)) |
301 return Unknown; | 316 return Unknown; |
302 char buffer[4]; | 317 char buffer[4]; |
303 const char* data = m_fastReader.getConsecutiveData(imageOffset, 4, buffer); | 318 const char* data = m_fastReader.getConsecutiveData(imageOffset, 4, buffer); |
304 return strncmp(data, "\x89PNG", 4) ? BMP : PNG; | 319 return strncmp(data, "\x89PNG", 4) ? BMP : PNG; |
305 } | 320 } |
306 | 321 |
307 } // namespace blink | 322 } // namespace blink |
OLD | NEW |