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],
TRACE_EVENT0("blink", "DecodingImageGenerator::onGetYUV8Planes");
PlatformInstrumentation::willDecodeLazyPixelRef(m_generationId);
bool decoded = m_frameGenerator->decodeToYUV(planes, rowBytes);
bool decoded = m_frameGenerator->decodeToYUV(sizes, planes, rowBytes);
PlatformInstrumentation::didDecodeLazyPixelRef();
return decoded;
}
......
......@@ -69,6 +69,22 @@ private:
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)
: m_fullSize(fullSize)
, m_isMultiFrame(isMultiFrame)
......@@ -133,7 +149,7 @@ bool ImageFrameGenerator::decodeAndScale(const SkImageInfo& info, size_t index,
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.
......@@ -165,6 +181,10 @@ bool ImageFrameGenerator::decodeToYUV(void* planes[3], size_t rowBytes[3])
OwnPtr<ImagePlanes> imagePlanes = adoptPtr(new ImagePlanes(planes, rowBytes));
decoder->setImagePlanes(imagePlanes.release());
bool sizeUpdated = updateYUVComponentSizes(decoder.get(), componentSizes, ImageDecoder::ActualSize);
RELEASE_ASSERT(sizeUpdated);
bool yuvDecoded = decoder->decodeToYUV();
if (yuvDecoded)
setHasAlpha(0, false); // YUV is always opaque
......@@ -314,18 +334,7 @@ bool ImageFrameGenerator::getYUVComponentSizes(SkISize componentSizes[3])
OwnPtr<ImagePlanes> dummyImagePlanes = adoptPtr(new ImagePlanes);
decoder->setImagePlanes(dummyImagePlanes.release());
// 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);
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;
return updateYUVComponentSizes(decoder.get(), componentSizes, ImageDecoder::SizeForMemoryAllocation);
}
} // namespace blink
......@@ -72,7 +72,7 @@ public:
bool decodeAndScale(const SkImageInfo&, size_t index, void* pixels, size_t rowBytes);
// 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);
......
......@@ -69,6 +69,8 @@ private:
class PLATFORM_EXPORT ImageDecoder {
WTF_MAKE_NONCOPYABLE(ImageDecoder); WTF_MAKE_FAST_ALLOCATED;
public:
enum SizeType { ActualSize, SizeForMemoryAllocation };
static const size_t noDecodedImageByteLimit = blink::Platform::noDecodedImageByteLimit;
ImageDecoder(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption, size_t maxDecodedBytes)
......@@ -120,7 +122,7 @@ public:
// Decoders which support YUV decoding can override this to
// 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
// different icon) or other formats where different frames are different
......
......@@ -252,11 +252,12 @@ static void readColorProfile(jpeg_decompress_struct* info, ColorProfile& colorPr
}
#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;
int v = info->cur_comp_info[0]->v_samp_factor;
return IntSize((info->output_width + h - 1) / h, (info->output_height + v - 1) / v);
if (sizeType == ImageDecoder::SizeForMemoryAllocation) {
return IntSize(info->cur_comp_info[component]->width_in_blocks * DCTSIZE, info->cur_comp_info[component]->height_in_blocks * DCTSIZE);
}
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)
......@@ -475,6 +476,7 @@ public:
if (overrideColorSpace == JCS_YCbCr) {
m_info.out_color_space = JCS_YCbCr;
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
......@@ -596,6 +598,7 @@ public:
jpeg_decompress_struct* info() { return &m_info; }
JSAMPARRAY samples() const { return m_samples; }
JPEGImageDecoder* decoder() { return m_decoder; }
IntSize uvSize() const { return m_uvSize; }
#if USE(QCMSLIB)
qcms_transform* colorTransform() const { return m_transform; }
......@@ -638,6 +641,8 @@ private:
JSAMPARRAY m_samples;
IntSize m_uvSize;
#if USE(QCMSLIB)
qcms_transform* m_transform;
#endif
......@@ -712,16 +717,13 @@ void JPEGImageDecoder::setDecodedSize(unsigned width, unsigned 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();
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
......@@ -855,7 +857,7 @@ static bool outputRawData(JPEGImageReader* reader, ImagePlanes* imagePlanes)
int yHeight = info->output_height;
int yMaxH = yHeight - 1;
int v = info->cur_comp_info[0]->v_samp_factor;
IntSize uvSize = computeUVSize(info);
IntSize uvSize = reader->uvSize();
int uvMaxH = uvSize.height() - 1;
JSAMPROW outputY = static_cast<JSAMPROW>(imagePlanes->plane(0));
JSAMPROW outputU = static_cast<JSAMPROW>(imagePlanes->plane(1));
......
......@@ -48,7 +48,7 @@ public:
virtual bool isSizeAvailable() OVERRIDE;
virtual bool hasColorProfile() const OVERRIDE { return m_hasColorProfile; }
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 ImageFrame* frameBufferAtIndex(size_t) OVERRIDE;
// CAUTION: setFailed() deletes |m_reader|. Be careful to avoid
......
......@@ -93,9 +93,9 @@ void readYUV(size_t maxDecodedBytes, unsigned* outputYWidth, unsigned* outputYHe
ASSERT_TRUE(sizeIsAvailable);
IntSize size = decoder->decodedSize();
IntSize ySize = decoder->decodedYUVSize(0);
IntSize uSize = decoder->decodedYUVSize(1);
IntSize vSize = decoder->decodedYUVSize(2);
IntSize ySize = decoder->decodedYUVSize(0, ImageDecoder::ActualSize);
IntSize uSize = decoder->decodedYUVSize(1, ImageDecoder::ActualSize);
IntSize vSize = decoder->decodedYUVSize(2, ImageDecoder::ActualSize);
ASSERT_TRUE(size.width() == ySize.width());
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