Home | History | Annotate | Download | only in image-decoders
      1 /*
      2  * Copyright (C) 2008-2009 Torch Mobile, Inc.
      3  * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
      4  *
      5  *  This library is free software; you can redistribute it and/or
      6  *  modify it under the terms of the GNU Library General Public
      7  *  License as published by the Free Software Foundation; either
      8  *  version 2 of the License, or (at your option) any later version.
      9  *
     10  *  This library is distributed in the hope that it will be useful,
     11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  *  Library General Public License for more details.
     14  *
     15  *  You should have received a copy of the GNU Library General Public License
     16  *  along with this library; see the file COPYING.LIB.  If not, write to
     17  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18  *  Boston, MA 02110-1301, USA.
     19  *
     20  */
     21 
     22 #include "config.h"
     23 
     24 #include "ImageDecoder.h"
     25 
     26 #include <algorithm>
     27 #include <cmath>
     28 
     29 #include "BMPImageDecoder.h"
     30 #include "GIFImageDecoder.h"
     31 #include "ICOImageDecoder.h"
     32 #include "JPEGImageDecoder.h"
     33 #include "PNGImageDecoder.h"
     34 #include "SharedBuffer.h"
     35 
     36 using namespace std;
     37 
     38 namespace WebCore {
     39 
     40 static unsigned copyFromSharedBuffer(char* buffer, unsigned bufferLength, const SharedBuffer& sharedBuffer, unsigned offset)
     41 {
     42     unsigned bytesExtracted = 0;
     43     const char* moreData;
     44     while (unsigned moreDataLength = sharedBuffer.getSomeData(moreData, offset)) {
     45         unsigned bytesToCopy = min(bufferLength - bytesExtracted, moreDataLength);
     46         memcpy(buffer + bytesExtracted, moreData, bytesToCopy);
     47         bytesExtracted += bytesToCopy;
     48         if (bytesExtracted == bufferLength)
     49             break;
     50         offset += bytesToCopy;
     51     }
     52     return bytesExtracted;
     53 }
     54 
     55 #if !OS(ANDROID)
     56 // This method requires BMPImageDecoder, PNGImageDecoder, ICOImageDecoder and
     57 // JPEGDecoder, which aren't used on Android, and which don't all compile.
     58 // TODO: Find a better fix.
     59 ImageDecoder* ImageDecoder::create(const SharedBuffer& data)
     60 {
     61     // We need at least 4 bytes to figure out what kind of image we're dealing with.
     62     static const unsigned maxMarkerLength = 4;
     63     char contents[maxMarkerLength];
     64     unsigned length = copyFromSharedBuffer(contents, maxMarkerLength, data, 0);
     65     if (length < maxMarkerLength)
     66         return 0;
     67 
     68     const unsigned char* uContents = reinterpret_cast<const unsigned char*>(contents);
     69 
     70     // GIFs begin with GIF8(7 or 9).
     71     if (strncmp(contents, "GIF8", 4) == 0)
     72         return new GIFImageDecoder();
     73 
     74     // Test for PNG.
     75     if (uContents[0]==0x89 &&
     76         uContents[1]==0x50 &&
     77         uContents[2]==0x4E &&
     78         uContents[3]==0x47)
     79         return new PNGImageDecoder();
     80 
     81     // JPEG
     82     if (uContents[0]==0xFF &&
     83         uContents[1]==0xD8 &&
     84         uContents[2]==0xFF)
     85         return new JPEGImageDecoder();
     86 
     87     // BMP
     88     if (strncmp(contents, "BM", 2) == 0)
     89         return new BMPImageDecoder();
     90 
     91     // ICOs always begin with a 2-byte 0 followed by a 2-byte 1.
     92     // CURs begin with 2-byte 0 followed by 2-byte 2.
     93     if (!memcmp(contents, "\000\000\001\000", 4) ||
     94         !memcmp(contents, "\000\000\002\000", 4))
     95         return new ICOImageDecoder();
     96 
     97     // Give up. We don't know what the heck this is.
     98     return 0;
     99 }
    100 #endif // !OS(ANDROID)
    101 
    102 #if !PLATFORM(SKIA)
    103 
    104 RGBA32Buffer::RGBA32Buffer()
    105     : m_hasAlpha(false)
    106     , m_status(FrameEmpty)
    107     , m_duration(0)
    108     , m_disposalMethod(DisposeNotSpecified)
    109 {
    110 }
    111 
    112 void RGBA32Buffer::clear()
    113 {
    114     m_bytes.clear();
    115     m_status = FrameEmpty;
    116     // NOTE: Do not reset other members here; clearFrameBufferCache()
    117     // calls this to free the bitmap data, but other functions like
    118     // initFrameBuffer() and frameComplete() may still need to read
    119     // other metadata out of this frame later.
    120 }
    121 
    122 void RGBA32Buffer::zeroFill()
    123 {
    124     m_bytes.fill(0);
    125     m_hasAlpha = true;
    126 }
    127 
    128 void RGBA32Buffer::copyBitmapData(const RGBA32Buffer& other)
    129 {
    130     if (this == &other)
    131         return;
    132 
    133     m_bytes = other.m_bytes;
    134     m_size = other.m_size;
    135     setHasAlpha(other.m_hasAlpha);
    136 }
    137 
    138 bool RGBA32Buffer::setSize(int newWidth, int newHeight)
    139 {
    140     // NOTE: This has no way to check for allocation failure if the
    141     // requested size was too big...
    142     m_bytes.resize(newWidth * newHeight);
    143     m_size = IntSize(newWidth, newHeight);
    144 
    145     // Zero the image.
    146     zeroFill();
    147 
    148     return true;
    149 }
    150 
    151 bool RGBA32Buffer::hasAlpha() const
    152 {
    153     return m_hasAlpha;
    154 }
    155 
    156 void RGBA32Buffer::setHasAlpha(bool alpha)
    157 {
    158     m_hasAlpha = alpha;
    159 }
    160 
    161 void RGBA32Buffer::setStatus(FrameStatus status)
    162 {
    163     m_status = status;
    164 }
    165 
    166 RGBA32Buffer& RGBA32Buffer::operator=(const RGBA32Buffer& other)
    167 {
    168     if (this == &other)
    169         return *this;
    170 
    171     copyBitmapData(other);
    172     setRect(other.rect());
    173     setStatus(other.status());
    174     setDuration(other.duration());
    175     setDisposalMethod(other.disposalMethod());
    176     return *this;
    177 }
    178 
    179 int RGBA32Buffer::width() const
    180 {
    181     return m_size.width();
    182 }
    183 
    184 int RGBA32Buffer::height() const
    185 {
    186     return m_size.height();
    187 }
    188 
    189 #endif
    190 
    191 namespace {
    192 
    193 enum MatchType {
    194     Exact,
    195     UpperBound,
    196     LowerBound
    197 };
    198 
    199 inline void fillScaledValues(Vector<int>& scaledValues, double scaleRate, int length)
    200 {
    201     double inflateRate = 1. / scaleRate;
    202     scaledValues.reserveCapacity(static_cast<int>(length * scaleRate + 0.5));
    203     for (int scaledIndex = 0;;) {
    204         int index = static_cast<int>(scaledIndex * inflateRate + 0.5);
    205         if (index < length) {
    206             scaledValues.append(index);
    207             ++scaledIndex;
    208         } else
    209             break;
    210     }
    211 }
    212 
    213 template <MatchType type> int getScaledValue(const Vector<int>& scaledValues, int valueToMatch, int searchStart)
    214 {
    215     if (scaledValues.isEmpty())
    216         return valueToMatch;
    217 
    218     const int* dataStart = scaledValues.data();
    219     const int* dataEnd = dataStart + scaledValues.size();
    220     const int* matched = std::lower_bound(dataStart + searchStart, dataEnd, valueToMatch);
    221     switch (type) {
    222     case Exact:
    223         return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : -1;
    224     case LowerBound:
    225         return matched != dataEnd && *matched == valueToMatch ? matched - dataStart : matched - dataStart - 1;
    226     case UpperBound:
    227     default:
    228         return matched != dataEnd ? matched - dataStart : -1;
    229     }
    230 }
    231 
    232 }
    233 
    234 void ImageDecoder::prepareScaleDataIfNecessary()
    235 {
    236     int width = size().width();
    237     int height = size().height();
    238     int numPixels = height * width;
    239     if (m_maxNumPixels > 0 && numPixels > m_maxNumPixels) {
    240         m_scaled = true;
    241         double scale = sqrt(m_maxNumPixels / (double)numPixels);
    242         fillScaledValues(m_scaledColumns, scale, width);
    243         fillScaledValues(m_scaledRows, scale, height);
    244     } else if (m_scaled) {
    245         m_scaled = false;
    246         m_scaledColumns.clear();
    247         m_scaledRows.clear();
    248     }
    249 }
    250 
    251 int ImageDecoder::upperBoundScaledX(int origX, int searchStart)
    252 {
    253     return getScaledValue<UpperBound>(m_scaledColumns, origX, searchStart);
    254 }
    255 
    256 int ImageDecoder::lowerBoundScaledX(int origX, int searchStart)
    257 {
    258     return getScaledValue<LowerBound>(m_scaledColumns, origX, searchStart);
    259 }
    260 
    261 int ImageDecoder::upperBoundScaledY(int origY, int searchStart)
    262 {
    263     return getScaledValue<UpperBound>(m_scaledRows, origY, searchStart);
    264 }
    265 
    266 int ImageDecoder::lowerBoundScaledY(int origY, int searchStart)
    267 {
    268     return getScaledValue<LowerBound>(m_scaledRows, origY, searchStart);
    269 }
    270 
    271 int ImageDecoder::scaledY(int origY, int searchStart)
    272 {
    273     return getScaledValue<Exact>(m_scaledRows, origY, searchStart);
    274 }
    275 
    276 }
    277