gfx/skia/trunk/src/images/SkImageDecoder_libwebp.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /*
     2  * Copyright 2010, The Android Open Source Project
     3  *
     4  * Licensed under the Apache License, Version 2.0 (the "License");
     5  * you may not use this file except in compliance with the License.
     6  * You may obtain a copy of the License at
     7  *
     8  *     http://www.apache.org/licenses/LICENSE-2.0
     9  *
    10  * Unless required by applicable law or agreed to in writing, software
    11  * distributed under the License is distributed on an "AS IS" BASIS,
    12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  * See the License for the specific language governing permissions and
    14  * limitations under the License.
    15  */
    17 #include "SkImageDecoder.h"
    18 #include "SkImageEncoder.h"
    19 #include "SkColorPriv.h"
    20 #include "SkScaledBitmapSampler.h"
    21 #include "SkStream.h"
    22 #include "SkTemplates.h"
    23 #include "SkUtils.h"
    25 // A WebP decoder only, on top of (subset of) libwebp
    26 // For more information on WebP image format, and libwebp library, see:
    27 //   http://code.google.com/speed/webp/
    28 //   http://www.webmproject.org/code/#libwebp_webp_image_decoder_library
    29 //   http://review.webmproject.org/gitweb?p=libwebp.git
    31 #include <stdio.h>
    32 extern "C" {
    33 // If moving libwebp out of skia source tree, path for webp headers must be
    34 // updated accordingly. Here, we enforce using local copy in webp sub-directory.
    35 #include "webp/decode.h"
    36 #include "webp/encode.h"
    37 }
    39 // this enables timing code to report milliseconds for a decode
    40 //#define TIME_DECODE
    42 //////////////////////////////////////////////////////////////////////////
    43 //////////////////////////////////////////////////////////////////////////
    45 // Define VP8 I/O on top of Skia stream
    47 //////////////////////////////////////////////////////////////////////////
    48 //////////////////////////////////////////////////////////////////////////
    50 static const size_t WEBP_VP8_HEADER_SIZE = 64;
    51 static const size_t WEBP_IDECODE_BUFFER_SZ = (1 << 16);
    53 // Parse headers of RIFF container, and check for valid Webp (VP8) content.
    54 static bool webp_parse_header(SkStream* stream, int* width, int* height, int* alpha) {
    55     unsigned char buffer[WEBP_VP8_HEADER_SIZE];
    56     size_t bytesToRead = WEBP_VP8_HEADER_SIZE;
    57     size_t totalBytesRead = 0;
    58     do {
    59         unsigned char* dst = buffer + totalBytesRead;
    60         const size_t bytesRead = stream->read(dst, bytesToRead);
    61         if (0 == bytesRead) {
    62             // Could not read any bytes. Check to see if we are at the end (exit
    63             // condition), and continue reading if not. Important for streams
    64             // that do not have all the data ready.
    65             continue;
    66         }
    67         bytesToRead -= bytesRead;
    68         totalBytesRead += bytesRead;
    69         SkASSERT(bytesToRead + totalBytesRead == WEBP_VP8_HEADER_SIZE);
    70     } while (!stream->isAtEnd() && bytesToRead > 0);
    72     WebPBitstreamFeatures features;
    73     VP8StatusCode status = WebPGetFeatures(buffer, totalBytesRead, &features);
    74     if (VP8_STATUS_OK != status) {
    75         return false; // Invalid WebP file.
    76     }
    77     *width = features.width;
    78     *height = features.height;
    79     *alpha = features.has_alpha;
    81     // sanity check for image size that's about to be decoded.
    82     {
    83         int64_t size = sk_64_mul(*width, *height);
    84         if (!sk_64_isS32(size)) {
    85             return false;
    86         }
    87         // now check that if we are 4-bytes per pixel, we also don't overflow
    88         if (sk_64_asS32(size) > (0x7FFFFFFF >> 2)) {
    89             return false;
    90         }
    91     }
    92     return true;
    93 }
    95 class SkWEBPImageDecoder: public SkImageDecoder {
    96 public:
    97     SkWEBPImageDecoder() {
    98         fInputStream = NULL;
    99         fOrigWidth = 0;
   100         fOrigHeight = 0;
   101         fHasAlpha = 0;
   102     }
   103     virtual ~SkWEBPImageDecoder() {
   104         SkSafeUnref(fInputStream);
   105     }
   107     virtual Format getFormat() const SK_OVERRIDE {
   108         return kWEBP_Format;
   109     }
   111 protected:
   112     virtual bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) SK_OVERRIDE;
   113     virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE;
   114     virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
   116 private:
   117     /**
   118      *  Called when determining the output config to request to webp.
   119      *  If the image does not have alpha, there is no need to premultiply.
   120      *  If the caller wants unpremultiplied colors, that is respected.
   121      */
   122     bool shouldPremultiply() const {
   123         return SkToBool(fHasAlpha) && !this->getRequireUnpremultipliedColors();
   124     }
   126     bool setDecodeConfig(SkBitmap* decodedBitmap, int width, int height);
   128     SkStream* fInputStream;
   129     int fOrigWidth;
   130     int fOrigHeight;
   131     int fHasAlpha;
   133     typedef SkImageDecoder INHERITED;
   134 };
   136 //////////////////////////////////////////////////////////////////////////
   138 #ifdef TIME_DECODE
   140 #include "SkTime.h"
   142 class AutoTimeMillis {
   143 public:
   144     AutoTimeMillis(const char label[]) :
   145         fLabel(label) {
   146         if (NULL == fLabel) {
   147             fLabel = "";
   148         }
   149         fNow = SkTime::GetMSecs();
   150     }
   151     ~AutoTimeMillis() {
   152         SkDebugf("---- Time (ms): %s %d\n", fLabel, SkTime::GetMSecs() - fNow);
   153     }
   154 private:
   155     const char* fLabel;
   156     SkMSec fNow;
   157 };
   159 #endif
   161 ///////////////////////////////////////////////////////////////////////////////
   163 // This guy exists just to aid in debugging, as it allows debuggers to just
   164 // set a break-point in one place to see all error exists.
   165 static bool return_false(const SkBitmap& bm, const char msg[]) {
   166     SkDEBUGF(("libwebp error %s [%d %d]", msg, bm.width(), bm.height()));
   167     return false; // must always return false
   168 }
   170 static WEBP_CSP_MODE webp_decode_mode(const SkBitmap* decodedBitmap, bool premultiply) {
   171     WEBP_CSP_MODE mode = MODE_LAST;
   172     SkBitmap::Config config = decodedBitmap->config();
   174     if (config == SkBitmap::kARGB_8888_Config) {
   175         #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
   176             mode = premultiply ? MODE_bgrA : MODE_BGRA;
   177         #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
   178             mode = premultiply ? MODE_rgbA : MODE_RGBA;
   179         #else
   180             #error "Skia uses BGRA or RGBA byte order"
   181         #endif
   182     } else if (config == SkBitmap::kARGB_4444_Config) {
   183         mode = premultiply ? MODE_rgbA_4444 : MODE_RGBA_4444;
   184     } else if (config == SkBitmap::kRGB_565_Config) {
   185         mode = MODE_RGB_565;
   186     }
   187     SkASSERT(MODE_LAST != mode);
   188     return mode;
   189 }
   191 // Incremental WebP image decoding. Reads input buffer of 64K size iteratively
   192 // and decodes this block to appropriate color-space as per config object.
   193 static bool webp_idecode(SkStream* stream, WebPDecoderConfig* config) {
   194     WebPIDecoder* idec = WebPIDecode(NULL, 0, config);
   195     if (NULL == idec) {
   196         WebPFreeDecBuffer(&config->output);
   197         return false;
   198     }
   200     if (!stream->rewind()) {
   201         SkDebugf("Failed to rewind webp stream!");
   202         return false;
   203     }
   204     const size_t readBufferSize = stream->hasLength() ?
   205             SkTMin(stream->getLength(), WEBP_IDECODE_BUFFER_SZ) : WEBP_IDECODE_BUFFER_SZ;
   206     SkAutoMalloc srcStorage(readBufferSize);
   207     unsigned char* input = (uint8_t*)srcStorage.get();
   208     if (NULL == input) {
   209         WebPIDelete(idec);
   210         WebPFreeDecBuffer(&config->output);
   211         return false;
   212     }
   214     bool success = true;
   215     VP8StatusCode status = VP8_STATUS_SUSPENDED;
   216     do {
   217         const size_t bytesRead = stream->read(input, readBufferSize);
   218         if (0 == bytesRead) {
   219             success = false;
   220             break;
   221         }
   223         status = WebPIAppend(idec, input, bytesRead);
   224         if (VP8_STATUS_OK != status && VP8_STATUS_SUSPENDED != status) {
   225             success = false;
   226             break;
   227         }
   228     } while (VP8_STATUS_OK != status);
   229     srcStorage.free();
   230     WebPIDelete(idec);
   231     WebPFreeDecBuffer(&config->output);
   233     return success;
   234 }
   236 static bool webp_get_config_resize(WebPDecoderConfig* config,
   237                                    SkBitmap* decodedBitmap,
   238                                    int width, int height, bool premultiply) {
   239     WEBP_CSP_MODE mode = webp_decode_mode(decodedBitmap, premultiply);
   240     if (MODE_LAST == mode) {
   241         return false;
   242     }
   244     if (0 == WebPInitDecoderConfig(config)) {
   245         return false;
   246     }
   248     config->output.colorspace = mode;
   249     config->output.u.RGBA.rgba = (uint8_t*)decodedBitmap->getPixels();
   250     config->output.u.RGBA.stride = (int) decodedBitmap->rowBytes();
   251     config->output.u.RGBA.size = decodedBitmap->getSize();
   252     config->output.is_external_memory = 1;
   254     if (width != decodedBitmap->width() || height != decodedBitmap->height()) {
   255         config->options.use_scaling = 1;
   256         config->options.scaled_width = decodedBitmap->width();
   257         config->options.scaled_height = decodedBitmap->height();
   258     }
   260     return true;
   261 }
   263 static bool webp_get_config_resize_crop(WebPDecoderConfig* config,
   264                                         SkBitmap* decodedBitmap,
   265                                         const SkIRect& region, bool premultiply) {
   267     if (!webp_get_config_resize(config, decodedBitmap, region.width(),
   268                                 region.height(), premultiply)) {
   269       return false;
   270     }
   272     config->options.use_cropping = 1;
   273     config->options.crop_left = region.fLeft;
   274     config->options.crop_top = region.fTop;
   275     config->options.crop_width = region.width();
   276     config->options.crop_height = region.height();
   278     return true;
   279 }
   281 bool SkWEBPImageDecoder::setDecodeConfig(SkBitmap* decodedBitmap,
   282                                          int width, int height) {
   283     SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, SkToBool(fHasAlpha));
   285     // YUV converter supports output in RGB565, RGBA4444 and RGBA8888 formats.
   286     if (fHasAlpha) {
   287         if (config != SkBitmap::kARGB_4444_Config) {
   288             config = SkBitmap::kARGB_8888_Config;
   289         }
   290     } else {
   291         if (config != SkBitmap::kRGB_565_Config &&
   292             config != SkBitmap::kARGB_4444_Config) {
   293             config = SkBitmap::kARGB_8888_Config;
   294         }
   295     }
   297     if (!this->chooseFromOneChoice(config, width, height)) {
   298         return false;
   299     }
   301     return decodedBitmap->setConfig(config, width, height, 0,
   302                                     fHasAlpha ? kPremul_SkAlphaType : kOpaque_SkAlphaType);
   303 }
   305 bool SkWEBPImageDecoder::onBuildTileIndex(SkStreamRewindable* stream,
   306                                           int *width, int *height) {
   307     int origWidth, origHeight, hasAlpha;
   308     if (!webp_parse_header(stream, &origWidth, &origHeight, &hasAlpha)) {
   309         return false;
   310     }
   312     if (!stream->rewind()) {
   313         SkDebugf("Failed to rewind webp stream!");
   314         return false;
   315     }
   317     *width = origWidth;
   318     *height = origHeight;
   320     SkRefCnt_SafeAssign(this->fInputStream, stream);
   321     this->fOrigWidth = origWidth;
   322     this->fOrigHeight = origHeight;
   323     this->fHasAlpha = hasAlpha;
   325     return true;
   326 }
   328 static bool is_config_compatible(const SkBitmap& bitmap) {
   329     SkBitmap::Config config = bitmap.config();
   330     return config == SkBitmap::kARGB_4444_Config ||
   331            config == SkBitmap::kRGB_565_Config ||
   332            config == SkBitmap::kARGB_8888_Config;
   333 }
   335 bool SkWEBPImageDecoder::onDecodeSubset(SkBitmap* decodedBitmap,
   336                                         const SkIRect& region) {
   337     SkIRect rect = SkIRect::MakeWH(fOrigWidth, fOrigHeight);
   339     if (!rect.intersect(region)) {
   340         // If the requested region is entirely outsides the image, return false
   341         return false;
   342     }
   344     const int sampleSize = this->getSampleSize();
   345     SkScaledBitmapSampler sampler(rect.width(), rect.height(), sampleSize);
   346     const int width = sampler.scaledWidth();
   347     const int height = sampler.scaledHeight();
   349     // The image can be decoded directly to decodedBitmap if
   350     //   1. the region is within the image range
   351     //   2. bitmap's config is compatible
   352     //   3. bitmap's size is same as the required region (after sampled)
   353     bool directDecode = (rect == region) &&
   354                         (decodedBitmap->isNull() ||
   355                          (is_config_compatible(*decodedBitmap) &&
   356                          (decodedBitmap->width() == width) &&
   357                          (decodedBitmap->height() == height)));
   359     SkBitmap tmpBitmap;
   360     SkBitmap *bitmap = decodedBitmap;
   362     if (!directDecode) {
   363         bitmap = &tmpBitmap;
   364     }
   366     if (bitmap->isNull()) {
   367         if (!setDecodeConfig(bitmap, width, height)) {
   368             return false;
   369         }
   370         // alloc from native heap if it is a temp bitmap. (prevent GC)
   371         bool allocResult = (bitmap == decodedBitmap)
   372                                ? allocPixelRef(bitmap, NULL)
   373                                : bitmap->allocPixels();
   374         if (!allocResult) {
   375             return return_false(*decodedBitmap, "allocPixelRef");
   376         }
   377     } else {
   378         // This is also called in setDecodeConfig in above block.
   379         // i.e., when bitmap->isNull() is true.
   380         if (!chooseFromOneChoice(bitmap->config(), width, height)) {
   381             return false;
   382         }
   383     }
   385     SkAutoLockPixels alp(*bitmap);
   386     WebPDecoderConfig config;
   387     if (!webp_get_config_resize_crop(&config, bitmap, rect,
   388                                      this->shouldPremultiply())) {
   389         return false;
   390     }
   392     // Decode the WebP image data stream using WebP incremental decoding for
   393     // the specified cropped image-region.
   394     if (!webp_idecode(this->fInputStream, &config)) {
   395         return false;
   396     }
   398     if (!directDecode) {
   399         cropBitmap(decodedBitmap, bitmap, sampleSize, region.x(), region.y(),
   400                    region.width(), region.height(), rect.x(), rect.y());
   401     }
   402     return true;
   403 }
   405 bool SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
   406                                   Mode mode) {
   407 #ifdef TIME_DECODE
   408     AutoTimeMillis atm("WEBP Decode");
   409 #endif
   411     int origWidth, origHeight, hasAlpha;
   412     if (!webp_parse_header(stream, &origWidth, &origHeight, &hasAlpha)) {
   413         return false;
   414     }
   415     this->fHasAlpha = hasAlpha;
   417     const int sampleSize = this->getSampleSize();
   418     SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
   419     if (!setDecodeConfig(decodedBitmap, sampler.scaledWidth(),
   420                          sampler.scaledHeight())) {
   421         return false;
   422     }
   424     // If only bounds are requested, done
   425     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
   426         return true;
   427     }
   429     if (!this->allocPixelRef(decodedBitmap, NULL)) {
   430         return return_false(*decodedBitmap, "allocPixelRef");
   431     }
   433     SkAutoLockPixels alp(*decodedBitmap);
   435     WebPDecoderConfig config;
   436     if (!webp_get_config_resize(&config, decodedBitmap, origWidth, origHeight,
   437                                 this->shouldPremultiply())) {
   438         return false;
   439     }
   441     // Decode the WebP image data stream using WebP incremental decoding.
   442     return webp_idecode(stream, &config);
   443 }
   445 ///////////////////////////////////////////////////////////////////////////////
   447 #include "SkUnPreMultiply.h"
   449 typedef void (*ScanlineImporter)(const uint8_t* in, uint8_t* out, int width,
   450                                  const SkPMColor* SK_RESTRICT ctable);
   452 static void ARGB_8888_To_RGB(const uint8_t* in, uint8_t* rgb, int width,
   453                              const SkPMColor*) {
   454   const uint32_t* SK_RESTRICT src = (const uint32_t*)in;
   455   for (int i = 0; i < width; ++i) {
   456       const uint32_t c = *src++;
   457       rgb[0] = SkGetPackedR32(c);
   458       rgb[1] = SkGetPackedG32(c);
   459       rgb[2] = SkGetPackedB32(c);
   460       rgb += 3;
   461   }
   462 }
   464 static void ARGB_8888_To_RGBA(const uint8_t* in, uint8_t* rgb, int width,
   465                               const SkPMColor*) {
   466   const uint32_t* SK_RESTRICT src = (const uint32_t*)in;
   467   const SkUnPreMultiply::Scale* SK_RESTRICT table =
   468       SkUnPreMultiply::GetScaleTable();
   469   for (int i = 0; i < width; ++i) {
   470       const uint32_t c = *src++;
   471       uint8_t a = SkGetPackedA32(c);
   472       uint8_t r = SkGetPackedR32(c);
   473       uint8_t g = SkGetPackedG32(c);
   474       uint8_t b = SkGetPackedB32(c);
   475       if (0 != a && 255 != a) {
   476         SkUnPreMultiply::Scale scale = table[a];
   477         r = SkUnPreMultiply::ApplyScale(scale, r);
   478         g = SkUnPreMultiply::ApplyScale(scale, g);
   479         b = SkUnPreMultiply::ApplyScale(scale, b);
   480       }
   481       rgb[0] = r;
   482       rgb[1] = g;
   483       rgb[2] = b;
   484       rgb[3] = a;
   485       rgb += 4;
   486   }
   487 }
   489 static void RGB_565_To_RGB(const uint8_t* in, uint8_t* rgb, int width,
   490                            const SkPMColor*) {
   491   const uint16_t* SK_RESTRICT src = (const uint16_t*)in;
   492   for (int i = 0; i < width; ++i) {
   493       const uint16_t c = *src++;
   494       rgb[0] = SkPacked16ToR32(c);
   495       rgb[1] = SkPacked16ToG32(c);
   496       rgb[2] = SkPacked16ToB32(c);
   497       rgb += 3;
   498   }
   499 }
   501 static void ARGB_4444_To_RGB(const uint8_t* in, uint8_t* rgb, int width,
   502                              const SkPMColor*) {
   503   const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)in;
   504   for (int i = 0; i < width; ++i) {
   505       const SkPMColor16 c = *src++;
   506       rgb[0] = SkPacked4444ToR32(c);
   507       rgb[1] = SkPacked4444ToG32(c);
   508       rgb[2] = SkPacked4444ToB32(c);
   509       rgb += 3;
   510   }
   511 }
   513 static void ARGB_4444_To_RGBA(const uint8_t* in, uint8_t* rgb, int width,
   514                               const SkPMColor*) {
   515   const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)in;
   516   const SkUnPreMultiply::Scale* SK_RESTRICT table =
   517       SkUnPreMultiply::GetScaleTable();
   518   for (int i = 0; i < width; ++i) {
   519       const SkPMColor16 c = *src++;
   520       uint8_t a = SkPacked4444ToA32(c);
   521       uint8_t r = SkPacked4444ToR32(c);
   522       uint8_t g = SkPacked4444ToG32(c);
   523       uint8_t b = SkPacked4444ToB32(c);
   524       if (0 != a && 255 != a) {
   525         SkUnPreMultiply::Scale scale = table[a];
   526         r = SkUnPreMultiply::ApplyScale(scale, r);
   527         g = SkUnPreMultiply::ApplyScale(scale, g);
   528         b = SkUnPreMultiply::ApplyScale(scale, b);
   529       }
   530       rgb[0] = r;
   531       rgb[1] = g;
   532       rgb[2] = b;
   533       rgb[3] = a;
   534       rgb += 4;
   535   }
   536 }
   538 static void Index8_To_RGB(const uint8_t* in, uint8_t* rgb, int width,
   539                           const SkPMColor* SK_RESTRICT ctable) {
   540   const uint8_t* SK_RESTRICT src = (const uint8_t*)in;
   541   for (int i = 0; i < width; ++i) {
   542       const uint32_t c = ctable[*src++];
   543       rgb[0] = SkGetPackedR32(c);
   544       rgb[1] = SkGetPackedG32(c);
   545       rgb[2] = SkGetPackedB32(c);
   546       rgb += 3;
   547   }
   548 }
   550 static ScanlineImporter ChooseImporter(const SkBitmap::Config& config,
   551                                        bool  hasAlpha,
   552                                        int*  bpp) {
   553     switch (config) {
   554         case SkBitmap::kARGB_8888_Config:
   555             if (hasAlpha) {
   556                 *bpp = 4;
   557                 return ARGB_8888_To_RGBA;
   558             } else {
   559                 *bpp = 3;
   560                 return ARGB_8888_To_RGB;
   561             }
   562         case SkBitmap::kARGB_4444_Config:
   563             if (hasAlpha) {
   564                 *bpp = 4;
   565                 return ARGB_4444_To_RGBA;
   566             } else {
   567                 *bpp = 3;
   568                 return ARGB_4444_To_RGB;
   569             }
   570         case SkBitmap::kRGB_565_Config:
   571             *bpp = 3;
   572             return RGB_565_To_RGB;
   573         case SkBitmap::kIndex8_Config:
   574             *bpp = 3;
   575             return Index8_To_RGB;
   576         default:
   577             return NULL;
   578     }
   579 }
   581 static int stream_writer(const uint8_t* data, size_t data_size,
   582                          const WebPPicture* const picture) {
   583   SkWStream* const stream = (SkWStream*)picture->custom_ptr;
   584   return stream->write(data, data_size) ? 1 : 0;
   585 }
   587 class SkWEBPImageEncoder : public SkImageEncoder {
   588 protected:
   589     virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) SK_OVERRIDE;
   591 private:
   592     typedef SkImageEncoder INHERITED;
   593 };
   595 bool SkWEBPImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bm,
   596                                   int quality) {
   597     const SkBitmap::Config config = bm.config();
   598     const bool hasAlpha = !bm.isOpaque();
   599     int bpp = -1;
   600     const ScanlineImporter scanline_import = ChooseImporter(config, hasAlpha,
   601                                                             &bpp);
   602     if (NULL == scanline_import) {
   603         return false;
   604     }
   605     if (-1 == bpp) {
   606         return false;
   607     }
   609     SkAutoLockPixels alp(bm);
   610     SkAutoLockColors ctLocker;
   611     if (NULL == bm.getPixels()) {
   612         return false;
   613     }
   615     WebPConfig webp_config;
   616     if (!WebPConfigPreset(&webp_config, WEBP_PRESET_DEFAULT, (float) quality)) {
   617         return false;
   618     }
   620     WebPPicture pic;
   621     WebPPictureInit(&pic);
   622     pic.width = bm.width();
   623     pic.height = bm.height();
   624     pic.writer = stream_writer;
   625     pic.custom_ptr = (void*)stream;
   627     const SkPMColor* colors = ctLocker.lockColors(bm);
   628     const uint8_t* src = (uint8_t*)bm.getPixels();
   629     const int rgbStride = pic.width * bpp;
   631     // Import (for each scanline) the bit-map image (in appropriate color-space)
   632     // to RGB color space.
   633     uint8_t* rgb = new uint8_t[rgbStride * pic.height];
   634     for (int y = 0; y < pic.height; ++y) {
   635         scanline_import(src + y * bm.rowBytes(), rgb + y * rgbStride,
   636                         pic.width, colors);
   637     }
   639     bool ok;
   640     if (bpp == 3) {
   641         ok = SkToBool(WebPPictureImportRGB(&pic, rgb, rgbStride));
   642     } else {
   643         ok = SkToBool(WebPPictureImportRGBA(&pic, rgb, rgbStride));
   644     }
   645     delete[] rgb;
   647     ok = ok && WebPEncode(&webp_config, &pic);
   648     WebPPictureFree(&pic);
   650     return ok;
   651 }
   654 ///////////////////////////////////////////////////////////////////////////////
   655 DEFINE_DECODER_CREATOR(WEBPImageDecoder);
   656 DEFINE_ENCODER_CREATOR(WEBPImageEncoder);
   657 ///////////////////////////////////////////////////////////////////////////////
   659 static SkImageDecoder* sk_libwebp_dfactory(SkStreamRewindable* stream) {
   660     int width, height, hasAlpha;
   661     if (!webp_parse_header(stream, &width, &height, &hasAlpha)) {
   662         return NULL;
   663     }
   665     // Magic matches, call decoder
   666     return SkNEW(SkWEBPImageDecoder);
   667 }
   669 static SkImageDecoder::Format get_format_webp(SkStreamRewindable* stream) {
   670     int width, height, hasAlpha;
   671     if (webp_parse_header(stream, &width, &height, &hasAlpha)) {
   672         return SkImageDecoder::kWEBP_Format;
   673     }
   674     return SkImageDecoder::kUnknown_Format;
   675 }
   677 static SkImageEncoder* sk_libwebp_efactory(SkImageEncoder::Type t) {
   678       return (SkImageEncoder::kWEBP_Type == t) ? SkNEW(SkWEBPImageEncoder) : NULL;
   679 }
   681 static SkImageDecoder_DecodeReg gDReg(sk_libwebp_dfactory);
   682 static SkImageDecoder_FormatReg gFormatReg(get_format_webp);
   683 static SkImageEncoder_EncodeReg gEReg(sk_libwebp_efactory);

mercurial