1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/images/SkImageDecoder_libico.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,417 @@ 1.4 +/* 1.5 + * Copyright 2006 The Android Open Source Project 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkColorPriv.h" 1.12 +#include "SkImageDecoder.h" 1.13 +#include "SkStream.h" 1.14 +#include "SkStreamHelpers.h" 1.15 +#include "SkTypes.h" 1.16 + 1.17 +class SkICOImageDecoder : public SkImageDecoder { 1.18 +public: 1.19 + SkICOImageDecoder(); 1.20 + 1.21 + virtual Format getFormat() const SK_OVERRIDE { 1.22 + return kICO_Format; 1.23 + } 1.24 + 1.25 +protected: 1.26 + virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; 1.27 + 1.28 +private: 1.29 + typedef SkImageDecoder INHERITED; 1.30 +}; 1.31 + 1.32 +///////////////////////////////////////////////////////////////////////////////////////// 1.33 + 1.34 +//read bytes starting from the begin-th index in the buffer 1.35 +//read in Intel order, and return an integer 1.36 + 1.37 +#define readByte(buffer,begin) buffer[begin] 1.38 +#define read2Bytes(buffer,begin) buffer[begin]+(buffer[begin+1]<<8) 1.39 +#define read4Bytes(buffer,begin) buffer[begin]+(buffer[begin+1]<<8)+(buffer[begin+2]<<16)+(buffer[begin+3]<<24) 1.40 + 1.41 +///////////////////////////////////////////////////////////////////////////////////////// 1.42 + 1.43 +SkICOImageDecoder::SkICOImageDecoder() 1.44 +{ 1.45 +} 1.46 + 1.47 +//helpers - my function pointer will call one of these, depending on the bitCount, each time through the inner loop 1.48 +static void editPixelBit1(const int pixelNo, const unsigned char* buf, 1.49 + const int xorOffset, int& x, int y, const int w, 1.50 + SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors); 1.51 +static void editPixelBit4(const int pixelNo, const unsigned char* buf, 1.52 + const int xorOffset, int& x, int y, const int w, 1.53 + SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors); 1.54 +static void editPixelBit8(const int pixelNo, const unsigned char* buf, 1.55 + const int xorOffset, int& x, int y, const int w, 1.56 + SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors); 1.57 +static void editPixelBit24(const int pixelNo, const unsigned char* buf, 1.58 + const int xorOffset, int& x, int y, const int w, 1.59 + SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors); 1.60 +static void editPixelBit32(const int pixelNo, const unsigned char* buf, 1.61 + const int xorOffset, int& x, int y, const int w, 1.62 + SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors); 1.63 + 1.64 + 1.65 +static int calculateRowBytesFor8888(int w, int bitCount) 1.66 +{ 1.67 + // Default rowBytes is w << 2 for kARGB_8888 1.68 + // In the case of a 4 bit image with an odd width, we need to add some 1.69 + // so we can go off the end of the drawn bitmap. 1.70 + // Add 4 to ensure that it is still a multiple of 4. 1.71 + if (4 == bitCount && (w & 0x1)) { 1.72 + return (w + 1) << 2; 1.73 + } 1.74 + // Otherwise return 0, which will allow it to be calculated automatically. 1.75 + return 0; 1.76 +} 1.77 + 1.78 +bool SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) 1.79 +{ 1.80 + SkAutoMalloc autoMal; 1.81 + const size_t length = CopyStreamToStorage(&autoMal, stream); 1.82 + if (0 == length) { 1.83 + return false; 1.84 + } 1.85 + 1.86 + unsigned char* buf = (unsigned char*)autoMal.get(); 1.87 + 1.88 + //these should always be the same - should i use for error checking? - what about files that have some 1.89 + //incorrect values, but still decode properly? 1.90 + int reserved = read2Bytes(buf, 0); // 0 1.91 + int type = read2Bytes(buf, 2); // 1 1.92 + if (reserved != 0 || type != 1) 1.93 + return false; 1.94 + int count = read2Bytes(buf, 4); 1.95 + 1.96 + //need to at least have enough space to hold the initial table of info 1.97 + if (length < (size_t)(6 + count*16)) 1.98 + return false; 1.99 + 1.100 + int choice; 1.101 + Chooser* chooser = this->getChooser(); 1.102 + //FIXME:if no chooser, consider providing the largest color image 1.103 + //what are the odds that the largest image would be monochrome? 1.104 + if (NULL == chooser) { 1.105 + choice = 0; 1.106 + } else { 1.107 + chooser->begin(count); 1.108 + for (int i = 0; i < count; i++) 1.109 + { 1.110 + //need to find out the config, width, and height from the stream 1.111 + int width = readByte(buf, 6 + i*16); 1.112 + int height = readByte(buf, 7 + i*16); 1.113 + int offset = read4Bytes(buf, 18 + i*16); 1.114 + int bitCount = read2Bytes(buf, offset+14); 1.115 + SkBitmap::Config c; 1.116 + //currently only provide ARGB_8888_, but maybe we want kIndex8_Config for 1 and 4, and possibly 8? 1.117 + //or maybe we'll determine this based on the provided config 1.118 + switch (bitCount) 1.119 + { 1.120 + case 1: 1.121 + case 4: 1.122 + // In reality, at least for the moment, these will be decoded into kARGB_8888 bitmaps. 1.123 + // However, this will be used to distinguish between the lower quality 1bpp and 4 bpp 1.124 + // images and the higher quality images. 1.125 + c = SkBitmap::kIndex8_Config; 1.126 + break; 1.127 + case 8: 1.128 + case 24: 1.129 + case 32: 1.130 + c = SkBitmap::kARGB_8888_Config; 1.131 + break; 1.132 + default: 1.133 + SkDEBUGF(("Image with %ibpp not supported\n", bitCount)); 1.134 + continue; 1.135 + } 1.136 + chooser->inspect(i, c, width, height); 1.137 + } 1.138 + choice = chooser->choose(); 1.139 + } 1.140 + 1.141 + //you never know what the chooser is going to supply 1.142 + if (choice >= count || choice < 0) 1.143 + return false; 1.144 + 1.145 + //skip ahead to the correct header 1.146 + //commented out lines are not used, but if i switch to other read method, need to know how many to skip 1.147 + //otherwise, they could be used for error checking 1.148 + int w = readByte(buf, 6 + choice*16); 1.149 + int h = readByte(buf, 7 + choice*16); 1.150 + int colorCount = readByte(buf, 8 + choice*16); 1.151 + //int reservedToo = readByte(buf, 9 + choice*16); //0 1.152 + //int planes = read2Bytes(buf, 10 + choice*16); //1 - but often 0 1.153 + //int fakeBitCount = read2Bytes(buf, 12 + choice*16); //should be real - usually 0 1.154 + int size = read4Bytes(buf, 14 + choice*16); //matters? 1.155 + int offset = read4Bytes(buf, 18 + choice*16); 1.156 + if ((size_t)(offset + size) > length) 1.157 + return false; 1.158 + 1.159 + // Check to see if this is a PNG image inside the ICO 1.160 + { 1.161 + SkMemoryStream subStream(buf + offset, size, false); 1.162 + SkAutoTDelete<SkImageDecoder> otherDecoder(SkImageDecoder::Factory(&subStream)); 1.163 + if (otherDecoder.get() != NULL) { 1.164 + // Set fields on the other decoder to be the same as this one. 1.165 + this->copyFieldsToOther(otherDecoder.get()); 1.166 + if(otherDecoder->decode(&subStream, bm, this->getDefaultPref(), mode)) { 1.167 + return true; 1.168 + } 1.169 + } 1.170 + } 1.171 + 1.172 + //int infoSize = read4Bytes(buf, offset); //40 1.173 + //int width = read4Bytes(buf, offset+4); //should == w 1.174 + //int height = read4Bytes(buf, offset+8); //should == 2*h 1.175 + //int planesToo = read2Bytes(buf, offset+12); //should == 1 (does it?) 1.176 + int bitCount = read2Bytes(buf, offset+14); 1.177 + 1.178 + void (*placePixel)(const int pixelNo, const unsigned char* buf, 1.179 + const int xorOffset, int& x, int y, const int w, 1.180 + SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) = NULL; 1.181 + switch (bitCount) 1.182 + { 1.183 + case 1: 1.184 + placePixel = &editPixelBit1; 1.185 + colorCount = 2; 1.186 + break; 1.187 + case 4: 1.188 + placePixel = &editPixelBit4; 1.189 + colorCount = 16; 1.190 + break; 1.191 + case 8: 1.192 + placePixel = &editPixelBit8; 1.193 + colorCount = 256; 1.194 + break; 1.195 + case 24: 1.196 + placePixel = &editPixelBit24; 1.197 + colorCount = 0; 1.198 + break; 1.199 + case 32: 1.200 + placePixel = &editPixelBit32; 1.201 + colorCount = 0; 1.202 + break; 1.203 + default: 1.204 + SkDEBUGF(("Decoding %ibpp is unimplemented\n", bitCount)); 1.205 + return false; 1.206 + } 1.207 + 1.208 + //these should all be zero, but perhaps are not - need to check 1.209 + //int compression = read4Bytes(buf, offset+16); //0 1.210 + //int imageSize = read4Bytes(buf, offset+20); //0 - sometimes has a value 1.211 + //int xPixels = read4Bytes(buf, offset+24); //0 1.212 + //int yPixels = read4Bytes(buf, offset+28); //0 1.213 + //int colorsUsed = read4Bytes(buf, offset+32) //0 - might have an actual value though 1.214 + //int colorsImportant = read4Bytes(buf, offset+36); //0 1.215 + 1.216 + int begin = offset + 40; 1.217 + //this array represents the colortable 1.218 + //if i allow other types of bitmaps, it may actually be used as a part of the bitmap 1.219 + SkPMColor* colors = NULL; 1.220 + int blue, green, red; 1.221 + if (colorCount) 1.222 + { 1.223 + colors = new SkPMColor[colorCount]; 1.224 + for (int j = 0; j < colorCount; j++) 1.225 + { 1.226 + //should this be a function - maybe a #define? 1.227 + blue = readByte(buf, begin + 4*j); 1.228 + green = readByte(buf, begin + 4*j + 1); 1.229 + red = readByte(buf, begin + 4*j + 2); 1.230 + colors[j] = SkPackARGB32(0xFF, red & 0xFF, green & 0xFF, blue & 0xFF); 1.231 + } 1.232 + } 1.233 + int bitWidth = w*bitCount; 1.234 + int test = bitWidth & 0x1F; 1.235 + int mask = -(((test >> 4) | (test >> 3) | (test >> 2) | (test >> 1) | test) & 0x1); //either 0xFFFFFFFF or 0 1.236 + int lineBitWidth = (bitWidth & 0xFFFFFFE0) + (0x20 & mask); 1.237 + int lineWidth = lineBitWidth/bitCount; 1.238 + 1.239 + int xorOffset = begin + colorCount*4; //beginning of the color bitmap 1.240 + //other read method means we will just be here already 1.241 + int andOffset = xorOffset + ((lineWidth*h*bitCount) >> 3); 1.242 + 1.243 + /*int */test = w & 0x1F; //the low 5 bits - we are rounding up to the next 32 (2^5) 1.244 + /*int */mask = -(((test >> 4) | (test >> 3) | (test >> 2) | (test >> 1) | test) & 0x1); //either 0xFFFFFFFF or 0 1.245 + int andLineWidth = (w & 0xFFFFFFE0) + (0x20 & mask); 1.246 + //if we allow different Configs, everything is the same til here 1.247 + //change the config, and use different address getter, and place index vs color, and add the color table 1.248 + //FIXME: what is the tradeoff in size? 1.249 + //if the andbitmap (mask) is all zeroes, then we can easily do an index bitmap 1.250 + //however, with small images with large colortables, maybe it's better to still do argb_8888 1.251 + 1.252 + bm->setConfig(SkBitmap::kARGB_8888_Config, w, h, calculateRowBytesFor8888(w, bitCount)); 1.253 + 1.254 + if (SkImageDecoder::kDecodeBounds_Mode == mode) { 1.255 + delete[] colors; 1.256 + return true; 1.257 + } 1.258 + 1.259 + if (!this->allocPixelRef(bm, NULL)) 1.260 + { 1.261 + delete[] colors; 1.262 + return false; 1.263 + } 1.264 + 1.265 + SkAutoLockPixels alp(*bm); 1.266 + 1.267 + for (int y = 0; y < h; y++) 1.268 + { 1.269 + for (int x = 0; x < w; x++) 1.270 + { 1.271 + //U32* address = bm->getAddr32(x, y); 1.272 + 1.273 + //check the alpha bit first, but pass it along to the function to figure out how to deal with it 1.274 + int andPixelNo = andLineWidth*(h-y-1)+x; 1.275 + //only need to get a new alphaByte when x %8 == 0 1.276 + //but that introduces an if and a mod - probably much slower 1.277 + //that's ok, it's just a read of an array, not a stream 1.278 + int alphaByte = readByte(buf, andOffset + (andPixelNo >> 3)); 1.279 + int shift = 7 - (andPixelNo & 0x7); 1.280 + int m = 1 << shift; 1.281 + 1.282 + int pixelNo = lineWidth*(h-y-1)+x; 1.283 + placePixel(pixelNo, buf, xorOffset, x, y, w, bm, alphaByte, m, shift, colors); 1.284 + 1.285 + } 1.286 + } 1.287 + 1.288 + delete [] colors; 1.289 + //ensure we haven't read off the end? 1.290 + //of course this doesn't help us if the andOffset was a lie... 1.291 + //return andOffset + (andLineWidth >> 3) <= length; 1.292 + return true; 1.293 +} //onDecode 1.294 + 1.295 +//function to place the pixel, determined by the bitCount 1.296 +static void editPixelBit1(const int pixelNo, const unsigned char* buf, 1.297 + const int xorOffset, int& x, int y, const int w, 1.298 + SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) 1.299 +{ 1.300 + // note that this should be the same as/similar to the AND bitmap 1.301 + SkPMColor* address = bm->getAddr32(x,y); 1.302 + int byte = readByte(buf, xorOffset + (pixelNo >> 3)); 1.303 + int colorBit; 1.304 + int alphaBit; 1.305 + // Read all of the bits in this byte. 1.306 + int i = x + 8; 1.307 + // Pin to the width so we do not write outside the bounds of 1.308 + // our color table. 1.309 + i = i > w ? w : i; 1.310 + // While loop to check all 8 bits individually. 1.311 + while (x < i) 1.312 + { 1.313 + 1.314 + colorBit = (byte & m) >> shift; 1.315 + alphaBit = (alphaByte & m) >> shift; 1.316 + *address = (alphaBit-1)&(colors[colorBit]); 1.317 + x++; 1.318 + // setup for the next pixel 1.319 + address = address + 1; 1.320 + m = m >> 1; 1.321 + shift -= 1; 1.322 + } 1.323 + x--; 1.324 +} 1.325 +static void editPixelBit4(const int pixelNo, const unsigned char* buf, 1.326 + const int xorOffset, int& x, int y, const int w, 1.327 + SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) 1.328 +{ 1.329 + SkPMColor* address = bm->getAddr32(x, y); 1.330 + int byte = readByte(buf, xorOffset + (pixelNo >> 1)); 1.331 + int pixel = (byte >> 4) & 0xF; 1.332 + int alphaBit = (alphaByte & m) >> shift; 1.333 + *address = (alphaBit-1)&(colors[pixel]); 1.334 + x++; 1.335 + //if w is odd, x may be the same as w, which means we are writing to an unused portion of the bitmap 1.336 + //but that's okay, since i've added an extra rowByte for just this purpose 1.337 + address = address + 1; 1.338 + pixel = byte & 0xF; 1.339 + m = m >> 1; 1.340 + alphaBit = (alphaByte & m) >> (shift-1); 1.341 + //speed up trick here 1.342 + *address = (alphaBit-1)&(colors[pixel]); 1.343 +} 1.344 + 1.345 +static void editPixelBit8(const int pixelNo, const unsigned char* buf, 1.346 + const int xorOffset, int& x, int y, const int w, 1.347 + SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) 1.348 +{ 1.349 + SkPMColor* address = bm->getAddr32(x, y); 1.350 + int pixel = readByte(buf, xorOffset + pixelNo); 1.351 + int alphaBit = (alphaByte & m) >> shift; 1.352 + *address = (alphaBit-1)&(colors[pixel]); 1.353 +} 1.354 + 1.355 +static void editPixelBit24(const int pixelNo, const unsigned char* buf, 1.356 + const int xorOffset, int& x, int y, const int w, 1.357 + SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) 1.358 +{ 1.359 + SkPMColor* address = bm->getAddr32(x, y); 1.360 + int blue = readByte(buf, xorOffset + 3*pixelNo); 1.361 + int green = readByte(buf, xorOffset + 3*pixelNo + 1); 1.362 + int red = readByte(buf, xorOffset + 3*pixelNo + 2); 1.363 + int alphaBit = (alphaByte & m) >> shift; 1.364 + //alphaBit == 1 => alpha = 0 1.365 + int alpha = (alphaBit-1) & 0xFF; 1.366 + *address = SkPreMultiplyARGB(alpha, red, green, blue); 1.367 +} 1.368 + 1.369 +static void editPixelBit32(const int pixelNo, const unsigned char* buf, 1.370 + const int xorOffset, int& x, int y, const int w, 1.371 + SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) 1.372 +{ 1.373 + SkPMColor* address = bm->getAddr32(x, y); 1.374 + int blue = readByte(buf, xorOffset + 4*pixelNo); 1.375 + int green = readByte(buf, xorOffset + 4*pixelNo + 1); 1.376 + int red = readByte(buf, xorOffset + 4*pixelNo + 2); 1.377 + int alphaBit = (alphaByte & m) >> shift; 1.378 +#if 1 // don't trust the alphaBit for 32bit images <mrr> 1.379 + alphaBit = 0; 1.380 +#endif 1.381 + int alpha = readByte(buf, xorOffset + 4*pixelNo + 3) & ((alphaBit-1)&0xFF); 1.382 + *address = SkPreMultiplyARGB(alpha, red, green, blue); 1.383 +} 1.384 + 1.385 +/////////////////////////////////////////////////////////////////////////////// 1.386 +DEFINE_DECODER_CREATOR(ICOImageDecoder); 1.387 +///////////////////////////////////////////////////////////////////////////////////////// 1.388 + 1.389 +static bool is_ico(SkStreamRewindable* stream) { 1.390 + // Check to see if the first four bytes are 0,0,1,0 1.391 + // FIXME: Is that required and sufficient? 1.392 + SkAutoMalloc autoMal(4); 1.393 + unsigned char* buf = (unsigned char*)autoMal.get(); 1.394 + stream->read((void*)buf, 4); 1.395 + int reserved = read2Bytes(buf, 0); 1.396 + int type = read2Bytes(buf, 2); 1.397 + if (reserved != 0 || type != 1) { 1.398 + // This stream does not represent an ICO image. 1.399 + return false; 1.400 + } 1.401 + return true; 1.402 +} 1.403 + 1.404 +static SkImageDecoder* sk_libico_dfactory(SkStreamRewindable* stream) { 1.405 + if (is_ico(stream)) { 1.406 + return SkNEW(SkICOImageDecoder); 1.407 + } 1.408 + return NULL; 1.409 +} 1.410 + 1.411 +static SkImageDecoder_DecodeReg gReg(sk_libico_dfactory); 1.412 + 1.413 +static SkImageDecoder::Format get_format_ico(SkStreamRewindable* stream) { 1.414 + if (is_ico(stream)) { 1.415 + return SkImageDecoder::kICO_Format; 1.416 + } 1.417 + return SkImageDecoder::kUnknown_Format; 1.418 +} 1.419 + 1.420 +static SkImageDecoder_FormatReg gFormatReg(get_format_ico);