Commit 04365d3e authored by sugoi@chromium.org's avatar sugoi@chromium.org

Non DCTSIZE multiple width support for JPEG YUV decoding

Since jpeg_read_raw_data reads blocks of memory, we have to make sure
that the memory allocated is a multiple of the DCT block size. For
example, if DCTSIZE is 8, which is generally the case, we have to make
sure that the allocated memory to read the raw JPEG data has a width
rounded up to the next multiple of 8 (if it's not already a multiple
of 8) to avoid writing data out of the bounds of the memory. If this
isn't done properly, the end of some decode image lines can overwrite
the beginning of the following lines.

BUG=411189

Review URL: https://codereview.chromium.org/544323002

git-svn-id: svn://svn.chromium.org/blink/trunk@181749 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent df62f034
...@@ -91,7 +91,7 @@ bool DecodingImageGenerator::onGetYUV8Planes(SkISize sizes[3], void* planes[3], ...@@ -91,7 +91,7 @@ bool DecodingImageGenerator::onGetYUV8Planes(SkISize sizes[3], void* planes[3],
TRACE_EVENT0("blink", "DecodingImageGenerator::onGetYUV8Planes"); TRACE_EVENT0("blink", "DecodingImageGenerator::onGetYUV8Planes");
PlatformInstrumentation::willDecodeLazyPixelRef(m_generationId); PlatformInstrumentation::willDecodeLazyPixelRef(m_generationId);
bool decoded = m_frameGenerator->decodeToYUV(planes, rowBytes); bool decoded = m_frameGenerator->decodeToYUV(sizes, planes, rowBytes);
PlatformInstrumentation::didDecodeLazyPixelRef(); PlatformInstrumentation::didDecodeLazyPixelRef();
return decoded; return decoded;
} }
......
...@@ -69,6 +69,22 @@ private: ...@@ -69,6 +69,22 @@ private:
size_t m_rowBytes; size_t m_rowBytes;
}; };
static bool updateYUVComponentSizes(const ImageDecoder* decoder, SkISize componentSizes[3], ImageDecoder::SizeType sizeType)
{
// canDecodeToYUV() has to be called AFTER isSizeAvailable(),
// otherwise the output color space may not be set in the decoder.
if (!decoder->isSizeAvailable() || !decoder->canDecodeToYUV())
return false;
IntSize size = decoder->decodedYUVSize(0, sizeType);
componentSizes[0].set(size.width(), size.height());
size = decoder->decodedYUVSize(1, sizeType);
componentSizes[1].set(size.width(), size.height());
size = decoder->decodedYUVSize(2, sizeType);
componentSizes[2].set(size.width(), size.height());
return true;
}
ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, PassRefPtr<SharedBuffer> data, bool allDataReceived, bool isMultiFrame) ImageFrameGenerator::ImageFrameGenerator(const SkISize& fullSize, PassRefPtr<SharedBuffer> data, bool allDataReceived, bool isMultiFrame)
: m_fullSize(fullSize) : m_fullSize(fullSize)
, m_isMultiFrame(isMultiFrame) , m_isMultiFrame(isMultiFrame)
...@@ -133,7 +149,7 @@ bool ImageFrameGenerator::decodeAndScale(const SkImageInfo& info, size_t index, ...@@ -133,7 +149,7 @@ bool ImageFrameGenerator::decodeAndScale(const SkImageInfo& info, size_t index,
return result; return result;
} }
bool ImageFrameGenerator::decodeToYUV(void* planes[3], size_t rowBytes[3]) bool ImageFrameGenerator::decodeToYUV(SkISize componentSizes[3], void* planes[3], size_t rowBytes[3])
{ {
// This method is called to populate a discardable memory owned by Skia. // This method is called to populate a discardable memory owned by Skia.
...@@ -165,6 +181,10 @@ bool ImageFrameGenerator::decodeToYUV(void* planes[3], size_t rowBytes[3]) ...@@ -165,6 +181,10 @@ bool ImageFrameGenerator::decodeToYUV(void* planes[3], size_t rowBytes[3])
OwnPtr<ImagePlanes> imagePlanes = adoptPtr(new ImagePlanes(planes, rowBytes)); OwnPtr<ImagePlanes> imagePlanes = adoptPtr(new ImagePlanes(planes, rowBytes));
decoder->setImagePlanes(imagePlanes.release()); decoder->setImagePlanes(imagePlanes.release());
bool sizeUpdated = updateYUVComponentSizes(decoder.get(), componentSizes, ImageDecoder::ActualSize);
RELEASE_ASSERT(sizeUpdated);
bool yuvDecoded = decoder->decodeToYUV(); bool yuvDecoded = decoder->decodeToYUV();
if (yuvDecoded) if (yuvDecoded)
setHasAlpha(0, false); // YUV is always opaque setHasAlpha(0, false); // YUV is always opaque
...@@ -314,18 +334,7 @@ bool ImageFrameGenerator::getYUVComponentSizes(SkISize componentSizes[3]) ...@@ -314,18 +334,7 @@ bool ImageFrameGenerator::getYUVComponentSizes(SkISize componentSizes[3])
OwnPtr<ImagePlanes> dummyImagePlanes = adoptPtr(new ImagePlanes); OwnPtr<ImagePlanes> dummyImagePlanes = adoptPtr(new ImagePlanes);
decoder->setImagePlanes(dummyImagePlanes.release()); decoder->setImagePlanes(dummyImagePlanes.release());
// canDecodeToYUV() has to be called AFTER isSizeAvailable(), return updateYUVComponentSizes(decoder.get(), componentSizes, ImageDecoder::SizeForMemoryAllocation);
// otherwise the output color space may not be set in the decoder.
if (!decoder->isSizeAvailable() || !decoder->canDecodeToYUV())
return false;
IntSize size = decoder->decodedYUVSize(0);
componentSizes[0].set(size.width(), size.height());
size = decoder->decodedYUVSize(1);
componentSizes[1].set(size.width(), size.height());
size = decoder->decodedYUVSize(2);
componentSizes[2].set(size.width(), size.height());
return true;
} }
} // namespace blink } // namespace blink
...@@ -72,7 +72,7 @@ public: ...@@ -72,7 +72,7 @@ public:
bool decodeAndScale(const SkImageInfo&, size_t index, void* pixels, size_t rowBytes); bool decodeAndScale(const SkImageInfo&, size_t index, void* pixels, size_t rowBytes);
// Decodes YUV components directly into the provided memory planes. // Decodes YUV components directly into the provided memory planes.
bool decodeToYUV(void* planes[3], size_t rowBytes[3]); bool decodeToYUV(SkISize componentSizes[3], void* planes[3], size_t rowBytes[3]);
void setData(PassRefPtr<SharedBuffer>, bool allDataReceived); void setData(PassRefPtr<SharedBuffer>, bool allDataReceived);
......
...@@ -69,6 +69,8 @@ private: ...@@ -69,6 +69,8 @@ private:
class PLATFORM_EXPORT ImageDecoder { class PLATFORM_EXPORT ImageDecoder {
WTF_MAKE_NONCOPYABLE(ImageDecoder); WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_NONCOPYABLE(ImageDecoder); WTF_MAKE_FAST_ALLOCATED;
public: public:
enum SizeType { ActualSize, SizeForMemoryAllocation };
static const size_t noDecodedImageByteLimit = blink::Platform::noDecodedImageByteLimit; static const size_t noDecodedImageByteLimit = blink::Platform::noDecodedImageByteLimit;
ImageDecoder(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption, size_t maxDecodedBytes) ImageDecoder(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption, size_t maxDecodedBytes)
...@@ -120,7 +122,7 @@ public: ...@@ -120,7 +122,7 @@ public:
// Decoders which support YUV decoding can override this to // Decoders which support YUV decoding can override this to
// give potentially different sizes per component. // give potentially different sizes per component.
virtual IntSize decodedYUVSize(int component) const { return decodedSize(); } virtual IntSize decodedYUVSize(int component, SizeType) const { return decodedSize(); }
// This will only differ from size() for ICO (where each frame is a // This will only differ from size() for ICO (where each frame is a
// different icon) or other formats where different frames are different // different icon) or other formats where different frames are different
......
...@@ -252,11 +252,12 @@ static void readColorProfile(jpeg_decompress_struct* info, ColorProfile& colorPr ...@@ -252,11 +252,12 @@ static void readColorProfile(jpeg_decompress_struct* info, ColorProfile& colorPr
} }
#endif #endif
static IntSize computeUVSize(const jpeg_decompress_struct* info) static IntSize computeYUVSize(const jpeg_decompress_struct* info, int component, ImageDecoder::SizeType sizeType)
{ {
int h = info->cur_comp_info[0]->h_samp_factor; if (sizeType == ImageDecoder::SizeForMemoryAllocation) {
int v = info->cur_comp_info[0]->v_samp_factor; return IntSize(info->cur_comp_info[component]->width_in_blocks * DCTSIZE, info->cur_comp_info[component]->height_in_blocks * DCTSIZE);
return IntSize((info->output_width + h - 1) / h, (info->output_height + v - 1) / v); }
return IntSize(info->cur_comp_info[component]->downsampled_width, info->cur_comp_info[component]->downsampled_height);
} }
static yuv_subsampling yuvSubsampling(const jpeg_decompress_struct& info) static yuv_subsampling yuvSubsampling(const jpeg_decompress_struct& info)
...@@ -475,6 +476,7 @@ public: ...@@ -475,6 +476,7 @@ public:
if (overrideColorSpace == JCS_YCbCr) { if (overrideColorSpace == JCS_YCbCr) {
m_info.out_color_space = JCS_YCbCr; m_info.out_color_space = JCS_YCbCr;
m_info.raw_data_out = TRUE; m_info.raw_data_out = TRUE;
m_uvSize = computeYUVSize(&m_info, 1, ImageDecoder::SizeForMemoryAllocation); // U size and V size have to be the same if we got here
} }
// Don't allocate a giant and superfluous memory buffer when the // Don't allocate a giant and superfluous memory buffer when the
...@@ -596,6 +598,7 @@ public: ...@@ -596,6 +598,7 @@ public:
jpeg_decompress_struct* info() { return &m_info; } jpeg_decompress_struct* info() { return &m_info; }
JSAMPARRAY samples() const { return m_samples; } JSAMPARRAY samples() const { return m_samples; }
JPEGImageDecoder* decoder() { return m_decoder; } JPEGImageDecoder* decoder() { return m_decoder; }
IntSize uvSize() const { return m_uvSize; }
#if USE(QCMSLIB) #if USE(QCMSLIB)
qcms_transform* colorTransform() const { return m_transform; } qcms_transform* colorTransform() const { return m_transform; }
...@@ -638,6 +641,8 @@ private: ...@@ -638,6 +641,8 @@ private:
JSAMPARRAY m_samples; JSAMPARRAY m_samples;
IntSize m_uvSize;
#if USE(QCMSLIB) #if USE(QCMSLIB)
qcms_transform* m_transform; qcms_transform* m_transform;
#endif #endif
...@@ -712,16 +717,13 @@ void JPEGImageDecoder::setDecodedSize(unsigned width, unsigned height) ...@@ -712,16 +717,13 @@ void JPEGImageDecoder::setDecodedSize(unsigned width, unsigned height)
m_decodedSize = IntSize(width, height); m_decodedSize = IntSize(width, height);
} }
IntSize JPEGImageDecoder::decodedYUVSize(int component) const IntSize JPEGImageDecoder::decodedYUVSize(int component, ImageDecoder::SizeType sizeType) const
{ {
if (((component == 1) || (component == 2)) && m_reader.get()) { // Asking for U or V ASSERT((component >= 0) && (component <= 2) && m_reader);
const jpeg_decompress_struct* info = m_reader->info(); const jpeg_decompress_struct* info = m_reader->info();
if (info && (info->out_color_space == JCS_YCbCr)) {
return computeUVSize(info);
}
}
return m_decodedSize; ASSERT(info->out_color_space == JCS_YCbCr);
return computeYUVSize(info, component, sizeType);
} }
unsigned JPEGImageDecoder::desiredScaleNumerator() const unsigned JPEGImageDecoder::desiredScaleNumerator() const
...@@ -855,7 +857,7 @@ static bool outputRawData(JPEGImageReader* reader, ImagePlanes* imagePlanes) ...@@ -855,7 +857,7 @@ static bool outputRawData(JPEGImageReader* reader, ImagePlanes* imagePlanes)
int yHeight = info->output_height; int yHeight = info->output_height;
int yMaxH = yHeight - 1; int yMaxH = yHeight - 1;
int v = info->cur_comp_info[0]->v_samp_factor; int v = info->cur_comp_info[0]->v_samp_factor;
IntSize uvSize = computeUVSize(info); IntSize uvSize = reader->uvSize();
int uvMaxH = uvSize.height() - 1; int uvMaxH = uvSize.height() - 1;
JSAMPROW outputY = static_cast<JSAMPROW>(imagePlanes->plane(0)); JSAMPROW outputY = static_cast<JSAMPROW>(imagePlanes->plane(0));
JSAMPROW outputU = static_cast<JSAMPROW>(imagePlanes->plane(1)); JSAMPROW outputU = static_cast<JSAMPROW>(imagePlanes->plane(1));
......
...@@ -48,7 +48,7 @@ public: ...@@ -48,7 +48,7 @@ public:
virtual bool isSizeAvailable() OVERRIDE; virtual bool isSizeAvailable() OVERRIDE;
virtual bool hasColorProfile() const OVERRIDE { return m_hasColorProfile; } virtual bool hasColorProfile() const OVERRIDE { return m_hasColorProfile; }
virtual IntSize decodedSize() const OVERRIDE { return m_decodedSize; } virtual IntSize decodedSize() const OVERRIDE { return m_decodedSize; }
virtual IntSize decodedYUVSize(int component) const OVERRIDE; virtual IntSize decodedYUVSize(int component, SizeType) const OVERRIDE;
virtual bool setSize(unsigned width, unsigned height) OVERRIDE; virtual bool setSize(unsigned width, unsigned height) OVERRIDE;
virtual ImageFrame* frameBufferAtIndex(size_t) OVERRIDE; virtual ImageFrame* frameBufferAtIndex(size_t) OVERRIDE;
// CAUTION: setFailed() deletes |m_reader|. Be careful to avoid // CAUTION: setFailed() deletes |m_reader|. Be careful to avoid
......
...@@ -93,9 +93,9 @@ void readYUV(size_t maxDecodedBytes, unsigned* outputYWidth, unsigned* outputYHe ...@@ -93,9 +93,9 @@ void readYUV(size_t maxDecodedBytes, unsigned* outputYWidth, unsigned* outputYHe
ASSERT_TRUE(sizeIsAvailable); ASSERT_TRUE(sizeIsAvailable);
IntSize size = decoder->decodedSize(); IntSize size = decoder->decodedSize();
IntSize ySize = decoder->decodedYUVSize(0); IntSize ySize = decoder->decodedYUVSize(0, ImageDecoder::ActualSize);
IntSize uSize = decoder->decodedYUVSize(1); IntSize uSize = decoder->decodedYUVSize(1, ImageDecoder::ActualSize);
IntSize vSize = decoder->decodedYUVSize(2); IntSize vSize = decoder->decodedYUVSize(2, ImageDecoder::ActualSize);
ASSERT_TRUE(size.width() == ySize.width()); ASSERT_TRUE(size.width() == ySize.width());
ASSERT_TRUE(size.height() == ySize.height()); ASSERT_TRUE(size.height() == ySize.height());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment