aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar scroggo <scroggo@google.com>2015-10-02 13:14:46 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-10-02 13:14:46 -0700
commite7fc14b55bb8c41ba054abf0bfa09cdd6ec84671 (patch)
tree81525743c2c436a60f4127cf04f0f96d5dc3bed5
parent65f7c9fa7ed028159a4a2c792ccc1dcdf718eed2 (diff)
Move all knowledge of X sampling into SkScaledCodec
Prior to this CL, each SkCodec subclass that allows sampling does an extra check in onStartScanlineDecode to determine whether the X dimension is supported for sampling. Remove this check, and provide a way for SkScaledCodec to directly access the SkSwizzler, and update it to do sampling. This way, the SkCodec knows nothing of sampling, but we can still save the extra step of sampling afterwards. FIXME: SkBmpRLECodec still calls SkScaledCodec::DimensionsSupported. It seems like it could directly support sampling, rather than dealing with SkScaledCodec (partially). Add a new base class for SkSwizzler. It allows updating the swizzler after it was created, which is done by SkScaledCodec. Modify SkSwizzler's constructor/factory function to stop taking any info about sampling, assume the sample size is one, and move modifying that into a virtual function overridden from the base class. BUG=skia:4284 Review URL: https://codereview.chromium.org/1372973002
-rw-r--r--include/codec/SkCodec.h35
-rw-r--r--include/codec/SkScaledCodec.h19
-rw-r--r--src/codec/SkBmpCodec.cpp5
-rw-r--r--src/codec/SkBmpCodec.h1
-rw-r--r--src/codec/SkBmpMaskCodec.h1
-rw-r--r--src/codec/SkBmpRLECodec.cpp46
-rw-r--r--src/codec/SkBmpRLECodec.h6
-rw-r--r--src/codec/SkBmpStandardCodec.cpp2
-rw-r--r--src/codec/SkBmpStandardCodec.h2
-rw-r--r--src/codec/SkCodec.cpp30
-rw-r--r--src/codec/SkCodec_libgif.cpp16
-rw-r--r--src/codec/SkCodec_libgif.h2
-rw-r--r--src/codec/SkCodec_libico.cpp18
-rw-r--r--src/codec/SkCodec_libico.h2
-rw-r--r--src/codec/SkCodec_libpng.cpp25
-rw-r--r--src/codec/SkCodec_libpng.h1
-rw-r--r--src/codec/SkCodec_wbmp.cpp15
-rw-r--r--src/codec/SkCodec_wbmp.h1
-rw-r--r--src/codec/SkJpegCodec.cpp109
-rw-r--r--src/codec/SkJpegCodec.h10
-rw-r--r--src/codec/SkMaskSwizzler.cpp33
-rw-r--r--src/codec/SkMaskSwizzler.h24
-rw-r--r--src/codec/SkSampler.h27
-rw-r--r--src/codec/SkScaledCodec.cpp106
-rw-r--r--src/codec/SkSwizzler.cpp33
-rw-r--r--src/codec/SkSwizzler.h33
-rw-r--r--src/codec/SkWebpCodec.cpp7
-rw-r--r--src/codec/SkWebpCodec.h2
28 files changed, 363 insertions, 248 deletions
diff --git a/include/codec/SkCodec.h b/include/codec/SkCodec.h
index c0cce853a3..7300a5c732 100644
--- a/include/codec/SkCodec.h
+++ b/include/codec/SkCodec.h
@@ -17,6 +17,7 @@
#include "SkTypes.h"
class SkData;
+class SkSampler;
/**
* Abstraction layer directly on top of an image codec.
@@ -382,6 +383,15 @@ protected:
return this->getInfo().dimensions();
}
+ // FIXME: What to do about subsets??
+ /**
+ * Subclasses should override if they support dimensions other than the
+ * srcInfo's.
+ */
+ virtual bool onDimensionsSupported(const SkISize&) {
+ return false;
+ }
+
virtual SkEncodedFormat onGetEncodedFormat() const = 0;
virtual Result onGetPixels(const SkImageInfo& info,
@@ -455,6 +465,19 @@ private:
SkCodec::Options fOptions;
int fCurrScanline;
+ /**
+ * Return whether these dimensions are supported as a scale.
+ *
+ * The codec may choose to cache the information about scale and subset.
+ * Either way, the same information will be passed to onGetPixels/onStart
+ * on success.
+ *
+ * This must return true for a size returned from getScaledDimensions.
+ */
+ bool dimensionsSupported(const SkISize& dim) {
+ return dim == fSrcInfo.dimensions() || this->onDimensionsSupported(dim);
+ }
+
// Methods for scanline decoding.
virtual SkCodec::Result onStartScanlineDecode(const SkImageInfo& dstInfo,
const SkCodec::Options& options, SkPMColor ctable[], int* ctableCount) {
@@ -477,5 +500,17 @@ private:
return kUnimplemented;
}
+ /**
+ * Return an object which will allow forcing scanline decodes to sample in X.
+ *
+ * May create a sampler, if one is not currently being used. Otherwise, does
+ * not affect ownership.
+ *
+ * Only valid during scanline decoding.
+ */
+ virtual SkSampler* getSampler() { return nullptr; }
+
+ // Needed to call getSampler and dimensionsSupported.
+ friend class SkScaledCodec;
};
#endif // SkCodec_DEFINED
diff --git a/include/codec/SkScaledCodec.h b/include/codec/SkScaledCodec.h
index 20428d8d73..92ef19e74f 100644
--- a/include/codec/SkScaledCodec.h
+++ b/include/codec/SkScaledCodec.h
@@ -22,23 +22,7 @@ public:
virtual ~SkScaledCodec();
- /**
- * returns whether a destination's dimensions are supported for down sampling
- */
- static bool DimensionsSupportedForSampling(const SkImageInfo& srcInfo,
- const SkImageInfo& dstInfo) {
- // heights must be equal as no native y sampling is supported
- if (dstInfo.height() != srcInfo.height()) {
- return false;
- }
- // only support down sampling, dstWidth cannot be larger that srcWidth
- if(dstInfo.width() > srcInfo.width()) {
- return false;
- }
- return true;
- }
-
- static void ComputeSampleSize(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo,
+ static void ComputeSampleSize(const SkISize& dstDim, const SkISize& srcDim,
int* sampleSizeX, int* sampleSizeY);
protected:
@@ -46,6 +30,7 @@ protected:
* Recommend a set of destination dimensions given a requested scale
*/
SkISize onGetScaledDimensions(float desiredScale) const override;
+ bool onDimensionsSupported(const SkISize&) override;
Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, SkPMColor*, int*)
override;
diff --git a/src/codec/SkBmpCodec.cpp b/src/codec/SkBmpCodec.cpp
index 4ae57c057a..da3e0a2807 100644
--- a/src/codec/SkBmpCodec.cpp
+++ b/src/codec/SkBmpCodec.cpp
@@ -580,11 +580,6 @@ SkCodec::Result SkBmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
// Subsets are not supported.
return kUnimplemented;
}
- if (dstInfo.dimensions() != this->getInfo().dimensions()) {
- if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
- return SkCodec::kInvalidScale;
- }
- }
if (!conversion_possible(dstInfo, this->getInfo())) {
SkCodecPrintf("Error: cannot convert input type to output type.\n");
return kInvalidConversion;
diff --git a/src/codec/SkBmpCodec.h b/src/codec/SkBmpCodec.h
index ea6f789407..19f66037e8 100644
--- a/src/codec/SkBmpCodec.h
+++ b/src/codec/SkBmpCodec.h
@@ -10,7 +10,6 @@
#include "SkCodec.h"
#include "SkColorTable.h"
#include "SkImageInfo.h"
-#include "SkMaskSwizzler.h"
#include "SkStream.h"
#include "SkSwizzler.h"
#include "SkTypes.h"
diff --git a/src/codec/SkBmpMaskCodec.h b/src/codec/SkBmpMaskCodec.h
index 0b1291266d..1c44c7fb40 100644
--- a/src/codec/SkBmpMaskCodec.h
+++ b/src/codec/SkBmpMaskCodec.h
@@ -45,6 +45,7 @@ protected:
private:
bool initializeSwizzler(const SkImageInfo& dstInfo);
+ SkSampler* getSampler() override { return fMaskSwizzler; }
Result decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes,
const Options& opts) override;
diff --git a/src/codec/SkBmpRLECodec.cpp b/src/codec/SkBmpRLECodec.cpp
index e76a23ed14..fe499c6a6d 100644
--- a/src/codec/SkBmpRLECodec.cpp
+++ b/src/codec/SkBmpRLECodec.cpp
@@ -43,10 +43,6 @@ SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo,
// Subsets are not supported.
return kUnimplemented;
}
- if (dstInfo.dimensions() != this->getInfo().dimensions()) {
- SkCodecPrintf("Error: scaling not supported.\n");
- return kInvalidScale;
- }
if (!conversion_possible(dstInfo, this->getInfo())) {
SkCodecPrintf("Error: cannot convert input type to output type.\n");
return kInvalidConversion;
@@ -253,6 +249,9 @@ void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes,
SkCodec::Result SkBmpRLECodec::prepareToDecode(const SkImageInfo& dstInfo,
const SkCodec::Options& options, SkPMColor inputColorPtr[], int* inputColorCount) {
+ // Reset fSampleX. If it needs to be a value other than 1, it will get modified by
+ // the sampler.
+ fSampleX = 1;
// Create the color table if necessary and prepare the stream for decode
// Note that if it is non-NULL, inputColorCount will be modified
if (!this->createColorTable(inputColorCount)) {
@@ -269,8 +268,6 @@ SkCodec::Result SkBmpRLECodec::prepareToDecode(const SkImageInfo& dstInfo,
return SkCodec::kInvalidConversion;
}
- SkScaledCodec::ComputeSampleSize(dstInfo, this->getInfo(), &fSampleX, NULL);
-
return SkCodec::kSuccess;
}
@@ -278,7 +275,7 @@ SkCodec::Result SkBmpRLECodec::prepareToDecode(const SkImageInfo& dstInfo,
* Performs the bitmap decoding for RLE input format
* RLE decoding is performed all at once, rather than a one row at a time
*/
-SkCodec::Result SkBmpRLECodec::decodeRows(const SkImageInfo& dstInfo,
+SkCodec::Result SkBmpRLECodec::decodeRows(const SkImageInfo& info,
void* dst, size_t dstRowBytes,
const Options& opts) {
// Set RLE flags
@@ -289,7 +286,10 @@ SkCodec::Result SkBmpRLECodec::decodeRows(const SkImageInfo& dstInfo,
// Set constant values
const int width = this->getInfo().width();
- const int height = dstInfo.height();
+ const int height = info.height();
+
+ // Account for sampling.
+ SkImageInfo dstInfo = info.makeWH(get_scaled_dimension(width, fSampleX), height);
// Destination parameters
int x = 0;
@@ -466,3 +466,33 @@ SkCodec::Result SkBmpRLECodec::decodeRows(const SkImageInfo& dstInfo,
}
}
}
+
+class SkBmpRLESampler : public SkSampler {
+public:
+ SkBmpRLESampler(SkBmpRLECodec* codec)
+ : fCodec(codec)
+ {
+ SkASSERT(fCodec);
+ }
+
+private:
+ int onSetSampleX(int sampleX) {
+ return fCodec->setSampleX(sampleX);
+ }
+
+ // Unowned pointer. fCodec will delete this class in its destructor.
+ SkBmpRLECodec* fCodec;
+};
+
+SkSampler* SkBmpRLECodec::getSampler() {
+ if (!fSampler) {
+ fSampler.reset(new SkBmpRLESampler(this));
+ }
+
+ return fSampler;
+}
+
+int SkBmpRLECodec::setSampleX(int sampleX) {
+ fSampleX = sampleX;
+ return get_scaled_dimension(this->getInfo().width(), sampleX);
+}
diff --git a/src/codec/SkBmpRLECodec.h b/src/codec/SkBmpRLECodec.h
index ea2c2b6bab..8721969a85 100644
--- a/src/codec/SkBmpRLECodec.h
+++ b/src/codec/SkBmpRLECodec.h
@@ -8,6 +8,7 @@
#include "SkBmpCodec.h"
#include "SkColorTable.h"
#include "SkImageInfo.h"
+#include "SkSampler.h"
#include "SkTypes.h"
/*
@@ -39,6 +40,8 @@ public:
uint32_t offset, SkCodec::SkScanlineOrder rowOrder,
size_t RLEBytes);
+ int setSampleX(int);
+
protected:
Result onGetPixels(const SkImageInfo& dstInfo, void* dst,
@@ -84,6 +87,8 @@ private:
Result decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes,
const Options& opts) override;
+ SkSampler* getSampler() override;
+
SkAutoTUnref<SkColorTable> fColorTable; // owned
const uint32_t fNumColors;
const uint32_t fBytesPerColor;
@@ -92,6 +97,7 @@ private:
size_t fRLEBytes;
uint32_t fCurrRLEByte;
int fSampleX;
+ SkAutoTDelete<SkSampler> fSampler;
typedef SkBmpCodec INHERITED;
};
diff --git a/src/codec/SkBmpStandardCodec.cpp b/src/codec/SkBmpStandardCodec.cpp
index 5e65ebbe53..540b9f3b2b 100644
--- a/src/codec/SkBmpStandardCodec.cpp
+++ b/src/codec/SkBmpStandardCodec.cpp
@@ -196,7 +196,7 @@ bool SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo,
// Create swizzler
fSwizzler.reset(SkSwizzler::CreateSwizzler(config,
- colorPtr, dstInfo, opts.fZeroInitialized, this->getInfo()));
+ colorPtr, dstInfo, opts.fZeroInitialized));
if (nullptr == fSwizzler.get()) {
return false;
diff --git a/src/codec/SkBmpStandardCodec.h b/src/codec/SkBmpStandardCodec.h
index 0d81cbfee4..0263570b85 100644
--- a/src/codec/SkBmpStandardCodec.h
+++ b/src/codec/SkBmpStandardCodec.h
@@ -54,6 +54,8 @@ protected:
const SkCodec::Options& options, SkPMColor inputColorPtr[],
int* inputColorCount) override;
+ SkSampler* getSampler() override { return fSwizzler; }
+
private:
/*
diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp
index cabcadcccd..1a901a97ac 100644
--- a/src/codec/SkCodec.cpp
+++ b/src/codec/SkCodec.cpp
@@ -152,7 +152,21 @@ SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t
Options optsStorage;
if (nullptr == options) {
options = &optsStorage;
+ } else if (options->fSubset) {
+ SkIRect subset(*options->fSubset);
+ if (!this->onGetValidSubset(&subset) || subset != *options->fSubset) {
+ // FIXME: How to differentiate between not supporting subset at all
+ // and not supporting this particular subset?
+ return kUnimplemented;
+ }
+ }
+
+ // FIXME: Support subsets somehow? Note that this works for SkWebpCodec
+ // because it supports arbitrary scaling/subset combinations.
+ if (!this->dimensionsSupported(info.dimensions())) {
+ return kInvalidScale;
}
+
const Result result = this->onGetPixels(info, pixels, rowBytes, *options, ctable, ctableCount);
if ((kIncompleteInput == result || kSuccess == result) && ctableCount) {
@@ -190,6 +204,18 @@ SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo,
Options optsStorage;
if (nullptr == options) {
options = &optsStorage;
+ } else if (options->fSubset) {
+ SkIRect subset(*options->fSubset);
+ if (!this->onGetValidSubset(&subset) || subset != *options->fSubset) {
+ // FIXME: How to differentiate between not supporting subset at all
+ // and not supporting this particular subset?
+ return kUnimplemented;
+ }
+ }
+
+ // FIXME: Support subsets somehow?
+ if (!this->dimensionsSupported(dstInfo.dimensions())) {
+ return kInvalidScale;
}
const Result result = this->onStartScanlineDecode(dstInfo, *options, ctable, ctableCount);
@@ -213,8 +239,8 @@ SkCodec::Result SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes
}
SkASSERT(!fDstInfo.isEmpty());
- if ((rowBytes < fDstInfo.minRowBytes() && countLines > 1 ) || countLines <= 0
- || fCurrScanline + countLines > fDstInfo.height()) {
+
+ if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) {
return kInvalidParameters;
}
diff --git a/src/codec/SkCodec_libgif.cpp b/src/codec/SkCodec_libgif.cpp
index e6d1141669..6134e96337 100644
--- a/src/codec/SkCodec_libgif.cpp
+++ b/src/codec/SkCodec_libgif.cpp
@@ -9,7 +9,6 @@
#include "SkCodecPriv.h"
#include "SkColorPriv.h"
#include "SkColorTable.h"
-#include "SkScaledCodec.h"
#include "SkStream.h"
#include "SkSwizzler.h"
#include "SkUtils.h"
@@ -485,7 +484,7 @@ SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo,
ZeroInitialized zeroInit) {
const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex,
- colorPtr, dstInfo, zeroInit, this->getInfo()));
+ colorPtr, dstInfo, zeroInit));
if (nullptr != fSwizzler.get()) {
return kSuccess;
}
@@ -585,20 +584,9 @@ SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
return result;
}
- // Check to see if scaling was requested.
- if (dstInfo.dimensions() != this->getInfo().dimensions()) {
- if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
- return gif_error("Scaling not supported.\n", SkCodec::kInvalidScale);
- }
- }
-
// Initialize the swizzler
if (fFrameIsSubset) {
- int sampleX;
- SkScaledCodec::ComputeSampleSize(dstInfo, this->getInfo(), &sampleX, NULL);
- const SkImageInfo subsetDstInfo = dstInfo.makeWH(
- get_scaled_dimension(fFrameDims.width(), sampleX),
- fFrameDims.height());
+ const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameDims.width(), fFrameDims.height());
if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts.fZeroInitialized)) {
return gif_error("Could not initialize swizzler.\n", kUnimplemented);
}
diff --git a/src/codec/SkCodec_libgif.h b/src/codec/SkCodec_libgif.h
index d7dc2b9e1d..c29cbdb9d5 100644
--- a/src/codec/SkCodec_libgif.h
+++ b/src/codec/SkCodec_libgif.h
@@ -124,6 +124,8 @@ private:
*/
Result initializeSwizzler(const SkImageInfo& dstInfo, ZeroInitialized zeroInit);
+ SkSampler* getSampler() override { return fSwizzler; }
+
/*
* @return kSuccess if the read is successful and kIncompleteInput if the
* read fails.
diff --git a/src/codec/SkCodec_libico.cpp b/src/codec/SkCodec_libico.cpp
index 798169d82b..8b38148adf 100644
--- a/src/codec/SkCodec_libico.cpp
+++ b/src/codec/SkCodec_libico.cpp
@@ -206,10 +206,6 @@ SkISize SkIcoCodec::onGetScaledDimensions(float desiredScale) const {
// We set the dimensions to the largest candidate image by default.
// Regardless of the scale request, this is the largest image that we
// will decode.
- if (desiredScale >= 1.0) {
- return this->getInfo().dimensions();
- }
-
int origWidth = this->getInfo().width();
int origHeight = this->getInfo().height();
float desiredSize = desiredScale * origWidth * origHeight;
@@ -230,6 +226,17 @@ SkISize SkIcoCodec::onGetScaledDimensions(float desiredScale) const {
return fEmbeddedCodecs->operator[](minIndex)->getInfo().dimensions();
}
+bool SkIcoCodec::onDimensionsSupported(const SkISize& dim) {
+ // FIXME: Cache the index from onGetScaledDimensions?
+ for (int32_t i = 0; i < fEmbeddedCodecs->count(); i++) {
+ if (fEmbeddedCodecs->operator[](i)->getInfo().dimensions() == dim) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
/*
* Initiates the Ico decode
*/
@@ -286,6 +293,9 @@ SkCodec::Result SkIcoCodec::onGetPixels(const SkImageInfo& dstInfo,
}
}
+ // This should never be reached, since onDimensionsSupported should have rejected the
+ // dimensions sooner.
+ SkASSERT(false);
SkCodecPrintf("Error: No matching candidate image in ico.\n");
return result;
}
diff --git a/src/codec/SkCodec_libico.h b/src/codec/SkCodec_libico.h
index a690cdd81d..a815e300dd 100644
--- a/src/codec/SkCodec_libico.h
+++ b/src/codec/SkCodec_libico.h
@@ -35,6 +35,8 @@ protected:
*/
SkISize onGetScaledDimensions(float desiredScale) const override;
+ bool onDimensionsSupported(const SkISize&) override;
+
/*
* Initiates the Ico decode
*/
diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp
index 1af8658e1e..ee8d49263f 100644
--- a/src/codec/SkCodec_libpng.cpp
+++ b/src/codec/SkCodec_libpng.cpp
@@ -436,7 +436,7 @@ SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
// Create the swizzler. SkPngCodec retains ownership of the color table.
const SkPMColor* colors = get_color_ptr(fColorTable.get());
fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo,
- options.fZeroInitialized, this->getInfo()));
+ options.fZeroInitialized));
if (!fSwizzler) {
// FIXME: CreateSwizzler could fail for another reason.
return kUnimplemented;
@@ -474,9 +474,6 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
// Subsets are not supported.
return kUnimplemented;
}
- if (requestedInfo.dimensions() != this->getInfo().dimensions()) {
- return kInvalidScale;
- }
// Note that ctable and ctableCount may be modified if there is a color table
const Result result = this->initializeSwizzler(requestedInfo, options,
@@ -593,13 +590,6 @@ public:
return kInvalidConversion;
}
- // Check to see if scaling was requested.
- if (dstInfo.dimensions() != this->getInfo().dimensions()) {
- if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
- return kInvalidScale;
- }
- }
-
const Result result = this->initializeSwizzler(dstInfo, options, ctable,
ctableCount);
if (result != kSuccess) {
@@ -687,16 +677,9 @@ public:
return kInvalidConversion;
}
- // Check to see if scaling was requested.
- if (dstInfo.dimensions() != this->getInfo().dimensions()) {
- if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
- return kInvalidScale;
- }
- }
-
- const Result result = this->initializeSwizzler(dstInfo, options, ctable,
- ctableCount);
- if (result != kSuccess) {
+ const SkCodec::Result result = this->initializeSwizzler(dstInfo, options, ctable,
+ ctableCount);
+ if (result != SkCodec::kSuccess) {
return result;
}
diff --git a/src/codec/SkCodec_libpng.h b/src/codec/SkCodec_libpng.h
index 8ef1ae2c17..3a16cc6813 100644
--- a/src/codec/SkCodec_libpng.h
+++ b/src/codec/SkCodec_libpng.h
@@ -41,6 +41,7 @@ protected:
// Helper to set up swizzler and color table. Also calls png_read_update_info.
Result initializeSwizzler(const SkImageInfo& requestedInfo, const Options&,
SkPMColor*, int* ctableCount);
+ SkSampler* getSampler() override { return fSwizzler; }
SkPngCodec(const SkImageInfo&, SkStream*, png_structp, png_infop, int, int);
diff --git a/src/codec/SkCodec_wbmp.cpp b/src/codec/SkCodec_wbmp.cpp
index 1696dfb585..d7f446bb57 100644
--- a/src/codec/SkCodec_wbmp.cpp
+++ b/src/codec/SkCodec_wbmp.cpp
@@ -9,7 +9,6 @@
#include "SkCodecPriv.h"
#include "SkColorPriv.h"
#include "SkColorTable.h"
-#include "SkScaledCodec.h"
#include "SkStream.h"
#include "SkCodec_wbmp.h"
@@ -79,11 +78,12 @@ SkSwizzler* SkWbmpCodec::initializeSwizzler(const SkImageInfo& info,
case kN32_SkColorType:
case kRGB_565_SkColorType:
case kGray_8_SkColorType:
- return SkSwizzler::CreateSwizzler(SkSwizzler::kBit, ctable, info, opts.fZeroInitialized,
- this->getInfo());
+ break;
default:
return nullptr;
}
+ return SkSwizzler::CreateSwizzler(SkSwizzler::kBit, ctable, info,
+ opts.fZeroInitialized);
}
SkCodec::Result SkWbmpCodec::readRow(uint8_t* row) {
@@ -114,9 +114,6 @@ SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info,
// Subsets are not supported.
return kUnimplemented;
}
- if (info.dimensions() != this->getInfo().dimensions()) {
- return kInvalidScale;
- }
if (!valid_alpha(info.alphaType(), this->getInfo().alphaType())) {
return kInvalidConversion;
@@ -125,7 +122,6 @@ SkCodec::Result SkWbmpCodec::onGetPixels(const SkImageInfo& info,
// Prepare a color table if necessary
setup_color_table(info.colorType(), ctable, ctableCount);
-
// Initialize the swizzler
SkAutoTDelete<SkSwizzler> swizzler(this->initializeSwizzler(info, ctable, options));
if (nullptr == swizzler.get()) {
@@ -181,11 +177,6 @@ SkCodec::Result SkWbmpCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
// Subsets are not supported.
return kUnimplemented;
}
- if (dstInfo.dimensions() != this->getInfo().dimensions()) {
- if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
- return kInvalidScale;
- }
- }
if (!valid_alpha(dstInfo.alphaType(), this->getInfo().alphaType())) {
return kInvalidConversion;
diff --git a/src/codec/SkCodec_wbmp.h b/src/codec/SkCodec_wbmp.h
index 220570b0db..976a5a22f0 100644
--- a/src/codec/SkCodec_wbmp.h
+++ b/src/codec/SkCodec_wbmp.h
@@ -33,6 +33,7 @@ private:
*/
SkSwizzler* initializeSwizzler(const SkImageInfo& info, const SkPMColor* ctable,
const Options& opts);
+ SkSampler* getSampler() override { return fSwizzler; }
/*
* Read a src row from the encoded stream
diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp
index b4c794c906..c9dee9a663 100644
--- a/src/codec/SkJpegCodec.cpp
+++ b/src/codec/SkJpegCodec.cpp
@@ -155,14 +155,28 @@ static int get_row_bytes(const j_decompress_ptr dinfo) {
return dinfo->output_width * colorBytes;
}
+
+/*
+ * Calculate output dimensions based on the provided factors.
+ *
+ * Not to be used on the actual jpeg_decompress_struct used for decoding, since it will
+ * incorrectly modify num_components.
+ */
+void calc_output_dimensions(jpeg_decompress_struct* dinfo, unsigned int num, unsigned int denom) {
+ dinfo->num_components = 0;
+ dinfo->scale_num = num;
+ dinfo->scale_denom = denom;
+ jpeg_calc_output_dimensions(dinfo);
+}
+
/*
* Return a valid set of output dimensions for this decoder, given an input scale
*/
SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const {
// libjpeg-turbo supports scaling by 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1, so we will
// support these as well
- long num;
- long denom = 8;
+ unsigned int num;
+ unsigned int denom = 8;
if (desiredScale > 0.875f) {
num = 8;
} else if (desiredScale > 0.75f) {
@@ -187,10 +201,7 @@ SkISize SkJpegCodec::onGetScaledDimensions(float desiredScale) const {
dinfo.image_width = this->getInfo().width();
dinfo.image_height = this->getInfo().height();
dinfo.global_state = fReadyState;
- dinfo.num_components = 0;
- dinfo.scale_num = num;
- dinfo.scale_denom = denom;
- jpeg_calc_output_dimensions(&dinfo);
+ calc_output_dimensions(&dinfo, num, denom);
// Return the calculated output dimensions for the given scale
return SkISize::Make(dinfo.output_width, dinfo.output_height);
@@ -272,28 +283,40 @@ bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dst) {
* Checks if we can natively scale to the requested dimensions and natively scales the
* dimensions if possible
*/
-bool SkJpegCodec::nativelyScaleToDimensions(uint32_t dstWidth, uint32_t dstHeight) {
+bool SkJpegCodec::onDimensionsSupported(const SkISize& size) {
+ if (setjmp(fDecoderMgr->getJmpBuf())) {
+ return fDecoderMgr->returnFalse("onDimensionsSupported/setjmp");
+ }
+
+ const unsigned int dstWidth = size.width();
+ const unsigned int dstHeight = size.height();
+
+ // Set up a fake decompress struct in order to use libjpeg to calculate output dimensions
+ // FIXME: Why is this necessary?
+ jpeg_decompress_struct dinfo;
+ sk_bzero(&dinfo, sizeof(dinfo));
+ dinfo.image_width = this->getInfo().width();
+ dinfo.image_height = this->getInfo().height();
+ dinfo.global_state = fReadyState;
+
// libjpeg-turbo can scale to 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, and 1/1
- fDecoderMgr->dinfo()->scale_denom = 8;
- fDecoderMgr->dinfo()->scale_num = 8;
- jpeg_calc_output_dimensions(fDecoderMgr->dinfo());
- while (fDecoderMgr->dinfo()->output_width != dstWidth ||
- fDecoderMgr->dinfo()->output_height != dstHeight) {
+ unsigned int num = 8;
+ const unsigned int denom = 8;
+ calc_output_dimensions(&dinfo, num, denom);
+ while (dinfo.output_width != dstWidth || dinfo.output_height != dstHeight) {
// Return a failure if we have tried all of the possible scales
- if (1 == fDecoderMgr->dinfo()->scale_num ||
- dstWidth > fDecoderMgr->dinfo()->output_width ||
- dstHeight > fDecoderMgr->dinfo()->output_height) {
- // reset native scale settings on failure because this may be supported by the swizzler
- this->fDecoderMgr->dinfo()->scale_num = 8;
- jpeg_calc_output_dimensions(this->fDecoderMgr->dinfo());
+ if (1 == num || dstWidth > dinfo.output_width || dstHeight > dinfo.output_height) {
return false;
}
// Try the next scale
- fDecoderMgr->dinfo()->scale_num -= 1;
- jpeg_calc_output_dimensions(fDecoderMgr->dinfo());
+ num -= 1;
+ calc_output_dimensions(&dinfo, num, denom);
}
+
+ fDecoderMgr->dinfo()->scale_num = num;
+ fDecoderMgr->dinfo()->scale_denom = denom;
return true;
}
@@ -321,11 +344,6 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
return fDecoderMgr->returnFailure("conversion_possible", kInvalidConversion);
}
- // Perform the necessary scaling
- if (!this->nativelyScaleToDimensions(dstInfo.width(), dstInfo.height())) {
- return fDecoderMgr->returnFailure("cannot scale to requested dims", kInvalidScale);
- }
-
// Now, given valid output dimensions, we can start the decompress
if (!jpeg_start_decompress(dinfo)) {
return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
@@ -376,7 +394,13 @@ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo,
return kSuccess;
}
-SkCodec::Result SkJpegCodec::initializeSwizzler(const SkImageInfo& info, const Options& options) {
+SkSampler* SkJpegCodec::getSampler() {
+ if (fSwizzler) {
+ SkASSERT(fSrcRow && static_cast<uint8_t*>(fStorage.get()) == fSrcRow);
+ return fSwizzler;
+ }
+
+ const SkImageInfo& info = this->dstInfo();
SkSwizzler::SrcConfig srcConfig;
switch (info.colorType()) {
case kGray_8_SkColorType:
@@ -396,13 +420,15 @@ SkCodec::Result SkJpegCodec::initializeSwizzler(const SkImageInfo& info, const O
SkASSERT(false);
}
- fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, info, options.fZeroInitialized,
- this->getInfo()));
+ fSwizzler.reset(SkSwizzler::CreateSwizzler(srcConfig, nullptr, info,
+ this->options().fZeroInitialized));
if (!fSwizzler) {
- return SkCodec::kUnimplemented;
+ return nullptr;
}
- return kSuccess;
+ fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
+ fSrcRow = static_cast<uint8_t*>(fStorage.get());
+ return fSwizzler;
}
SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
@@ -418,25 +444,10 @@ SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
return kInvalidConversion;
}
- // Perform the necessary scaling
- if (!this->nativelyScaleToDimensions(dstInfo.width(), dstInfo.height())) {
- // full native scaling to dstInfo dimensions not supported
-
- if (!SkScaledCodec::DimensionsSupportedForSampling(this->getInfo(), dstInfo)) {
- return kInvalidScale;
- }
- // create swizzler for sampling
- Result result = this->initializeSwizzler(dstInfo, options);
- if (kSuccess != result) {
- SkCodecPrintf("failed to initialize the swizzler.\n");
- return result;
- }
- fStorage.reset(get_row_bytes(fDecoderMgr->dinfo()));
- fSrcRow = static_cast<uint8_t*>(fStorage.get());
- } else {
- fSrcRow = nullptr;
- fSwizzler.reset(nullptr);
- }
+ // Remove objects used for sampling.
+ fSwizzler.reset(nullptr);
+ fSrcRow = nullptr;
+ fStorage.free();
// Now, given valid output dimensions, we can start the decompress
if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
diff --git a/src/codec/SkJpegCodec.h b/src/codec/SkJpegCodec.h
index b86396317b..24594c1226 100644
--- a/src/codec/SkJpegCodec.h
+++ b/src/codec/SkJpegCodec.h
@@ -58,6 +58,8 @@ protected:
bool onRewind() override;
+ bool onDimensionsSupported(const SkISize&) override;
+
private:
/*
@@ -102,14 +104,8 @@ private:
*/
bool setOutputColorSpace(const SkImageInfo& dst);
- /*
- * Checks if we can natively scale to the requested dimensions and natively scales the
- * dimensions if possible
- */
- bool nativelyScaleToDimensions(uint32_t width, uint32_t height);
-
// scanline decoding
- Result initializeSwizzler(const SkImageInfo&, const SkCodec::Options&);
+ SkSampler* getSampler() override;
Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options,
SkPMColor ctable[], int* ctableCount) override;
Result onGetScanlines(void* dst, int count, size_t rowBytes) override;
diff --git a/src/codec/SkMaskSwizzler.cpp b/src/codec/SkMaskSwizzler.cpp
index 6ca9b58f4e..9772d87e38 100644
--- a/src/codec/SkMaskSwizzler.cpp
+++ b/src/codec/SkMaskSwizzler.cpp
@@ -352,11 +352,7 @@ SkMaskSwizzler* SkMaskSwizzler::CreateMaskSwizzler(
return nullptr;
}
- // Get the sample size
- int sampleX;
- SkScaledCodec::ComputeSampleSize(dstInfo, srcInfo, &sampleX, NULL);
-
- return new SkMaskSwizzler(dstInfo, masks, proc, sampleX);
+ return new SkMaskSwizzler(dstInfo.width(), masks, proc);
}
/*
@@ -364,15 +360,28 @@ SkMaskSwizzler* SkMaskSwizzler::CreateMaskSwizzler(
* Constructor for mask swizzler
*
*/
-SkMaskSwizzler::SkMaskSwizzler(const SkImageInfo& dstInfo, SkMasks* masks,
- RowProc proc, uint32_t sampleX)
- : fDstInfo(dstInfo)
- , fMasks(masks)
+SkMaskSwizzler::SkMaskSwizzler(int width, SkMasks* masks, RowProc proc)
+ : fMasks(masks)
, fRowProc(proc)
- , fSampleX(sampleX)
- , fStartX(get_start_coord(sampleX))
+ , fSrcWidth(width)
+ , fDstWidth(width)
+ , fSampleX(1)
+ , fX0(0)
{}
+int SkMaskSwizzler::onSetSampleX(int sampleX) {
+ // FIXME: Share this function with SkSwizzler?
+ SkASSERT(sampleX > 0); // Surely there is an upper limit? Should there be
+ // way to report failure?
+ fSampleX = sampleX;
+ fX0 = get_start_coord(sampleX);
+ fDstWidth = get_scaled_dimension(fSrcWidth, sampleX);
+
+ // check that fX0 is less than original width
+ SkASSERT(fX0 >= 0 && fX0 < fSrcWidth);
+ return fDstWidth;
+}
+
/*
*
* Swizzle the specified row
@@ -380,5 +389,5 @@ SkMaskSwizzler::SkMaskSwizzler(const SkImageInfo& dstInfo, SkMasks* masks,
*/
SkSwizzler::ResultAlpha SkMaskSwizzler::swizzle(void* dst, const uint8_t* SK_RESTRICT src) {
SkASSERT(nullptr != dst && nullptr != src);
- return fRowProc(dst, src, fDstInfo.width(), fMasks, fStartX, fSampleX);
+ return fRowProc(dst, src, fDstWidth, fMasks, fX0, fSampleX);
}
diff --git a/src/codec/SkMaskSwizzler.h b/src/codec/SkMaskSwizzler.h
index 794dcd16e4..fbc951a070 100644
--- a/src/codec/SkMaskSwizzler.h
+++ b/src/codec/SkMaskSwizzler.h
@@ -8,6 +8,7 @@
#define SkMaskSwizzler_DEFINED
#include "SkMasks.h"
+#include "SkSampler.h"
#include "SkSwizzler.h"
#include "SkTypes.h"
@@ -17,7 +18,7 @@
* Currently only used by bmp
*
*/
-class SkMaskSwizzler {
+class SkMaskSwizzler : public SkSampler {
public:
/*
@@ -46,15 +47,18 @@ private:
/*
* Constructor for mask swizzler
*/
- SkMaskSwizzler(const SkImageInfo& info, SkMasks* masks, RowProc proc,
- uint32_t sampleX);
-
- // Fields
- const SkImageInfo& fDstInfo;
- SkMasks* fMasks; // unowned
- const RowProc fRowProc;
- const uint32_t fSampleX;
- const uint32_t fStartX;
+ SkMaskSwizzler(int width, SkMasks* masks, RowProc proc);
+
+ int onSetSampleX(int) override;
+
+ SkMasks* fMasks; // unowned
+ const RowProc fRowProc;
+
+ // FIXME: Can this class share more with SkSwizzler? These variables are all the same.
+ const int fSrcWidth; // Width of the source - i.e. before any sampling.
+ int fDstWidth; // Width of dst, which may differ with sampling.
+ int fSampleX;
+ int fX0;
};
#endif
diff --git a/src/codec/SkSampler.h b/src/codec/SkSampler.h
new file mode 100644
index 0000000000..d7b4c98f23
--- /dev/null
+++ b/src/codec/SkSampler.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef SkSampler_DEFINED
+#define SkSampler_DEFINED
+
+#include "SkTypes.h"
+
+class SkSampler : public SkNoncopyable {
+public:
+ /**
+ * Update the sampler to sample every sampleX'th pixel. Returns the
+ * width after sampling.
+ */
+ int setSampleX(int sampleX) {
+ return this->onSetSampleX(sampleX);
+ }
+
+ virtual ~SkSampler() {}
+private:
+ virtual int onSetSampleX(int) = 0;
+};
+
+#endif // SkSampler_DEFINED
diff --git a/src/codec/SkScaledCodec.cpp b/src/codec/SkScaledCodec.cpp
index 36aeda98cf..078a0261a0 100644
--- a/src/codec/SkScaledCodec.cpp
+++ b/src/codec/SkScaledCodec.cpp
@@ -100,13 +100,13 @@ SkISize SkScaledCodec::onGetScaledDimensions(float desiredScale) const {
}
// check if scaling to dstInfo size from srcInfo size using sampleSize is possible
-static bool scaling_supported(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo,
+static bool scaling_supported(const SkISize& dstDim, const SkISize& srcDim,
int* sampleX, int* sampleY) {
- SkScaledCodec::ComputeSampleSize(dstInfo, srcInfo, sampleX, sampleY);
- const int dstWidth = dstInfo.width();
- const int dstHeight = dstInfo.height();
- const int srcWidth = srcInfo.width();
- const int srcHeight = srcInfo.height();
+ SkScaledCodec::ComputeSampleSize(dstDim, srcDim, sampleX, sampleY);
+ const int dstWidth = dstDim.width();
+ const int dstHeight = dstDim.height();
+ const int srcWidth = srcDim.width();
+ const int srcHeight = srcDim.height();
// only support down sampling, not up sampling
if (dstWidth > srcWidth || dstHeight > srcHeight) {
return false;
@@ -130,13 +130,29 @@ static bool scaling_supported(const SkImageInfo& dstInfo, const SkImageInfo& src
return true;
}
+bool SkScaledCodec::onDimensionsSupported(const SkISize& dim) {
+ // Check with fCodec first. No need to call the non-virtual version, which
+ // just checks if it matches the original, since a match means this method
+ // will not be called.
+ if (fCodec->onDimensionsSupported(dim)) {
+ return true;
+ }
+
+ // FIXME: These variables are unused, but are needed by scaling_supported.
+ // This class could also cache these values, and avoid calling this in
+ // onGetPixels (since getPixels already calls it).
+ int sampleX;
+ int sampleY;
+ return scaling_supported(dim, this->getInfo().dimensions(), &sampleX, &sampleY);
+}
+
// calculates sampleSize in x and y direction
-void SkScaledCodec::ComputeSampleSize(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo,
+void SkScaledCodec::ComputeSampleSize(const SkISize& dstDim, const SkISize& srcDim,
int* sampleXPtr, int* sampleYPtr) {
- int srcWidth = srcInfo.width();
- int dstWidth = dstInfo.width();
- int srcHeight = srcInfo.height();
- int dstHeight = dstInfo.height();
+ int srcWidth = srcDim.width();
+ int dstWidth = dstDim.width();
+ int srcHeight = srcDim.height();
+ int dstHeight = dstDim.height();
int sampleX = srcWidth / dstWidth;
int sampleY = srcHeight / dstHeight;
@@ -183,62 +199,46 @@ SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi
if (options.fSubset) {
// Subsets are not supported.
return kUnimplemented;
- }
-
- // FIXME: If no scaling/subsets are requested, we can call fCodec->getPixels.
- Result result = fCodec->startScanlineDecode(requestedInfo, &options, ctable, ctableCount);
- if (kSuccess == result) {
- // native decode supported
- switch (fCodec->getScanlineOrder()) {
- case SkCodec::kTopDown_SkScanlineOrder:
- case SkCodec::kBottomUp_SkScanlineOrder:
- case SkCodec::kNone_SkScanlineOrder:
- return fCodec->getScanlines(dst, requestedInfo.height(), rowBytes);
- case SkCodec::kOutOfOrder_SkScanlineOrder: {
- for (int y = 0; y < requestedInfo.height(); y++) {
- int dstY = fCodec->nextScanline();
- void* dstPtr = SkTAddOffset<void>(dst, rowBytes * dstY);
- result = fCodec->getScanlines(dstPtr, 1, rowBytes);
- // FIXME (msarett): Make the SkCodec base class take care of filling
- // uninitialized pixels so we can return immediately on kIncompleteInput.
- if (kSuccess != result && kIncompleteInput != result) {
- return result;
- }
- }
- return result;
- }
- }
}
- if (kInvalidScale != result) {
- // no scaling requested
- return result;
+ if (fCodec->dimensionsSupported(requestedInfo.dimensions())) {
+ return fCodec->getPixels(requestedInfo, dst, rowBytes, &options, ctable, ctableCount);
}
// scaling requested
int sampleX;
int sampleY;
- if (!scaling_supported(requestedInfo, fCodec->getInfo(), &sampleX, &sampleY)) {
+ if (!scaling_supported(requestedInfo.dimensions(), fCodec->getInfo().dimensions(),
+ &sampleX, &sampleY)) {
+ // onDimensionsSupported would have returned false, meaning we should never reach here.
+ SkASSERT(false);
return kInvalidScale;
}
+
// set first sample pixel in y direction
- int Y0 = get_start_coord(sampleY);
-
- int dstHeight = requestedInfo.height();
- int srcHeight = fCodec->getInfo().height();
-
- SkImageInfo info = requestedInfo;
- // use original height as codec does not support y sampling natively
- info = info.makeWH(requestedInfo.width(), srcHeight);
-
- // update codec with new info
- // FIXME: The previous call to start returned kInvalidScale. This call may
- // require a rewind. (skbug.com/4284)
- result = fCodec->startScanlineDecode(info, &options, ctable, ctableCount);
+ const int Y0 = get_start_coord(sampleY);
+
+ const int dstHeight = requestedInfo.height();
+ const int srcWidth = fCodec->getInfo().width();
+ const int srcHeight = fCodec->getInfo().height();
+
+ const SkImageInfo info = requestedInfo.makeWH(srcWidth, srcHeight);
+
+ Result result = fCodec->startScanlineDecode(info, &options, ctable, ctableCount);
+
if (kSuccess != result) {
return result;
}
+ SkSampler* sampler = fCodec->getSampler();
+ if (!sampler) {
+ return kUnimplemented;
+ }
+
+ if (sampler->setSampleX(sampleX) != requestedInfo.width()) {
+ return kInvalidScale;
+ }
+
switch(fCodec->getScanlineOrder()) {
case SkCodec::kTopDown_SkScanlineOrder: {
result = fCodec->skipScanlines(Y0);
diff --git a/src/codec/SkSwizzler.cpp b/src/codec/SkSwizzler.cpp
index a3f1488171..214655b85b 100644
--- a/src/codec/SkSwizzler.cpp
+++ b/src/codec/SkSwizzler.cpp
@@ -516,8 +516,7 @@ static bool swizzle_rgba_to_n32_unpremul_skipZ(void* SK_RESTRICT dstRow,
SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc,
const SkPMColor* ctable,
const SkImageInfo& dstInfo,
- SkCodec::ZeroInitialized zeroInit,
- const SkImageInfo& srcInfo) {
+ SkCodec::ZeroInitialized zeroInit) {
if (dstInfo.colorType() == kUnknown_SkColorType || kUnknown == sc) {
return nullptr;
}
@@ -688,29 +687,35 @@ SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc,
// Store deltaSrc in bytes if it is an even multiple, otherwise use bits
int deltaSrc = SkIsAlign8(BitsPerPixel(sc)) ? BytesPerPixel(sc) : BitsPerPixel(sc);
- // get sampleX based on srcInfo and dstInfo dimensions
- int sampleX;
- SkScaledCodec::ComputeSampleSize(dstInfo, srcInfo, &sampleX, nullptr);
-
- return new SkSwizzler(proc, ctable, deltaSrc, dstInfo, sampleX);
+ return new SkSwizzler(proc, ctable, deltaSrc, dstInfo.width());
}
SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable,
- int deltaSrc, const SkImageInfo& info, int sampleX)
+ int deltaSrc, int srcWidth)
: fRowProc(proc)
, fColorTable(ctable)
, fDeltaSrc(deltaSrc)
- , fDstInfo(info)
- , fSampleX(sampleX)
- , fX0(get_start_coord(sampleX))
-{
+ , fSrcWidth(srcWidth)
+ , fDstWidth(srcWidth)
+ , fSampleX(1)
+ , fX0(0)
+{}
+
+int SkSwizzler::onSetSampleX(int sampleX) {
+ SkASSERT(sampleX > 0); // Surely there is an upper limit? Should there be
+ // way to report failure?
+ fSampleX = sampleX;
+ fX0 = get_start_coord(sampleX);
+ fDstWidth = get_scaled_dimension(fSrcWidth, sampleX);
+
// check that fX0 is less than original width
- SkASSERT(fX0 >= 0 && fX0 < fDstInfo.width() * fSampleX);
+ SkASSERT(fX0 >= 0 && fX0 < fSrcWidth);
+ return fDstWidth;
}
SkSwizzler::ResultAlpha SkSwizzler::swizzle(void* dst, const uint8_t* SK_RESTRICT src) {
SkASSERT(nullptr != dst && nullptr != src);
- return fRowProc(dst, src, fDstInfo.width(), fDeltaSrc, fSampleX * fDeltaSrc,
+ return fRowProc(dst, src, fDstWidth, fDeltaSrc, fSampleX * fDeltaSrc,
fX0 * fDeltaSrc, fColorTable);
}
diff --git a/src/codec/SkSwizzler.h b/src/codec/SkSwizzler.h
index a7f29b0763..9bffccbb47 100644
--- a/src/codec/SkSwizzler.h
+++ b/src/codec/SkSwizzler.h
@@ -11,8 +11,9 @@
#include "SkCodec.h"
#include "SkColor.h"
#include "SkImageInfo.h"
+#include "SkSampler.h"
-class SkSwizzler : public SkNoncopyable {
+class SkSwizzler : public SkSampler {
public:
/**
* Enum describing the config of the source data.
@@ -117,22 +118,17 @@ public:
/**
* Create a new SkSwizzler.
* @param SrcConfig Description of the format of the source.
- * @param dstInfo describes the destination.
+ * @param ctable Unowned pointer to an array of up to 256 colors for an
+ * index source.
+ * @param dstInfo Describes the destination.
* @param ZeroInitialized Whether dst is zero-initialized. The
- implementation may choose to skip writing zeroes
+ * implementation may choose to skip writing zeroes
* if set to kYes_ZeroInitialized.
- * @param srcInfo is the info of the source. Used to calculate the width samplesize.
- * Width sampling is supported by the swizzler, by skipping pixels when
- swizzling the row. Height sampling is not supported by the swizzler,
- but is implemented in SkScaledCodec.
- Sampling in Y can be done by a client with a scanline decoder,
- but sampling in X allows the swizzler to skip swizzling pixels and
- reading from and writing to memory.
* @return A new SkSwizzler or nullptr on failure.
*/
static SkSwizzler* CreateSwizzler(SrcConfig, const SkPMColor* ctable,
- const SkImageInfo& dstInfo, SkCodec::ZeroInitialized,
- const SkImageInfo& srcInfo);
+ const SkImageInfo& dstInfo, SkCodec::ZeroInitialized);
+
/**
* Fill the remainder of the destination with a single color
*
@@ -210,12 +206,13 @@ private:
// deltaSrc is bytesPerPixel
// else
// deltaSrc is bitsPerPixel
- const SkImageInfo fDstInfo;
- int fCurrY;
- const int fX0; // first X coord to sample
- const int fSampleX; // step between X samples
+ const int fSrcWidth; // Width of the source - i.e. before any sampling.
+ int fDstWidth; // Width of dst, which may differ with sampling.
+ int fX0; // first X coord to sample
+ int fSampleX; // step between X samples
+
+ SkSwizzler(RowProc proc, const SkPMColor* ctable, int deltaSrc, int srcWidth);
- SkSwizzler(RowProc proc, const SkPMColor* ctable, int deltaSrc, const SkImageInfo& info,
- int sampleX);
+ int onSetSampleX(int) override;
};
#endif // SkSwizzler_DEFINED
diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp
index 5970baeef6..ccffda9276 100644
--- a/src/codec/SkWebpCodec.cpp
+++ b/src/codec/SkWebpCodec.cpp
@@ -114,6 +114,13 @@ SkISize SkWebpCodec::onGetScaledDimensions(float desiredScale) const {
return dim;
}
+bool SkWebpCodec::onDimensionsSupported(const SkISize& dim) {
+ const SkImageInfo& info = this->getInfo();
+ return dim.width() >= 1 && dim.width() <= info.width()
+ && dim.height() >= 1 && dim.height() <= info.height();
+}
+
+
static WEBP_CSP_MODE webp_decode_mode(SkColorType ct, bool premultiply) {
switch (ct) {
case kBGRA_8888_SkColorType:
diff --git a/src/codec/SkWebpCodec.h b/src/codec/SkWebpCodec.h
index 1fd3acbd16..d60acede7b 100644
--- a/src/codec/SkWebpCodec.h
+++ b/src/codec/SkWebpCodec.h
@@ -31,6 +31,8 @@ protected:
SkISize onGetScaledDimensions(float desiredScale) const override;
+ bool onDimensionsSupported(const SkISize&) override;
+
bool onGetValidSubset(SkIRect* /* desiredSubset */) const override;
private:
SkWebpCodec(const SkImageInfo&, SkStream*);