18432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold/*
28432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold * Copyright 2010, The Android Open Source Project
38432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold *
48432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold * Licensed under the Apache License, Version 2.0 (the "License");
58432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold * you may not use this file except in compliance with the License.
68432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold * You may obtain a copy of the License at
78432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold *
88432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold *     http://www.apache.org/licenses/LICENSE-2.0
98432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold *
108432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold * Unless required by applicable law or agreed to in writing, software
118432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold * distributed under the License is distributed on an "AS IS" BASIS,
128432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold * See the License for the specific language governing permissions and
148432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold * limitations under the License.
158432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold */
168432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
178432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#include "SkImageDecoder.h"
188432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#include "SkImageEncoder.h"
198432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#include "SkColorPriv.h"
208432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#include "SkScaledBitmapSampler.h"
218432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#include "SkStream.h"
228432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#include "SkTemplates.h"
238432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#include "SkUtils.h"
24943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin#include "SkTScopedPtr.h"
258432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
268432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold// A WebP decoder only, on top of (subset of) libwebp
278432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold// For more information on WebP image format, and libwebp library, see:
288432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold//   http://code.google.com/speed/webp/
298432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold//   http://www.webmproject.org/code/#libwebp_webp_image_decoder_library
308432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold//   http://review.webmproject.org/gitweb?p=libwebp.git
318432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
328432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#include <stdio.h>
338432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassoldextern "C" {
348c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora// If moving libwebp out of skia source tree, path for webp headers must be
358c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora// updated accordingly. Here, we enforce using local copy in webp sub-directory.
368432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#include "webp/decode.h"
37a059123d8eb75302b13a7fd831478413d124d618Vikas Arora#include "webp/encode.h"
388432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold}
398432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
408432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#ifdef ANDROID
418432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#include <cutils/properties.h>
428432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
438432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold// Key to lookup the size of memory buffer set in system property
448432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassoldstatic const char KEY_MEM_CAP[] = "ro.media.dec.webp.memcap";
458432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#endif
468432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
478432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold// this enables timing code to report milliseconds for a decode
488432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold//#define TIME_DECODE
498432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
508432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold//////////////////////////////////////////////////////////////////////////
518432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold//////////////////////////////////////////////////////////////////////////
528432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
538432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold// Define VP8 I/O on top of Skia stream
548432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
558432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold//////////////////////////////////////////////////////////////////////////
568432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold//////////////////////////////////////////////////////////////////////////
578432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
5822c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arorastatic const size_t WEBP_VP8_HEADER_SIZE = 64;
5982ed38078af4a2b643415a76e84f88754f804709Vikas Arorastatic const size_t WEBP_IDECODE_BUFFER_SZ = (1 << 16);
608432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
6182ed38078af4a2b643415a76e84f88754f804709Vikas Arora// Parse headers of RIFF container, and check for valid Webp (VP8) content.
6222c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arorastatic bool webp_parse_header(SkStream* stream, int* width, int* height,
6322c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora                              int* alpha) {
6482ed38078af4a2b643415a76e84f88754f804709Vikas Arora    unsigned char buffer[WEBP_VP8_HEADER_SIZE];
6522c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    const uint32_t contentSize = stream->getLength();
6682ed38078af4a2b643415a76e84f88754f804709Vikas Arora    const size_t len = stream->read(buffer, WEBP_VP8_HEADER_SIZE);
6722c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    const uint32_t read_bytes = (contentSize < WEBP_VP8_HEADER_SIZE) ?
6822c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora        contentSize : WEBP_VP8_HEADER_SIZE;
6922c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    if (len != read_bytes) {
7082ed38078af4a2b643415a76e84f88754f804709Vikas Arora        return false; // can't read enough
718432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    }
728432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
7322c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    WebPBitstreamFeatures features;
7422c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    VP8StatusCode status = WebPGetFeatures(buffer, read_bytes, &features);
7522c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    if (status != VP8_STATUS_OK) {
7682ed38078af4a2b643415a76e84f88754f804709Vikas Arora        return false; // Invalid WebP file.
778432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    }
7822c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    *width = features.width;
7922c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    *height = features.height;
8022c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    *alpha = features.has_alpha;
818432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
8282ed38078af4a2b643415a76e84f88754f804709Vikas Arora    // sanity check for image size that's about to be decoded.
8382ed38078af4a2b643415a76e84f88754f804709Vikas Arora    {
8482ed38078af4a2b643415a76e84f88754f804709Vikas Arora        Sk64 size;
8582ed38078af4a2b643415a76e84f88754f804709Vikas Arora        size.setMul(*width, *height);
8682ed38078af4a2b643415a76e84f88754f804709Vikas Arora        if (size.isNeg() || !size.is32()) {
8782ed38078af4a2b643415a76e84f88754f804709Vikas Arora            return false;
8882ed38078af4a2b643415a76e84f88754f804709Vikas Arora        }
8982ed38078af4a2b643415a76e84f88754f804709Vikas Arora        // now check that if we are 4-bytes per pixel, we also don't overflow
9082ed38078af4a2b643415a76e84f88754f804709Vikas Arora        if (size.get32() > (0x7FFFFFFF >> 2)) {
9182ed38078af4a2b643415a76e84f88754f804709Vikas Arora            return false;
9282ed38078af4a2b643415a76e84f88754f804709Vikas Arora        }
938432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    }
9482ed38078af4a2b643415a76e84f88754f804709Vikas Arora    return true;
958432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold}
968432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
978432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassoldclass SkWEBPImageDecoder: public SkImageDecoder {
988432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassoldpublic:
998432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    virtual Format getFormat() const {
1008432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold        return kWEBP_Format;
1018432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    }
1028432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
1038432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassoldprotected:
1048c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height);
1058c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    virtual bool onDecodeRegion(SkBitmap* bitmap, SkIRect rect);
1068432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
10782ed38078af4a2b643415a76e84f88754f804709Vikas Arora
10882ed38078af4a2b643415a76e84f88754f804709Vikas Aroraprivate:
10982ed38078af4a2b643415a76e84f88754f804709Vikas Arora    bool setDecodeConfig(SkBitmap* decodedBitmap, int width, int height);
1108c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    SkStream *inputStream;
1118c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    int origWidth;
1128c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    int origHeight;
11322c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    int hasAlpha;
1148432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold};
1158432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
1168432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold//////////////////////////////////////////////////////////////////////////
1178432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
1188432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#include "SkTime.h"
1198432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
1208432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassoldclass AutoTimeMillis {
1218432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassoldpublic:
1228432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    AutoTimeMillis(const char label[]) :
1238432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold        fLabel(label) {
1248432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold        if (!fLabel) {
1258432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold            fLabel = "";
1268432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold        }
1278432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold        fNow = SkTime::GetMSecs();
1288432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    }
1298432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    ~AutoTimeMillis() {
1308432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold        SkDebugf("---- Time (ms): %s %d\n", fLabel, SkTime::GetMSecs() - fNow);
1318432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    }
1328432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassoldprivate:
1338432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    const char* fLabel;
1348432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    SkMSec fNow;
1358432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold};
1368432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
1378432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold///////////////////////////////////////////////////////////////////////////////
1388432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
1398432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold// This guy exists just to aid in debugging, as it allows debuggers to just
1408432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold// set a break-point in one place to see all error exists.
1418432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassoldstatic bool return_false(const SkBitmap& bm, const char msg[]) {
1428432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#if 0
1438432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    SkDebugf("libwebp error %s [%d %d]", msg, bm.width(), bm.height());
1448432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#endif
1458432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    return false; // must always return false
1468432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold}
1478432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
1484981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arorastatic WEBP_CSP_MODE webp_decode_mode(SkBitmap* decodedBitmap, int hasAlpha) {
14913f6c47b625101944c936a20fb673cbe47b5c747Vikas Arora    WEBP_CSP_MODE mode = MODE_LAST;
15013f6c47b625101944c936a20fb673cbe47b5c747Vikas Arora    SkBitmap::Config config = decodedBitmap->config();
1514981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora    // For images that have alpha, choose appropriate color mode (MODE_rgbA,
1524981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora    // MODE_rgbA_4444) that pre-multiplies RGB pixel values with transparency
1534981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora    // factor (alpha).
15413f6c47b625101944c936a20fb673cbe47b5c747Vikas Arora    if (config == SkBitmap::kARGB_8888_Config) {
1554981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora      mode = hasAlpha ? MODE_rgbA : MODE_RGBA;
15613f6c47b625101944c936a20fb673cbe47b5c747Vikas Arora    } else if (config == SkBitmap::kARGB_4444_Config) {
1574981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora      mode = hasAlpha ? MODE_rgbA_4444 : MODE_RGBA_4444;
15813f6c47b625101944c936a20fb673cbe47b5c747Vikas Arora    } else if (config == SkBitmap::kRGB_565_Config) {
15913f6c47b625101944c936a20fb673cbe47b5c747Vikas Arora      mode = MODE_RGB_565;
160c5013e3870ecf5a7798c1857a3060d880a7bf2c3Vikas Arora    }
1614981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora    SkASSERT(mode != MODE_LAST);
1628c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    return mode;
1638c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora}
16413f6c47b625101944c936a20fb673cbe47b5c747Vikas Arora
1658c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora// Incremental WebP image decoding. Reads input buffer of 64K size iteratively
1668c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora// and decodes this block to appropriate color-space as per config object.
1678c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arorastatic bool webp_idecode(SkStream* stream, WebPDecoderConfig& config) {
168943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    WebPIDecoder* idec = WebPIDecode(NULL, 0, &config);
16913f6c47b625101944c936a20fb673cbe47b5c747Vikas Arora    if (idec == NULL) {
1708c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora        WebPFreeDecBuffer(&config.output);
1718432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold        return false;
1728432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    }
1738432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
1748c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    stream->rewind();
1758c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    const uint32_t contentSize = stream->getLength();
17622c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    const uint32_t read_buffer_size = (contentSize < WEBP_IDECODE_BUFFER_SZ) ?
17722c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora        contentSize : WEBP_IDECODE_BUFFER_SZ;
17882ed38078af4a2b643415a76e84f88754f804709Vikas Arora    SkAutoMalloc srcStorage(read_buffer_size);
17982ed38078af4a2b643415a76e84f88754f804709Vikas Arora    unsigned char* input = (uint8_t*)srcStorage.get();
18082ed38078af4a2b643415a76e84f88754f804709Vikas Arora    if (input == NULL) {
18182ed38078af4a2b643415a76e84f88754f804709Vikas Arora        WebPIDelete(idec);
1828c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora        WebPFreeDecBuffer(&config.output);
1838432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold        return false;
1848432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    }
18582ed38078af4a2b643415a76e84f88754f804709Vikas Arora
18682ed38078af4a2b643415a76e84f88754f804709Vikas Arora    uint32_t bytes_remaining = contentSize;
18782ed38078af4a2b643415a76e84f88754f804709Vikas Arora    while (bytes_remaining > 0) {
18882ed38078af4a2b643415a76e84f88754f804709Vikas Arora        const uint32_t bytes_to_read =
18922c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora            (bytes_remaining < WEBP_IDECODE_BUFFER_SZ) ?
19022c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora                bytes_remaining : WEBP_IDECODE_BUFFER_SZ;
19182ed38078af4a2b643415a76e84f88754f804709Vikas Arora
19282ed38078af4a2b643415a76e84f88754f804709Vikas Arora        const size_t bytes_read = stream->read(input, bytes_to_read);
19382ed38078af4a2b643415a76e84f88754f804709Vikas Arora        if (bytes_read == 0) {
19482ed38078af4a2b643415a76e84f88754f804709Vikas Arora            break;
19582ed38078af4a2b643415a76e84f88754f804709Vikas Arora        }
19682ed38078af4a2b643415a76e84f88754f804709Vikas Arora
19782ed38078af4a2b643415a76e84f88754f804709Vikas Arora        VP8StatusCode status = WebPIAppend(idec, input, bytes_read);
19882ed38078af4a2b643415a76e84f88754f804709Vikas Arora        if (status == VP8_STATUS_OK || status == VP8_STATUS_SUSPENDED) {
19982ed38078af4a2b643415a76e84f88754f804709Vikas Arora            bytes_remaining -= bytes_read;
20082ed38078af4a2b643415a76e84f88754f804709Vikas Arora        } else {
20182ed38078af4a2b643415a76e84f88754f804709Vikas Arora            break;
20282ed38078af4a2b643415a76e84f88754f804709Vikas Arora        }
20382ed38078af4a2b643415a76e84f88754f804709Vikas Arora    }
20482ed38078af4a2b643415a76e84f88754f804709Vikas Arora    srcStorage.free();
20582ed38078af4a2b643415a76e84f88754f804709Vikas Arora    WebPIDelete(idec);
2068c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    WebPFreeDecBuffer(&config.output);
20782ed38078af4a2b643415a76e84f88754f804709Vikas Arora
20882ed38078af4a2b643415a76e84f88754f804709Vikas Arora    if (bytes_remaining > 0) {
2098432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold        return false;
21082ed38078af4a2b643415a76e84f88754f804709Vikas Arora    } else {
21182ed38078af4a2b643415a76e84f88754f804709Vikas Arora        return true;
2128432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    }
21382ed38078af4a2b643415a76e84f88754f804709Vikas Arora}
2148432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
21522c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arorastatic bool webp_get_config_resize(WebPDecoderConfig& config,
21622c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora                                   SkBitmap* decodedBitmap,
2174981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora                                   int width, int height, int hasAlpha) {
2184981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora    WEBP_CSP_MODE mode = webp_decode_mode(decodedBitmap, hasAlpha);
2198c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    if (mode == MODE_LAST) {
2208c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora        return false;
2218c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    }
2228c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
2238c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    if (WebPInitDecoderConfig(&config) == 0) {
2248c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora        return false;
2258c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    }
2268c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
2278c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    config.output.colorspace = mode;
2288c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    config.output.u.RGBA.rgba = (uint8_t*)decodedBitmap->getPixels();
2298c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    config.output.u.RGBA.stride = decodedBitmap->rowBytes();
2308c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    config.output.u.RGBA.size = decodedBitmap->getSize();
2318c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    config.output.is_external_memory = 1;
2328c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
23322c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    if (width != decodedBitmap->width() ||
23422c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora        height != decodedBitmap->height()) {
2358c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora        config.options.use_scaling = 1;
2368c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora        config.options.scaled_width = decodedBitmap->width();
2378c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora        config.options.scaled_height = decodedBitmap->height();
2388c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    }
2398c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
2408c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    return true;
2418c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora}
2428c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
24322c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arorastatic bool webp_get_config_resize_crop(WebPDecoderConfig& config,
24422c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora                                        SkBitmap* decodedBitmap,
2454981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora                                        SkIRect region, int hasAlpha) {
2468c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
2474981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora    if (!webp_get_config_resize(
2484981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora        config, decodedBitmap, region.width(), region.height(), hasAlpha)) {
2494981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora      return false;
2504981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora    }
2518c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
25222c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    config.options.use_cropping = 1;
25322c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    config.options.crop_left = region.fLeft;
25422c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    config.options.crop_top = region.fTop;
25522c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    config.options.crop_width = region.width();
25622c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    config.options.crop_height = region.height();
2578c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
2588c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    return true;
2598c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora}
2608c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
26182ed38078af4a2b643415a76e84f88754f804709Vikas Arorabool SkWEBPImageDecoder::setDecodeConfig(SkBitmap* decodedBitmap,
262c5013e3870ecf5a7798c1857a3060d880a7bf2c3Vikas Arora                                         int width, int height) {
26382ed38078af4a2b643415a76e84f88754f804709Vikas Arora    SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, hasAlpha);
2648432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
2658c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    // YUV converter supports output in RGB565, RGBA4444 and RGBA8888 formats.
2668432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    if (hasAlpha) {
2678432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold        if (config != SkBitmap::kARGB_4444_Config) {
2688432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold            config = SkBitmap::kARGB_8888_Config;
2698432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold        }
2708432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    } else {
27182ed38078af4a2b643415a76e84f88754f804709Vikas Arora        if (config != SkBitmap::kRGB_565_Config &&
27282ed38078af4a2b643415a76e84f88754f804709Vikas Arora            config != SkBitmap::kARGB_4444_Config) {
2738432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold            config = SkBitmap::kARGB_8888_Config;
2748432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold        }
2758432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    }
2768432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
277c5013e3870ecf5a7798c1857a3060d880a7bf2c3Vikas Arora    if (!this->chooseFromOneChoice(config, width, height)) {
2788432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold        return false;
2798432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    }
2808432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
281c5013e3870ecf5a7798c1857a3060d880a7bf2c3Vikas Arora    decodedBitmap->setConfig(config, width, height, 0);
2828432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
28322c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    decodedBitmap->setIsOpaque(!hasAlpha);
2848432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
28582ed38078af4a2b643415a76e84f88754f804709Vikas Arora    return true;
28682ed38078af4a2b643415a76e84f88754f804709Vikas Arora}
2878432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
2888c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arorabool SkWEBPImageDecoder::onBuildTileIndex(SkStream* stream,
2898c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora                                          int *width, int *height) {
29022c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    int origWidth, origHeight, hasAlpha;
29122c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    if (!webp_parse_header(stream, &origWidth, &origHeight, &hasAlpha)) {
2928c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora        return false;
2938c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    }
2948c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
2958c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    stream->rewind();
2968c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    *width = origWidth;
2978c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    *height = origHeight;
2988c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
2998c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    this->inputStream = stream;
3008c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    this->origWidth = origWidth;
3018c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    this->origHeight = origHeight;
30222c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    this->hasAlpha = hasAlpha;
3038c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
3048c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    return true;
3058c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora}
3068c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
30722c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arorastatic bool isConfigCompatible(SkBitmap* bitmap) {
308943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    SkBitmap::Config config = bitmap->config();
309943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    return config == SkBitmap::kARGB_4444_Config ||
310943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin           config == SkBitmap::kRGB_565_Config ||
311943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin           config == SkBitmap::kARGB_8888_Config;
312943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin}
313943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin
3148c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arorabool SkWEBPImageDecoder::onDecodeRegion(SkBitmap* decodedBitmap,
3158c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora                                        SkIRect region) {
316943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    SkIRect rect = SkIRect::MakeWH(origWidth, origHeight);
3178c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
318943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    if (!rect.intersect(region)) {
319943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        // If the requested region is entirely outsides the image, just
320943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        // returns false
3218c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora        return false;
3228c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    }
3238c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
324943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    const int sampleSize = this->getSampleSize();
325943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    SkScaledBitmapSampler sampler(rect.width(), rect.height(), sampleSize);
326943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    const int width = sampler.scaledWidth();
327943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    const int height = sampler.scaledHeight();
328943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin
329943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    // The image can be decoded directly to decodedBitmap if
330943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    //   1. the region is within the image range
331943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    //   2. bitmap's config is compatible
332943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    //   3. bitmap's size is same as the required region (after sampled)
333943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    bool directDecode = (rect == region) &&
334943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin                        (decodedBitmap->isNull() ||
33522c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora                         (isConfigCompatible(decodedBitmap) &&
336943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin                         (decodedBitmap->width() == width) &&
33722c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora                         (decodedBitmap->height() == height)));
338943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    SkTScopedPtr<SkBitmap> adb;
339943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    SkBitmap *bitmap = decodedBitmap;
340943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin
341943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    if (!directDecode) {
342943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        // allocates a temp bitmap
343943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        bitmap = new SkBitmap;
344943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        adb.reset(bitmap);
3458c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    }
3468c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
347943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    if (bitmap->isNull()) {
348943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        if (!setDecodeConfig(bitmap, width, height)) {
349943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin            return false;
350943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        }
351943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        // alloc from native heap if it is a temp bitmap. (prevent GC)
352943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        bool allocResult = (bitmap == decodedBitmap)
353943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin                               ? allocPixelRef(bitmap, NULL)
354943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin                               : bitmap->allocPixels();
355943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        if (!allocResult) {
356943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin            return return_false(*decodedBitmap, "allocPixelRef");
357943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        }
358943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    } else {
359943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        // This is also called in setDecodeConfig in above block.
360943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        // i.e., when bitmap->isNull() is true.
361943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        if (!chooseFromOneChoice(bitmap->config(), width, height)) {
362943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin            return false;
363943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        }
364943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    }
3658c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
366943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    SkAutoLockPixels alp(*bitmap);
3678c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    WebPDecoderConfig config;
3684981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora    if (!webp_get_config_resize_crop(config, bitmap, rect, hasAlpha)) {
3698c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora        return false;
3708c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    }
3718c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
3728c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    // Decode the WebP image data stream using WebP incremental decoding for
3738c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    // the specified cropped image-region.
374943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    if (!webp_idecode(this->inputStream, config)) {
375943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        return false;
376943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    }
377943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin
378943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    if (!directDecode) {
379943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin        cropBitmap(decodedBitmap, bitmap, sampleSize, region.x(), region.y(),
380943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin                  region.width(), region.height(), rect.x(), rect.y());
381943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    }
382943e1fde4c6ecf0eb8998cd86012caa341a02ccfOwen Lin    return true;
3838c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora}
3848c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
38582ed38078af4a2b643415a76e84f88754f804709Vikas Arorabool SkWEBPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
38682ed38078af4a2b643415a76e84f88754f804709Vikas Arora                                  Mode mode) {
38782ed38078af4a2b643415a76e84f88754f804709Vikas Arora#ifdef TIME_DECODE
38882ed38078af4a2b643415a76e84f88754f804709Vikas Arora    AutoTimeMillis atm("WEBP Decode");
3898432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#endif
39082ed38078af4a2b643415a76e84f88754f804709Vikas Arora
39122c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    int origWidth, origHeight, hasAlpha;
39222c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    if (!webp_parse_header(stream, &origWidth, &origHeight, &hasAlpha)) {
3938432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold        return false;
3948432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    }
39522c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    this->hasAlpha = hasAlpha;
3968432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
397c5013e3870ecf5a7798c1857a3060d880a7bf2c3Vikas Arora    const int sampleSize = this->getSampleSize();
398c5013e3870ecf5a7798c1857a3060d880a7bf2c3Vikas Arora    SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
399c5013e3870ecf5a7798c1857a3060d880a7bf2c3Vikas Arora
40082ed38078af4a2b643415a76e84f88754f804709Vikas Arora    // If only bounds are requested, done
40182ed38078af4a2b643415a76e84f88754f804709Vikas Arora    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
402c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase        if (!setDecodeConfig(decodedBitmap, sampler.scaledWidth(),
403c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase                             sampler.scaledHeight())) {
404c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase            return false;
405c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase        }
40682ed38078af4a2b643415a76e84f88754f804709Vikas Arora        return true;
40782ed38078af4a2b643415a76e84f88754f804709Vikas Arora    }
408c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase#ifdef SK_BUILD_FOR_ANDROID
409c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase    // No Bitmap reuse supported for this format
410c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase    if (!decodedBitmap->isNull()) {
411c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase        return false;
412c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase    }
413c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase#endif
414c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase    if (!setDecodeConfig(decodedBitmap, sampler.scaledWidth(),
415c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase                         sampler.scaledHeight())) {
416c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase        return false;
417c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase    }
4188432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
41982ed38078af4a2b643415a76e84f88754f804709Vikas Arora    if (!this->allocPixelRef(decodedBitmap, NULL)) {
42082ed38078af4a2b643415a76e84f88754f804709Vikas Arora        return return_false(*decodedBitmap, "allocPixelRef");
4218432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    }
4228432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
4238c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    SkAutoLockPixels alp(*decodedBitmap);
4248c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora
4258c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    WebPDecoderConfig config;
4264981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora    if (!webp_get_config_resize(config, decodedBitmap, origWidth, origHeight,
4274981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora                                hasAlpha)) {
4288432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold        return false;
4298432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    }
4308432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
4318c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    // Decode the WebP image data stream using WebP incremental decoding.
4328c52c218e8b00b33f837ac4891fcde3a08817169Vikas Arora    return webp_idecode(stream, config);
4338432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold}
4348432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
4358432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold///////////////////////////////////////////////////////////////////////////////
4368432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
437a059123d8eb75302b13a7fd831478413d124d618Vikas Aroratypedef void (*ScanlineImporter)(const uint8_t* in, uint8_t* out, int width,
438a059123d8eb75302b13a7fd831478413d124d618Vikas Arora                                 const SkPMColor* SK_RESTRICT ctable);
439a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
440a059123d8eb75302b13a7fd831478413d124d618Vikas Arorastatic void ARGB_8888_To_RGB(const uint8_t* in, uint8_t* rgb, int width,
441a059123d8eb75302b13a7fd831478413d124d618Vikas Arora                             const SkPMColor*) {
442a059123d8eb75302b13a7fd831478413d124d618Vikas Arora  const uint32_t* SK_RESTRICT src = (const uint32_t*)in;
443a059123d8eb75302b13a7fd831478413d124d618Vikas Arora  for (int i = 0; i < width; ++i) {
444a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      const uint32_t c = *src++;
445a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb[0] = SkGetPackedR32(c);
446a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb[1] = SkGetPackedG32(c);
447a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb[2] = SkGetPackedB32(c);
448a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb += 3;
449a059123d8eb75302b13a7fd831478413d124d618Vikas Arora  }
450a059123d8eb75302b13a7fd831478413d124d618Vikas Arora}
451a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
452a059123d8eb75302b13a7fd831478413d124d618Vikas Arorastatic void RGB_565_To_RGB(const uint8_t* in, uint8_t* rgb, int width,
453a059123d8eb75302b13a7fd831478413d124d618Vikas Arora                           const SkPMColor*) {
454a059123d8eb75302b13a7fd831478413d124d618Vikas Arora  const uint16_t* SK_RESTRICT src = (const uint16_t*)in;
455a059123d8eb75302b13a7fd831478413d124d618Vikas Arora  for (int i = 0; i < width; ++i) {
456a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      const uint16_t c = *src++;
457a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb[0] = SkPacked16ToR32(c);
458a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb[1] = SkPacked16ToG32(c);
459a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb[2] = SkPacked16ToB32(c);
460a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb += 3;
461a059123d8eb75302b13a7fd831478413d124d618Vikas Arora  }
462a059123d8eb75302b13a7fd831478413d124d618Vikas Arora}
463a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
464a059123d8eb75302b13a7fd831478413d124d618Vikas Arorastatic void ARGB_4444_To_RGB(const uint8_t* in, uint8_t* rgb, int width,
465a059123d8eb75302b13a7fd831478413d124d618Vikas Arora                             const SkPMColor*) {
466a059123d8eb75302b13a7fd831478413d124d618Vikas Arora  const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)in;
467a059123d8eb75302b13a7fd831478413d124d618Vikas Arora  for (int i = 0; i < width; ++i) {
468a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      const SkPMColor16 c = *src++;
469a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb[0] = SkPacked4444ToR32(c);
470a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb[1] = SkPacked4444ToG32(c);
471a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb[2] = SkPacked4444ToB32(c);
472a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb += 3;
473a059123d8eb75302b13a7fd831478413d124d618Vikas Arora  }
474a059123d8eb75302b13a7fd831478413d124d618Vikas Arora}
475a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
476a059123d8eb75302b13a7fd831478413d124d618Vikas Arorastatic void Index8_To_RGB(const uint8_t* in, uint8_t* rgb, int width,
477a059123d8eb75302b13a7fd831478413d124d618Vikas Arora                          const SkPMColor* SK_RESTRICT ctable) {
478a059123d8eb75302b13a7fd831478413d124d618Vikas Arora  const uint8_t* SK_RESTRICT src = (const uint8_t*)in;
479a059123d8eb75302b13a7fd831478413d124d618Vikas Arora  for (int i = 0; i < width; ++i) {
480a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      const uint32_t c = ctable[*src++];
481a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb[0] = SkGetPackedR32(c);
482a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb[1] = SkGetPackedG32(c);
483a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb[2] = SkGetPackedB32(c);
484a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      rgb += 3;
485a059123d8eb75302b13a7fd831478413d124d618Vikas Arora  }
486a059123d8eb75302b13a7fd831478413d124d618Vikas Arora}
487a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
488a059123d8eb75302b13a7fd831478413d124d618Vikas Arorastatic ScanlineImporter ChooseImporter(const SkBitmap::Config& config) {
489a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    switch (config) {
490a059123d8eb75302b13a7fd831478413d124d618Vikas Arora        case SkBitmap::kARGB_8888_Config:
491a059123d8eb75302b13a7fd831478413d124d618Vikas Arora            return ARGB_8888_To_RGB;
492a059123d8eb75302b13a7fd831478413d124d618Vikas Arora        case SkBitmap::kRGB_565_Config:
493a059123d8eb75302b13a7fd831478413d124d618Vikas Arora            return RGB_565_To_RGB;
494a059123d8eb75302b13a7fd831478413d124d618Vikas Arora        case SkBitmap::kARGB_4444_Config:
495a059123d8eb75302b13a7fd831478413d124d618Vikas Arora            return ARGB_4444_To_RGB;
496a059123d8eb75302b13a7fd831478413d124d618Vikas Arora        case SkBitmap::kIndex8_Config:
497a059123d8eb75302b13a7fd831478413d124d618Vikas Arora            return Index8_To_RGB;
498a059123d8eb75302b13a7fd831478413d124d618Vikas Arora        default:
499a059123d8eb75302b13a7fd831478413d124d618Vikas Arora            return NULL;
500a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    }
501a059123d8eb75302b13a7fd831478413d124d618Vikas Arora}
502a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
503a059123d8eb75302b13a7fd831478413d124d618Vikas Arorastatic int StreamWriter(const uint8_t* data, size_t data_size,
504a059123d8eb75302b13a7fd831478413d124d618Vikas Arora                        const WebPPicture* const picture) {
505a059123d8eb75302b13a7fd831478413d124d618Vikas Arora  SkWStream* const stream = (SkWStream*)picture->custom_ptr;
506a059123d8eb75302b13a7fd831478413d124d618Vikas Arora  return stream->write(data, data_size) ? 1 : 0;
507a059123d8eb75302b13a7fd831478413d124d618Vikas Arora}
508a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
509a059123d8eb75302b13a7fd831478413d124d618Vikas Aroraclass SkWEBPImageEncoder : public SkImageEncoder {
510a059123d8eb75302b13a7fd831478413d124d618Vikas Aroraprotected:
511a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
512a059123d8eb75302b13a7fd831478413d124d618Vikas Arora};
513a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
514a059123d8eb75302b13a7fd831478413d124d618Vikas Arorabool SkWEBPImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bm,
515a059123d8eb75302b13a7fd831478413d124d618Vikas Arora                                  int quality) {
516a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    const SkBitmap::Config config = bm.getConfig();
517a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    const ScanlineImporter scanline_import = ChooseImporter(config);
518a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    if (NULL == scanline_import) {
519a059123d8eb75302b13a7fd831478413d124d618Vikas Arora        return false;
520a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    }
521a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
522a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    SkAutoLockPixels alp(bm);
523a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    SkAutoLockColors ctLocker;
524a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    if (NULL == bm.getPixels()) {
525a059123d8eb75302b13a7fd831478413d124d618Vikas Arora        return false;
526a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    }
527a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
528a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    WebPConfig webp_config;
529a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    if (!WebPConfigPreset(&webp_config, WEBP_PRESET_DEFAULT, quality)) {
530a059123d8eb75302b13a7fd831478413d124d618Vikas Arora        return false;
531a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    }
532a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
533a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    WebPPicture pic;
534a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    WebPPictureInit(&pic);
535a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    pic.width = bm.width();
536a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    pic.height = bm.height();
537a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    pic.writer = StreamWriter;
538a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    pic.custom_ptr = (void*)stream;
539a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
540a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    const SkPMColor* colors = ctLocker.lockColors(bm);
541a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    const uint8_t* src = (uint8_t*)bm.getPixels();
542a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    const int rgb_stride = pic.width * 3;
543a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
544a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    // Import (for each scanline) the bit-map image (in appropriate color-space)
545a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    // to RGB color space.
546a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    uint8_t* rgb = new uint8_t[rgb_stride * pic.height];
547a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    for (int y = 0; y < pic.height; ++y) {
548a059123d8eb75302b13a7fd831478413d124d618Vikas Arora        scanline_import(src + y * bm.rowBytes(), rgb + y * rgb_stride,
549a059123d8eb75302b13a7fd831478413d124d618Vikas Arora                        pic.width, colors);
550a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    }
551a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
552a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    bool ok = WebPPictureImportRGB(&pic, rgb, rgb_stride);
553a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    delete[] rgb;
554a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
555a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    ok = ok && WebPEncode(&webp_config, &pic);
556a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    WebPPictureFree(&pic);
557a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
558a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    return ok;
559a059123d8eb75302b13a7fd831478413d124d618Vikas Arora}
560a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
561a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
562a059123d8eb75302b13a7fd831478413d124d618Vikas Arora///////////////////////////////////////////////////////////////////////////////
563a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
5648432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold#include "SkTRegistry.h"
5658432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
5668432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassoldstatic SkImageDecoder* DFactory(SkStream* stream) {
56722c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    int width, height, hasAlpha;
56822c3eb1bb4ab1c58edb7b3dd159e5c1969136c51Vikas Arora    if (!webp_parse_header(stream, &width, &height, &hasAlpha)) {
5694981d1421e31f4229bb3d00d8b6dc93f21b03871Vikas Arora        return NULL;
5708432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    }
5718432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
5728432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    // Magic matches, call decoder
5738432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    return SkNEW(SkWEBPImageDecoder);
5748432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold}
5758432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
5768432fc7b32e4de877bb86b38c050b944bed53f14Eric HassoldSkImageDecoder* sk_libwebp_dfactory(SkStream* stream) {
5778432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold    return DFactory(stream);
5788432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold}
5798432fc7b32e4de877bb86b38c050b944bed53f14Eric Hassold
580a059123d8eb75302b13a7fd831478413d124d618Vikas Arorastatic SkImageEncoder* EFactory(SkImageEncoder::Type t) {
581a059123d8eb75302b13a7fd831478413d124d618Vikas Arora      return (SkImageEncoder::kWEBP_Type == t) ? SkNEW(SkWEBPImageEncoder) : NULL;
582a059123d8eb75302b13a7fd831478413d124d618Vikas Arora}
583a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
584a059123d8eb75302b13a7fd831478413d124d618Vikas AroraSkImageEncoder* sk_libwebp_efactory(SkImageEncoder::Type t) {
585a059123d8eb75302b13a7fd831478413d124d618Vikas Arora    return EFactory(t);
586a059123d8eb75302b13a7fd831478413d124d618Vikas Arora}
587a059123d8eb75302b13a7fd831478413d124d618Vikas Arora
588a059123d8eb75302b13a7fd831478413d124d618Vikas Arorastatic SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libwebp_dfactory);
589a059123d8eb75302b13a7fd831478413d124d618Vikas Arorastatic SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libwebp_efactory);
590