Bug 28308 - allow down-sampling images during decoding
Summary: allow down-sampling images during decoding
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Images (show other bugs)
Version: 528+ (Nightly build)
Hardware: All All
: P2 Normal
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks: 23154
  Show dependency treegraph
 
Reported: 2009-08-14 09:59 PDT by Yong Li
Modified: 2009-08-28 15:09 PDT (History)
3 users (show)

See Also:


Attachments
the patch (17.45 KB, patch)
2009-08-14 10:06 PDT, Yong Li
manyoso: review-
Details | Formatted Diff | Diff
modified for coding style... (17.41 KB, patch)
2009-08-14 12:44 PDT, Yong Li
eric: review-
Details | Formatted Diff | Diff
modified as Eric Seidel requires (17.53 KB, patch)
2009-08-14 19:50 PDT, Yong Li
manyoso: review+
Details | Formatted Diff | Diff
Fix warnings (2.18 KB, patch)
2009-08-28 13:48 PDT, Peter Kasting
jmalonzo: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Yong Li 2009-08-14 09:59:46 PDT
separated from bug 27561
Comment 1 Yong Li 2009-08-14 10:06:44 PDT
Created attachment 34851 [details]
the patch

only JPEG and PNG decoders are modified to support this feature. Other decoders just ignore it.
Comment 2 Adam Treat 2009-08-14 10:51:26 PDT
Comment on attachment 34851 [details]
the patch

Looking much, much better!  A few issues:

> +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
> +        if (m_decoder) {
> +#   ifdef IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS
> +            m_decoder->setMaxNumPixels(IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS);
> +#   else
> +            m_decoder->setMaxNumPixels(1024 * 1024);
> +#   endif
> +        }
> +#endif
> +    }

Shift this block down below to the next 'if (m_decoder)' and you eliminate an extra conditional and a nested one at that.  Also, there is weird indenting on the '#    ifdef' Please remove.

> +namespace {
> +	enum MatchType{
> +		Exact,
> +		UpperBound,
> +		LowerBound
> +	};
> +}

More weird indentation.

> +template <MatchType type> static int getScaledValue(const Vector<int>& scaledValues, int orig, int searchStart)
> +{
> +	int size = scaledValues.size();
> +    const int* dataStart = scaledValues.data();
> +    const int* dataEnd = dataStart + size;
> +    const int* pos = std::lower_bound(dataStart + searchStart, dataEnd, orig);
> +    switch (type) {
> +        case Exact:
> +            return pos != dataEnd && *pos == orig ? pos - dataStart : -1;
> +        case LowerBound:
> +            return pos != dataEnd && *pos == orig ? pos - dataStart : pos - dataStart - 1;
> +        case UpperBound:
> +        default:
> +            return pos != dataEnd ? pos - dataStart : -1;
> +    }
> +}

More weird indentation and the case labels should line up with switch statement. Please check with check-webkit-style.  Why is this templated?

> +int ImageDecoder::upperBoundScaledX(int origX, int searchStart)
> +{
> +	return getScaledValue<UpperBound>(m_scaledColumns, origX, searchStart);
> +}

Is this tabbed indentation? Please remove all tabs and check thoroughly for coding style.

> +        // ENABLE(IMAGE_DECODER_DOWN_SAMPLING) allows image decoders writedirectly to scaled output buffers

Typo. "allows image decoders to write directly to..."

> +        // by down sampling. Call setMaxNumPixels() to specify the biggest size that decoded images
> +        // can have. Image decoders will deflate those images that are bigger than m_maxNumPixels.
> +        // (Not supported by all image decoders yet)

> -static void convertCMYKToRGBA(RGBA32Buffer& dest, JSAMPROW src, jpeg_decompress_struct* info)
> +static void convertCMYKToRGBA(RGBA32Buffer& dest, int destY, JSAMPROW src, int srcWidth
> +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
> +                              , bool scaled, const Vector<int>& scaledColumns
> +#endif
> +                              )
>  {
> -    ASSERT(info->out_color_space == JCS_CMYK);

Why do you remove this assert and change the behavior of this method even when IMAGE_DECODER_DOWN_SAMPLING is disabled?

> @@ -491,21 +507,33 @@ static void convertCMYKToRGBA(RGBA32Buffer& dest, JSAMPROW src, jpeg_decompress_
>  
>          // read_scanlines has increased the scanline counter, so we
>          // actually mean the previous one.
> -        dest.setRGBA(x, info->output_scanline - 1, c * k / 255, m * k / 255, y * k / 255, 0xFF);
> +        dest.setRGBA(x, destY, c * k / 255, m * k / 255, y * k / 255, 0xFF);

Same question as above and repeated for hunks below.

>      while (info->output_scanline < info->output_height) {
>          /* Request one scanline.  Returns 0 or 1 scanlines. */
> -        if (jpeg_read_scanlines(info, samples, 1) != 1)
> +        int sourceY = info->output_scanline;
> +        int sourceRows = jpeg_read_scanlines(info, samples, 1);
> +        if (sourceRows != 1) {
> +            if (sourceRows != 0)
> +                m_failed = true;
>              return false;
> +        }

Another change that is not guarded by ENABLE(IMAGE_DECODER_DOWN_SAMPLING)

Each of these changes should be described.  I simply don't have context to understand them.

> +#if ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
> +        bool setSize(int width, int height) {

Brace goes on next line.

I'll stop there and say that this still needs coding style cleanups.  And if at all possible the patch should have no behavior changes for when ENABLE(IMAGE_DECODER_DOWN_SAMPLING) is false.  Any other changes should either have some explanation or broken out into separate patch.
Comment 3 Yong Li 2009-08-14 11:08:42 PDT
(In reply to comment #2)
> (From update of attachment 34851 [details])
> Looking much, much better!  A few issues:
 
> Shift this block down below to the next 'if (m_decoder)' and you eliminate an
> extra conditional and a nested one at that.

They are different. this 'if (m_decoder)' is reached only for the first time, where the below one is reached every time.

> Why is this templated?
To be faster. template argument is kind of const values.
> 
> Why do you remove this assert and change the behavior of this method even when
> IMAGE_DECODER_DOWN_SAMPLING is disabled?

info becomes useless except in this ASSERT. I removed 'info' argument. ASSERT is not necessary because the caller takes care of that.

> 
> >      while (info->output_scanline < info->output_height) {
> >          /* Request one scanline.  Returns 0 or 1 scanlines. */
> > -        if (jpeg_read_scanlines(info, samples, 1) != 1)
> > +        int sourceY = info->output_scanline;
> > +        int sourceRows = jpeg_read_scanlines(info, samples, 1);
> > +        if (sourceRows != 1) {
> > +            if (sourceRows != 0)
> > +                m_failed = true;
> >              return false;
> > +        }
> 
> Another change that is not guarded by ENABLE(IMAGE_DECODER_DOWN_SAMPLING)

I can remove the sourceRows change. sourceY is used to record the current row. With this change, there can be more code shared.
Comment 4 Adam Treat 2009-08-14 11:23:38 PDT
(In reply to comment #3)
> (In reply to comment #2)
> > (From update of attachment 34851 [details] [details])
> > Looking much, much better!  A few issues:
> 
> > Shift this block down below to the next 'if (m_decoder)' and you eliminate an
> > extra conditional and a nested one at that.
> 
> They are different. this 'if (m_decoder)' is reached only for the first time,
> where the below one is reached every time.

Ahh, the wonders of reading diffs.  Sorry!

> > Why is this templated?
> To be faster. template argument is kind of const values.

Ok.

> > Why do you remove this assert and change the behavior of this method even when
> > IMAGE_DECODER_DOWN_SAMPLING is disabled?
> 
> info becomes useless except in this ASSERT. I removed 'info' argument. ASSERT
> is not necessary because the caller takes care of that.

Ok, I didn't see the added ASSERT.
 
> > Another change that is not guarded by ENABLE(IMAGE_DECODER_DOWN_SAMPLING)
> 
> I can remove the sourceRows change. 

Thanks.
Comment 5 Yong Li 2009-08-14 12:44:23 PDT
Created attachment 34867 [details]
modified for coding style...
Comment 6 Eric Seidel (no email) 2009-08-14 15:19:29 PDT
Comment on attachment 34867 [details]
modified for coding style...

 126 #ifdef IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS
 127             m_decoder->setMaxNumPixels(IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS);
 128 #else
 129             m_decoder->setMaxNumPixels(1024 * 1024);
 130 #endif

Would be better to check #ifdef IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS at the top fo the file, and define IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS to 1024 * 1024 if not defined.

Seems we'd benifit from some nicely named local variables:
47     case Exact:
 48         return pos != dataEnd && *pos == orig ? pos - dataStart : -1;
 49     case LowerBound:
 50         return pos != dataEnd && *pos == orig ? pos - dataStart : pos - dataStart - 1;
 51     case UpperBound:
 52     default:
 53         return pos != dataEnd ? pos - dataStart : -1;

Style:
 84     double zoom = 1. /shrink;

I would have made this a static inline function to prevent copy/paste:
94     m_scaledRows.reserveCapacity(height * shrink + 0.5);
 95     for (int scaledY = 0;;) {
 96         int y = scaledY * zoom + 0.5;
 97         if (y < height) {
 98             m_scaledRows.append(y);
 99             ++scaledY;
 100         } else
 101             break;
 102     }

 64             bool good = ImageDecoder::setSize(width, height);

good is not the word you want.  success would be better.  setSizeOK would be another option.
Comment 7 Yong Li 2009-08-14 16:09:02 PDT
(In reply to comment #6)
> (From update of attachment 34867 [details])
>  126 #ifdef IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS
>  127            
> m_decoder->setMaxNumPixels(IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS);
>  128 #else
>  129             m_decoder->setMaxNumPixels(1024 * 1024);
>  130 #endif
> 
> Would be better to check #ifdef
> IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS at the top fo the file, and
> define IMAGE_DECODER_DOWN_SAMPLING_MAX_NUMBER_OF_PIXELS to 1024 * 1024 if not
> defined.
> 
> Seems we'd benifit from some nicely named local variables:
> 47     case Exact:
>  48         return pos != dataEnd && *pos == orig ? pos - dataStart : -1;
>  49     case LowerBound:
>  50         return pos != dataEnd && *pos == orig ? pos - dataStart : pos -
> dataStart - 1;
>  51     case UpperBound:
>  52     default:
>  53         return pos != dataEnd ? pos - dataStart : -1;
> 
> Style:
>  84     double zoom = 1. /shrink;
> 
> I would have made this a static inline function to prevent copy/paste:

for this 1./x ? I think that's sick

> 94     m_scaledRows.reserveCapacity(height * shrink + 0.5);
>  95     for (int scaledY = 0;;) {
>  96         int y = scaledY * zoom + 0.5;
>  97         if (y < height) {
>  98             m_scaledRows.append(y);
>  99             ++scaledY;
>  100         } else
>  101             break;
>  102     }
> 
>  64             bool good = ImageDecoder::setSize(width, height);
> 
> good is not the word you want.  success would be better.  setSizeOK would be
> another option.

"good" means the size is good.

r- with all these tiny things?

BTW, after it's modified to be what you want above, are you going to accept it?
Comment 8 Yong Li 2009-08-14 19:50:30 PDT
Created attachment 34884 [details]
modified as Eric Seidel requires
Comment 9 Adam Treat 2009-08-17 08:23:36 PDT
Comment on attachment 34884 [details]
modified as Eric Seidel requires

This looks good, but needs a slight clarification on landing.  Basically, please initialize sourceY after the call to 'jpeg_read_scanlines' to 'int sourceY = info->output_scanline - 1;' to emphasize that no behavior change has occurred where the 'IMAGE_DECODER_DOWN_SAMPLING' is not enabled.  Also add appropriate comment.  r+ with those changes.  Thanks!
Comment 10 Yong Li 2009-08-17 11:41:05 PDT
landed @ r47371
Comment 11 Gustavo Noronha (kov) 2009-08-17 12:28:40 PDT
Reopenning, since I reverted the commit, because it broke the GTK+ build.
Comment 12 Yong Li 2009-08-17 13:15:33 PDT
47381 landed again
Comment 13 Peter Kasting 2009-08-28 13:48:07 PDT
Created attachment 38751 [details]
Fix warnings

The patch landed on here caused signed vs. unsigned warnings on GTK.  This fixes them.  Someone please rubber-stamp.
Comment 14 Jan Alonzo 2009-08-28 14:54:25 PDT
Comment on attachment 38751 [details]
Fix warnings

rs=me.
Comment 15 Peter Kasting 2009-08-28 15:09:43 PDT
Comment on attachment 38751 [details]
Fix warnings

Landed in r47876.