1 /* 2 * Copyright (c) 2008, 2009, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "ICOImageDecoder.h" 33 34 #include <algorithm> 35 36 #include "BMPImageReader.h" 37 #include "PNGImageDecoder.h" 38 39 namespace WebCore { 40 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 43 // some fields). 44 static const size_t sizeOfDirectory = 6; 45 static const size_t sizeOfDirEntry = 16; 46 47 ICOImageDecoder::ICOImageDecoder(ImageSource::AlphaOption alphaOption, 48 ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption) 49 : ImageDecoder(alphaOption, gammaAndColorProfileOption) 50 , m_decodedOffset(0) 51 { 52 } 53 54 ICOImageDecoder::~ICOImageDecoder() 55 { 56 } 57 58 void ICOImageDecoder::setData(SharedBuffer* data, bool allDataReceived) 59 { 60 if (failed()) 61 return; 62 63 ImageDecoder::setData(data, allDataReceived); 64 65 for (BMPReaders::iterator i(m_bmpReaders.begin()); i != m_bmpReaders.end(); ++i) { 66 if (*i) 67 (*i)->setData(data); 68 } 69 for (size_t i = 0; i < m_pngDecoders.size(); ++i) 70 setDataForPNGDecoderAtIndex(i); 71 } 72 73 bool ICOImageDecoder::isSizeAvailable() 74 { 75 if (!ImageDecoder::isSizeAvailable()) 76 decode(0, true); 77 78 return ImageDecoder::isSizeAvailable(); 79 } 80 81 IntSize ICOImageDecoder::size() const 82 { 83 return m_frameSize.isEmpty() ? ImageDecoder::size() : m_frameSize; 84 } 85 86 IntSize ICOImageDecoder::frameSizeAtIndex(size_t index) const 87 { 88 return (index && (index < m_dirEntries.size())) ? m_dirEntries[index].m_size : size(); 89 } 90 91 bool ICOImageDecoder::setSize(unsigned width, unsigned height) 92 { 93 // The size calculated inside the BMPImageReader had better match the one in 94 // the icon directory. 95 return m_frameSize.isEmpty() ? ImageDecoder::setSize(width, height) : ((IntSize(width, height) == m_frameSize) || setFailed()); 96 } 97 98 size_t ICOImageDecoder::frameCount() 99 { 100 decode(0, true); 101 if (m_frameBufferCache.isEmpty()) { 102 m_frameBufferCache.resize(m_dirEntries.size()); 103 for (size_t i = 0; i < m_dirEntries.size(); ++i) 104 m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha); 105 } 106 // CAUTION: We must not resize m_frameBufferCache again after this, as 107 // decodeAtIndex() may give a BMPImageReader a pointer to one of the 108 // entries. 109 return m_frameBufferCache.size(); 110 } 111 112 ImageFrame* ICOImageDecoder::frameBufferAtIndex(size_t index) 113 { 114 // Ensure |index| is valid. 115 if (index >= frameCount()) 116 return 0; 117 118 ImageFrame* buffer = &m_frameBufferCache[index]; 119 if (buffer->status() != ImageFrame::FrameComplete) 120 decode(index, false); 121 return buffer; 122 } 123 124 bool ICOImageDecoder::setFailed() 125 { 126 m_bmpReaders.clear(); 127 m_pngDecoders.clear(); 128 return ImageDecoder::setFailed(); 129 } 130 131 // static 132 bool ICOImageDecoder::compareEntries(const IconDirectoryEntry& a, const IconDirectoryEntry& b) 133 { 134 // Larger icons are better. After that, higher bit-depth icons are better. 135 const int aEntryArea = a.m_size.width() * a.m_size.height(); 136 const int bEntryArea = b.m_size.width() * b.m_size.height(); 137 return (aEntryArea == bEntryArea) ? (a.m_bitCount > b.m_bitCount) : (aEntryArea > bEntryArea); 138 } 139 140 void ICOImageDecoder::setDataForPNGDecoderAtIndex(size_t index) 141 { 142 if (!m_pngDecoders[index]) 143 return; 144 145 const IconDirectoryEntry& dirEntry = m_dirEntries[index]; 146 // Copy out PNG data to a separate vector and send to the PNG decoder. 147 // FIXME: Save this copy by making the PNG decoder able to take an 148 // optional offset. 149 RefPtr<SharedBuffer> pngData(SharedBuffer::create(&m_data->data()[dirEntry.m_imageOffset], m_data->size() - dirEntry.m_imageOffset)); 150 m_pngDecoders[index]->setData(pngData.get(), isAllDataReceived()); 151 } 152 153 void ICOImageDecoder::decode(size_t index, bool onlySize) 154 { 155 if (failed()) 156 return; 157 158 // If we couldn't decode the image but we've received all the data, decoding 159 // has failed. 160 if ((!decodeDirectory() || (!onlySize && !decodeAtIndex(index))) && isAllDataReceived()) 161 setFailed(); 162 // If we're done decoding this frame, we don't need the BMPImageReader or 163 // PNGImageDecoder anymore. (If we failed, these have already been 164 // cleared.) 165 else if ((m_frameBufferCache.size() > index) && (m_frameBufferCache[index].status() == ImageFrame::FrameComplete)) { 166 m_bmpReaders[index].clear(); 167 m_pngDecoders[index].clear(); 168 } 169 } 170 171 bool ICOImageDecoder::decodeDirectory() 172 { 173 // Read and process directory. 174 if ((m_decodedOffset < sizeOfDirectory) && !processDirectory()) 175 return false; 176 177 // Read and process directory entries. 178 return (m_decodedOffset >= (sizeOfDirectory + (m_dirEntries.size() * sizeOfDirEntry))) || processDirectoryEntries(); 179 } 180 181 bool ICOImageDecoder::decodeAtIndex(size_t index) 182 { 183 ASSERT(index < m_dirEntries.size()); 184 const IconDirectoryEntry& dirEntry = m_dirEntries[index]; 185 const ImageType imageType = imageTypeAtIndex(index); 186 if (imageType == Unknown) 187 return false; // Not enough data to determine image type yet. 188 189 if (imageType == BMP) { 190 if (!m_bmpReaders[index]) { 191 // We need to have already sized m_frameBufferCache before this, and 192 // we must not resize it again later (see caution in frameCount()). 193 ASSERT(m_frameBufferCache.size() == m_dirEntries.size()); 194 m_bmpReaders[index].set(new BMPImageReader(this, dirEntry.m_imageOffset, 0, true)); 195 m_bmpReaders[index]->setData(m_data.get()); 196 m_bmpReaders[index]->setBuffer(&m_frameBufferCache[index]); 197 } 198 m_frameSize = dirEntry.m_size; 199 bool result = m_bmpReaders[index]->decodeBMP(false); 200 m_frameSize = IntSize(); 201 return result; 202 } 203 204 if (!m_pngDecoders[index]) { 205 m_pngDecoders[index].set( 206 new PNGImageDecoder(m_premultiplyAlpha ? ImageSource::AlphaPremultiplied : ImageSource::AlphaNotPremultiplied, 207 m_ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied)); 208 setDataForPNGDecoderAtIndex(index); 209 } 210 // Fail if the size the PNGImageDecoder calculated does not match the size 211 // in the directory. 212 if (m_pngDecoders[index]->isSizeAvailable() && (m_pngDecoders[index]->size() != dirEntry.m_size)) 213 return setFailed(); 214 m_frameBufferCache[index] = *m_pngDecoders[index]->frameBufferAtIndex(0); 215 return !m_pngDecoders[index]->failed() || setFailed(); 216 } 217 218 bool ICOImageDecoder::processDirectory() 219 { 220 // Read directory. 221 ASSERT(!m_decodedOffset); 222 if (m_data->size() < sizeOfDirectory) 223 return false; 224 const uint16_t fileType = readUint16(2); 225 const uint16_t idCount = readUint16(4); 226 m_decodedOffset = sizeOfDirectory; 227 228 // See if this is an icon filetype we understand, and make sure we have at 229 // least one entry in the directory. 230 enum { 231 ICON = 1, 232 CURSOR = 2, 233 }; 234 if (((fileType != ICON) && (fileType != CURSOR)) || (!idCount)) 235 return setFailed(); 236 237 // Enlarge member vectors to hold all the entries. 238 m_dirEntries.resize(idCount); 239 m_bmpReaders.resize(idCount); 240 m_pngDecoders.resize(idCount); 241 return true; 242 } 243 244 bool ICOImageDecoder::processDirectoryEntries() 245 { 246 // Read directory entries. 247 ASSERT(m_decodedOffset == sizeOfDirectory); 248 if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset) < (m_dirEntries.size() * sizeOfDirEntry))) 249 return false; 250 for (IconDirectoryEntries::iterator i(m_dirEntries.begin()); i != m_dirEntries.end(); ++i) 251 *i = readDirectoryEntry(); // Updates m_decodedOffset. 252 253 // Make sure the specified image offsets are past the end of the directory 254 // entries. 255 for (IconDirectoryEntries::iterator i(m_dirEntries.begin()); i != m_dirEntries.end(); ++i) { 256 if (i->m_imageOffset < m_decodedOffset) 257 return setFailed(); 258 } 259 260 // Arrange frames in decreasing quality order. 261 std::sort(m_dirEntries.begin(), m_dirEntries.end(), compareEntries); 262 263 // The image size is the size of the largest entry. 264 const IconDirectoryEntry& dirEntry = m_dirEntries.first(); 265 // Technically, this next call shouldn't be able to fail, since the width 266 // and height here are each <= 256, and |m_frameSize| is empty. 267 return setSize(dirEntry.m_size.width(), dirEntry.m_size.height()); 268 } 269 270 ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry() 271 { 272 // Read icon data. 273 // The casts to uint8_t in the next few lines are because that's the on-disk 274 // type of the width and height values. Storing them in ints (instead of 275 // matching uint8_ts) is so we can record dimensions of size 256 (which is 276 // what a zero byte really means). 277 int width = static_cast<uint8_t>(m_data->data()[m_decodedOffset]); 278 if (!width) 279 width = 256; 280 int height = static_cast<uint8_t>(m_data->data()[m_decodedOffset + 1]); 281 if (!height) 282 height = 256; 283 IconDirectoryEntry entry; 284 entry.m_size = IntSize(width, height); 285 entry.m_bitCount = readUint16(6); 286 entry.m_imageOffset = readUint32(12); 287 288 // Some icons don't have a bit depth, only a color count. Convert the 289 // color count to the minimum necessary bit depth. It doesn't matter if 290 // this isn't quite what the bitmap info header says later, as we only use 291 // this value to determine which icon entry is best. 292 if (!entry.m_bitCount) { 293 int colorCount = static_cast<uint8_t>(m_data->data()[m_decodedOffset + 2]); 294 if (!colorCount) 295 colorCount = 256; // Vague in the spec, needed by real-world icons. 296 for (--colorCount; colorCount; colorCount >>= 1) 297 ++entry.m_bitCount; 298 } 299 300 m_decodedOffset += sizeOfDirEntry; 301 return entry; 302 } 303 304 ICOImageDecoder::ImageType ICOImageDecoder::imageTypeAtIndex(size_t index) 305 { 306 // Check if this entry is a BMP or a PNG; we need 4 bytes to check the magic 307 // number. 308 ASSERT(index < m_dirEntries.size()); 309 const uint32_t imageOffset = m_dirEntries[index].m_imageOffset; 310 if ((imageOffset > m_data->size()) || ((m_data->size() - imageOffset) < 4)) 311 return Unknown; 312 return strncmp(&m_data->data()[imageOffset], "\x89PNG", 4) ? BMP : PNG; 313 } 314 315 } 316