1d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/*
2d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com * Copyright 2007 The Android Open Source Project
3d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com *
4d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com * Use of this source code is governed by a BSD-style license that can be
5d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com * found in the LICENSE file.
6d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */
7d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
8d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
9d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkImageDecoder.h"
10d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkImageEncoder.h"
11d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkJpegUtility.h"
12d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkColorPriv.h"
13d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkDither.h"
14d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkScaledBitmapSampler.h"
15d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkStream.h"
16d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkTemplates.h"
17113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#include "SkTime.h"
18d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkUtils.h"
192a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.com#include "SkRTConf.h"
20113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#include "SkRect.h"
21113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#include "SkCanvas.h"
22d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
23fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com
24d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include <stdio.h>
25d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comextern "C" {
26d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #include "jpeglib.h"
27d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #include "jerror.h"
28d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
29d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
30113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// These enable timing code that report milliseconds for an encoding/decoding
31d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com//#define TIME_ENCODE
32d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com//#define TIME_DECODE
33d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
34d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// this enables our rgb->yuv code, which is faster than libjpeg on ARM
35d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#define WE_CONVERT_TO_YUV
36d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
37113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// If ANDROID_RGB is defined by in the jpeg headers it indicates that jpeg offers
38113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com// support for two additional formats (1) JCS_RGBA_8888 and (2) JCS_RGB_565.
39113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
40fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com#if defined(SK_DEBUG)
412a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.com#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS false
4204b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS false
432a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.com#else  // !defined(SK_DEBUG)
442a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.com#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS true
4504b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com#define DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS true
46fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com#endif  // defined(SK_DEBUG)
472a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.comSK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderWarnings,
482a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.com                "images.jpeg.suppressDecoderWarnings",
492a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.com                DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_WARNINGS,
502a10318814fa9f2dd70122bf58d994b19bb9a8cfhalcanary@google.com                "Suppress most JPG warnings when calling decode functions.");
5104b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.comSK_CONF_DECLARE(bool, c_suppressJPEGImageDecoderErrors,
5204b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com                "images.jpeg.suppressDecoderErrors",
5304b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com                DEFAULT_FOR_SUPPRESS_JPEG_IMAGE_DECODER_ERRORS,
5404b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com                "Suppress most JPG error messages when decode "
5504b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com                "function fails.");
56fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com
57d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com//////////////////////////////////////////////////////////////////////////
58d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com//////////////////////////////////////////////////////////////////////////
59d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
60590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void overwrite_mem_buffer_size(jpeg_decompress_struct* cinfo) {
61113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID
62113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    /* Check if the device indicates that it has a large amount of system memory
63113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com     * if so, increase the memory allocation to 30MB instead of the default 5MB.
64113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com     */
65113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef ANDROID_LARGE_MEMORY_DEVICE
66113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->mem->max_memory_to_use = 30 * 1024 * 1024;
67113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#else
68113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->mem->max_memory_to_use = 5 * 1024 * 1024;
69113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
70113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif // SK_BUILD_FOR_ANDROID
71113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com}
72113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
73113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com//////////////////////////////////////////////////////////////////////////
74113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com//////////////////////////////////////////////////////////////////////////
75113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
76fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.comstatic void do_nothing_emit_message(jpeg_common_struct*, int) {
77fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com    /* do nothing */
78fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com}
7904b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.comstatic void do_nothing_output_message(j_common_ptr) {
8004b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com    /* do nothing */
8104b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com}
82fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com
83590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void initialize_info(jpeg_decompress_struct* cinfo, skjpeg_source_mgr* src_mgr) {
84590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(cinfo != NULL);
85590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(src_mgr != NULL);
86590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    jpeg_create_decompress(cinfo);
87590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    overwrite_mem_buffer_size(cinfo);
88590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    cinfo->src = src_mgr;
89fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com    /* To suppress warnings with a SK_DEBUG binary, set the
90fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com     * environment variable "skia_images_jpeg_suppressDecoderWarnings"
91fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com     * to "true".  Inside a program that links to skia:
92fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com     * SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true); */
93fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com    if (c_suppressJPEGImageDecoderWarnings) {
94fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com        cinfo->err->emit_message = &do_nothing_emit_message;
95fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com    }
9604b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com    /* To suppress error messages with a SK_DEBUG binary, set the
9704b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com     * environment variable "skia_images_jpeg_suppressDecoderErrors"
9804b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com     * to "true".  Inside a program that links to skia:
9904b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com     * SK_CONF_SET("images.jpeg.suppressDecoderErrors", true); */
10004b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com    if (c_suppressJPEGImageDecoderErrors) {
10104b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com        cinfo->err->output_message = &do_nothing_output_message;
10204b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com    }
103590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com}
104590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
105a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
106113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comclass SkJPEGImageIndex {
107d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic:
108a1193e4b0e34a7e4e1bd33e9708d7341679f8321scroggo    // Takes ownership of stream.
109b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.com    SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder)
110a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        : fSrcMgr(stream, decoder)
111a1193e4b0e34a7e4e1bd33e9708d7341679f8321scroggo        , fStream(stream)
112a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        , fInfoInitialized(false)
113a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        , fHuffmanCreated(false)
114a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        , fDecompressStarted(false)
115a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        {
116a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            SkDEBUGCODE(fReadHeaderSucceeded = false;)
117a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        }
118113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
119113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    ~SkJPEGImageIndex() {
120a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        if (fHuffmanCreated) {
121590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // Set to false before calling the libjpeg function, in case
122590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // the libjpeg function calls longjmp. Our setjmp handler may
123590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // attempt to delete this SkJPEGImageIndex, thus entering this
124590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // destructor again. Setting fHuffmanCreated to false first
125590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // prevents an infinite loop.
126a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            fHuffmanCreated = false;
127a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            jpeg_destroy_huffman_index(&fHuffmanIndex);
128a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        }
129a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        if (fDecompressStarted) {
130590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // Like fHuffmanCreated, set to false before calling libjpeg
131590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // function to prevent potential infinite loop.
132a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            fDecompressStarted = false;
133a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            jpeg_finish_decompress(&fCInfo);
134a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        }
135a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        if (fInfoInitialized) {
136a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            this->destroyInfo();
137a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        }
138a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    }
139a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com
140a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    /**
141a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  Destroy the cinfo struct.
142a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  After this call, if a huffman index was already built, it
143a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  can be used after calling initializeInfoAndReadHeader
144a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  again. Must not be called after startTileDecompress except
145a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  in the destructor.
146a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     */
147a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    void destroyInfo() {
148a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(fInfoInitialized);
149a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(!fDecompressStarted);
150590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        // Like fHuffmanCreated, set to false before calling libjpeg
151590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        // function to prevent potential infinite loop.
152a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        fInfoInitialized = false;
153113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        jpeg_destroy_decompress(&fCInfo);
154a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkDEBUGCODE(fReadHeaderSucceeded = false;)
155d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
156d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
157113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    /**
158a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  Initialize the cinfo struct.
159a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  Calls jpeg_create_decompress, makes customizations, and
160a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  finally calls jpeg_read_header. Returns true if jpeg_read_header
161a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  returns JPEG_HEADER_OK.
162a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  If cinfo was already initialized, destroyInfo must be called to
163a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  destroy the old one. Must not be called after startTileDecompress.
164113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com     */
165a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    bool initializeInfoAndReadHeader() {
166a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(!fInfoInitialized && !fDecompressStarted);
167590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        initialize_info(&fCInfo, &fSrcMgr);
168a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        fInfoInitialized = true;
169a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true));
170a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkDEBUGCODE(fReadHeaderSucceeded = success;)
171a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        return success;
172113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
173d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
174113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_decompress_struct* cinfo() { return &fCInfo; }
175d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
176113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    huffman_index* huffmanIndex() { return &fHuffmanIndex; }
177a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com
178a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    /**
179a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  Build the index to be used for tile based decoding.
180a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  Must only be called after a successful call to
181a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  initializeInfoAndReadHeader and must not be called more
182a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  than once.
183a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     */
184a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    bool buildHuffmanIndex() {
185a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(fReadHeaderSucceeded);
186a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(!fHuffmanCreated);
187a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        jpeg_create_huffman_index(&fCInfo, &fHuffmanIndex);
188a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(1 == fCInfo.scale_num && 1 == fCInfo.scale_denom);
18957a529877e65687de1fa4d19d52746427c6896dcscroggo@google.com        fHuffmanCreated = jpeg_build_huffman_index(&fCInfo, &fHuffmanIndex);
19057a529877e65687de1fa4d19d52746427c6896dcscroggo@google.com        return fHuffmanCreated;
191a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    }
192a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com
193a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    /**
194a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  Start tile based decoding. Must only be called after a
195a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  successful call to buildHuffmanIndex, and must only be
196a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  called once.
197a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     */
198a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    bool startTileDecompress() {
199a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(fHuffmanCreated);
200a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(fReadHeaderSucceeded);
201a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(!fDecompressStarted);
202a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        if (jpeg_start_tile_decompress(&fCInfo)) {
203a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            fDecompressStarted = true;
204a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            return true;
205a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        }
206a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        return false;
207a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    }
208113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
209113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comprivate:
210113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    skjpeg_source_mgr  fSrcMgr;
211a1193e4b0e34a7e4e1bd33e9708d7341679f8321scroggo    SkAutoTDelete<SkStream> fStream;
212113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_decompress_struct fCInfo;
213113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    huffman_index fHuffmanIndex;
214a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    bool fInfoInitialized;
215a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    bool fHuffmanCreated;
216a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    bool fDecompressStarted;
217a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    SkDEBUGCODE(bool fReadHeaderSucceeded;)
218113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com};
219a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#endif
220d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
221113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comclass SkJPEGImageDecoder : public SkImageDecoder {
222d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic:
223a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
224113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkJPEGImageDecoder() {
225113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        fImageIndex = NULL;
226113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        fImageWidth = 0;
227113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        fImageHeight = 0;
228d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
229113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
230113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    virtual ~SkJPEGImageDecoder() {
231113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        SkDELETE(fImageIndex);
232d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
233a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#endif
234113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
23536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    Format getFormat() const override {
236113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return kJPEG_Format;
237113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
238113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
239113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comprotected:
240d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
24136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) override;
24236352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) override;
243113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
24436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
2457831a4bbb46a919316efc7c70808dcaaf8ee629atfarina    bool onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3],
2467831a4bbb46a919316efc7c70808dcaaf8ee629atfarina                            void* planes[3], size_t rowBytes[3],
2477831a4bbb46a919316efc7c70808dcaaf8ee629atfarina                            SkYUVColorSpace* colorSpace) override;
248113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
249d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprivate:
250a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
251113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkJPEGImageIndex* fImageIndex;
252113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int fImageWidth;
253113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int fImageHeight;
254a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#endif
255113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
256590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    /**
2576c22573edb234ad14df947278cfed010669a39a7reed     *  Determine the appropriate bitmap colortype and out_color_space based on
258590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com     *  both the preference of the caller and the jpeg_color_space on the
259590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com     *  jpeg_decompress_struct passed in.
260590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com     *  Must be called after jpeg_read_header.
261590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com     */
2626c22573edb234ad14df947278cfed010669a39a7reed    SkColorType getBitmapColorType(jpeg_decompress_struct*);
263590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
264113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    typedef SkImageDecoder INHERITED;
265d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com};
266d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
267113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com//////////////////////////////////////////////////////////////////////////
268113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
269d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/* Automatically clean up after throwing an exception */
270d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comclass JPEGAutoClean {
271d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic:
272d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    JPEGAutoClean(): cinfo_ptr(NULL) {}
273d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    ~JPEGAutoClean() {
274d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (cinfo_ptr) {
275d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            jpeg_destroy_decompress(cinfo_ptr);
276d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
277d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
278d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    void set(jpeg_decompress_struct* info) {
279d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo_ptr = info;
280d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
281d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprivate:
282d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    jpeg_decompress_struct* cinfo_ptr;
283d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com};
284d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
285d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com///////////////////////////////////////////////////////////////////////////////
286d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
287d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/*  If we need to better match the request, we might examine the image and
288d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     output dimensions, and determine if the downsampling jpeg provided is
289d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     not sufficient. If so, we can recompute a modified sampleSize value to
290d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     make up the difference.
291d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
292d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     To skip this additional scaling, just set sampleSize = 1; below.
293d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */
294d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic int recompute_sampleSize(int sampleSize,
295d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                                const jpeg_decompress_struct& cinfo) {
296d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    return sampleSize * cinfo.output_width / cinfo.image_width;
297d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
298d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
299d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) {
300d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    /* These are initialized to 0, so if they have non-zero values, we assume
301d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com       they are "valid" (i.e. have been computed by libjpeg)
302d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     */
303113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    return 0 != cinfo.output_width && 0 != cinfo.output_height;
304d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
305d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
306113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comstatic bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count) {
307d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    for (int i = 0; i < count; i++) {
308d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        JSAMPLE* rowptr = (JSAMPLE*)buffer;
309d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1);
310113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (1 != row_count) {
311d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return false;
312d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
313d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
314d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    return true;
315d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
316d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
317d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
318113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comstatic bool skip_src_rows_tile(jpeg_decompress_struct* cinfo,
319113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                               huffman_index *index, void* buffer, int count) {
320113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    for (int i = 0; i < count; i++) {
321113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        JSAMPLE* rowptr = (JSAMPLE*)buffer;
322113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr);
323113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (1 != row_count) {
324113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return false;
325113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
326113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
327113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    return true;
328113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com}
329113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
330113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
3312a1208017dd676f94a53bbb228197c3978dbdd8ascroggo///////////////////////////////////////////////////////////////////////////////
3322a1208017dd676f94a53bbb228197c3978dbdd8ascroggo
333d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// This guy exists just to aid in debugging, as it allows debuggers to just
334d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// set a break-point in one place to see all error exists.
3352a1208017dd676f94a53bbb228197c3978dbdd8ascroggostatic void print_jpeg_decoder_errors(const jpeg_decompress_struct& cinfo,
336b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                         int width, int height, const char caller[]) {
33704b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com    if (!(c_suppressJPEGImageDecoderErrors)) {
33804b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com        char buffer[JMSG_LENGTH_MAX];
33904b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com        cinfo.err->format_message((const j_common_ptr)&cinfo, buffer);
34004b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com        SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n",
341b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                 cinfo.err->msg_code, buffer, caller, width, height);
34204b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com    }
3432a1208017dd676f94a53bbb228197c3978dbdd8ascroggo}
3442a1208017dd676f94a53bbb228197c3978dbdd8ascroggo
3452a1208017dd676f94a53bbb228197c3978dbdd8ascroggostatic bool return_false(const jpeg_decompress_struct& cinfo,
3462a1208017dd676f94a53bbb228197c3978dbdd8ascroggo                         const char caller[]) {
3472a1208017dd676f94a53bbb228197c3978dbdd8ascroggo    print_jpeg_decoder_errors(cinfo, 0, 0, caller);
3482a1208017dd676f94a53bbb228197c3978dbdd8ascroggo    return false;
349d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
350d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
351df78d0a81cfada516fe98b1f02d954e831e5d9e7mtklein#ifdef SK_BUILD_FOR_ANDROID
352b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic bool return_false(const jpeg_decompress_struct& cinfo,
353b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                         const SkBitmap& bm, const char caller[]) {
3542a1208017dd676f94a53bbb228197c3978dbdd8ascroggo    print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller);
3552a1208017dd676f94a53bbb228197c3978dbdd8ascroggo    return false;
3562a1208017dd676f94a53bbb228197c3978dbdd8ascroggo}
357df78d0a81cfada516fe98b1f02d954e831e5d9e7mtklein#endif
3582a1208017dd676f94a53bbb228197c3978dbdd8ascroggo
3592a1208017dd676f94a53bbb228197c3978dbdd8ascroggostatic SkImageDecoder::Result return_failure(const jpeg_decompress_struct& cinfo,
3602a1208017dd676f94a53bbb228197c3978dbdd8ascroggo                                             const SkBitmap& bm, const char caller[]) {
3612a1208017dd676f94a53bbb228197c3978dbdd8ascroggo    print_jpeg_decoder_errors(cinfo, bm.width(), bm.height(), caller);
3622a1208017dd676f94a53bbb228197c3978dbdd8ascroggo    return SkImageDecoder::kFailure;
363b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi}
364b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
3652a1208017dd676f94a53bbb228197c3978dbdd8ascroggo///////////////////////////////////////////////////////////////////////////////
3662a1208017dd676f94a53bbb228197c3978dbdd8ascroggo
3678570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com// Convert a scanline of CMYK samples to RGBX in place. Note that this
3688570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com// method moves the "scanline" pointer in its processing
3698570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) {
3708570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // At this point we've received CMYK pixels from libjpeg. We
371d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    // perform a crude conversion to RGB (based on the formulae
3728570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // from easyrgb.com):
3738570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //  CMYK -> CMY
3748570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //    C = ( C * (1 - K) + K )      // for each CMY component
3758570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //  CMY -> RGB
3768570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //    R = ( 1 - C ) * 255          // for each RGB component
3778570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // Unfortunately we are seeing inverted CMYK so all the original terms
3788570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // are 1-. This yields:
3798570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //  CMYK -> CMY
3808570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //    C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K
3818570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // The conversion from CMY->RGB remains the same
3828570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    for (unsigned int x = 0; x < width; ++x, scanline += 4) {
3838570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]);
3848570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]);
3858570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]);
3868570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        scanline[3] = 255;
3878570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    }
3888570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com}
3898570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com
390590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/**
391590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com *  Common code for setting the error manager.
392590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */
393590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* errorManager) {
394590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(cinfo != NULL);
395590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(errorManager != NULL);
396590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    cinfo->err = jpeg_std_error(errorManager);
397590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    errorManager->error_exit = skjpeg_error_exit;
398590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com}
399590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
400590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/**
401590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com *  Common code for turning off upsampling and smoothing. Turning these
402590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com *  off helps performance without showing noticable differences in the
403590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com *  resulting bitmap.
404590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */
405590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void turn_off_visual_optimizations(jpeg_decompress_struct* cinfo) {
406590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(cinfo != NULL);
407590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    /* this gives about 30% performance improvement. In theory it may
408590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com       reduce the visual quality, in practice I'm not seeing a difference
409590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com     */
410590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    cinfo->do_fancy_upsampling = 0;
411590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
412590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    /* this gives another few percents */
413590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    cinfo->do_block_smoothing = 0;
414590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com}
415590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
416590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/**
417590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * Common code for setting the dct method.
418590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */
419590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void set_dct_method(const SkImageDecoder& decoder, jpeg_decompress_struct* cinfo) {
420590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(cinfo != NULL);
421590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#ifdef DCT_IFAST_SUPPORTED
422590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    if (decoder.getPreferQualityOverSpeed()) {
423590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        cinfo->dct_method = JDCT_ISLOW;
424590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    } else {
425590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        cinfo->dct_method = JDCT_IFAST;
426590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
427590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#else
428590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    cinfo->dct_method = JDCT_ISLOW;
429590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#endif
430590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com}
431590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
4326c22573edb234ad14df947278cfed010669a39a7reedSkColorType SkJPEGImageDecoder::getBitmapColorType(jpeg_decompress_struct* cinfo) {
433590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(cinfo != NULL);
434590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
435590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SrcDepth srcDepth = k32Bit_SrcDepth;
436590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    if (JCS_GRAYSCALE == cinfo->jpeg_color_space) {
437590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        srcDepth = k8BitGray_SrcDepth;
438590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
439590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
4406c22573edb234ad14df947278cfed010669a39a7reed    SkColorType colorType = this->getPrefColorType(srcDepth, /*hasAlpha*/ false);
4416c22573edb234ad14df947278cfed010669a39a7reed    switch (colorType) {
4426c22573edb234ad14df947278cfed010669a39a7reed        case kAlpha_8_SkColorType:
4436c22573edb234ad14df947278cfed010669a39a7reed            // Only respect A8 colortype if the original is grayscale,
444590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // in which case we will treat the grayscale as alpha
445590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // values.
446590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            if (cinfo->jpeg_color_space != JCS_GRAYSCALE) {
4476c22573edb234ad14df947278cfed010669a39a7reed                colorType = kN32_SkColorType;
448590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            }
449590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
4506c22573edb234ad14df947278cfed010669a39a7reed        case kN32_SkColorType:
451590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // Fall through.
4526c22573edb234ad14df947278cfed010669a39a7reed        case kARGB_4444_SkColorType:
453590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // Fall through.
4546c22573edb234ad14df947278cfed010669a39a7reed        case kRGB_565_SkColorType:
4556c22573edb234ad14df947278cfed010669a39a7reed            // These are acceptable destination colortypes.
456590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
457590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        default:
4586c22573edb234ad14df947278cfed010669a39a7reed            // Force all other colortypes to 8888.
4596c22573edb234ad14df947278cfed010669a39a7reed            colorType = kN32_SkColorType;
460590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
461590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
462590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
463590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    switch (cinfo->jpeg_color_space) {
464590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        case JCS_CMYK:
465590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // Fall through.
466590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        case JCS_YCCK:
467590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // libjpeg cannot convert from CMYK or YCCK to RGB - here we set up
468590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // so libjpeg will give us CMYK samples back and we will later
469590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // manually convert them to RGB
470590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            cinfo->out_color_space = JCS_CMYK;
471590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
472590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        case JCS_GRAYSCALE:
4736c22573edb234ad14df947278cfed010669a39a7reed            if (kAlpha_8_SkColorType == colorType) {
474590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com                cinfo->out_color_space = JCS_GRAYSCALE;
475590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com                break;
476590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            }
477590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // The data is JCS_GRAYSCALE, but the caller wants some sort of RGB
4786c22573edb234ad14df947278cfed010669a39a7reed            // colortype. Fall through to set to the default.
479590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        default:
480590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            cinfo->out_color_space = JCS_RGB;
481590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
482590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
4836c22573edb234ad14df947278cfed010669a39a7reed    return colorType;
484590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com}
485590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
486590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/**
4876c22573edb234ad14df947278cfed010669a39a7reed *  Based on the colortype and dither mode, adjust out_color_space and
4886c22573edb234ad14df947278cfed010669a39a7reed *  dither_mode of cinfo. Only does work in ANDROID_RGB
489590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */
490590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void adjust_out_color_space_and_dither(jpeg_decompress_struct* cinfo,
4916c22573edb234ad14df947278cfed010669a39a7reed                                              SkColorType colorType,
492590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com                                              const SkImageDecoder& decoder) {
493590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(cinfo != NULL);
4946c22573edb234ad14df947278cfed010669a39a7reed#ifdef ANDROID_RGB
495590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    cinfo->dither_mode = JDITHER_NONE;
496590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    if (JCS_CMYK == cinfo->out_color_space) {
497590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        return;
498590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
4996c22573edb234ad14df947278cfed010669a39a7reed    switch (colorType) {
5006c22573edb234ad14df947278cfed010669a39a7reed        case kN32_SkColorType:
501590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            cinfo->out_color_space = JCS_RGBA_8888;
502590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
5036c22573edb234ad14df947278cfed010669a39a7reed        case kRGB_565_SkColorType:
504590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            cinfo->out_color_space = JCS_RGB_565;
505590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            if (decoder.getDitherImage()) {
506590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com                cinfo->dither_mode = JDITHER_ORDERED;
507590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            }
508590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
509590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        default:
510590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
511590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
512590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#endif
5136c22573edb234ad14df947278cfed010669a39a7reed}
514590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
515fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com/**
516fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com   Sets all pixels in given bitmap to SK_ColorWHITE for all rows >= y.
517fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com   Used when decoding fails partway through reading scanlines to fill
518fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com   remaining lines. */
519fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.comstatic void fill_below_level(int y, SkBitmap* bitmap) {
5202dcf36e25186bb0396eaa692bda402993252b88ahalcanary@google.com    SkIRect rect = SkIRect::MakeLTRB(0, y, bitmap->width(), bitmap->height());
521fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com    SkCanvas canvas(*bitmap);
5222dcf36e25186bb0396eaa692bda402993252b88ahalcanary@google.com    canvas.clipRect(SkRect::Make(rect));
523fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com    canvas.drawColor(SK_ColorWHITE);
524fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com}
525fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com
5265ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com/**
5275ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *  Get the config and bytes per pixel of the source data. Return
5285ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *  whether the data is supported.
5295ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com */
5305ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.comstatic bool get_src_config(const jpeg_decompress_struct& cinfo,
5315ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com                           SkScaledBitmapSampler::SrcConfig* sc,
5325ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com                           int* srcBytesPerPixel) {
5335ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    SkASSERT(sc != NULL && srcBytesPerPixel != NULL);
5345ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    if (JCS_CMYK == cinfo.out_color_space) {
5355ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        // In this case we will manually convert the CMYK values to RGB
5365ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *sc = SkScaledBitmapSampler::kRGBX;
5375ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        // The CMYK work-around relies on 4 components per pixel here
5385ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *srcBytesPerPixel = 4;
5395ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) {
5405ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *sc = SkScaledBitmapSampler::kRGB;
5415ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *srcBytesPerPixel = 3;
5425ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com#ifdef ANDROID_RGB
5435ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
5445ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *sc = SkScaledBitmapSampler::kRGBX;
5455ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *srcBytesPerPixel = 4;
5465ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    } else if (JCS_RGB_565 == cinfo.out_color_space) {
5475ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *sc = SkScaledBitmapSampler::kRGB_565;
5485ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *srcBytesPerPixel = 2;
5495ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com#endif
5505ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    } else if (1 == cinfo.out_color_components &&
5515ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com               JCS_GRAYSCALE == cinfo.out_color_space) {
5525ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *sc = SkScaledBitmapSampler::kGray;
5535ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *srcBytesPerPixel = 1;
5545ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    } else {
5555ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        return false;
5565ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    }
5575ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    return true;
5585ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com}
559fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com
5602a1208017dd676f94a53bbb228197c3978dbdd8ascroggoSkImageDecoder::Result SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
561d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef TIME_DECODE
562113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkAutoTime atm("JPEG Decode");
563d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
564d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
565d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    JPEGAutoClean autoClean;
566d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
567d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    jpeg_decompress_struct  cinfo;
568d4c3565aac5c83ff0008453abed4c6d6009bb394scroggo@google.com    skjpeg_source_mgr       srcManager(stream, this);
569d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
570590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    skjpeg_error_mgr errorManager;
571590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    set_error_mgr(&cinfo, &errorManager);
572d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
573d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // All objects need to be instantiated before this setjmp call so that
574d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // they will be cleaned up properly if an error occurs.
575113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (setjmp(errorManager.fJmpBuf)) {
5762a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        return return_failure(cinfo, *bm, "setjmp");
577d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
578d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
579590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    initialize_info(&cinfo, &srcManager);
580d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    autoClean.set(&cinfo);
581d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
582d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int status = jpeg_read_header(&cinfo, true);
583d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (status != JPEG_HEADER_OK) {
5842a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        return return_failure(cinfo, *bm, "read_header");
585d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
586d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
587d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    /*  Try to fulfill the requested sampleSize. Since jpeg can do it (when it
588d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        can) much faster that we, just use their num/denom api to approximate
589d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        the size.
590d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    */
591d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int sampleSize = this->getSampleSize();
592d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
593590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    set_dct_method(*this, &cinfo);
594113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
595590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(1 == cinfo.scale_num);
596d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    cinfo.scale_denom = sampleSize;
597d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
598590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    turn_off_visual_optimizations(&cinfo);
599d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
6006c22573edb234ad14df947278cfed010669a39a7reed    const SkColorType colorType = this->getBitmapColorType(&cinfo);
6016c22573edb234ad14df947278cfed010669a39a7reed    const SkAlphaType alphaType = kAlpha_8_SkColorType == colorType ?
6026c22573edb234ad14df947278cfed010669a39a7reed                                      kPremul_SkAlphaType : kOpaque_SkAlphaType;
603d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
6046c22573edb234ad14df947278cfed010669a39a7reed    adjust_out_color_space_and_dither(&cinfo, colorType, *this);
605d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
606113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) {
6075ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        // Assume an A8 bitmap is not opaque to avoid the check of each
6085ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        // individual pixel. It is very unlikely to be opaque, since
6095ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        // an opaque A8 bitmap would not be very interesting.
6105ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        // Otherwise, a jpeg image is opaque.
6112a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        bool success = bm->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.image_height,
6122a1208017dd676f94a53bbb228197c3978dbdd8ascroggo                                                     colorType, alphaType));
6132a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        return success ? kSuccess : kFailure;
614d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
615d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
616d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    /*  image_width and image_height are the original dimensions, available
617d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        after jpeg_read_header(). To see the scaled dimensions, we have to call
618d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_start_decompress(), and then read output_width and output_height.
619d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    */
620d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (!jpeg_start_decompress(&cinfo)) {
621d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        /*  If we failed here, we may still have enough information to return
622d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            to the caller if they just wanted (subsampled bounds). If sampleSize
623d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            was 1, then we would have already returned. Thus we just check if
624d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            we're in kDecodeBounds_Mode, and that we have valid output sizes.
625d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
626d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            One reason to fail here is that we have insufficient stream data
627d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            to complete the setup. However, output dimensions seem to get
628d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            computed very early, which is why this special check can pay off.
629d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com         */
630113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) {
631d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height,
632d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                                       recompute_sampleSize(sampleSize, cinfo));
6335ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com            // Assume an A8 bitmap is not opaque to avoid the check of each
6345ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com            // individual pixel. It is very unlikely to be opaque, since
6355ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com            // an opaque A8 bitmap would not be very interesting.
6365ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com            // Otherwise, a jpeg image is opaque.
6372a1208017dd676f94a53bbb228197c3978dbdd8ascroggo            bool success = bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaledHeight(),
6382a1208017dd676f94a53bbb228197c3978dbdd8ascroggo                                                         colorType, alphaType));
6392a1208017dd676f94a53bbb228197c3978dbdd8ascroggo            return success ? kSuccess : kFailure;
640d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        } else {
6412a1208017dd676f94a53bbb228197c3978dbdd8ascroggo            return return_failure(cinfo, *bm, "start_decompress");
642d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
643d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
644d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    sampleSize = recompute_sampleSize(sampleSize, cinfo);
645d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
646113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize);
6475ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // Assume an A8 bitmap is not opaque to avoid the check of each
6485ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // individual pixel. It is very unlikely to be opaque, since
6495ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // an opaque A8 bitmap would not be very interesting.
6505ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // Otherwise, a jpeg image is opaque.
6516c22573edb234ad14df947278cfed010669a39a7reed    bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(),
6526c22573edb234ad14df947278cfed010669a39a7reed                                  colorType, alphaType));
653bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
6542a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        return kSuccess;
655bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com    }
656bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com    if (!this->allocPixelRef(bm, NULL)) {
6572a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        return return_failure(cinfo, *bm, "allocPixelRef");
658113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
659113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
660113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkAutoLockPixels alp(*bm);
661113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
662d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef ANDROID_RGB
663d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    /* short-circuit the SkScaledBitmapSampler when possible, as this gives
664d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com       a significant performance boost.
665d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    */
666d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (sampleSize == 1 &&
6676c22573edb234ad14df947278cfed010669a39a7reed        ((kN32_SkColorType == colorType && cinfo.out_color_space == JCS_RGBA_8888) ||
6686c22573edb234ad14df947278cfed010669a39a7reed         (kRGB_565_SkColorType == colorType && cinfo.out_color_space == JCS_RGB_565)))
669d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    {
670bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com        JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
671d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        INT32 const bpr =  bm->rowBytes();
672d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
673d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        while (cinfo.output_scanline < cinfo.output_height) {
674d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
675d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            if (0 == row_count) {
676fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com                // if row_count == 0, then we didn't get a scanline,
677fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com                // so return early.  We will return a partial image.
678fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com                fill_below_level(cinfo.output_scanline, bm);
679fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com                cinfo.output_scanline = cinfo.output_height;
6802a1208017dd676f94a53bbb228197c3978dbdd8ascroggo                jpeg_finish_decompress(&cinfo);
6812a1208017dd676f94a53bbb228197c3978dbdd8ascroggo                return kPartialSuccess;
682d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            }
683d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            if (this->shouldCancelDecode()) {
6842a1208017dd676f94a53bbb228197c3978dbdd8ascroggo                return return_failure(cinfo, *bm, "shouldCancelDecode");
685d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            }
686d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            rowptr += bpr;
687d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
688d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_finish_decompress(&cinfo);
6892a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        return kSuccess;
690d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
691d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
6928570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com
693d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // check for supported formats
694d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    SkScaledBitmapSampler::SrcConfig sc;
6955ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    int srcBytesPerPixel;
6965ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com
6975ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) {
6982a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        return return_failure(cinfo, *bm, "jpeg colorspace");
699d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
700d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
7018d2392487cd97e68c0a71da9fd5d2b42ecac5ec8scroggo@google.com    if (!sampler.begin(bm, sc, *this)) {
7022a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        return return_failure(cinfo, *bm, "sampler.begin");
703d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
704d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
7055ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel);
706113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    uint8_t* srcRow = (uint8_t*)srcStorage.get();
707d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
708d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    //  Possibly skip initial rows [sampler.srcY0]
709d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
7102a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        return return_failure(cinfo, *bm, "skip rows");
711d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
712d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
713d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // now loop through scanlines until y == bm->height() - 1
714d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    for (int y = 0;; y++) {
715d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        JSAMPLE* rowptr = (JSAMPLE*)srcRow;
716d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
717d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (0 == row_count) {
718fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com            // if row_count == 0, then we didn't get a scanline,
719fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com            // so return early.  We will return a partial image.
720fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com            fill_below_level(y, bm);
721fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com            cinfo.output_scanline = cinfo.output_height;
7222a1208017dd676f94a53bbb228197c3978dbdd8ascroggo            jpeg_finish_decompress(&cinfo);
723c6b8ffa0ac953f1c66016c5655e2c1057a31c5c3scroggo            return kPartialSuccess;
724d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
725d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (this->shouldCancelDecode()) {
7262a1208017dd676f94a53bbb228197c3978dbdd8ascroggo            return return_failure(cinfo, *bm, "shouldCancelDecode");
727d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
7288570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com
7298570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        if (JCS_CMYK == cinfo.out_color_space) {
7308570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com            convert_CMYK_to_RGB(srcRow, cinfo.output_width);
7318570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        }
7328570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com
733d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        sampler.next(srcRow);
734d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (bm->height() - 1 == y) {
735d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            // we're done
736d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            break;
737d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
738d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
739d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) {
7402a1208017dd676f94a53bbb228197c3978dbdd8ascroggo            return return_failure(cinfo, *bm, "skip rows");
741d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
742d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
743d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
744d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // we formally skip the rest, so we don't get a complaint from libjpeg
745d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (!skip_src_rows(&cinfo, srcRow,
746d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                       cinfo.output_height - cinfo.output_scanline)) {
7472a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        return return_failure(cinfo, *bm, "skip rows");
748d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
749d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    jpeg_finish_decompress(&cinfo);
750d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
7512a1208017dd676f94a53bbb228197c3978dbdd8ascroggo    return kSuccess;
752d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
753d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
7542a1208017dd676f94a53bbb228197c3978dbdd8ascroggo///////////////////////////////////////////////////////////////////////////////
7552a1208017dd676f94a53bbb228197c3978dbdd8ascroggo
756b227e37eae36ccf630c4baef00b1354d42b40fd1sugoienum SizeType {
757b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    kSizeForMemoryAllocation_SizeType,
758b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    kActualSize_SizeType
759b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi};
760b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
761b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic SkISize compute_yuv_size(const jpeg_decompress_struct& info, int component,
762b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                                SizeType sizeType) {
763b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (sizeType == kSizeForMemoryAllocation_SizeType) {
764b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        return SkISize::Make(info.cur_comp_info[component]->width_in_blocks * DCTSIZE,
765b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                             info.cur_comp_info[component]->height_in_blocks * DCTSIZE);
766b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
767b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    return SkISize::Make(info.cur_comp_info[component]->downsampled_width,
768b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                         info.cur_comp_info[component]->downsampled_height);
769b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi}
770b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
771b3e5e4d314301617d2d48b7589dfd426bd68a671mtkleinstatic bool appears_to_be_yuv(const jpeg_decompress_struct& info) {
772b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein    return (info.jpeg_color_space == JCS_YCbCr)
773b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein        && (DCTSIZE == 8)
774b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein        && (info.num_components == 3)
775b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein        && (info.comps_in_scan >= info.num_components)
776b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein        && (info.scale_denom <= 8)
777b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein        && (info.cur_comp_info[0])
778b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein        && (info.cur_comp_info[1])
779b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein        && (info.cur_comp_info[2])
780b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein        && (info.cur_comp_info[1]->h_samp_factor == 1)
781b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein        && (info.cur_comp_info[1]->v_samp_factor == 1)
782b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein        && (info.cur_comp_info[2]->h_samp_factor == 1)
783b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein        && (info.cur_comp_info[2]->v_samp_factor == 1);
784b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein}
785b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein
786b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic void update_components_sizes(const jpeg_decompress_struct& cinfo, SkISize componentSizes[3],
787b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                                    SizeType sizeType) {
788b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein    SkASSERT(appears_to_be_yuv(cinfo));
789b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    for (int i = 0; i < 3; ++i) {
790b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        componentSizes[i] = compute_yuv_size(cinfo, i, sizeType);
791b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
792b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi}
793b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
794b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic bool output_raw_data(jpeg_decompress_struct& cinfo, void* planes[3], size_t rowBytes[3]) {
795b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein    SkASSERT(appears_to_be_yuv(cinfo));
796b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    // U size and V size have to be the same if we're calling output_raw_data()
797b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    SkISize uvSize = compute_yuv_size(cinfo, 1, kSizeForMemoryAllocation_SizeType);
798b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    SkASSERT(uvSize == compute_yuv_size(cinfo, 2, kSizeForMemoryAllocation_SizeType));
799b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
800b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JSAMPARRAY bufferraw[3];
801b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JSAMPROW bufferraw2[32];
802b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    bufferraw[0] = &bufferraw2[0]; // Y channel rows (8 or 16)
803b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    bufferraw[1] = &bufferraw2[16]; // U channel rows (8)
804b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    bufferraw[2] = &bufferraw2[24]; // V channel rows (8)
805b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    int yWidth = cinfo.output_width;
806b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    int yHeight = cinfo.output_height;
807b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    int yMaxH = yHeight - 1;
808b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    int v = cinfo.cur_comp_info[0]->v_samp_factor;
809b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    int uvMaxH = uvSize.height() - 1;
810b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JSAMPROW outputY = static_cast<JSAMPROW>(planes[0]);
811b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JSAMPROW outputU = static_cast<JSAMPROW>(planes[1]);
812b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JSAMPROW outputV = static_cast<JSAMPROW>(planes[2]);
813b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    size_t rowBytesY = rowBytes[0];
814b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    size_t rowBytesU = rowBytes[1];
815b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    size_t rowBytesV = rowBytes[2];
816b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
817b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    int yScanlinesToRead = DCTSIZE * v;
818f421ec6cc9c8f32d717b9b1df71fd9e79817a16csugoi    SkAutoMalloc lastRowStorage(rowBytesY * 4);
819b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JSAMPROW yLastRow = (JSAMPROW)lastRowStorage.get();
820f421ec6cc9c8f32d717b9b1df71fd9e79817a16csugoi    JSAMPROW uLastRow = yLastRow + rowBytesY;
821f421ec6cc9c8f32d717b9b1df71fd9e79817a16csugoi    JSAMPROW vLastRow = uLastRow + rowBytesY;
822f421ec6cc9c8f32d717b9b1df71fd9e79817a16csugoi    JSAMPROW dummyRow = vLastRow + rowBytesY;
823b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
824b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    while (cinfo.output_scanline < cinfo.output_height) {
825b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        // Request 8 or 16 scanlines: returns 0 or more scanlines.
826b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        bool hasYLastRow(false), hasUVLastRow(false);
827b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        // Assign 8 or 16 rows of memory to read the Y channel.
828b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        for (int i = 0; i < yScanlinesToRead; ++i) {
829b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            int scanline = (cinfo.output_scanline + i);
830b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            if (scanline < yMaxH) {
831b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[i] = &outputY[scanline * rowBytesY];
832b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            } else if (scanline == yMaxH) {
833b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[i] = yLastRow;
834b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                hasYLastRow = true;
835b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            } else {
836b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[i] = dummyRow;
837b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            }
838b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        }
839b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        int scaledScanline = cinfo.output_scanline / v;
840b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        // Assign 8 rows of memory to read the U and V channels.
841b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        for (int i = 0; i < 8; ++i) {
842b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            int scanline = (scaledScanline + i);
843b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            if (scanline < uvMaxH) {
844b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[16 + i] = &outputU[scanline * rowBytesU];
845b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[24 + i] = &outputV[scanline * rowBytesV];
846b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            } else if (scanline == uvMaxH) {
847b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[16 + i] = uLastRow;
848b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[24 + i] = vLastRow;
849b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                hasUVLastRow = true;
850b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            } else {
851b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[16 + i] = dummyRow;
852b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[24 + i] = dummyRow;
853b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            }
854b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        }
855b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        JDIMENSION scanlinesRead = jpeg_read_raw_data(&cinfo, bufferraw, yScanlinesToRead);
856b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
8572a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        if (scanlinesRead == 0) {
858b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            return false;
8592a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        }
860b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
861b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        if (hasYLastRow) {
862b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            memcpy(&outputY[yMaxH * rowBytesY], yLastRow, yWidth);
863b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        }
864b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        if (hasUVLastRow) {
865b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            memcpy(&outputU[uvMaxH * rowBytesU], uLastRow, uvSize.width());
866b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            memcpy(&outputV[uvMaxH * rowBytesV], vLastRow, uvSize.width());
867b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        }
868b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
869b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
870b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    cinfo.output_scanline = SkMin32(cinfo.output_scanline, cinfo.output_height);
871b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
872b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    return true;
873b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi}
874b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
875b227e37eae36ccf630c4baef00b1354d42b40fd1sugoibool SkJPEGImageDecoder::onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3],
876b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                                            void* planes[3], size_t rowBytes[3],
877b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                                            SkYUVColorSpace* colorSpace) {
878b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#ifdef TIME_DECODE
879b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    SkAutoTime atm("JPEG YUV8 Decode");
880b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#endif
881b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (this->getSampleSize() != 1) {
882b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        return false; // Resizing not supported
883b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
884b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
885b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JPEGAutoClean autoClean;
886b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
887b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    jpeg_decompress_struct  cinfo;
888b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    skjpeg_source_mgr       srcManager(stream, this);
889b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
890b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    skjpeg_error_mgr errorManager;
891b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    set_error_mgr(&cinfo, &errorManager);
892b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
893b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    // All objects need to be instantiated before this setjmp call so that
894b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    // they will be cleaned up properly if an error occurs.
895b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (setjmp(errorManager.fJmpBuf)) {
8962a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        return return_false(cinfo, "setjmp YUV8");
897b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
898b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
899b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    initialize_info(&cinfo, &srcManager);
900b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    autoClean.set(&cinfo);
901b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
902b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    int status = jpeg_read_header(&cinfo, true);
903b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (status != JPEG_HEADER_OK) {
9042a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        return return_false(cinfo, "read_header YUV8");
905b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
906b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
907b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein    if (!appears_to_be_yuv(cinfo)) {
908b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        // It's not an error to not be encoded in YUV, so no need to use return_false()
909b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        return false;
910b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
911b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
912b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    cinfo.out_color_space = JCS_YCbCr;
913b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    cinfo.raw_data_out = TRUE;
914b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
915b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (!planes || !planes[0] || !rowBytes || !rowBytes[0]) { // Compute size only
916b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        update_components_sizes(cinfo, componentSizes, kSizeForMemoryAllocation_SizeType);
917b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        return true;
918b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
919b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
920b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    set_dct_method(*this, &cinfo);
921b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
922b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    SkASSERT(1 == cinfo.scale_num);
923b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    cinfo.scale_denom = 1;
924b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
925b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    turn_off_visual_optimizations(&cinfo);
926b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
927b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#ifdef ANDROID_RGB
928b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    cinfo.dither_mode = JDITHER_NONE;
929b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#endif
930b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
931b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    /*  image_width and image_height are the original dimensions, available
932b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        after jpeg_read_header(). To see the scaled dimensions, we have to call
933b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        jpeg_start_decompress(), and then read output_width and output_height.
934b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    */
935b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (!jpeg_start_decompress(&cinfo)) {
9362a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        return return_false(cinfo, "start_decompress YUV8");
937b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
938b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
939b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein    // Seems like jpeg_start_decompress is updating our opinion of whether cinfo represents YUV.
940b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein    // Again, not really an error.
941b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein    if (!appears_to_be_yuv(cinfo)) {
942b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein        return false;
943b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein    }
944b3e5e4d314301617d2d48b7589dfd426bd68a671mtklein
945b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (!output_raw_data(cinfo, planes, rowBytes)) {
9462a1208017dd676f94a53bbb228197c3978dbdd8ascroggo        return return_false(cinfo, "output_raw_data");
947b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
948b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
949b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    update_components_sizes(cinfo, componentSizes, kActualSize_SizeType);
950b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    jpeg_finish_decompress(&cinfo);
951b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
952b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (NULL != colorSpace) {
953b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        *colorSpace = kJPEG_SkYUVColorSpace;
954b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
955b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
956b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    return true;
957b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi}
958b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
9592a1208017dd676f94a53bbb228197c3978dbdd8ascroggo///////////////////////////////////////////////////////////////////////////////
9602a1208017dd676f94a53bbb228197c3978dbdd8ascroggo
961d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
962b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.combool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width, int *height) {
963113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
964a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (stream, this)));
965113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
966113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    skjpeg_error_mgr sk_err;
9676d7e47a8e0c8fd80ad33f659b01ec84f9e93a94bscroggo    set_error_mgr(imageIndex->cinfo(), &sk_err);
968113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
969113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // All objects need to be instantiated before this setjmp call so that
970113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // they will be cleaned up properly if an error occurs.
971113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (setjmp(sk_err.fJmpBuf)) {
972113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
973113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
974113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
975113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // create the cinfo used to create/build the huffmanIndex
976a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    if (!imageIndex->initializeInfoAndReadHeader()) {
977113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
978113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
979113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
980a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    if (!imageIndex->buildHuffmanIndex()) {
981113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
982113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
983113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
984113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // destroy the cinfo used to create/build the huffman index
985a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    imageIndex->destroyInfo();
986113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
987113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // Init decoder to image decode mode
988a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    if (!imageIndex->initializeInfoAndReadHeader()) {
989113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
990113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
991113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
9926d7e47a8e0c8fd80ad33f659b01ec84f9e93a94bscroggo    jpeg_decompress_struct* cinfo = imageIndex->cinfo();
9936d7e47a8e0c8fd80ad33f659b01ec84f9e93a94bscroggo    // We have a new cinfo, so set the error mgr again.
9946d7e47a8e0c8fd80ad33f659b01ec84f9e93a94bscroggo    set_error_mgr(cinfo, &sk_err);
9956d7e47a8e0c8fd80ad33f659b01ec84f9e93a94bscroggo
996590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    // FIXME: This sets cinfo->out_color_space, which we may change later
997590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    // based on the config in onDecodeSubset. This should be fine, since
998590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    // jpeg_init_read_tile_scanline will check out_color_space again after
999590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    // that change (when it calls jinit_color_deconverter).
10006c22573edb234ad14df947278cfed010669a39a7reed    (void) this->getBitmapColorType(cinfo);
1001590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
1002590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    turn_off_visual_optimizations(cinfo);
1003113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1004113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // instead of jpeg_start_decompress() we start a tiled decompress
1005a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    if (!imageIndex->startTileDecompress()) {
1006a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        return false;
1007a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    }
1008113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1009a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    SkASSERT(1 == cinfo->scale_num);
1010590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    fImageWidth = cinfo->output_width;
1011590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    fImageHeight = cinfo->output_height;
1012590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
1013590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    if (width) {
1014590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        *width = fImageWidth;
1015590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
1016590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    if (height) {
1017590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        *height = fImageHeight;
1018590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
1019113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1020113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkDELETE(fImageIndex);
1021a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    fImageIndex = imageIndex.detach();
1022113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1023113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    return true;
1024113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com}
1025113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
10267e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.combool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
1027113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (NULL == fImageIndex) {
1028113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
1029113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1030113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_decompress_struct* cinfo = fImageIndex->cinfo();
1031113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1032113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight);
1033113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (!rect.intersect(region)) {
1034113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        // If the requested region is entirely outside the image return false
1035113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
1036113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1037113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1038113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1039113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    skjpeg_error_mgr errorManager;
1040590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    set_error_mgr(cinfo, &errorManager);
1041590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
1042113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (setjmp(errorManager.fJmpBuf)) {
1043113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
1044113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1045113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1046113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int requestedSampleSize = this->getSampleSize();
1047113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->scale_denom = requestedSampleSize;
1048113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1049590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    set_dct_method(*this, cinfo);
1050113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
10516c22573edb234ad14df947278cfed010669a39a7reed    const SkColorType colorType = this->getBitmapColorType(cinfo);
10526c22573edb234ad14df947278cfed010669a39a7reed    adjust_out_color_space_and_dither(cinfo, colorType, *this);
1053113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1054113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int startX = rect.fLeft;
1055113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int startY = rect.fTop;
1056113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int width = rect.width();
1057113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int height = rect.height();
1058113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1059113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(),
1060113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                                 &startX, &startY, &width, &height);
1061113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo);
1062113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size);
1063113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1064113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkScaledBitmapSampler sampler(width, height, skiaSampleSize);
1065113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1066113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkBitmap bitmap;
10675ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // Assume an A8 bitmap is not opaque to avoid the check of each
10685ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // individual pixel. It is very unlikely to be opaque, since
10695ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // an opaque A8 bitmap would not be very interesting.
10705ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // Otherwise, a jpeg image is opaque.
10716c22573edb234ad14df947278cfed010669a39a7reed    bitmap.setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), colorType,
10726c22573edb234ad14df947278cfed010669a39a7reed                                     kAlpha_8_SkColorType == colorType ?
10736c22573edb234ad14df947278cfed010669a39a7reed                                         kPremul_SkAlphaType : kOpaque_SkAlphaType));
1074113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1075113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // Check ahead of time if the swap(dest, src) is possible or not.
1076113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // If yes, then we will stick to AllocPixelRef since it's cheaper with the
1077113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // swap happening. If no, then we will use alloc to allocate pixels to
1078113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // prevent garbage collection.
1079113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int w = rect.width() / actualSampleSize;
1080113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int h = rect.height() / actualSampleSize;
1081113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    bool swapOnly = (rect == region) && bm->isNull() &&
1082113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                    (w == bitmap.width()) && (h == bitmap.height()) &&
1083113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                    ((startX - rect.x()) / actualSampleSize == 0) &&
1084113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                    ((startY - rect.y()) / actualSampleSize == 0);
1085113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (swapOnly) {
1086113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (!this->allocPixelRef(&bitmap, NULL)) {
1087113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return return_false(*cinfo, bitmap, "allocPixelRef");
1088113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1089113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    } else {
1090848250415eddc54075f7eb8795e8db79e749c6abreed        if (!bitmap.tryAllocPixels()) {
1091113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return return_false(*cinfo, bitmap, "allocPixels");
1092113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1093113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1094113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1095113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkAutoLockPixels alp(bitmap);
1096113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1097113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef ANDROID_RGB
1098113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    /* short-circuit the SkScaledBitmapSampler when possible, as this gives
1099113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com       a significant performance boost.
1100113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    */
1101113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (skiaSampleSize == 1 &&
11026c22573edb234ad14df947278cfed010669a39a7reed        ((kN32_SkColorType == colorType && cinfo->out_color_space == JCS_RGBA_8888) ||
11036c22573edb234ad14df947278cfed010669a39a7reed         (kRGB_565_SkColorType == colorType && cinfo->out_color_space == JCS_RGB_565)))
1104113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    {
1105113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels();
1106113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        INT32 const bpr = bitmap.rowBytes();
1107113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        int rowTotalCount = 0;
1108113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1109113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        while (rowTotalCount < height) {
1110113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            int rowCount = jpeg_read_tile_scanline(cinfo,
1111113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                                                   fImageIndex->huffmanIndex(),
1112113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                                                   &rowptr);
1113fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com            // if rowCount == 0, then we didn't get a scanline, so abort.
1114fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com            // onDecodeSubset() relies on onBuildTileIndex(), which
1115fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com            // needs a complete image to succeed.
1116113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            if (0 == rowCount) {
1117113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                return return_false(*cinfo, bitmap, "read_scanlines");
1118113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            }
1119113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            if (this->shouldCancelDecode()) {
1120113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                return return_false(*cinfo, bitmap, "shouldCancelDecode");
1121113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            }
1122113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            rowTotalCount += rowCount;
1123113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            rowptr += bpr;
1124113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1125113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1126113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (swapOnly) {
1127113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            bm->swap(bitmap);
11287f00acbda6d35d2ba445a1e2909bb599b156cc5czoran.jovanovic            return true;
1129113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
11307f00acbda6d35d2ba445a1e2909bb599b156cc5czoran.jovanovic
11317f00acbda6d35d2ba445a1e2909bb599b156cc5czoran.jovanovic        return cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
11327f00acbda6d35d2ba445a1e2909bb599b156cc5czoran.jovanovic                          region.width(), region.height(), startX, startY);
1133113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1134113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
1135113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1136113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // check for supported formats
1137113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkScaledBitmapSampler::SrcConfig sc;
11385ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    int srcBytesPerPixel;
11395ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com
11405ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) {
1141113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return return_false(*cinfo, *bm, "jpeg colorspace");
1142113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1143113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
11448d2392487cd97e68c0a71da9fd5d2b42ecac5ec8scroggo@google.com    if (!sampler.begin(&bitmap, sc, *this)) {
1145113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return return_false(*cinfo, bitmap, "sampler.begin");
1146113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1147113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
11485ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    SkAutoMalloc  srcStorage(width * srcBytesPerPixel);
1149113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    uint8_t* srcRow = (uint8_t*)srcStorage.get();
1150113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1151113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    //  Possibly skip initial rows [sampler.srcY0]
1152113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) {
1153113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return return_false(*cinfo, bitmap, "skip rows");
1154113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1155113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1156113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // now loop through scanlines until y == bitmap->height() - 1
1157113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    for (int y = 0;; y++) {
1158113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        JSAMPLE* rowptr = (JSAMPLE*)srcRow;
1159113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr);
1160fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com        // if row_count == 0, then we didn't get a scanline, so abort.
1161fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com        // onDecodeSubset() relies on onBuildTileIndex(), which
1162fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com        // needs a complete image to succeed.
1163113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (0 == row_count) {
1164113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return return_false(*cinfo, bitmap, "read_scanlines");
1165113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1166113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (this->shouldCancelDecode()) {
1167113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return return_false(*cinfo, bitmap, "shouldCancelDecode");
1168113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1169113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1170113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (JCS_CMYK == cinfo->out_color_space) {
1171113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            convert_CMYK_to_RGB(srcRow, width);
1172113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1173113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1174113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        sampler.next(srcRow);
1175113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (bitmap.height() - 1 == y) {
1176113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            // we're done
1177113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            break;
1178113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1179113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1180113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow,
1181113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                                sampler.srcDY() - 1)) {
1182113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return return_false(*cinfo, bitmap, "skip rows");
1183113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1184113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1185113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (swapOnly) {
1186113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        bm->swap(bitmap);
11877f00acbda6d35d2ba445a1e2909bb599b156cc5czoran.jovanovic        return true;
1188113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
11897f00acbda6d35d2ba445a1e2909bb599b156cc5czoran.jovanovic    return cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
11907f00acbda6d35d2ba445a1e2909bb599b156cc5czoran.jovanovic                      region.width(), region.height(), startX, startY);
1191113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com}
1192113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
1193113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1194d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com///////////////////////////////////////////////////////////////////////////////
1195d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1196d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkColorPriv.h"
1197d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1198d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// taken from jcolor.c in libjpeg
1199d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#if 0   // 16bit - precise but slow
1200d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYR     19595   // 0.299
1201d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYG     38470   // 0.587
1202d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYB      7471   // 0.114
1203d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1204d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUR    -11059   // -0.16874
1205d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUG    -21709   // -0.33126
1206d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUB     32768   // 0.5
1207d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1208d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVR     32768   // 0.5
1209d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVG    -27439   // -0.41869
1210d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVB     -5329   // -0.08131
1211d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1212d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CSHIFT  16
1213d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else      // 8bit - fast, slightly less precise
1214d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYR     77    // 0.299
1215d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYG     150    // 0.587
1216d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYB      29    // 0.114
1217d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1218d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUR     -43    // -0.16874
1219d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUG    -85    // -0.33126
1220d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUB     128    // 0.5
1221d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1222d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVR      128   // 0.5
1223d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVG     -107   // -0.41869
1224d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVB      -21   // -0.08131
1225d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1226d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CSHIFT  8
1227d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
1228d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1229d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void rgb2yuv_32(uint8_t dst[], SkPMColor c) {
1230d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int r = SkGetPackedR32(c);
1231d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int g = SkGetPackedG32(c);
1232d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int b = SkGetPackedB32(c);
1233d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1234d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT;
1235d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT;
1236d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT;
1237d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1238d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[0] = SkToU8(y);
1239d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[1] = SkToU8(u + 128);
1240d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[2] = SkToU8(v + 128);
1241d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1242d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1243d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void rgb2yuv_4444(uint8_t dst[], U16CPU c) {
1244d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int r = SkGetPackedR4444(c);
1245d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int g = SkGetPackedG4444(c);
1246d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int b = SkGetPackedB4444(c);
1247d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1248d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4);
1249d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4);
1250d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4);
1251d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1252d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[0] = SkToU8(y);
1253d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[1] = SkToU8(u + 128);
1254d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[2] = SkToU8(v + 128);
1255d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1256d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1257d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void rgb2yuv_16(uint8_t dst[], U16CPU c) {
1258d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int r = SkGetPackedR16(c);
1259d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int g = SkGetPackedG16(c);
1260d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int b = SkGetPackedB16(c);
1261d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1262d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2);
1263d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2);
1264d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2);
1265d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1266d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[0] = SkToU8(y);
1267d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[1] = SkToU8(u + 128);
1268d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[2] = SkToU8(v + 128);
1269d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1270d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1271d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com///////////////////////////////////////////////////////////////////////////////
1272d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1273d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comtypedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst,
1274d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                              const void* SK_RESTRICT src, int width,
1275d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                              const SkPMColor* SK_RESTRICT ctable);
1276d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1277d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_32_YUV(uint8_t* SK_RESTRICT dst,
1278d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                         const void* SK_RESTRICT srcRow, int width,
1279d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                         const SkPMColor*) {
1280d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow;
1281d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    while (--width >= 0) {
1282d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV
1283d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        rgb2yuv_32(dst, *src++);
1284d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else
1285d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        uint32_t c = *src++;
1286d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[0] = SkGetPackedR32(c);
1287d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[1] = SkGetPackedG32(c);
1288d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[2] = SkGetPackedB32(c);
1289d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
1290d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst += 3;
1291d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
1292d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1293d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1294d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_4444_YUV(uint8_t* SK_RESTRICT dst,
1295d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                           const void* SK_RESTRICT srcRow, int width,
1296d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                           const SkPMColor*) {
1297d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow;
1298d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    while (--width >= 0) {
1299d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV
1300d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        rgb2yuv_4444(dst, *src++);
1301d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else
1302d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        SkPMColor16 c = *src++;
1303d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[0] = SkPacked4444ToR32(c);
1304d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[1] = SkPacked4444ToG32(c);
1305d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[2] = SkPacked4444ToB32(c);
1306d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
1307d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst += 3;
1308d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
1309d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1310d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1311d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_16_YUV(uint8_t* SK_RESTRICT dst,
1312d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                         const void* SK_RESTRICT srcRow, int width,
1313d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                         const SkPMColor*) {
1314d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow;
1315d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    while (--width >= 0) {
1316d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV
1317d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        rgb2yuv_16(dst, *src++);
1318d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else
1319d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        uint16_t c = *src++;
1320d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[0] = SkPacked16ToR32(c);
1321d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[1] = SkPacked16ToG32(c);
1322d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[2] = SkPacked16ToB32(c);
1323d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
1324d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst += 3;
1325d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
1326d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1327d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1328d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_Index_YUV(uint8_t* SK_RESTRICT dst,
1329d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                            const void* SK_RESTRICT srcRow, int width,
1330d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                            const SkPMColor* SK_RESTRICT ctable) {
1331d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow;
1332d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    while (--width >= 0) {
1333d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV
1334d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        rgb2yuv_32(dst, ctable[*src++]);
1335d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else
1336d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        uint32_t c = ctable[*src++];
1337d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[0] = SkGetPackedR32(c);
1338d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[1] = SkGetPackedG32(c);
1339d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[2] = SkGetPackedB32(c);
1340d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
1341d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst += 3;
1342d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
1343d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1344d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1345d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic WriteScanline ChooseWriter(const SkBitmap& bm) {
13466c22573edb234ad14df947278cfed010669a39a7reed    switch (bm.colorType()) {
13476c22573edb234ad14df947278cfed010669a39a7reed        case kN32_SkColorType:
1348d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return Write_32_YUV;
13496c22573edb234ad14df947278cfed010669a39a7reed        case kRGB_565_SkColorType:
1350d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return Write_16_YUV;
13516c22573edb234ad14df947278cfed010669a39a7reed        case kARGB_4444_SkColorType:
1352d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return Write_4444_YUV;
13536c22573edb234ad14df947278cfed010669a39a7reed        case kIndex_8_SkColorType:
1354d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return Write_Index_YUV;
1355d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        default:
1356d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return NULL;
1357d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
1358d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1359d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1360d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comclass SkJPEGImageEncoder : public SkImageEncoder {
1361d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprotected:
1362d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) {
1363d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef TIME_ENCODE
1364113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        SkAutoTime atm("JPEG Encode");
1365d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
1366d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1367d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        SkAutoLockPixels alp(bm);
1368d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (NULL == bm.getPixels()) {
1369d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return false;
1370d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
1371d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1372d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_compress_struct    cinfo;
1373d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        skjpeg_error_mgr        sk_err;
1374d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        skjpeg_destination_mgr  sk_wstream(stream);
1375d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1376d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        // allocate these before set call setjmp
1377d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        SkAutoMalloc    oneRow;
1378d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1379d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.err = jpeg_std_error(&sk_err);
1380d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        sk_err.error_exit = skjpeg_error_exit;
1381d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (setjmp(sk_err.fJmpBuf)) {
1382d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return false;
1383d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
1384d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
13858d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com        // Keep after setjmp or mark volatile.
13868d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com        const WriteScanline writer = ChooseWriter(bm);
13878d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com        if (NULL == writer) {
13888d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com            return false;
13898d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com        }
13908d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com
13918d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com        jpeg_create_compress(&cinfo);
1392d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.dest = &sk_wstream;
1393d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.image_width = bm.width();
1394d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.image_height = bm.height();
1395d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.input_components = 3;
1396d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV
1397d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.in_color_space = JCS_YCbCr;
1398d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else
1399d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.in_color_space = JCS_RGB;
1400d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
1401d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.input_gamma = 1;
1402d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1403d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_set_defaults(&cinfo);
1404d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
1405b7decc539887069f3fb0f9fc80d543b437bdd624scroggo@google.com#ifdef DCT_IFAST_SUPPORTED
1406d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.dct_method = JDCT_IFAST;
1407b7decc539887069f3fb0f9fc80d543b437bdd624scroggo@google.com#endif
1408d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1409d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_start_compress(&cinfo, TRUE);
1410d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1411d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        const int       width = bm.width();
14128570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        uint8_t*        oneRowP = (uint8_t*)oneRow.reset(width * 3);
1413d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1414775b8199a214af57c3ea7969e9d456f5f3eb137fmtklein        const SkPMColor* colors = bm.getColorTable() ? bm.getColorTable()->readColors() : NULL;
1415d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        const void*      srcRow = bm.getPixels();
1416d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1417d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        while (cinfo.next_scanline < cinfo.image_height) {
1418d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            JSAMPROW row_pointer[1];    /* pointer to JSAMPLE row[s] */
1419d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1420d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            writer(oneRowP, srcRow, width, colors);
1421d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            row_pointer[0] = oneRowP;
1422d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
1423d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            srcRow = (const void*)((const char*)srcRow + bm.rowBytes());
1424d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
1425d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1426d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_finish_compress(&cinfo);
1427d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_destroy_compress(&cinfo);
1428d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1429d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return true;
1430d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
1431d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com};
1432d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1433d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com///////////////////////////////////////////////////////////////////////////////
1434ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.comDEFINE_DECODER_CREATOR(JPEGImageDecoder);
1435ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.comDEFINE_ENCODER_CREATOR(JPEGImageEncoder);
1436ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.com///////////////////////////////////////////////////////////////////////////////
1437d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1438b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.comstatic bool is_jpeg(SkStreamRewindable* stream) {
1439ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.com    static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF };
1440d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    static const size_t HEADER_SIZE = sizeof(gHeader);
1441d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1442d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    char buffer[HEADER_SIZE];
1443d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    size_t len = stream->read(buffer, HEADER_SIZE);
1444d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1445d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (len != HEADER_SIZE) {
144639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com        return false;   // can't read enough
1447d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
1448d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (memcmp(buffer, gHeader, HEADER_SIZE)) {
144939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com        return false;
145039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    }
145139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    return true;
145239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com}
145339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com
1454b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.com
1455b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.comstatic SkImageDecoder* sk_libjpeg_dfactory(SkStreamRewindable* stream) {
145639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    if (is_jpeg(stream)) {
145739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com        return SkNEW(SkJPEGImageDecoder);
145839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    }
145939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    return NULL;
146039edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com}
146139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com
1462b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.comstatic SkImageDecoder::Format get_format_jpeg(SkStreamRewindable* stream) {
146339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    if (is_jpeg(stream)) {
146439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com        return SkImageDecoder::kJPEG_Format;
1465d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
146639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    return SkImageDecoder::kUnknown_Format;
1467d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1468d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
14698570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) {
1470d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL;
1471d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1472d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1473bd6343b1d60d2a85e930f33f4b06b4502b3e8caamtklein@google.comstatic SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory);
1474bd6343b1d60d2a85e930f33f4b06b4502b3e8caamtklein@google.comstatic SkImageDecoder_FormatReg gFormatReg(get_format_jpeg);
1475bd6343b1d60d2a85e930f33f4b06b4502b3e8caamtklein@google.comstatic SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory);
1476