Add reallyHasAlpha() to SkAndroidCodec
authormsarett <msarett@google.com>
Thu, 10 Dec 2015 21:09:24 +0000 (13:09 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 10 Dec 2015 21:09:24 +0000 (13:09 -0800)
This also modified the default implementation
of onReallyHasAlpha() in SkCodec.

BUG=skia:

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

include/codec/SkAndroidCodec.h
include/codec/SkCodec.h
src/codec/SkAndroidCodec.cpp
src/codec/SkSampledCodec.cpp
src/codec/SkSampledCodec.h
src/codec/SkWebpAdapterCodec.cpp
src/codec/SkWebpAdapterCodec.h
src/codec/SkWebpCodec.h

index f979886..9d02de0 100644 (file)
@@ -50,7 +50,7 @@ public:
     /**
      *  Format of the encoded data.
      */
-    SkEncodedFormat getEncodedFormat() const { return this->onGetEncodedFormat(); }
+    SkEncodedFormat getEncodedFormat() const { return fCodec->getEncodedFormat(); }
 
     /**
      *  Returns the dimensions of the scaled output image, for an input
@@ -208,11 +208,23 @@ public:
      */
     SkCodec::Result getAndroidPixels(const SkImageInfo& info, void* pixels, size_t rowBytes);
 
+    /**
+     *  Some images may initially report that they have alpha due to the format
+     *  of the encoded data, but then never use any colors which have alpha
+     *  less than 100%. This function can be called *after* decoding to
+     *  determine if such an image truly had alpha. Calling it before decoding
+     *  is undefined.
+     *  FIXME: see skbug.com/3582.
+     */
+    bool reallyHasAlpha() const {
+        return fCodec->reallyHasAlpha();
+    }
+
 protected:
 
-    SkAndroidCodec(const SkImageInfo&);
+    SkAndroidCodec(SkCodec*);
 
-    virtual SkEncodedFormat onGetEncodedFormat() const = 0;
+    SkCodec* codec() const { return fCodec.get(); }
 
     virtual SkISize onGetSampledDimensions(int sampleSize) const = 0;
 
@@ -226,5 +238,7 @@ private:
     // This will always be a reference to the info that is contained by the
     // embedded SkCodec.
     const SkImageInfo& fInfo;
+
+    SkAutoTDelete<SkCodec> fCodec;
 };
 #endif // SkAndroidCodec_DEFINED
index 67ccdb2..d06c2c3 100644 (file)
@@ -286,7 +286,7 @@ public:
      *  FIXME: see skbug.com/3582.
      */
     bool reallyHasAlpha() const {
-        return this->onReallyHasAlpha();
+        return kOpaque_SkAlphaType != this->getInfo().alphaType() && this->onReallyHasAlpha();
     }
 
     /**
@@ -486,7 +486,15 @@ protected:
         return false;
     }
 
-    virtual bool onReallyHasAlpha() const { return false; }
+    /**
+     * This is only called if the image indicates that it is not opaque.
+     * By default we will assume that the image is in fact non-opaque.
+     * Subclasses may override this function if they intend to verify
+     * that the image actually has alpha.
+     */
+    virtual bool onReallyHasAlpha() const {
+        return true;
+    }
 
     /**
      *  If the stream was previously read, attempt to rewind.
index c26b3ef..5962102 100644 (file)
@@ -16,8 +16,9 @@ static bool is_valid_sample_size(int sampleSize) {
     return sampleSize > 0;
 }
 
-SkAndroidCodec::SkAndroidCodec(const SkImageInfo& info)
-    : fInfo(info)
+SkAndroidCodec::SkAndroidCodec(SkCodec* codec)
+    : fInfo(codec->getInfo())
+    , fCodec(codec)
 {}
 
 SkAndroidCodec* SkAndroidCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) {
index 38859ad..515edc5 100644 (file)
 #include "SkTemplates.h"
 
 SkSampledCodec::SkSampledCodec(SkCodec* codec)
-    : INHERITED(codec->getInfo())
-    , fCodec(codec)
+    : INHERITED(codec)
 {}
 
 SkISize SkSampledCodec::accountForNativeScaling(int* sampleSizePtr, int* nativeSampleSize) const {
-    SkISize preSampledSize = fCodec->getInfo().dimensions();
+    SkISize preSampledSize = this->codec()->getInfo().dimensions();
     int sampleSize = *sampleSizePtr;
     SkASSERT(sampleSize > 1);
 
@@ -26,7 +25,7 @@ SkISize SkSampledCodec::accountForNativeScaling(int* sampleSizePtr, int* nativeS
     }
 
     // Only JPEG supports native downsampling.
-    if (fCodec->getEncodedFormat() == kJPEG_SkEncodedFormat) {
+    if (this->codec()->getEncodedFormat() == kJPEG_SkEncodedFormat) {
         // See if libjpeg supports this scale directly
         switch (sampleSize) {
             case 2:
@@ -34,7 +33,7 @@ SkISize SkSampledCodec::accountForNativeScaling(int* sampleSizePtr, int* nativeS
             case 8:
                 // This class does not need to do any sampling.
                 *sampleSizePtr = 1;
-                return fCodec->getScaledDimensions(get_scale_from_sample_size(sampleSize));
+                return this->codec()->getScaledDimensions(get_scale_from_sample_size(sampleSize));
             default:
                 break;
         }
@@ -48,8 +47,8 @@ SkISize SkSampledCodec::accountForNativeScaling(int* sampleSizePtr, int* nativeS
             if (0 == remainder) {
                 float scale = get_scale_from_sample_size(supportedSampleSize);
 
-                // fCodec will scale to this size.
-                preSampledSize = fCodec->getScaledDimensions(scale);
+                // this->codec() will scale to this size.
+                preSampledSize = this->codec()->getScaledDimensions(scale);
 
                 // And then this class will sample it.
                 *sampleSizePtr = actualSampleSize;
@@ -77,10 +76,10 @@ SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void
     codecOptions.fZeroInitialized = options.fZeroInitialized;
 
     SkIRect* subset = options.fSubset;
-    if (!subset || subset->size() == fCodec->getInfo().dimensions()) {
-        if (fCodec->dimensionsSupported(info.dimensions())) {
-            return fCodec->getPixels(info, pixels, rowBytes, &codecOptions, options.fColorPtr,
-                    options.fColorCount);
+    if (!subset || subset->size() == this->codec()->getInfo().dimensions()) {
+        if (this->codec()->dimensionsSupported(info.dimensions())) {
+            return this->codec()->getPixels(info, pixels, rowBytes, &codecOptions,
+                    options.fColorPtr, options.fColorCount);
         }
 
         // If the native codec does not support the requested scale, scale by sampling.
@@ -90,7 +89,7 @@ SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void
     // We are performing a subset decode.
     int sampleSize = options.fSampleSize;
     SkISize scaledSize = this->getSampledDimensions(sampleSize);
-    if (!fCodec->dimensionsSupported(scaledSize)) {
+    if (!this->codec()->dimensionsSupported(scaledSize)) {
         // If the native codec does not support the requested scale, scale by sampling.
         return this->sampledDecode(info, pixels, rowBytes, options);
     }
@@ -105,24 +104,24 @@ SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void
     SkIRect scanlineSubset = SkIRect::MakeXYWH(scaledSubsetX, 0, scaledSubsetWidth,
             scaledSize.height());
     codecOptions.fSubset = &scanlineSubset;
-    SkCodec::Result result = fCodec->startScanlineDecode(info.makeWH(scaledSize.width(),
+    SkCodec::Result result = this->codec()->startScanlineDecode(info.makeWH(scaledSize.width(),
             scaledSize.height()), &codecOptions, options.fColorPtr, options.fColorCount);
     if (SkCodec::kSuccess != result) {
         return result;
     }
 
     // At this point, we are only concerned with subsetting.  Either no scale was
-    // requested, or the fCodec is handling the scale.
-    switch (fCodec->getScanlineOrder()) {
+    // requested, or the this->codec() is handling the scale.
+    switch (this->codec()->getScanlineOrder()) {
         case SkCodec::kTopDown_SkScanlineOrder:
         case SkCodec::kNone_SkScanlineOrder: {
-            if (!fCodec->skipScanlines(scaledSubsetY)) {
-                fCodec->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized,
+            if (!this->codec()->skipScanlines(scaledSubsetY)) {
+                this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized,
                         scaledSubsetHeight, 0);
                 return SkCodec::kIncompleteInput;
             }
 
-            int decodedLines = fCodec->getScanlines(pixels, scaledSubsetHeight, rowBytes);
+            int decodedLines = this->codec()->getScanlines(pixels, scaledSubsetHeight, rowBytes);
             if (decodedLines != scaledSubsetHeight) {
                 return SkCodec::kIncompleteInput;
             }
@@ -157,7 +156,7 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix
     if (options.fSubset) {
         // We will need to know about subsetting in the y-dimension in order to use the
         // scanline decoder.
-        // Update the subset to account for scaling done by fCodec.
+        // Update the subset to account for scaling done by this->codec().
         SkIRect* subsetPtr = options.fSubset;
 
         // Do the divide ourselves, instead of calling get_scaled_dimension. If
@@ -175,14 +174,14 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix
     }
 
     // Start the scanline decode.
-    SkCodec::Result result = fCodec->startScanlineDecode(
+    SkCodec::Result result = this->codec()->startScanlineDecode(
             info.makeWH(nativeSize.width(), nativeSize.height()), &sampledOptions,
             options.fColorPtr, options.fColorCount);
     if (SkCodec::kSuccess != result) {
         return result;
     }
 
-    SkSampler* sampler = fCodec->getSampler(true);
+    SkSampler* sampler = this->codec()->getSampler(true);
     if (!sampler) {
         return SkCodec::kUnimplemented;
     }
@@ -202,23 +201,23 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix
     const int samplingOffsetY = get_start_coord(sampleY);
     const int startY = samplingOffsetY + subsetY;
     int dstHeight = info.height();
-    switch(fCodec->getScanlineOrder()) {
+    switch(this->codec()->getScanlineOrder()) {
         case SkCodec::kTopDown_SkScanlineOrder: {
-            if (!fCodec->skipScanlines(startY)) {
-                fCodec->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized,
+            if (!this->codec()->skipScanlines(startY)) {
+                this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized,
                         dstHeight, 0);
                 return SkCodec::kIncompleteInput;
             }
             void* pixelPtr = pixels;
             for (int y = 0; y < dstHeight; y++) {
-                if (1 != fCodec->getScanlines(pixelPtr, 1, rowBytes)) {
-                    fCodec->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized,
-                            dstHeight, y + 1);
+                if (1 != this->codec()->getScanlines(pixelPtr, 1, rowBytes)) {
+                    this->codec()->fillIncompleteImage(info, pixels, rowBytes,
+                            options.fZeroInitialized, dstHeight, y + 1);
                     return SkCodec::kIncompleteInput;
                 }
                 if (y < dstHeight - 1) {
-                    if (!fCodec->skipScanlines(sampleY - 1)) {
-                        fCodec->fillIncompleteImage(info, pixels, rowBytes,
+                    if (!this->codec()->skipScanlines(sampleY - 1)) {
+                        this->codec()->fillIncompleteImage(info, pixels, rowBytes,
                                 options.fZeroInitialized, dstHeight, y + 1);
                         return SkCodec::kIncompleteInput;
                     }
@@ -233,15 +232,15 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix
             SkASSERT(0 == subsetY && nativeSize.height() == subsetHeight);
             int y;
             for (y = 0; y < nativeSize.height(); y++) {
-                int srcY = fCodec->nextScanline();
+                int srcY = this->codec()->nextScanline();
                 if (is_coord_necessary(srcY, sampleY, dstHeight)) {
                     void* pixelPtr = SkTAddOffset<void>(pixels,
                             rowBytes * get_dst_coord(srcY, sampleY));
-                    if (1 != fCodec->getScanlines(pixelPtr, 1, rowBytes)) {
+                    if (1 != this->codec()->getScanlines(pixelPtr, 1, rowBytes)) {
                         break;
                     }
                 } else {
-                    if (!fCodec->skipScanlines(1)) {
+                    if (!this->codec()->skipScanlines(1)) {
                         break;
                     }
                 }
@@ -251,12 +250,13 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix
                 return SkCodec::kSuccess;
             }
 
-            // We handle filling uninitialized memory here instead of using fCodec.
-            // fCodec does not know that we are sampling.
-            const uint32_t fillValue = fCodec->getFillValue(info.colorType(), info.alphaType());
+            // We handle filling uninitialized memory here instead of using this->codec().
+            // this->codec() does not know that we are sampling.
+            const uint32_t fillValue = this->codec()->getFillValue(info.colorType(),
+                    info.alphaType());
             const SkImageInfo fillInfo = info.makeWH(info.width(), 1);
             for (; y < nativeSize.height(); y++) {
-                int srcY = fCodec->outputScanline(y);
+                int srcY = this->codec()->outputScanline(y);
                 if (!is_coord_necessary(srcY, sampleY, dstHeight)) {
                     continue;
                 }
@@ -271,12 +271,12 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix
             SkAutoTMalloc<uint8_t> storage(linesNeeded * rowBytes);
             uint8_t* storagePtr = storage.get();
 
-            if (!fCodec->skipScanlines(startY)) {
-                fCodec->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized,
+            if (!this->codec()->skipScanlines(startY)) {
+                this->codec()->fillIncompleteImage(info, pixels, rowBytes, options.fZeroInitialized,
                         dstHeight, 0);
                 return SkCodec::kIncompleteInput;
             }
-            int scanlines = fCodec->getScanlines(storagePtr, linesNeeded, rowBytes);
+            int scanlines = this->codec()->getScanlines(storagePtr, linesNeeded, rowBytes);
 
             for (int y = 0; y < dstHeight; y++) {
                 memcpy(pixels, storagePtr, info.minRowBytes());
@@ -285,7 +285,7 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix
             }
 
             if (scanlines < dstHeight) {
-                // fCodec has already handled filling uninitialized memory.
+                // this->codec() has already handled filling uninitialized memory.
                 return SkCodec::kIncompleteInput;
             }
             return SkCodec::kSuccess;
index b3a5912..35e4f57 100644 (file)
@@ -23,8 +23,6 @@ public:
 
 protected:
 
-    SkEncodedFormat onGetEncodedFormat() const override { return fCodec->getEncodedFormat(); };
-
     SkISize onGetSampledDimensions(int sampleSize) const override;
 
     bool onGetSupportedSubset(SkIRect* desiredSubset) const override { return true; }
@@ -57,8 +55,6 @@ private:
     SkCodec::Result sampledDecode(const SkImageInfo& info, void* pixels, size_t rowBytes,
             const AndroidOptions& options);
 
-    SkAutoTDelete<SkCodec> fCodec;
-
     typedef SkAndroidCodec INHERITED;
 };
 #endif // SkSampledCodec_DEFINED
index fb1eace..5aefe5d 100644 (file)
 #include "SkWebpAdapterCodec.h"
 
 SkWebpAdapterCodec::SkWebpAdapterCodec(SkWebpCodec* codec)
-    : INHERITED(codec->getInfo())
-    , fCodec(codec)
+    : INHERITED(codec)
 {}
 
 SkISize SkWebpAdapterCodec::onGetSampledDimensions(int sampleSize) const {
     float scale = get_scale_from_sample_size(sampleSize);
-    return fCodec->getScaledDimensions(scale);
+    return this->codec()->getScaledDimensions(scale);
 }
 
 bool SkWebpAdapterCodec::onGetSupportedSubset(SkIRect* desiredSubset) const {
-    return fCodec->getValidSubset(desiredSubset);
+    return this->codec()->getValidSubset(desiredSubset);
 }
 
 SkCodec::Result SkWebpAdapterCodec::onGetAndroidPixels(const SkImageInfo& info, void* pixels,
@@ -41,6 +40,6 @@ SkCodec::Result SkWebpAdapterCodec::onGetAndroidPixels(const SkImageInfo& info,
     SkCodec::Options codecOptions;
     codecOptions.fZeroInitialized = options.fZeroInitialized;
     codecOptions.fSubset = options.fSubset;
-    return fCodec->getPixels(info, pixels, rowBytes, &codecOptions, options.fColorPtr,
+    return this->codec()->getPixels(info, pixels, rowBytes, &codecOptions, options.fColorPtr,
             options.fColorCount);
 }
index ed0292a..ece46a6 100644 (file)
@@ -23,8 +23,6 @@ public:
 
 protected:
 
-    SkEncodedFormat onGetEncodedFormat() const override { return kWEBP_SkEncodedFormat; };
-
     SkISize onGetSampledDimensions(int sampleSize) const override;
 
     bool onGetSupportedSubset(SkIRect* desiredSubset) const override;
@@ -34,8 +32,6 @@ protected:
 
 private:
 
-    SkAutoTDelete<SkWebpCodec> fCodec;
-
     typedef SkAndroidCodec INHERITED;
 };
 #endif // SkWebpAdapterCodec_DEFINED
index 5c0f028..dfc9f12 100644 (file)
@@ -27,10 +27,6 @@ protected:
             override;
     SkEncodedFormat onGetEncodedFormat() const override { return kWEBP_SkEncodedFormat; }
 
-    bool onReallyHasAlpha() const override {
-        return this->getInfo().alphaType() != kOpaque_SkAlphaType;
-    }
-
     SkISize onGetScaledDimensions(float desiredScale) const override;
 
     bool onDimensionsSupported(const SkISize&) override;