| Index: src/images/SkImageDecoder_libjpeg.cpp
 | 
| diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp
 | 
| index 937fe903dc1bd4130a65a1479f0fb29160cc5d07..99401e6b627cdc9fd023b304a6c40789c3fbec3d 100644
 | 
| --- a/src/images/SkImageDecoder_libjpeg.cpp
 | 
| +++ b/src/images/SkImageDecoder_libjpeg.cpp
 | 
| @@ -239,9 +239,6 @@
 | 
|      virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& rect) SK_OVERRIDE;
 | 
|  #endif
 | 
|      virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
 | 
| -    virtual bool onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3],
 | 
| -                                    void* planes[3], size_t rowBytes[3],
 | 
| -                                    SkYUVColorSpace* colorSpace) SK_OVERRIDE;
 | 
|  
 | 
|  private:
 | 
|  #ifdef SK_BUILD_FOR_ANDROID
 | 
| @@ -328,19 +325,14 @@
 | 
|  // This guy exists just to aid in debugging, as it allows debuggers to just
 | 
|  // set a break-point in one place to see all error exists.
 | 
|  static bool return_false(const jpeg_decompress_struct& cinfo,
 | 
| -                         int width, int height, const char caller[]) {
 | 
| +                         const SkBitmap& bm, const char caller[]) {
 | 
|      if (!(c_suppressJPEGImageDecoderErrors)) {
 | 
|          char buffer[JMSG_LENGTH_MAX];
 | 
|          cinfo.err->format_message((const j_common_ptr)&cinfo, buffer);
 | 
|          SkDebugf("libjpeg error %d <%s> from %s [%d %d]\n",
 | 
| -                 cinfo.err->msg_code, buffer, caller, width, height);
 | 
| +                 cinfo.err->msg_code, buffer, caller, bm.width(), bm.height());
 | 
|      }
 | 
|      return false;   // must always return false
 | 
| -}
 | 
| -
 | 
| -static bool return_false(const jpeg_decompress_struct& cinfo,
 | 
| -                         const SkBitmap& bm, const char caller[]) {
 | 
| -    return return_false(cinfo, bm.width(), bm.height(), caller);
 | 
|  }
 | 
|  
 | 
|  // Convert a scanline of CMYK samples to RGBX in place. Note that this
 | 
| @@ -734,246 +726,6 @@
 | 
|      return true;
 | 
|  }
 | 
|  
 | 
| -enum SizeType {
 | 
| -    kSizeForMemoryAllocation_SizeType,
 | 
| -    kActualSize_SizeType
 | 
| -};
 | 
| -
 | 
| -static SkISize compute_yuv_size(const jpeg_decompress_struct& info, int component,
 | 
| -                                SizeType sizeType) {
 | 
| -    if (sizeType == kSizeForMemoryAllocation_SizeType) {
 | 
| -        return SkISize::Make(info.cur_comp_info[component]->width_in_blocks * DCTSIZE,
 | 
| -                             info.cur_comp_info[component]->height_in_blocks * DCTSIZE);
 | 
| -    }
 | 
| -    return SkISize::Make(info.cur_comp_info[component]->downsampled_width,
 | 
| -                         info.cur_comp_info[component]->downsampled_height);
 | 
| -}
 | 
| -
 | 
| -// Enum for YUV decoding
 | 
| -enum YUVSubsampling {
 | 
| -    kUNKNOWN_YUVSubsampling,
 | 
| -    k410_YUVSubsampling,
 | 
| -    k411_YUVSubsampling,
 | 
| -    k420_YUVSubsampling,
 | 
| -    k422_YUVSubsampling,
 | 
| -    k440_YUVSubsampling,
 | 
| -    k444_YUVSubsampling
 | 
| -};
 | 
| -
 | 
| -static YUVSubsampling yuv_subsampling(const jpeg_decompress_struct& info) {
 | 
| -    if ((DCTSIZE == 8)
 | 
| -        && (info.num_components == 3)
 | 
| -        && (info.comps_in_scan >= info.num_components)
 | 
| -        && (info.scale_denom <= 8)
 | 
| -        && (info.cur_comp_info[0])
 | 
| -        && (info.cur_comp_info[1])
 | 
| -        && (info.cur_comp_info[2])
 | 
| -        && (info.cur_comp_info[1]->h_samp_factor == 1)
 | 
| -        && (info.cur_comp_info[1]->v_samp_factor == 1)
 | 
| -        && (info.cur_comp_info[2]->h_samp_factor == 1)
 | 
| -        && (info.cur_comp_info[2]->v_samp_factor == 1))
 | 
| -    {
 | 
| -        int h = info.cur_comp_info[0]->h_samp_factor;
 | 
| -        int v = info.cur_comp_info[0]->v_samp_factor;
 | 
| -        // 4:4:4 : (h == 1) && (v == 1)
 | 
| -        // 4:4:0 : (h == 1) && (v == 2)
 | 
| -        // 4:2:2 : (h == 2) && (v == 1)
 | 
| -        // 4:2:0 : (h == 2) && (v == 2)
 | 
| -        // 4:1:1 : (h == 4) && (v == 1)
 | 
| -        // 4:1:0 : (h == 4) && (v == 2)
 | 
| -        if (v == 1) {
 | 
| -            switch (h) {
 | 
| -                case 1:
 | 
| -                    return k444_YUVSubsampling;
 | 
| -                case 2:
 | 
| -                    return k422_YUVSubsampling;
 | 
| -                case 4:
 | 
| -                    return k411_YUVSubsampling;
 | 
| -                default:
 | 
| -                    break;
 | 
| -            }
 | 
| -        } else if (v == 2) {
 | 
| -            switch (h) {
 | 
| -                case 1:
 | 
| -                    return k440_YUVSubsampling;
 | 
| -                case 2:
 | 
| -                    return k420_YUVSubsampling;
 | 
| -                case 4:
 | 
| -                    return k410_YUVSubsampling;
 | 
| -                default:
 | 
| -                    break;
 | 
| -            }
 | 
| -        }
 | 
| -    }
 | 
| -
 | 
| -    return kUNKNOWN_YUVSubsampling;
 | 
| -}
 | 
| -
 | 
| -static void update_components_sizes(const jpeg_decompress_struct& cinfo, SkISize componentSizes[3],
 | 
| -                                    SizeType sizeType) {
 | 
| -    for (int i = 0; i < 3; ++i) {
 | 
| -        componentSizes[i] = compute_yuv_size(cinfo, i, sizeType);
 | 
| -    }
 | 
| -}
 | 
| -
 | 
| -static bool output_raw_data(jpeg_decompress_struct& cinfo, void* planes[3], size_t rowBytes[3]) {
 | 
| -    // U size and V size have to be the same if we're calling output_raw_data()
 | 
| -    SkISize uvSize = compute_yuv_size(cinfo, 1, kSizeForMemoryAllocation_SizeType);
 | 
| -    SkASSERT(uvSize == compute_yuv_size(cinfo, 2, kSizeForMemoryAllocation_SizeType));
 | 
| -
 | 
| -    JSAMPARRAY bufferraw[3];
 | 
| -    JSAMPROW bufferraw2[32];
 | 
| -    bufferraw[0] = &bufferraw2[0]; // Y channel rows (8 or 16)
 | 
| -    bufferraw[1] = &bufferraw2[16]; // U channel rows (8)
 | 
| -    bufferraw[2] = &bufferraw2[24]; // V channel rows (8)
 | 
| -    int yWidth = cinfo.output_width;
 | 
| -    int yHeight = cinfo.output_height;
 | 
| -    int yMaxH = yHeight - 1;
 | 
| -    int v = cinfo.cur_comp_info[0]->v_samp_factor;
 | 
| -    int uvMaxH = uvSize.height() - 1;
 | 
| -    JSAMPROW outputY = static_cast<JSAMPROW>(planes[0]);
 | 
| -    JSAMPROW outputU = static_cast<JSAMPROW>(planes[1]);
 | 
| -    JSAMPROW outputV = static_cast<JSAMPROW>(planes[2]);
 | 
| -    size_t rowBytesY = rowBytes[0];
 | 
| -    size_t rowBytesU = rowBytes[1];
 | 
| -    size_t rowBytesV = rowBytes[2];
 | 
| -
 | 
| -    int yScanlinesToRead = DCTSIZE * v;
 | 
| -    SkAutoMalloc lastRowStorage(yWidth * 8);
 | 
| -    JSAMPROW yLastRow = (JSAMPROW)lastRowStorage.get();
 | 
| -    JSAMPROW uLastRow = yLastRow + 2 * yWidth;
 | 
| -    JSAMPROW vLastRow = uLastRow + 2 * yWidth;
 | 
| -    JSAMPROW dummyRow = vLastRow + 2 * yWidth;
 | 
| -
 | 
| -    while (cinfo.output_scanline < cinfo.output_height) {
 | 
| -        // Request 8 or 16 scanlines: returns 0 or more scanlines.
 | 
| -        bool hasYLastRow(false), hasUVLastRow(false);
 | 
| -        // Assign 8 or 16 rows of memory to read the Y channel.
 | 
| -        for (int i = 0; i < yScanlinesToRead; ++i) {
 | 
| -            int scanline = (cinfo.output_scanline + i);
 | 
| -            if (scanline < yMaxH) {
 | 
| -                bufferraw2[i] = &outputY[scanline * rowBytesY];
 | 
| -            } else if (scanline == yMaxH) {
 | 
| -                bufferraw2[i] = yLastRow;
 | 
| -                hasYLastRow = true;
 | 
| -            } else {
 | 
| -                bufferraw2[i] = dummyRow;
 | 
| -            }
 | 
| -        }
 | 
| -        int scaledScanline = cinfo.output_scanline / v;
 | 
| -        // Assign 8 rows of memory to read the U and V channels.
 | 
| -        for (int i = 0; i < 8; ++i) {
 | 
| -            int scanline = (scaledScanline + i);
 | 
| -            if (scanline < uvMaxH) {
 | 
| -                bufferraw2[16 + i] = &outputU[scanline * rowBytesU];
 | 
| -                bufferraw2[24 + i] = &outputV[scanline * rowBytesV];
 | 
| -            } else if (scanline == uvMaxH) {
 | 
| -                bufferraw2[16 + i] = uLastRow;
 | 
| -                bufferraw2[24 + i] = vLastRow;
 | 
| -                hasUVLastRow = true;
 | 
| -            } else {
 | 
| -                bufferraw2[16 + i] = dummyRow;
 | 
| -                bufferraw2[24 + i] = dummyRow;
 | 
| -            }
 | 
| -        }
 | 
| -        JDIMENSION scanlinesRead = jpeg_read_raw_data(&cinfo, bufferraw, yScanlinesToRead);
 | 
| -
 | 
| -        if (scanlinesRead == 0)
 | 
| -            return false;
 | 
| -
 | 
| -        if (hasYLastRow) {
 | 
| -            memcpy(&outputY[yMaxH * rowBytesY], yLastRow, yWidth);
 | 
| -        }
 | 
| -        if (hasUVLastRow) {
 | 
| -            memcpy(&outputU[uvMaxH * rowBytesU], uLastRow, uvSize.width());
 | 
| -            memcpy(&outputV[uvMaxH * rowBytesV], vLastRow, uvSize.width());
 | 
| -        }
 | 
| -    }
 | 
| -
 | 
| -    cinfo.output_scanline = SkMin32(cinfo.output_scanline, cinfo.output_height);
 | 
| -
 | 
| -    return true;
 | 
| -}
 | 
| -
 | 
| -bool SkJPEGImageDecoder::onDecodeYUV8Planes(SkStream* stream, SkISize componentSizes[3],
 | 
| -                                            void* planes[3], size_t rowBytes[3],
 | 
| -                                            SkYUVColorSpace* colorSpace) {
 | 
| -#ifdef TIME_DECODE
 | 
| -    SkAutoTime atm("JPEG YUV8 Decode");
 | 
| -#endif
 | 
| -
 | 
| -    if (this->getSampleSize() != 1) {
 | 
| -        return false; // Resizing not supported
 | 
| -    }
 | 
| -
 | 
| -    JPEGAutoClean autoClean;
 | 
| -
 | 
| -    jpeg_decompress_struct  cinfo;
 | 
| -    skjpeg_source_mgr       srcManager(stream, this);
 | 
| -
 | 
| -    skjpeg_error_mgr errorManager;
 | 
| -    set_error_mgr(&cinfo, &errorManager);
 | 
| -
 | 
| -    // All objects need to be instantiated before this setjmp call so that
 | 
| -    // they will be cleaned up properly if an error occurs.
 | 
| -    if (setjmp(errorManager.fJmpBuf)) {
 | 
| -        return return_false(cinfo, 0, 0, "setjmp");
 | 
| -    }
 | 
| -
 | 
| -    initialize_info(&cinfo, &srcManager);
 | 
| -    autoClean.set(&cinfo);
 | 
| -
 | 
| -    int status = jpeg_read_header(&cinfo, true);
 | 
| -    if (status != JPEG_HEADER_OK) {
 | 
| -        return return_false(cinfo, 0, 0, "read_header");
 | 
| -    }
 | 
| -
 | 
| -    if (cinfo.jpeg_color_space != JCS_YCbCr) {
 | 
| -        // It's not an error to not be encoded in YUV, so no need to use return_false()
 | 
| -        return false;
 | 
| -    }
 | 
| -
 | 
| -    cinfo.out_color_space = JCS_YCbCr;
 | 
| -    cinfo.raw_data_out = TRUE;
 | 
| -
 | 
| -    if (!planes || !planes[0] || !rowBytes || !rowBytes[0]) { // Compute size only
 | 
| -        update_components_sizes(cinfo, componentSizes, kSizeForMemoryAllocation_SizeType);
 | 
| -        return true;
 | 
| -    }
 | 
| -
 | 
| -    set_dct_method(*this, &cinfo);
 | 
| -
 | 
| -    SkASSERT(1 == cinfo.scale_num);
 | 
| -    cinfo.scale_denom = 1;
 | 
| -
 | 
| -    turn_off_visual_optimizations(&cinfo);
 | 
| -
 | 
| -#ifdef ANDROID_RGB
 | 
| -    cinfo.dither_mode = JDITHER_NONE;
 | 
| -#endif
 | 
| -
 | 
| -    /*  image_width and image_height are the original dimensions, available
 | 
| -        after jpeg_read_header(). To see the scaled dimensions, we have to call
 | 
| -        jpeg_start_decompress(), and then read output_width and output_height.
 | 
| -    */
 | 
| -    if (!jpeg_start_decompress(&cinfo)) {
 | 
| -        return return_false(cinfo, 0, 0, "start_decompress");
 | 
| -    }
 | 
| -
 | 
| -    if (!output_raw_data(cinfo, planes, rowBytes)) {
 | 
| -        return return_false(cinfo, 0, 0, "output_raw_data");
 | 
| -    }
 | 
| -
 | 
| -    update_components_sizes(cinfo, componentSizes, kActualSize_SizeType);
 | 
| -    jpeg_finish_decompress(&cinfo);
 | 
| -
 | 
| -    if (NULL != colorSpace) {
 | 
| -        *colorSpace = kJPEG_SkYUVColorSpace;
 | 
| -    }
 | 
| -
 | 
| -    return true;
 | 
| -}
 | 
| -
 | 
|  #ifdef SK_BUILD_FOR_ANDROID
 | 
|  bool SkJPEGImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int *width, int *height) {
 | 
|  
 | 
| 
 |