SkImageDecoder_libjpeg.cpp revision b227e37eae36ccf630c4baef00b1354d42b40fd1
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:
108b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.com    SkJPEGImageIndex(SkStreamRewindable* stream, SkImageDecoder* decoder)
109a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        : fSrcMgr(stream, decoder)
110a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        , fInfoInitialized(false)
111a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        , fHuffmanCreated(false)
112a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        , fDecompressStarted(false)
113a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        {
114a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            SkDEBUGCODE(fReadHeaderSucceeded = false;)
115a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        }
116113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
117113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    ~SkJPEGImageIndex() {
118a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        if (fHuffmanCreated) {
119590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // Set to false before calling the libjpeg function, in case
120590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // the libjpeg function calls longjmp. Our setjmp handler may
121590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // attempt to delete this SkJPEGImageIndex, thus entering this
122590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // destructor again. Setting fHuffmanCreated to false first
123590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // prevents an infinite loop.
124a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            fHuffmanCreated = false;
125a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            jpeg_destroy_huffman_index(&fHuffmanIndex);
126a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        }
127a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        if (fDecompressStarted) {
128590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // Like fHuffmanCreated, set to false before calling libjpeg
129590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // function to prevent potential infinite loop.
130a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            fDecompressStarted = false;
131a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            jpeg_finish_decompress(&fCInfo);
132a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        }
133a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        if (fInfoInitialized) {
134a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            this->destroyInfo();
135a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        }
136a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    }
137a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com
138a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    /**
139a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  Destroy the cinfo struct.
140a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  After this call, if a huffman index was already built, it
141a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  can be used after calling initializeInfoAndReadHeader
142a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  again. Must not be called after startTileDecompress except
143a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  in the destructor.
144a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     */
145a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    void destroyInfo() {
146a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(fInfoInitialized);
147a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(!fDecompressStarted);
148590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        // Like fHuffmanCreated, set to false before calling libjpeg
149590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        // function to prevent potential infinite loop.
150a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        fInfoInitialized = false;
151113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        jpeg_destroy_decompress(&fCInfo);
152a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkDEBUGCODE(fReadHeaderSucceeded = false;)
153d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
154d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
155113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    /**
156a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  Initialize the cinfo struct.
157a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  Calls jpeg_create_decompress, makes customizations, and
158a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  finally calls jpeg_read_header. Returns true if jpeg_read_header
159a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  returns JPEG_HEADER_OK.
160a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  If cinfo was already initialized, destroyInfo must be called to
161a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  destroy the old one. Must not be called after startTileDecompress.
162113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com     */
163a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    bool initializeInfoAndReadHeader() {
164a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(!fInfoInitialized && !fDecompressStarted);
165590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        initialize_info(&fCInfo, &fSrcMgr);
166a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        fInfoInitialized = true;
167a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        const bool success = (JPEG_HEADER_OK == jpeg_read_header(&fCInfo, true));
168a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkDEBUGCODE(fReadHeaderSucceeded = success;)
169a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        return success;
170113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
171d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
172113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_decompress_struct* cinfo() { return &fCInfo; }
173d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
174113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    huffman_index* huffmanIndex() { return &fHuffmanIndex; }
175a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com
176a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    /**
177a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  Build the index to be used for tile based decoding.
178a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  Must only be called after a successful call to
179a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  initializeInfoAndReadHeader and must not be called more
180a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  than once.
181a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     */
182a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    bool buildHuffmanIndex() {
183a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(fReadHeaderSucceeded);
184a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(!fHuffmanCreated);
185a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        jpeg_create_huffman_index(&fCInfo, &fHuffmanIndex);
186a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(1 == fCInfo.scale_num && 1 == fCInfo.scale_denom);
18757a529877e65687de1fa4d19d52746427c6896dcscroggo@google.com        fHuffmanCreated = jpeg_build_huffman_index(&fCInfo, &fHuffmanIndex);
18857a529877e65687de1fa4d19d52746427c6896dcscroggo@google.com        return fHuffmanCreated;
189a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    }
190a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com
191a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    /**
192a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  Start tile based decoding. Must only be called after a
193a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  successful call to buildHuffmanIndex, and must only be
194a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     *  called once.
195a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com     */
196a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    bool startTileDecompress() {
197a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(fHuffmanCreated);
198a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(fReadHeaderSucceeded);
199a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        SkASSERT(!fDecompressStarted);
200a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        if (jpeg_start_tile_decompress(&fCInfo)) {
201a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            fDecompressStarted = true;
202a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com            return true;
203a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        }
204a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        return false;
205a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    }
206113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
207113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comprivate:
208113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    skjpeg_source_mgr  fSrcMgr;
209113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_decompress_struct fCInfo;
210113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    huffman_index fHuffmanIndex;
211a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    bool fInfoInitialized;
212a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    bool fHuffmanCreated;
213a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    bool fDecompressStarted;
214a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    SkDEBUGCODE(bool fReadHeaderSucceeded;)
215113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com};
216a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#endif
217d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
218113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comclass SkJPEGImageDecoder : public SkImageDecoder {
219d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic:
220a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
221113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkJPEGImageDecoder() {
222113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        fImageIndex = NULL;
223113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        fImageWidth = 0;
224113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        fImageHeight = 0;
225d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
226113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
227113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    virtual ~SkJPEGImageDecoder() {
228113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        SkDELETE(fImageIndex);
229d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
230a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#endif
231113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
232113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    virtual Format getFormat() const {
233113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return kJPEG_Format;
234113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
235113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
236113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comprotected:
237d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
238b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.com    virtual bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) SK_OVERRIDE;
2397e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.com    virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE;
240113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
241113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
242b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    virtual bool onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3],
243b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                                    void* planes[3], size_t rowBytes[3],
244b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                                    SkYUVColorSpace* colorSpace) SK_OVERRIDE;
245113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
246d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprivate:
247a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
248113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkJPEGImageIndex* fImageIndex;
249113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int fImageWidth;
250113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int fImageHeight;
251a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com#endif
252113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
253590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    /**
2546c22573edb234ad14df947278cfed010669a39a7reed     *  Determine the appropriate bitmap colortype and out_color_space based on
255590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com     *  both the preference of the caller and the jpeg_color_space on the
256590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com     *  jpeg_decompress_struct passed in.
257590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com     *  Must be called after jpeg_read_header.
258590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com     */
2596c22573edb234ad14df947278cfed010669a39a7reed    SkColorType getBitmapColorType(jpeg_decompress_struct*);
260590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
261113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    typedef SkImageDecoder INHERITED;
262d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com};
263d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
264113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com//////////////////////////////////////////////////////////////////////////
265113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
266d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/* Automatically clean up after throwing an exception */
267d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comclass JPEGAutoClean {
268d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.compublic:
269d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    JPEGAutoClean(): cinfo_ptr(NULL) {}
270d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    ~JPEGAutoClean() {
271d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (cinfo_ptr) {
272d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            jpeg_destroy_decompress(cinfo_ptr);
273d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
274d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
275d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    void set(jpeg_decompress_struct* info) {
276d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo_ptr = info;
277d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
278d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprivate:
279d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    jpeg_decompress_struct* cinfo_ptr;
280d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com};
281d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
282d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com///////////////////////////////////////////////////////////////////////////////
283d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
284d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com/*  If we need to better match the request, we might examine the image and
285d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     output dimensions, and determine if the downsampling jpeg provided is
286d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     not sufficient. If so, we can recompute a modified sampleSize value to
287d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     make up the difference.
288d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
289d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     To skip this additional scaling, just set sampleSize = 1; below.
290d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com */
291d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic int recompute_sampleSize(int sampleSize,
292d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                                const jpeg_decompress_struct& cinfo) {
293d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    return sampleSize * cinfo.output_width / cinfo.image_width;
294d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
295d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
296d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic bool valid_output_dimensions(const jpeg_decompress_struct& cinfo) {
297d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    /* These are initialized to 0, so if they have non-zero values, we assume
298d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com       they are "valid" (i.e. have been computed by libjpeg)
299d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com     */
300113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    return 0 != cinfo.output_width && 0 != cinfo.output_height;
301d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
302d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
303113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comstatic bool skip_src_rows(jpeg_decompress_struct* cinfo, void* buffer, int count) {
304d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    for (int i = 0; i < count; i++) {
305d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        JSAMPLE* rowptr = (JSAMPLE*)buffer;
306d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        int row_count = jpeg_read_scanlines(cinfo, &rowptr, 1);
307113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (1 != row_count) {
308d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return false;
309d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
310d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
311d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    return true;
312d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
313d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
314d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
315113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comstatic bool skip_src_rows_tile(jpeg_decompress_struct* cinfo,
316113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                               huffman_index *index, void* buffer, int count) {
317113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    for (int i = 0; i < count; i++) {
318113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        JSAMPLE* rowptr = (JSAMPLE*)buffer;
319113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        int row_count = jpeg_read_tile_scanline(cinfo, index, &rowptr);
320113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (1 != row_count) {
321113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return false;
322113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
323113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
324113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    return true;
325113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com}
326113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
327113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
328d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// This guy exists just to aid in debugging, as it allows debuggers to just
329d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// set a break-point in one place to see all error exists.
330d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic bool return_false(const jpeg_decompress_struct& cinfo,
331b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                         int width, int height, const char caller[]) {
33204b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com    if (!(c_suppressJPEGImageDecoderErrors)) {
33304b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com        char buffer[JMSG_LENGTH_MAX];
33404b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com        cinfo.err->format_message((const j_common_ptr)&cinfo, buffer);
33504b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com        SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n",
336b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                 cinfo.err->msg_code, buffer, caller, width, height);
33704b57f87ab6789f7fc302eda8a993d88d4feea8fhalcanary@google.com    }
338d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    return false;   // must always return false
339d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
340d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
341b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic bool return_false(const jpeg_decompress_struct& cinfo,
342b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                         const SkBitmap& bm, const char caller[]) {
343b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    return return_false(cinfo, bm.width(), bm.height(), caller);
344b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi}
345b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
3468570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com// Convert a scanline of CMYK samples to RGBX in place. Note that this
3478570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com// method moves the "scanline" pointer in its processing
3488570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic void convert_CMYK_to_RGB(uint8_t* scanline, unsigned int width) {
3498570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // At this point we've received CMYK pixels from libjpeg. We
350d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    // perform a crude conversion to RGB (based on the formulae
3518570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // from easyrgb.com):
3528570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //  CMYK -> CMY
3538570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //    C = ( C * (1 - K) + K )      // for each CMY component
3548570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //  CMY -> RGB
3558570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //    R = ( 1 - C ) * 255          // for each RGB component
3568570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // Unfortunately we are seeing inverted CMYK so all the original terms
3578570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // are 1-. This yields:
3588570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //  CMYK -> CMY
3598570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    //    C = ( (1-C) * (1 - (1-K) + (1-K) ) -> C = 1 - C*K
3608570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    // The conversion from CMY->RGB remains the same
3618570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    for (unsigned int x = 0; x < width; ++x, scanline += 4) {
3628570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        scanline[0] = SkMulDiv255Round(scanline[0], scanline[3]);
3638570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        scanline[1] = SkMulDiv255Round(scanline[1], scanline[3]);
3648570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        scanline[2] = SkMulDiv255Round(scanline[2], scanline[3]);
3658570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        scanline[3] = 255;
3668570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com    }
3678570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com}
3688570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com
369590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/**
370590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com *  Common code for setting the error manager.
371590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */
372590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void set_error_mgr(jpeg_decompress_struct* cinfo, skjpeg_error_mgr* errorManager) {
373590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(cinfo != NULL);
374590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(errorManager != NULL);
375590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    cinfo->err = jpeg_std_error(errorManager);
376590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    errorManager->error_exit = skjpeg_error_exit;
377590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com}
378590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
379590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/**
380590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com *  Common code for turning off upsampling and smoothing. Turning these
381590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com *  off helps performance without showing noticable differences in the
382590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com *  resulting bitmap.
383590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */
384590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void turn_off_visual_optimizations(jpeg_decompress_struct* cinfo) {
385590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(cinfo != NULL);
386590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    /* this gives about 30% performance improvement. In theory it may
387590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com       reduce the visual quality, in practice I'm not seeing a difference
388590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com     */
389590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    cinfo->do_fancy_upsampling = 0;
390590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
391590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    /* this gives another few percents */
392590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    cinfo->do_block_smoothing = 0;
393590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com}
394590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
395590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/**
396590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com * Common code for setting the dct method.
397590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */
398590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void set_dct_method(const SkImageDecoder& decoder, jpeg_decompress_struct* cinfo) {
399590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(cinfo != NULL);
400590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#ifdef DCT_IFAST_SUPPORTED
401590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    if (decoder.getPreferQualityOverSpeed()) {
402590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        cinfo->dct_method = JDCT_ISLOW;
403590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    } else {
404590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        cinfo->dct_method = JDCT_IFAST;
405590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
406590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#else
407590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    cinfo->dct_method = JDCT_ISLOW;
408590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#endif
409590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com}
410590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
4116c22573edb234ad14df947278cfed010669a39a7reedSkColorType SkJPEGImageDecoder::getBitmapColorType(jpeg_decompress_struct* cinfo) {
412590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(cinfo != NULL);
413590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
414590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SrcDepth srcDepth = k32Bit_SrcDepth;
415590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    if (JCS_GRAYSCALE == cinfo->jpeg_color_space) {
416590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        srcDepth = k8BitGray_SrcDepth;
417590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
418590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
4196c22573edb234ad14df947278cfed010669a39a7reed    SkColorType colorType = this->getPrefColorType(srcDepth, /*hasAlpha*/ false);
4206c22573edb234ad14df947278cfed010669a39a7reed    switch (colorType) {
4216c22573edb234ad14df947278cfed010669a39a7reed        case kAlpha_8_SkColorType:
4226c22573edb234ad14df947278cfed010669a39a7reed            // Only respect A8 colortype if the original is grayscale,
423590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // in which case we will treat the grayscale as alpha
424590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // values.
425590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            if (cinfo->jpeg_color_space != JCS_GRAYSCALE) {
4266c22573edb234ad14df947278cfed010669a39a7reed                colorType = kN32_SkColorType;
427590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            }
428590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
4296c22573edb234ad14df947278cfed010669a39a7reed        case kN32_SkColorType:
430590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // Fall through.
4316c22573edb234ad14df947278cfed010669a39a7reed        case kARGB_4444_SkColorType:
432590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // Fall through.
4336c22573edb234ad14df947278cfed010669a39a7reed        case kRGB_565_SkColorType:
4346c22573edb234ad14df947278cfed010669a39a7reed            // These are acceptable destination colortypes.
435590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
436590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        default:
4376c22573edb234ad14df947278cfed010669a39a7reed            // Force all other colortypes to 8888.
4386c22573edb234ad14df947278cfed010669a39a7reed            colorType = kN32_SkColorType;
439590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
440590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
441590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
442590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    switch (cinfo->jpeg_color_space) {
443590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        case JCS_CMYK:
444590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // Fall through.
445590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        case JCS_YCCK:
446590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // libjpeg cannot convert from CMYK or YCCK to RGB - here we set up
447590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // so libjpeg will give us CMYK samples back and we will later
448590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // manually convert them to RGB
449590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            cinfo->out_color_space = JCS_CMYK;
450590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
451590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        case JCS_GRAYSCALE:
4526c22573edb234ad14df947278cfed010669a39a7reed            if (kAlpha_8_SkColorType == colorType) {
453590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com                cinfo->out_color_space = JCS_GRAYSCALE;
454590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com                break;
455590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            }
456590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            // The data is JCS_GRAYSCALE, but the caller wants some sort of RGB
4576c22573edb234ad14df947278cfed010669a39a7reed            // colortype. Fall through to set to the default.
458590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        default:
459590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            cinfo->out_color_space = JCS_RGB;
460590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
461590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
4626c22573edb234ad14df947278cfed010669a39a7reed    return colorType;
463590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com}
464590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
465590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com/**
4666c22573edb234ad14df947278cfed010669a39a7reed *  Based on the colortype and dither mode, adjust out_color_space and
4676c22573edb234ad14df947278cfed010669a39a7reed *  dither_mode of cinfo. Only does work in ANDROID_RGB
468590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com */
469590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.comstatic void adjust_out_color_space_and_dither(jpeg_decompress_struct* cinfo,
4706c22573edb234ad14df947278cfed010669a39a7reed                                              SkColorType colorType,
471590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com                                              const SkImageDecoder& decoder) {
472590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(cinfo != NULL);
4736c22573edb234ad14df947278cfed010669a39a7reed#ifdef ANDROID_RGB
474590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    cinfo->dither_mode = JDITHER_NONE;
475590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    if (JCS_CMYK == cinfo->out_color_space) {
476590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        return;
477590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
4786c22573edb234ad14df947278cfed010669a39a7reed    switch (colorType) {
4796c22573edb234ad14df947278cfed010669a39a7reed        case kN32_SkColorType:
480590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            cinfo->out_color_space = JCS_RGBA_8888;
481590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
4826c22573edb234ad14df947278cfed010669a39a7reed        case kRGB_565_SkColorType:
483590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            cinfo->out_color_space = JCS_RGB_565;
484590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            if (decoder.getDitherImage()) {
485590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com                cinfo->dither_mode = JDITHER_ORDERED;
486590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            }
487590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
488590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        default:
489590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com            break;
490590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
491590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com#endif
4926c22573edb234ad14df947278cfed010669a39a7reed}
493590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
494fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com
495fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com/**
496fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com   Sets all pixels in given bitmap to SK_ColorWHITE for all rows >= y.
497fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com   Used when decoding fails partway through reading scanlines to fill
498fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com   remaining lines. */
499fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.comstatic void fill_below_level(int y, SkBitmap* bitmap) {
5002dcf36e25186bb0396eaa692bda402993252b88ahalcanary@google.com    SkIRect rect = SkIRect::MakeLTRB(0, y, bitmap->width(), bitmap->height());
501fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com    SkCanvas canvas(*bitmap);
5022dcf36e25186bb0396eaa692bda402993252b88ahalcanary@google.com    canvas.clipRect(SkRect::Make(rect));
503fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com    canvas.drawColor(SK_ColorWHITE);
504fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com}
505fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com
5065ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com/**
5075ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *  Get the config and bytes per pixel of the source data. Return
5085ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com *  whether the data is supported.
5095ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com */
5105ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.comstatic bool get_src_config(const jpeg_decompress_struct& cinfo,
5115ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com                           SkScaledBitmapSampler::SrcConfig* sc,
5125ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com                           int* srcBytesPerPixel) {
5135ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    SkASSERT(sc != NULL && srcBytesPerPixel != NULL);
5145ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    if (JCS_CMYK == cinfo.out_color_space) {
5155ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        // In this case we will manually convert the CMYK values to RGB
5165ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *sc = SkScaledBitmapSampler::kRGBX;
5175ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        // The CMYK work-around relies on 4 components per pixel here
5185ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *srcBytesPerPixel = 4;
5195ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    } else if (3 == cinfo.out_color_components && JCS_RGB == cinfo.out_color_space) {
5205ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *sc = SkScaledBitmapSampler::kRGB;
5215ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *srcBytesPerPixel = 3;
5225ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com#ifdef ANDROID_RGB
5235ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    } else if (JCS_RGBA_8888 == cinfo.out_color_space) {
5245ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *sc = SkScaledBitmapSampler::kRGBX;
5255ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *srcBytesPerPixel = 4;
5265ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    } else if (JCS_RGB_565 == cinfo.out_color_space) {
5275ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *sc = SkScaledBitmapSampler::kRGB_565;
5285ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *srcBytesPerPixel = 2;
5295ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com#endif
5305ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    } else if (1 == cinfo.out_color_components &&
5315ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com               JCS_GRAYSCALE == cinfo.out_color_space) {
5325ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *sc = SkScaledBitmapSampler::kGray;
5335ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        *srcBytesPerPixel = 1;
5345ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    } else {
5355ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        return false;
5365ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    }
5375ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    return true;
5385ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com}
539fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com
540d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.combool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
541d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef TIME_DECODE
542113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkAutoTime atm("JPEG Decode");
543d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
544d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
545d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    JPEGAutoClean autoClean;
546d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
547d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    jpeg_decompress_struct  cinfo;
548d4c3565aac5c83ff0008453abed4c6d6009bb394scroggo@google.com    skjpeg_source_mgr       srcManager(stream, this);
549d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
550590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    skjpeg_error_mgr errorManager;
551590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    set_error_mgr(&cinfo, &errorManager);
552d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
553d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // All objects need to be instantiated before this setjmp call so that
554d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // they will be cleaned up properly if an error occurs.
555113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (setjmp(errorManager.fJmpBuf)) {
556d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return return_false(cinfo, *bm, "setjmp");
557d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
558d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
559590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    initialize_info(&cinfo, &srcManager);
560d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    autoClean.set(&cinfo);
561d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
562d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int status = jpeg_read_header(&cinfo, true);
563d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (status != JPEG_HEADER_OK) {
564d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return return_false(cinfo, *bm, "read_header");
565d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
566d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
567d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    /*  Try to fulfill the requested sampleSize. Since jpeg can do it (when it
568d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        can) much faster that we, just use their num/denom api to approximate
569d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        the size.
570d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    */
571d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int sampleSize = this->getSampleSize();
572d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
573590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    set_dct_method(*this, &cinfo);
574113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
575590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    SkASSERT(1 == cinfo.scale_num);
576d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    cinfo.scale_denom = sampleSize;
577d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
578590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    turn_off_visual_optimizations(&cinfo);
579d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
5806c22573edb234ad14df947278cfed010669a39a7reed    const SkColorType colorType = this->getBitmapColorType(&cinfo);
5816c22573edb234ad14df947278cfed010669a39a7reed    const SkAlphaType alphaType = kAlpha_8_SkColorType == colorType ?
5826c22573edb234ad14df947278cfed010669a39a7reed                                      kPremul_SkAlphaType : kOpaque_SkAlphaType;
583d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
5846c22573edb234ad14df947278cfed010669a39a7reed    adjust_out_color_space_and_dither(&cinfo, colorType, *this);
585d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
586113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (1 == sampleSize && SkImageDecoder::kDecodeBounds_Mode == mode) {
5875ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        // Assume an A8 bitmap is not opaque to avoid the check of each
5885ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        // individual pixel. It is very unlikely to be opaque, since
5895ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        // an opaque A8 bitmap would not be very interesting.
5905ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com        // Otherwise, a jpeg image is opaque.
5916c22573edb234ad14df947278cfed010669a39a7reed        return bm->setInfo(SkImageInfo::Make(cinfo.image_width, cinfo.image_height,
5926c22573edb234ad14df947278cfed010669a39a7reed                                             colorType, alphaType));
593d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
594d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
595d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    /*  image_width and image_height are the original dimensions, available
596d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        after jpeg_read_header(). To see the scaled dimensions, we have to call
597d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_start_decompress(), and then read output_width and output_height.
598d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    */
599d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (!jpeg_start_decompress(&cinfo)) {
600d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        /*  If we failed here, we may still have enough information to return
601d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            to the caller if they just wanted (subsampled bounds). If sampleSize
602d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            was 1, then we would have already returned. Thus we just check if
603d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            we're in kDecodeBounds_Mode, and that we have valid output sizes.
604d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
605d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            One reason to fail here is that we have insufficient stream data
606d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            to complete the setup. However, output dimensions seem to get
607d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            computed very early, which is why this special check can pay off.
608d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com         */
609113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (SkImageDecoder::kDecodeBounds_Mode == mode && valid_output_dimensions(cinfo)) {
610d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            SkScaledBitmapSampler smpl(cinfo.output_width, cinfo.output_height,
611d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                                       recompute_sampleSize(sampleSize, cinfo));
6125ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com            // Assume an A8 bitmap is not opaque to avoid the check of each
6135ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com            // individual pixel. It is very unlikely to be opaque, since
6145ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com            // an opaque A8 bitmap would not be very interesting.
6155ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com            // Otherwise, a jpeg image is opaque.
6166c22573edb234ad14df947278cfed010669a39a7reed            return bm->setInfo(SkImageInfo::Make(smpl.scaledWidth(), smpl.scaledHeight(),
6176c22573edb234ad14df947278cfed010669a39a7reed                                                 colorType, alphaType));
618d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        } else {
619d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return return_false(cinfo, *bm, "start_decompress");
620d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
621d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
622d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    sampleSize = recompute_sampleSize(sampleSize, cinfo);
623d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
6245926b86b90c68bffefbdc8639e41b5bc9102cec6reed#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
6256c22573edb234ad14df947278cfed010669a39a7reed    // should we allow the Chooser (if present) to pick a colortype for us???
6266c22573edb234ad14df947278cfed010669a39a7reed    if (!this->chooseFromOneChoice(colorType, cinfo.output_width, cinfo.output_height)) {
627d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return return_false(cinfo, *bm, "chooseFromOneChoice");
628d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
6295926b86b90c68bffefbdc8639e41b5bc9102cec6reed#endif
630d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
631113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkScaledBitmapSampler sampler(cinfo.output_width, cinfo.output_height, sampleSize);
6325ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // Assume an A8 bitmap is not opaque to avoid the check of each
6335ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // individual pixel. It is very unlikely to be opaque, since
6345ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // an opaque A8 bitmap would not be very interesting.
6355ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // Otherwise, a jpeg image is opaque.
6366c22573edb234ad14df947278cfed010669a39a7reed    bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(),
6376c22573edb234ad14df947278cfed010669a39a7reed                                  colorType, alphaType));
638bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
639bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com        return true;
640bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com    }
641bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com    if (!this->allocPixelRef(bm, NULL)) {
642bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com        return return_false(cinfo, *bm, "allocPixelRef");
643113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
644113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
645113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkAutoLockPixels alp(*bm);
646113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
647d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef ANDROID_RGB
648d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    /* short-circuit the SkScaledBitmapSampler when possible, as this gives
649d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com       a significant performance boost.
650d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    */
651d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (sampleSize == 1 &&
6526c22573edb234ad14df947278cfed010669a39a7reed        ((kN32_SkColorType == colorType && cinfo.out_color_space == JCS_RGBA_8888) ||
6536c22573edb234ad14df947278cfed010669a39a7reed         (kRGB_565_SkColorType == colorType && cinfo.out_color_space == JCS_RGB_565)))
654d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    {
655bc69ce982f8374742ca910587485f0d741350c2dscroggo@google.com        JSAMPLE* rowptr = (JSAMPLE*)bm->getPixels();
656d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        INT32 const bpr =  bm->rowBytes();
657d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
658d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        while (cinfo.output_scanline < cinfo.output_height) {
659d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
660d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            if (0 == row_count) {
661fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com                // if row_count == 0, then we didn't get a scanline,
662fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com                // so return early.  We will return a partial image.
663fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com                fill_below_level(cinfo.output_scanline, bm);
664fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com                cinfo.output_scanline = cinfo.output_height;
665fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com                break;  // Skip to jpeg_finish_decompress()
666d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            }
667d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            if (this->shouldCancelDecode()) {
668d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                return return_false(cinfo, *bm, "shouldCancelDecode");
669d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            }
670d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            rowptr += bpr;
671d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
672d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_finish_decompress(&cinfo);
673d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return true;
674d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
675d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
6768570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com
677d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // check for supported formats
678d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    SkScaledBitmapSampler::SrcConfig sc;
6795ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    int srcBytesPerPixel;
6805ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com
6815ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    if (!get_src_config(cinfo, &sc, &srcBytesPerPixel)) {
682d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return return_false(cinfo, *bm, "jpeg colorspace");
683d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
684d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
6858d2392487cd97e68c0a71da9fd5d2b42ecac5ec8scroggo@google.com    if (!sampler.begin(bm, sc, *this)) {
686d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return return_false(cinfo, *bm, "sampler.begin");
687d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
688d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
6895ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    SkAutoMalloc srcStorage(cinfo.output_width * srcBytesPerPixel);
690113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    uint8_t* srcRow = (uint8_t*)srcStorage.get();
691d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
692d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    //  Possibly skip initial rows [sampler.srcY0]
693d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (!skip_src_rows(&cinfo, srcRow, sampler.srcY0())) {
694d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return return_false(cinfo, *bm, "skip rows");
695d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
696d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
697d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // now loop through scanlines until y == bm->height() - 1
698d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    for (int y = 0;; y++) {
699d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        JSAMPLE* rowptr = (JSAMPLE*)srcRow;
700d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        int row_count = jpeg_read_scanlines(&cinfo, &rowptr, 1);
701d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (0 == row_count) {
702fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com            // if row_count == 0, then we didn't get a scanline,
703fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com            // so return early.  We will return a partial image.
704fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com            fill_below_level(y, bm);
705fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com            cinfo.output_scanline = cinfo.output_height;
706fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com            break;  // Skip to jpeg_finish_decompress()
707d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
708d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (this->shouldCancelDecode()) {
709d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return return_false(cinfo, *bm, "shouldCancelDecode");
710d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
7118570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com
7128570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        if (JCS_CMYK == cinfo.out_color_space) {
7138570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com            convert_CMYK_to_RGB(srcRow, cinfo.output_width);
7148570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        }
7158570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com
716d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        sampler.next(srcRow);
717d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (bm->height() - 1 == y) {
718d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            // we're done
719d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            break;
720d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
721d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
722d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (!skip_src_rows(&cinfo, srcRow, sampler.srcDY() - 1)) {
723d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return return_false(cinfo, *bm, "skip rows");
724d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
725d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
726d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
727d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    // we formally skip the rest, so we don't get a complaint from libjpeg
728d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (!skip_src_rows(&cinfo, srcRow,
729d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                       cinfo.output_height - cinfo.output_scanline)) {
730d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return return_false(cinfo, *bm, "skip rows");
731d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
732d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    jpeg_finish_decompress(&cinfo);
733d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
734d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    return true;
735d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
736d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
737b227e37eae36ccf630c4baef00b1354d42b40fd1sugoienum SizeType {
738b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    kSizeForMemoryAllocation_SizeType,
739b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    kActualSize_SizeType
740b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi};
741b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
742b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic SkISize compute_yuv_size(const jpeg_decompress_struct& info, int component,
743b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                                SizeType sizeType) {
744b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (sizeType == kSizeForMemoryAllocation_SizeType) {
745b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        return SkISize::Make(info.cur_comp_info[component]->width_in_blocks * DCTSIZE,
746b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                             info.cur_comp_info[component]->height_in_blocks * DCTSIZE);
747b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
748b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    return SkISize::Make(info.cur_comp_info[component]->downsampled_width,
749b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                         info.cur_comp_info[component]->downsampled_height);
750b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi}
751b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
752b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi// Enum for YUV decoding
753b227e37eae36ccf630c4baef00b1354d42b40fd1sugoienum YUVSubsampling {
754b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    kUNKNOWN_YUVSubsampling,
755b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    k410_YUVSubsampling,
756b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    k411_YUVSubsampling,
757b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    k420_YUVSubsampling,
758b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    k422_YUVSubsampling,
759b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    k440_YUVSubsampling,
760b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    k444_YUVSubsampling
761b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi};
762b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
763b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic YUVSubsampling yuv_subsampling(const jpeg_decompress_struct& info) {
764b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if ((DCTSIZE == 8)
765b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        && (info.num_components == 3)
766b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        && (info.comps_in_scan >= info.num_components)
767b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        && (info.scale_denom <= 8)
768b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        && (info.cur_comp_info[0])
769b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        && (info.cur_comp_info[1])
770b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        && (info.cur_comp_info[2])
771b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        && (info.cur_comp_info[1]->h_samp_factor == 1)
772b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        && (info.cur_comp_info[1]->v_samp_factor == 1)
773b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        && (info.cur_comp_info[2]->h_samp_factor == 1)
774b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        && (info.cur_comp_info[2]->v_samp_factor == 1))
775b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    {
776b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        int h = info.cur_comp_info[0]->h_samp_factor;
777b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        int v = info.cur_comp_info[0]->v_samp_factor;
778b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        // 4:4:4 : (h == 1) && (v == 1)
779b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        // 4:4:0 : (h == 1) && (v == 2)
780b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        // 4:2:2 : (h == 2) && (v == 1)
781b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        // 4:2:0 : (h == 2) && (v == 2)
782b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        // 4:1:1 : (h == 4) && (v == 1)
783b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        // 4:1:0 : (h == 4) && (v == 2)
784b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        if (v == 1) {
785b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            switch (h) {
786b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                case 1:
787b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                    return k444_YUVSubsampling;
788b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                case 2:
789b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                    return k422_YUVSubsampling;
790b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                case 4:
791b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                    return k411_YUVSubsampling;
792b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                default:
793b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                    break;
794b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            }
795b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        } else if (v == 2) {
796b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            switch (h) {
797b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                case 1:
798b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                    return k440_YUVSubsampling;
799b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                case 2:
800b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                    return k420_YUVSubsampling;
801b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                case 4:
802b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                    return k410_YUVSubsampling;
803b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                default:
804b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                    break;
805b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            }
806b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        }
807b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
808b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
809b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    return kUNKNOWN_YUVSubsampling;
810b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi}
811b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
812b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic void update_components_sizes(const jpeg_decompress_struct& cinfo, SkISize componentSizes[3],
813b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                                    SizeType sizeType) {
814b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    for (int i = 0; i < 3; ++i) {
815b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        componentSizes[i] = compute_yuv_size(cinfo, i, sizeType);
816b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
817b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi}
818b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
819b227e37eae36ccf630c4baef00b1354d42b40fd1sugoistatic bool output_raw_data(jpeg_decompress_struct& cinfo, void* planes[3], size_t rowBytes[3]) {
820b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    // U size and V size have to be the same if we're calling output_raw_data()
821b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    SkISize uvSize = compute_yuv_size(cinfo, 1, kSizeForMemoryAllocation_SizeType);
822b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    SkASSERT(uvSize == compute_yuv_size(cinfo, 2, kSizeForMemoryAllocation_SizeType));
823b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
824b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JSAMPARRAY bufferraw[3];
825b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JSAMPROW bufferraw2[32];
826b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    bufferraw[0] = &bufferraw2[0]; // Y channel rows (8 or 16)
827b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    bufferraw[1] = &bufferraw2[16]; // U channel rows (8)
828b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    bufferraw[2] = &bufferraw2[24]; // V channel rows (8)
829b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    int yWidth = cinfo.output_width;
830b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    int yHeight = cinfo.output_height;
831b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    int yMaxH = yHeight - 1;
832b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    int v = cinfo.cur_comp_info[0]->v_samp_factor;
833b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    int uvMaxH = uvSize.height() - 1;
834b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JSAMPROW outputY = static_cast<JSAMPROW>(planes[0]);
835b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JSAMPROW outputU = static_cast<JSAMPROW>(planes[1]);
836b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JSAMPROW outputV = static_cast<JSAMPROW>(planes[2]);
837b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    size_t rowBytesY = rowBytes[0];
838b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    size_t rowBytesU = rowBytes[1];
839b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    size_t rowBytesV = rowBytes[2];
840b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
841b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    int yScanlinesToRead = DCTSIZE * v;
842b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    SkAutoMalloc lastRowStorage(yWidth * 8);
843b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JSAMPROW yLastRow = (JSAMPROW)lastRowStorage.get();
844b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JSAMPROW uLastRow = yLastRow + 2 * yWidth;
845b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JSAMPROW vLastRow = uLastRow + 2 * yWidth;
846b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JSAMPROW dummyRow = vLastRow + 2 * yWidth;
847b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
848b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    while (cinfo.output_scanline < cinfo.output_height) {
849b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        // Request 8 or 16 scanlines: returns 0 or more scanlines.
850b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        bool hasYLastRow(false), hasUVLastRow(false);
851b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        // Assign 8 or 16 rows of memory to read the Y channel.
852b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        for (int i = 0; i < yScanlinesToRead; ++i) {
853b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            int scanline = (cinfo.output_scanline + i);
854b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            if (scanline < yMaxH) {
855b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[i] = &outputY[scanline * rowBytesY];
856b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            } else if (scanline == yMaxH) {
857b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[i] = yLastRow;
858b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                hasYLastRow = true;
859b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            } else {
860b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[i] = dummyRow;
861b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            }
862b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        }
863b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        int scaledScanline = cinfo.output_scanline / v;
864b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        // Assign 8 rows of memory to read the U and V channels.
865b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        for (int i = 0; i < 8; ++i) {
866b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            int scanline = (scaledScanline + i);
867b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            if (scanline < uvMaxH) {
868b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[16 + i] = &outputU[scanline * rowBytesU];
869b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[24 + i] = &outputV[scanline * rowBytesV];
870b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            } else if (scanline == uvMaxH) {
871b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[16 + i] = uLastRow;
872b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[24 + i] = vLastRow;
873b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                hasUVLastRow = true;
874b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            } else {
875b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[16 + i] = dummyRow;
876b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                bufferraw2[24 + i] = dummyRow;
877b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            }
878b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        }
879b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        JDIMENSION scanlinesRead = jpeg_read_raw_data(&cinfo, bufferraw, yScanlinesToRead);
880b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
881b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        if (scanlinesRead == 0)
882b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            return false;
883b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
884b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        if (hasYLastRow) {
885b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            memcpy(&outputY[yMaxH * rowBytesY], yLastRow, yWidth);
886b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        }
887b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        if (hasUVLastRow) {
888b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            memcpy(&outputU[uvMaxH * rowBytesU], uLastRow, uvSize.width());
889b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi            memcpy(&outputV[uvMaxH * rowBytesV], vLastRow, uvSize.width());
890b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        }
891b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
892b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
893b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    cinfo.output_scanline = SkMin32(cinfo.output_scanline, cinfo.output_height);
894b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
895b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    return true;
896b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi}
897b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
898b227e37eae36ccf630c4baef00b1354d42b40fd1sugoibool SkJPEGImageDecoder::onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3],
899b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                                            void* planes[3], size_t rowBytes[3],
900b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi                                            SkYUVColorSpace* colorSpace) {
901b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#ifdef TIME_DECODE
902b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    SkAutoTime atm("JPEG YUV8 Decode");
903b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#endif
904b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
905b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (this->getSampleSize() != 1) {
906b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        return false; // Resizing not supported
907b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
908b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
909b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    JPEGAutoClean autoClean;
910b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
911b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    jpeg_decompress_struct  cinfo;
912b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    skjpeg_source_mgr       srcManager(stream, this);
913b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
914b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    skjpeg_error_mgr errorManager;
915b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    set_error_mgr(&cinfo, &errorManager);
916b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
917b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    // All objects need to be instantiated before this setjmp call so that
918b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    // they will be cleaned up properly if an error occurs.
919b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (setjmp(errorManager.fJmpBuf)) {
920b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        return return_false(cinfo, 0, 0, "setjmp YUV8");
921b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
922b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
923b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    initialize_info(&cinfo, &srcManager);
924b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    autoClean.set(&cinfo);
925b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
926b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    int status = jpeg_read_header(&cinfo, true);
927b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (status != JPEG_HEADER_OK) {
928b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        return return_false(cinfo, 0, 0, "read_header YUV8");
929b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
930b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
931b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (cinfo.jpeg_color_space != JCS_YCbCr) {
932b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        // It's not an error to not be encoded in YUV, so no need to use return_false()
933b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        return false;
934b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
935b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
936b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    cinfo.out_color_space = JCS_YCbCr;
937b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    cinfo.raw_data_out = TRUE;
938b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
939b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (!planes || !planes[0] || !rowBytes || !rowBytes[0]) { // Compute size only
940b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        update_components_sizes(cinfo, componentSizes, kSizeForMemoryAllocation_SizeType);
941b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        return true;
942b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
943b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
944b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    set_dct_method(*this, &cinfo);
945b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
946b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    SkASSERT(1 == cinfo.scale_num);
947b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    cinfo.scale_denom = 1;
948b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
949b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    turn_off_visual_optimizations(&cinfo);
950b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
951b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#ifdef ANDROID_RGB
952b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    cinfo.dither_mode = JDITHER_NONE;
953b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi#endif
954b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
955b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    /*  image_width and image_height are the original dimensions, available
956b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        after jpeg_read_header(). To see the scaled dimensions, we have to call
957b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        jpeg_start_decompress(), and then read output_width and output_height.
958b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    */
959b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (!jpeg_start_decompress(&cinfo)) {
960b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        return return_false(cinfo, 0, 0, "start_decompress YUV8");
961b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
962b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
963b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (!output_raw_data(cinfo, planes, rowBytes)) {
964b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        return return_false(cinfo, 0, 0, "output_raw_data");
965b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
966b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
967b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    update_components_sizes(cinfo, componentSizes, kActualSize_SizeType);
968b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    jpeg_finish_decompress(&cinfo);
969b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
970b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    if (NULL != colorSpace) {
971b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi        *colorSpace = kJPEG_SkYUVColorSpace;
972b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    }
973b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
974b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi    return true;
975b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi}
976b227e37eae36ccf630c4baef00b1354d42b40fd1sugoi
977d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
978b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.combool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width, int *height) {
979113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
980a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    SkAutoTDelete<SkJPEGImageIndex> imageIndex(SkNEW_ARGS(SkJPEGImageIndex, (stream, this)));
981113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_decompress_struct* cinfo = imageIndex->cinfo();
982113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
983113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    skjpeg_error_mgr sk_err;
984590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    set_error_mgr(cinfo, &sk_err);
985113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
986113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // All objects need to be instantiated before this setjmp call so that
987113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // they will be cleaned up properly if an error occurs.
988113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (setjmp(sk_err.fJmpBuf)) {
989113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
990113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
991113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
992113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // create the cinfo used to create/build the huffmanIndex
993a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    if (!imageIndex->initializeInfoAndReadHeader()) {
994113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
995113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
996113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
997a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    if (!imageIndex->buildHuffmanIndex()) {
998113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
999113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1000113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1001113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // destroy the cinfo used to create/build the huffman index
1002a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    imageIndex->destroyInfo();
1003113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1004113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // Init decoder to image decode mode
1005a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    if (!imageIndex->initializeInfoAndReadHeader()) {
1006113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
1007113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1008113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1009590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    // FIXME: This sets cinfo->out_color_space, which we may change later
1010590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    // based on the config in onDecodeSubset. This should be fine, since
1011590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    // jpeg_init_read_tile_scanline will check out_color_space again after
1012590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    // that change (when it calls jinit_color_deconverter).
10136c22573edb234ad14df947278cfed010669a39a7reed    (void) this->getBitmapColorType(cinfo);
1014590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
1015590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    turn_off_visual_optimizations(cinfo);
1016113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1017113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // instead of jpeg_start_decompress() we start a tiled decompress
1018a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    if (!imageIndex->startTileDecompress()) {
1019a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com        return false;
1020a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    }
1021113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1022a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    SkASSERT(1 == cinfo->scale_num);
1023590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    fImageWidth = cinfo->output_width;
1024590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    fImageHeight = cinfo->output_height;
1025590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
1026590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    if (width) {
1027590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        *width = fImageWidth;
1028590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
1029590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    if (height) {
1030590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com        *height = fImageHeight;
1031590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    }
1032113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1033113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkDELETE(fImageIndex);
1034a1a515474de376708d8361d95af2f680ea01fe60scroggo@google.com    fImageIndex = imageIndex.detach();
1035113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1036113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    return true;
1037113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com}
1038113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
10397e6fceeffd250d99eff9f1dbb459a916ae4a754escroggo@google.combool SkJPEGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
1040113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (NULL == fImageIndex) {
1041113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
1042113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1043113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_decompress_struct* cinfo = fImageIndex->cinfo();
1044113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1045113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkIRect rect = SkIRect::MakeWH(fImageWidth, fImageHeight);
1046113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (!rect.intersect(region)) {
1047113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        // If the requested region is entirely outside the image return false
1048113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
1049113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1050113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1051113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1052113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    skjpeg_error_mgr errorManager;
1053590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    set_error_mgr(cinfo, &errorManager);
1054590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com
1055113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (setjmp(errorManager.fJmpBuf)) {
1056113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return false;
1057113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1058113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1059113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int requestedSampleSize = this->getSampleSize();
1060113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    cinfo->scale_denom = requestedSampleSize;
1061113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1062590a5af1210bb66e0087a654229763a1822d6d50scroggo@google.com    set_dct_method(*this, cinfo);
1063113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
10646c22573edb234ad14df947278cfed010669a39a7reed    const SkColorType colorType = this->getBitmapColorType(cinfo);
10656c22573edb234ad14df947278cfed010669a39a7reed    adjust_out_color_space_and_dither(cinfo, colorType, *this);
1066113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1067113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int startX = rect.fLeft;
1068113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int startY = rect.fTop;
1069113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int width = rect.width();
1070113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int height = rect.height();
1071113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1072113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    jpeg_init_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(),
1073113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                                 &startX, &startY, &width, &height);
1074113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int skiaSampleSize = recompute_sampleSize(requestedSampleSize, *cinfo);
1075113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int actualSampleSize = skiaSampleSize * (DCTSIZE / cinfo->min_DCT_scaled_size);
1076113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1077113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkScaledBitmapSampler sampler(width, height, skiaSampleSize);
1078113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1079113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkBitmap bitmap;
10805ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // Assume an A8 bitmap is not opaque to avoid the check of each
10815ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // individual pixel. It is very unlikely to be opaque, since
10825ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // an opaque A8 bitmap would not be very interesting.
10835ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    // Otherwise, a jpeg image is opaque.
10846c22573edb234ad14df947278cfed010669a39a7reed    bitmap.setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), colorType,
10856c22573edb234ad14df947278cfed010669a39a7reed                                     kAlpha_8_SkColorType == colorType ?
10866c22573edb234ad14df947278cfed010669a39a7reed                                         kPremul_SkAlphaType : kOpaque_SkAlphaType));
1087113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1088113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // Check ahead of time if the swap(dest, src) is possible or not.
1089113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // If yes, then we will stick to AllocPixelRef since it's cheaper with the
1090113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // swap happening. If no, then we will use alloc to allocate pixels to
1091113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // prevent garbage collection.
1092113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int w = rect.width() / actualSampleSize;
1093113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    int h = rect.height() / actualSampleSize;
1094113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    bool swapOnly = (rect == region) && bm->isNull() &&
1095113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                    (w == bitmap.width()) && (h == bitmap.height()) &&
1096113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                    ((startX - rect.x()) / actualSampleSize == 0) &&
1097113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                    ((startY - rect.y()) / actualSampleSize == 0);
1098113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (swapOnly) {
1099113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (!this->allocPixelRef(&bitmap, NULL)) {
1100113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return return_false(*cinfo, bitmap, "allocPixelRef");
1101113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1102113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    } else {
1103848250415eddc54075f7eb8795e8db79e749c6abreed        if (!bitmap.tryAllocPixels()) {
1104113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return return_false(*cinfo, bitmap, "allocPixels");
1105113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1106113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1107113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1108113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkAutoLockPixels alp(bitmap);
1109113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1110113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#ifdef ANDROID_RGB
1111113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    /* short-circuit the SkScaledBitmapSampler when possible, as this gives
1112113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com       a significant performance boost.
1113113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    */
1114113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (skiaSampleSize == 1 &&
11156c22573edb234ad14df947278cfed010669a39a7reed        ((kN32_SkColorType == colorType && cinfo->out_color_space == JCS_RGBA_8888) ||
11166c22573edb234ad14df947278cfed010669a39a7reed         (kRGB_565_SkColorType == colorType && cinfo->out_color_space == JCS_RGB_565)))
1117113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    {
1118113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        JSAMPLE* rowptr = (JSAMPLE*)bitmap.getPixels();
1119113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        INT32 const bpr = bitmap.rowBytes();
1120113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        int rowTotalCount = 0;
1121113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1122113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        while (rowTotalCount < height) {
1123113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            int rowCount = jpeg_read_tile_scanline(cinfo,
1124113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                                                   fImageIndex->huffmanIndex(),
1125113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                                                   &rowptr);
1126fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com            // if rowCount == 0, then we didn't get a scanline, so abort.
1127fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com            // onDecodeSubset() relies on onBuildTileIndex(), which
1128fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com            // needs a complete image to succeed.
1129113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            if (0 == rowCount) {
1130113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                return return_false(*cinfo, bitmap, "read_scanlines");
1131113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            }
1132113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            if (this->shouldCancelDecode()) {
1133113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                return return_false(*cinfo, bitmap, "shouldCancelDecode");
1134113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            }
1135113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            rowTotalCount += rowCount;
1136113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            rowptr += bpr;
1137113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1138113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1139113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (swapOnly) {
1140113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            bm->swap(bitmap);
1141113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        } else {
1142113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
1143113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                       region.width(), region.height(), startX, startY);
1144113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1145113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return true;
1146113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1147113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
1148113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1149113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // check for supported formats
1150113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    SkScaledBitmapSampler::SrcConfig sc;
11515ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    int srcBytesPerPixel;
11525ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com
11535ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    if (!get_src_config(*cinfo, &sc, &srcBytesPerPixel)) {
1154113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return return_false(*cinfo, *bm, "jpeg colorspace");
1155113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1156113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
11578d2392487cd97e68c0a71da9fd5d2b42ecac5ec8scroggo@google.com    if (!sampler.begin(&bitmap, sc, *this)) {
1158113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return return_false(*cinfo, bitmap, "sampler.begin");
1159113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1160113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
11615ee18dd20192d020884a95c7991c63ce33af3137scroggo@google.com    SkAutoMalloc  srcStorage(width * srcBytesPerPixel);
1162113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    uint8_t* srcRow = (uint8_t*)srcStorage.get();
1163113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1164113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    //  Possibly skip initial rows [sampler.srcY0]
1165113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow, sampler.srcY0())) {
1166113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        return return_false(*cinfo, bitmap, "skip rows");
1167113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1168113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1169113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    // now loop through scanlines until y == bitmap->height() - 1
1170113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    for (int y = 0;; y++) {
1171113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        JSAMPLE* rowptr = (JSAMPLE*)srcRow;
1172113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        int row_count = jpeg_read_tile_scanline(cinfo, fImageIndex->huffmanIndex(), &rowptr);
1173fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com        // if row_count == 0, then we didn't get a scanline, so abort.
1174fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com        // onDecodeSubset() relies on onBuildTileIndex(), which
1175fed3037217e51ecd2fcd794a4d35fc7f689dd23dhalcanary@google.com        // needs a complete image to succeed.
1176113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (0 == row_count) {
1177113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return return_false(*cinfo, bitmap, "read_scanlines");
1178113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1179113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (this->shouldCancelDecode()) {
1180113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return return_false(*cinfo, bitmap, "shouldCancelDecode");
1181113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1182113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1183113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (JCS_CMYK == cinfo->out_color_space) {
1184113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            convert_CMYK_to_RGB(srcRow, width);
1185113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1186113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1187113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        sampler.next(srcRow);
1188113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (bitmap.height() - 1 == y) {
1189113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            // we're done
1190113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            break;
1191113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1192113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1193113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        if (!skip_src_rows_tile(cinfo, fImageIndex->huffmanIndex(), srcRow,
1194113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                                sampler.srcDY() - 1)) {
1195113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            return return_false(*cinfo, bitmap, "skip rows");
1196113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        }
1197113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1198113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    if (swapOnly) {
1199113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        bm->swap(bitmap);
1200113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    } else {
1201113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        cropBitmap(bm, &bitmap, actualSampleSize, region.x(), region.y(),
1202113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com                   region.width(), region.height(), startX, startY);
1203113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
1204113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    return true;
1205113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com}
1206113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
1207113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
1208d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com///////////////////////////////////////////////////////////////////////////////
1209d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1210d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#include "SkColorPriv.h"
1211d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1212d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com// taken from jcolor.c in libjpeg
1213d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#if 0   // 16bit - precise but slow
1214d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYR     19595   // 0.299
1215d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYG     38470   // 0.587
1216d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYB      7471   // 0.114
1217d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1218d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUR    -11059   // -0.16874
1219d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUG    -21709   // -0.33126
1220d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUB     32768   // 0.5
1221d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1222d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVR     32768   // 0.5
1223d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVG    -27439   // -0.41869
1224d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVB     -5329   // -0.08131
1225d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1226d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CSHIFT  16
1227d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else      // 8bit - fast, slightly less precise
1228d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYR     77    // 0.299
1229d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYG     150    // 0.587
1230d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CYB      29    // 0.114
1231d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1232d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUR     -43    // -0.16874
1233d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUG    -85    // -0.33126
1234d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CUB     128    // 0.5
1235d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1236d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVR      128   // 0.5
1237d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVG     -107   // -0.41869
1238d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CVB      -21   // -0.08131
1239d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1240d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    #define CSHIFT  8
1241d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
1242d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1243d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void rgb2yuv_32(uint8_t dst[], SkPMColor c) {
1244d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int r = SkGetPackedR32(c);
1245d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int g = SkGetPackedG32(c);
1246d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int b = SkGetPackedB32(c);
1247d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1248d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  y = ( CYR*r + CYG*g + CYB*b ) >> CSHIFT;
1249d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  u = ( CUR*r + CUG*g + CUB*b ) >> CSHIFT;
1250d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  v = ( CVR*r + CVG*g + CVB*b ) >> CSHIFT;
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_4444(uint8_t dst[], U16CPU c) {
1258d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int r = SkGetPackedR4444(c);
1259d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int g = SkGetPackedG4444(c);
1260d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int b = SkGetPackedB4444(c);
1261d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1262d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  y = ( CYR*r + CYG*g + CYB*b ) >> (CSHIFT - 4);
1263d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  u = ( CUR*r + CUG*g + CUB*b ) >> (CSHIFT - 4);
1264d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  v = ( CVR*r + CVG*g + CVB*b ) >> (CSHIFT - 4);
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.comstatic void rgb2yuv_16(uint8_t dst[], U16CPU c) {
1272d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int r = SkGetPackedR16(c);
1273d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int g = SkGetPackedG16(c);
1274d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int b = SkGetPackedB16(c);
1275d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1276d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  y = ( 2*CYR*r + CYG*g + 2*CYB*b ) >> (CSHIFT - 2);
1277d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  u = ( 2*CUR*r + CUG*g + 2*CUB*b ) >> (CSHIFT - 2);
1278d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    int  v = ( 2*CVR*r + CVG*g + 2*CVB*b ) >> (CSHIFT - 2);
1279d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1280d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[0] = SkToU8(y);
1281d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[1] = SkToU8(u + 128);
1282d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    dst[2] = SkToU8(v + 128);
1283d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1284d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1285d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com///////////////////////////////////////////////////////////////////////////////
1286d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1287d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comtypedef void (*WriteScanline)(uint8_t* SK_RESTRICT dst,
1288d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                              const void* SK_RESTRICT src, int width,
1289d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                              const SkPMColor* SK_RESTRICT ctable);
1290d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1291d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_32_YUV(uint8_t* SK_RESTRICT dst,
1292d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                         const void* SK_RESTRICT srcRow, int width,
1293d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                         const SkPMColor*) {
1294d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    const uint32_t* SK_RESTRICT src = (const uint32_t*)srcRow;
1295d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    while (--width >= 0) {
1296d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV
1297d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        rgb2yuv_32(dst, *src++);
1298d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else
1299d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        uint32_t c = *src++;
1300d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[0] = SkGetPackedR32(c);
1301d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[1] = SkGetPackedG32(c);
1302d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[2] = SkGetPackedB32(c);
1303d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
1304d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst += 3;
1305d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
1306d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1307d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1308d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_4444_YUV(uint8_t* SK_RESTRICT dst,
1309d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                           const void* SK_RESTRICT srcRow, int width,
1310d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                           const SkPMColor*) {
1311d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    const SkPMColor16* SK_RESTRICT src = (const SkPMColor16*)srcRow;
1312d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    while (--width >= 0) {
1313d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV
1314d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        rgb2yuv_4444(dst, *src++);
1315d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else
1316d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        SkPMColor16 c = *src++;
1317d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[0] = SkPacked4444ToR32(c);
1318d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[1] = SkPacked4444ToG32(c);
1319d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[2] = SkPacked4444ToB32(c);
1320d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
1321d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst += 3;
1322d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
1323d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1324d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1325d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_16_YUV(uint8_t* SK_RESTRICT dst,
1326d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                         const void* SK_RESTRICT srcRow, int width,
1327d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                         const SkPMColor*) {
1328d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    const uint16_t* SK_RESTRICT src = (const uint16_t*)srcRow;
1329d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    while (--width >= 0) {
1330d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV
1331d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        rgb2yuv_16(dst, *src++);
1332d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else
1333d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        uint16_t c = *src++;
1334d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[0] = SkPacked16ToR32(c);
1335d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[1] = SkPacked16ToG32(c);
1336d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[2] = SkPacked16ToB32(c);
1337d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
1338d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst += 3;
1339d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
1340d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1341d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1342d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic void Write_Index_YUV(uint8_t* SK_RESTRICT dst,
1343d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                            const void* SK_RESTRICT srcRow, int width,
1344d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com                            const SkPMColor* SK_RESTRICT ctable) {
1345d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    const uint8_t* SK_RESTRICT src = (const uint8_t*)srcRow;
1346d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    while (--width >= 0) {
1347d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV
1348d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        rgb2yuv_32(dst, ctable[*src++]);
1349d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else
1350d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        uint32_t c = ctable[*src++];
1351d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[0] = SkGetPackedR32(c);
1352d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[1] = SkGetPackedG32(c);
1353d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst[2] = SkGetPackedB32(c);
1354d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
1355d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        dst += 3;
1356d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
1357d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1358d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1359d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comstatic WriteScanline ChooseWriter(const SkBitmap& bm) {
13606c22573edb234ad14df947278cfed010669a39a7reed    switch (bm.colorType()) {
13616c22573edb234ad14df947278cfed010669a39a7reed        case kN32_SkColorType:
1362d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return Write_32_YUV;
13636c22573edb234ad14df947278cfed010669a39a7reed        case kRGB_565_SkColorType:
1364d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return Write_16_YUV;
13656c22573edb234ad14df947278cfed010669a39a7reed        case kARGB_4444_SkColorType:
1366d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return Write_4444_YUV;
13676c22573edb234ad14df947278cfed010669a39a7reed        case kIndex_8_SkColorType:
1368d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return Write_Index_YUV;
1369d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        default:
1370d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return NULL;
1371d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
1372d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1373d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1374d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comclass SkJPEGImageEncoder : public SkImageEncoder {
1375d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.comprotected:
1376d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) {
1377d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef TIME_ENCODE
1378113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com        SkAutoTime atm("JPEG Encode");
1379d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
1380d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1381d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        SkAutoLockPixels alp(bm);
1382d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (NULL == bm.getPixels()) {
1383d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return false;
1384d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
1385d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1386d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_compress_struct    cinfo;
1387d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        skjpeg_error_mgr        sk_err;
1388d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        skjpeg_destination_mgr  sk_wstream(stream);
1389d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1390d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        // allocate these before set call setjmp
1391d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        SkAutoMalloc    oneRow;
1392d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        SkAutoLockColors ctLocker;
1393d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1394d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.err = jpeg_std_error(&sk_err);
1395d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        sk_err.error_exit = skjpeg_error_exit;
1396d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        if (setjmp(sk_err.fJmpBuf)) {
1397d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            return false;
1398d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
1399d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
14008d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com        // Keep after setjmp or mark volatile.
14018d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com        const WriteScanline writer = ChooseWriter(bm);
14028d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com        if (NULL == writer) {
14038d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com            return false;
14048d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com        }
14058d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com
14068d725b25a6287e49e2b0cb2965871186e716ededmtklein@google.com        jpeg_create_compress(&cinfo);
1407d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.dest = &sk_wstream;
1408d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.image_width = bm.width();
1409d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.image_height = bm.height();
1410d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.input_components = 3;
1411d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#ifdef WE_CONVERT_TO_YUV
1412d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.in_color_space = JCS_YCbCr;
1413d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#else
1414d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.in_color_space = JCS_RGB;
1415d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com#endif
1416d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.input_gamma = 1;
1417d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1418d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_set_defaults(&cinfo);
1419d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
1420b7decc539887069f3fb0f9fc80d543b437bdd624scroggo@google.com#ifdef DCT_IFAST_SUPPORTED
1421d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        cinfo.dct_method = JDCT_IFAST;
1422b7decc539887069f3fb0f9fc80d543b437bdd624scroggo@google.com#endif
1423d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1424d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_start_compress(&cinfo, TRUE);
1425d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1426d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        const int       width = bm.width();
14278570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.com        uint8_t*        oneRowP = (uint8_t*)oneRow.reset(width * 3);
1428d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1429d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        const SkPMColor* colors = ctLocker.lockColors(bm);
1430d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        const void*      srcRow = bm.getPixels();
1431d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1432d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        while (cinfo.next_scanline < cinfo.image_height) {
1433d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            JSAMPROW row_pointer[1];    /* pointer to JSAMPLE row[s] */
1434d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1435d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            writer(oneRowP, srcRow, width, colors);
1436d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            row_pointer[0] = oneRowP;
1437d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            (void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
1438d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com            srcRow = (const void*)((const char*)srcRow + bm.rowBytes());
1439d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        }
1440d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1441d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_finish_compress(&cinfo);
1442d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        jpeg_destroy_compress(&cinfo);
1443d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1444d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com        return true;
1445d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
1446d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com};
1447d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1448d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com///////////////////////////////////////////////////////////////////////////////
1449ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.comDEFINE_DECODER_CREATOR(JPEGImageDecoder);
1450ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.comDEFINE_ENCODER_CREATOR(JPEGImageEncoder);
1451ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.com///////////////////////////////////////////////////////////////////////////////
1452d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1453b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.comstatic bool is_jpeg(SkStreamRewindable* stream) {
1454ec51cb863409e238b40c5beef458669d9a824481robertphillips@google.com    static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF };
1455d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    static const size_t HEADER_SIZE = sizeof(gHeader);
1456d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1457d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    char buffer[HEADER_SIZE];
1458d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    size_t len = stream->read(buffer, HEADER_SIZE);
1459d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1460d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (len != HEADER_SIZE) {
146139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com        return false;   // can't read enough
1462d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
1463d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    if (memcmp(buffer, gHeader, HEADER_SIZE)) {
146439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com        return false;
146539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    }
146639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    return true;
146739edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com}
146839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com
1469b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.com
1470b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.comstatic SkImageDecoder* sk_libjpeg_dfactory(SkStreamRewindable* stream) {
147139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    if (is_jpeg(stream)) {
147239edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com        return SkNEW(SkJPEGImageDecoder);
147339edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    }
147439edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    return NULL;
147539edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com}
147639edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com
1477b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.comstatic SkImageDecoder::Format get_format_jpeg(SkStreamRewindable* stream) {
147839edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    if (is_jpeg(stream)) {
147939edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com        return SkImageDecoder::kJPEG_Format;
1480d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    }
148139edf4cd94e6fbeb8c1187a588b314e9795c81e4scroggo@google.com    return SkImageDecoder::kUnknown_Format;
1482d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1483d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
14848570b5c8695052378491b0c61e745d736fe85c8drobertphillips@google.comstatic SkImageEncoder* sk_libjpeg_efactory(SkImageEncoder::Type t) {
1485d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com    return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL;
1486d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com}
1487d33b26efe40565451cf5379cba52beb933f82925tomhudson@google.com
1488bd6343b1d60d2a85e930f33f4b06b4502b3e8caamtklein@google.comstatic SkImageDecoder_DecodeReg gDReg(sk_libjpeg_dfactory);
1489bd6343b1d60d2a85e930f33f4b06b4502b3e8caamtklein@google.comstatic SkImageDecoder_FormatReg gFormatReg(get_format_jpeg);
1490bd6343b1d60d2a85e930f33f4b06b4502b3e8caamtklein@google.comstatic SkImageEncoder_EncodeReg gEReg(sk_libjpeg_efactory);
1491