15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (c) 2008, 2009, Google Inc. All rights reserved. 302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch * 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions are 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * met: 702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch * 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * * Redistributions of source code must retain the above copyright 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer. 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * * Redistributions in binary form must reproduce the above 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * copyright notice, this list of conditions and the following disclaimer 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * in the documentation and/or other materials provided with the 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * distribution. 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * * Neither the name of Google Inc. nor the names of its 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * contributors may be used to endorse or promote products derived from 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * this software without specific prior written permission. 1702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch * 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */ 305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h" 32a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/image-decoders/ico/ICOImageDecoder.h" 335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include <algorithm> 355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)#include "platform/PlatformInstrumentation.h" 37a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/image-decoders/png/PNGImageDecoder.h" 387757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/PassOwnPtr.h" 395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 40c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink { 415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Number of bits in .ICO/.CUR used to store the directory and its entries, 435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// respectively (doesn't match sizeof values for member structs since we omit 445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// some fields). 455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const size_t sizeOfDirectory = 6; 465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const size_t sizeOfDirEntry = 16; 475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)ICOImageDecoder::ICOImageDecoder(ImageSource::AlphaOption alphaOption, 498abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption, 5006f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) size_t maxDecodedBytes) 5106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) : ImageDecoder(alphaOption, gammaAndColorProfileOption, maxDecodedBytes) 525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_decodedOffset(0) 535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)ICOImageDecoder::~ICOImageDecoder() 575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void ICOImageDecoder::setData(SharedBuffer* data, bool allDataReceived) 615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (failed()) 635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ImageDecoder::setData(data, allDataReceived); 665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (BMPReaders::iterator i(m_bmpReaders.begin()); i != m_bmpReaders.end(); ++i) { 685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (*i) 695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) (*i)->setData(data); 705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (size_t i = 0; i < m_pngDecoders.size(); ++i) 725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) setDataForPNGDecoderAtIndex(i); 735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool ICOImageDecoder::isSizeAvailable() 765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!ImageDecoder::isSizeAvailable()) 785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) decode(0, true); 795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return ImageDecoder::isSizeAvailable(); 815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)IntSize ICOImageDecoder::size() const 845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return m_frameSize.isEmpty() ? ImageDecoder::size() : m_frameSize; 865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)IntSize ICOImageDecoder::frameSizeAtIndex(size_t index) const 895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return (index && (index < m_dirEntries.size())) ? m_dirEntries[index].m_size : size(); 915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool ICOImageDecoder::setSize(unsigned width, unsigned height) 945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // The size calculated inside the BMPImageReader had better match the one in 965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // the icon directory. 975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return m_frameSize.isEmpty() ? ImageDecoder::setSize(width, height) : ((IntSize(width, height) == m_frameSize) || setFailed()); 985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)size_t ICOImageDecoder::frameCount() 1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) decode(0, true); 1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_frameBufferCache.isEmpty()) { 1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_frameBufferCache.resize(m_dirEntries.size()); 1055267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) for (size_t i = 0; i < m_dirEntries.size(); ++i) { 1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha); 10706f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) m_frameBufferCache[i].setRequiredPreviousFrameIndex(kNotFound); 1085267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) } 1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // CAUTION: We must not resize m_frameBufferCache again after this, as 1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // decodeAtIndex() may give a BMPImageReader a pointer to one of the 1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // entries. 1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return m_frameBufferCache.size(); 1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)ImageFrame* ICOImageDecoder::frameBufferAtIndex(size_t index) 1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Ensure |index| is valid. 1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (index >= frameCount()) 1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ImageFrame* buffer = &m_frameBufferCache[index]; 1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (buffer->status() != ImageFrame::FrameComplete) { 1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) PlatformInstrumentation::willDecodeImage("ICO"); 1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) decode(index, false); 1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) PlatformInstrumentation::didDecodeImage(); 1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return buffer; 1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool ICOImageDecoder::setFailed() 1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_bmpReaders.clear(); 1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_pngDecoders.clear(); 1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return ImageDecoder::setFailed(); 1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 138926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)bool ICOImageDecoder::hotSpot(IntPoint& hotSpot) const 139926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){ 140926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) // When unspecified, the default frame is always frame 0. This is consistent with 141926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) // BitmapImage where currentFrame() starts at 0 and only increases when animation is 142926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) // requested. 143926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return hotSpotAtIndex(0, hotSpot); 144926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)} 145926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 146926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)bool ICOImageDecoder::hotSpotAtIndex(size_t index, IntPoint& hotSpot) const 147926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){ 148926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (index >= m_dirEntries.size() || m_fileType != CURSOR) 149926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return false; 150926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 151926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) hotSpot = m_dirEntries[index].m_hotSpot; 152926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return true; 153926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)} 154926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 155926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// static 1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool ICOImageDecoder::compareEntries(const IconDirectoryEntry& a, const IconDirectoryEntry& b) 1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Larger icons are better. After that, higher bit-depth icons are better. 1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const int aEntryArea = a.m_size.width() * a.m_size.height(); 1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const int bEntryArea = b.m_size.width() * b.m_size.height(); 1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return (aEntryArea == bEntryArea) ? (a.m_bitCount > b.m_bitCount) : (aEntryArea > bEntryArea); 1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void ICOImageDecoder::setDataForPNGDecoderAtIndex(size_t index) 1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!m_pngDecoders[index]) 1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const IconDirectoryEntry& dirEntry = m_dirEntries[index]; 1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Copy out PNG data to a separate vector and send to the PNG decoder. 1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: Save this copy by making the PNG decoder able to take an 1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // optional offset. 1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<SharedBuffer> pngData(SharedBuffer::create(&m_data->data()[dirEntry.m_imageOffset], m_data->size() - dirEntry.m_imageOffset)); 1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_pngDecoders[index]->setData(pngData.get(), isAllDataReceived()); 1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void ICOImageDecoder::decode(size_t index, bool onlySize) 1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (failed()) 1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // If we couldn't decode the image but we've received all the data, decoding 1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // has failed. 1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if ((!decodeDirectory() || (!onlySize && !decodeAtIndex(index))) && isAllDataReceived()) 1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) setFailed(); 1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // If we're done decoding this frame, we don't need the BMPImageReader or 1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // PNGImageDecoder anymore. (If we failed, these have already been 1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // cleared.) 1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else if ((m_frameBufferCache.size() > index) && (m_frameBufferCache[index].status() == ImageFrame::FrameComplete)) { 1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_bmpReaders[index].clear(); 1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_pngDecoders[index].clear(); 1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool ICOImageDecoder::decodeDirectory() 1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Read and process directory. 1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if ((m_decodedOffset < sizeOfDirectory) && !processDirectory()) 2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Read and process directory entries. 2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return (m_decodedOffset >= (sizeOfDirectory + (m_dirEntries.size() * sizeOfDirEntry))) || processDirectoryEntries(); 2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool ICOImageDecoder::decodeAtIndex(size_t index) 2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 208926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) ASSERT_WITH_SECURITY_IMPLICATION(index < m_dirEntries.size()); 2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const IconDirectoryEntry& dirEntry = m_dirEntries[index]; 2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const ImageType imageType = imageTypeAtIndex(index); 2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (imageType == Unknown) 2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; // Not enough data to determine image type yet. 2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (imageType == BMP) { 2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!m_bmpReaders[index]) { 2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We need to have already sized m_frameBufferCache before this, and 2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // we must not resize it again later (see caution in frameCount()). 2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(m_frameBufferCache.size() == m_dirEntries.size()); 2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_bmpReaders[index] = adoptPtr(new BMPImageReader(this, dirEntry.m_imageOffset, 0, true)); 2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_bmpReaders[index]->setData(m_data.get()); 2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_bmpReaders[index]->setBuffer(&m_frameBufferCache[index]); 2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_frameSize = dirEntry.m_size; 2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool result = m_bmpReaders[index]->decodeBMP(false); 2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_frameSize = IntSize(); 2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return result; 2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!m_pngDecoders[index]) { 2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_pngDecoders[index] = adoptPtr( 2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) new PNGImageDecoder(m_premultiplyAlpha ? ImageSource::AlphaPremultiplied : ImageSource::AlphaNotPremultiplied, 23206f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) m_ignoreGammaAndColorProfile ? ImageSource::GammaAndColorProfileIgnored : ImageSource::GammaAndColorProfileApplied, m_maxDecodedBytes)); 2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) setDataForPNGDecoderAtIndex(index); 2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Fail if the size the PNGImageDecoder calculated does not match the size 2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // in the directory. 2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_pngDecoders[index]->isSizeAvailable() && (m_pngDecoders[index]->size() != dirEntry.m_size)) 2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return setFailed(); 2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_frameBufferCache[index] = *m_pngDecoders[index]->frameBufferAtIndex(0); 2405267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) m_frameBufferCache[index].setPremultiplyAlpha(m_premultiplyAlpha); 24106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) m_frameBufferCache[index].setRequiredPreviousFrameIndex(kNotFound); 2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return !m_pngDecoders[index]->failed() || setFailed(); 2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool ICOImageDecoder::processDirectory() 2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Read directory. 2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(!m_decodedOffset); 2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_data->size() < sizeOfDirectory) 2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const uint16_t fileType = readUint16(2); 2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const uint16_t idCount = readUint16(4); 2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_decodedOffset = sizeOfDirectory; 2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // See if this is an icon filetype we understand, and make sure we have at 2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // least one entry in the directory. 2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (((fileType != ICON) && (fileType != CURSOR)) || (!idCount)) 2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return setFailed(); 2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 260926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) m_fileType = static_cast<FileType>(fileType); 261926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Enlarge member vectors to hold all the entries. 2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_dirEntries.resize(idCount); 2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_bmpReaders.resize(idCount); 2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_pngDecoders.resize(idCount); 2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool ICOImageDecoder::processDirectoryEntries() 2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Read directory entries. 2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(m_decodedOffset == sizeOfDirectory); 2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if ((m_decodedOffset > m_data->size()) || ((m_data->size() - m_decodedOffset) < (m_dirEntries.size() * sizeOfDirEntry))) 2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (IconDirectoryEntries::iterator i(m_dirEntries.begin()); i != m_dirEntries.end(); ++i) 2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *i = readDirectoryEntry(); // Updates m_decodedOffset. 2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Make sure the specified image offsets are past the end of the directory 2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // entries. 2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (IconDirectoryEntries::iterator i(m_dirEntries.begin()); i != m_dirEntries.end(); ++i) { 2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (i->m_imageOffset < m_decodedOffset) 2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return setFailed(); 2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Arrange frames in decreasing quality order. 2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) std::sort(m_dirEntries.begin(), m_dirEntries.end(), compareEntries); 2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // The image size is the size of the largest entry. 2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const IconDirectoryEntry& dirEntry = m_dirEntries.first(); 2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Technically, this next call shouldn't be able to fail, since the width 2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // and height here are each <= 256, and |m_frameSize| is empty. 2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return setSize(dirEntry.m_size.width(), dirEntry.m_size.height()); 2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)ICOImageDecoder::IconDirectoryEntry ICOImageDecoder::readDirectoryEntry() 2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Read icon data. 2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // The casts to uint8_t in the next few lines are because that's the on-disk 2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // type of the width and height values. Storing them in ints (instead of 3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // matching uint8_ts) is so we can record dimensions of size 256 (which is 3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // what a zero byte really means). 3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int width = static_cast<uint8_t>(m_data->data()[m_decodedOffset]); 3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!width) 3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) width = 256; 3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int height = static_cast<uint8_t>(m_data->data()[m_decodedOffset + 1]); 3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!height) 3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) height = 256; 3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) IconDirectoryEntry entry; 3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) entry.m_size = IntSize(width, height); 310926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (m_fileType == CURSOR) { 311926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) entry.m_bitCount = 0; 312926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) entry.m_hotSpot = IntPoint(readUint16(4), readUint16(6)); 313926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) } else { 314926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) entry.m_bitCount = readUint16(6); 315926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) entry.m_hotSpot = IntPoint(); 316926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) } 3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) entry.m_imageOffset = readUint32(12); 3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Some icons don't have a bit depth, only a color count. Convert the 3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // color count to the minimum necessary bit depth. It doesn't matter if 3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // this isn't quite what the bitmap info header says later, as we only use 3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // this value to determine which icon entry is best. 3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!entry.m_bitCount) { 3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) int colorCount = static_cast<uint8_t>(m_data->data()[m_decodedOffset + 2]); 3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!colorCount) 3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) colorCount = 256; // Vague in the spec, needed by real-world icons. 3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (--colorCount; colorCount; colorCount >>= 1) 3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ++entry.m_bitCount; 3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_decodedOffset += sizeOfDirEntry; 3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return entry; 3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)ICOImageDecoder::ImageType ICOImageDecoder::imageTypeAtIndex(size_t index) 3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Check if this entry is a BMP or a PNG; we need 4 bytes to check the magic 3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // number. 339926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) ASSERT_WITH_SECURITY_IMPLICATION(index < m_dirEntries.size()); 3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const uint32_t imageOffset = m_dirEntries[index].m_imageOffset; 3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if ((imageOffset > m_data->size()) || ((m_data->size() - imageOffset) < 4)) 3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return Unknown; 3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return strncmp(&m_data->data()[imageOffset], "\x89PNG", 4) ? BMP : PNG; 3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 347