aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar msarett <msarett@google.com>2015-11-17 11:18:03 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2015-11-17 11:18:03 -0800
commit5af4e0bc8fd17944f3c0527462aeba367f6d590a (patch)
treeff0c7b83d85fc5480879732e8e7cee68757fc391 /src
parentc08d53ee175e190254d8fd6659d9ad051ac0ba46 (diff)
Make SkAndroidCodec support gif
Involves a few bug fixes in SkCodec_libgif and a bit more complexity in SkSwizzler. BUG=skia:4405 Review URL: https://codereview.chromium.org/1445313002
Diffstat (limited to 'src')
-rw-r--r--src/codec/SkAndroidCodec.cpp1
-rw-r--r--src/codec/SkCodec_libgif.cpp54
-rw-r--r--src/codec/SkSampledCodec.cpp3
-rw-r--r--src/codec/SkSwizzler.cpp47
-rw-r--r--src/codec/SkSwizzler.h106
5 files changed, 140 insertions, 71 deletions
diff --git a/src/codec/SkAndroidCodec.cpp b/src/codec/SkAndroidCodec.cpp
index b0a78d0b17..86c067558f 100644
--- a/src/codec/SkAndroidCodec.cpp
+++ b/src/codec/SkAndroidCodec.cpp
@@ -33,6 +33,7 @@ SkAndroidCodec* SkAndroidCodec::NewFromStream(SkStream* stream) {
case kJPEG_SkEncodedFormat:
case kWBMP_SkEncodedFormat:
case kBMP_SkEncodedFormat:
+ case kGIF_SkEncodedFormat:
return new SkSampledCodec(codec.detach());
default:
// FIXME: SkSampledCodec is temporarily disabled for other formats
diff --git a/src/codec/SkCodec_libgif.cpp b/src/codec/SkCodec_libgif.cpp
index 03107aba2e..65503558aa 100644
--- a/src/codec/SkCodec_libgif.cpp
+++ b/src/codec/SkCodec_libgif.cpp
@@ -436,12 +436,16 @@ SkCodec::Result SkGifCodec::prepareToDecode(const SkImageInfo& dstInfo, SkPMColo
// Initialize color table and copy to the client if necessary
this->initializeColorTable(dstInfo, inputColorPtr, inputColorCount);
- return kSuccess;
+
+ return this->initializeSwizzler(dstInfo, opts);
}
SkCodec::Result SkGifCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts) {
const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
- fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, colorPtr, dstInfo, opts));
+ const SkIRect* frameRect = fFrameIsSubset ? &fFrameRect : nullptr;
+ fSwizzler.reset(SkSwizzler::CreateSwizzler(SkSwizzler::kIndex, colorPtr, dstInfo, opts,
+ frameRect));
+
if (nullptr != fSwizzler.get()) {
return kSuccess;
}
@@ -472,29 +476,14 @@ SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo,
// Initialize the swizzler
if (fFrameIsSubset) {
- const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFrameRect.height());
- if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts)) {
- return gif_error("Could not initialize swizzler.\n", kUnimplemented);
- }
-
// Fill the background
SkSampler::Fill(dstInfo, dst, dstRowBytes,
this->getFillValue(dstInfo.colorType(), dstInfo.alphaType()),
opts.fZeroInitialized);
-
- // Modify the dst pointer
- const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorType());
- dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() +
- dstBytesPerPixel * fFrameRect.left());
- } else {
- if (kSuccess != this->initializeSwizzler(dstInfo, opts)) {
- return gif_error("Could not initialize swizzler.\n", kUnimplemented);
- }
}
// Iterate over rows of the input
- uint32_t height = fFrameRect.height();
- for (uint32_t y = 0; y < height; y++) {
+ for (int y = fFrameRect.top(); y < fFrameRect.bottom(); y++) {
if (!this->readRow()) {
*rowsDecoded = y;
return gif_error("Could not decode line.\n", kIncompleteInput);
@@ -514,25 +503,7 @@ uint32_t SkGifCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaType
SkCodec::Result SkGifCodec::onStartScanlineDecode(const SkImageInfo& dstInfo,
const SkCodec::Options& opts, SkPMColor inputColorPtr[], int* inputColorCount) {
-
- Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, this->options());
- if (kSuccess != result) {
- return result;
- }
-
- // Initialize the swizzler
- if (fFrameIsSubset) {
- const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFrameRect.height());
- if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts)) {
- return gif_error("Could not initialize swizzler.\n", kUnimplemented);
- }
- } else {
- if (kSuccess != this->initializeSwizzler(dstInfo, opts)) {
- return gif_error("Could not initialize swizzler.\n", kUnimplemented);
- }
- }
-
- return kSuccess;
+ return this->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, this->options());
}
int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) {
@@ -544,7 +515,7 @@ int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) {
SkImageInfo fillInfo = this->dstInfo().makeWH(this->dstInfo().width(), count);
uint32_t fillValue = this->onGetFillValue(this->dstInfo().colorType(),
this->dstInfo().alphaType());
- SkSampler::Fill(fillInfo, dst, rowBytes, fillValue, this->options().fZeroInitialized);
+ fSwizzler->fill(fillInfo, dst, rowBytes, fillValue, this->options().fZeroInitialized);
// Do nothing for rows before the image frame
rowsBeforeFrame = SkTMax(0, fFrameRect.top() - this->INHERITED::nextScanline());
@@ -555,10 +526,6 @@ int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) {
rowsAfterFrame = SkTMax(0,
this->INHERITED::nextScanline() + rowsInFrame - fFrameRect.bottom());
rowsInFrame = SkTMax(0, rowsInFrame - rowsAfterFrame);
-
- // Adjust dst pointer for left offset
- int offset = SkColorTypeBytesPerPixel(this->dstInfo().colorType()) * fFrameRect.left();
- dst = SkTAddOffset<void>(dst, offset);
}
for (int i = 0; i < rowsInFrame; i++) {
@@ -584,7 +551,8 @@ int SkGifCodec::onOutputScanline(int inputScanline) const {
if (inputScanline < fFrameRect.top() || inputScanline >= fFrameRect.bottom()) {
return inputScanline;
}
- return get_output_row_interlaced(inputScanline - fFrameRect.top(), fFrameRect.height());
+ return get_output_row_interlaced(inputScanline - fFrameRect.top(), fFrameRect.height()) +
+ fFrameRect.top();
}
return inputScanline;
}
diff --git a/src/codec/SkSampledCodec.cpp b/src/codec/SkSampledCodec.cpp
index 08c4f2a3ab..52e5648742 100644
--- a/src/codec/SkSampledCodec.cpp
+++ b/src/codec/SkSampledCodec.cpp
@@ -226,8 +226,9 @@ SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix
}
return SkCodec::kSuccess;
}
+ case SkCodec::kOutOfOrder_SkScanlineOrder:
case SkCodec::kBottomUp_SkScanlineOrder: {
- // Note that this mode does not support subsetting.
+ // Note that these modes do not support subsetting.
SkASSERT(0 == subsetY && nativeSize.height() == subsetHeight);
int y;
for (y = 0; y < nativeSize.height(); y++) {
diff --git a/src/codec/SkSwizzler.cpp b/src/codec/SkSwizzler.cpp
index 242866db44..d783380294 100644
--- a/src/codec/SkSwizzler.cpp
+++ b/src/codec/SkSwizzler.cpp
@@ -594,7 +594,8 @@ static bool swizzle_rgba_to_n32_unpremul_skipZ(void* SK_RESTRICT dstRow,
SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc,
const SkPMColor* ctable,
const SkImageInfo& dstInfo,
- const SkCodec::Options& options) {
+ const SkCodec::Options& options,
+ const SkIRect* frame) {
if (dstInfo.colorType() == kUnknown_SkColorType || kUnknown == sc) {
return nullptr;
}
@@ -776,43 +777,59 @@ SkSwizzler* SkSwizzler::CreateSwizzler(SkSwizzler::SrcConfig sc,
}
// Store bpp in bytes if it is an even multiple, otherwise use bits
- int bpp = SkIsAlign8(BitsPerPixel(sc)) ? BytesPerPixel(sc) : BitsPerPixel(sc);
+ int srcBPP = SkIsAlign8(BitsPerPixel(sc)) ? BytesPerPixel(sc) : BitsPerPixel(sc);
+ int dstBPP = SkColorTypeBytesPerPixel(dstInfo.colorType());
int srcOffset = 0;
int srcWidth = dstInfo.width();
+ int dstOffset = 0;
+ int dstWidth = srcWidth;
if (options.fSubset) {
+ // We do not currently support subset decodes for image types that may have
+ // frames (gif).
+ SkASSERT(!frame);
srcOffset = options.fSubset->left();
srcWidth = options.fSubset->width();
+ dstWidth = srcWidth;
+ } else if (frame) {
+ dstOffset = frame->left();
+ srcWidth = frame->width();
}
- return new SkSwizzler(proc, ctable, srcOffset, srcWidth, bpp);
+ return new SkSwizzler(proc, ctable, srcOffset, srcWidth, dstOffset, dstWidth, srcBPP, dstBPP);
}
-SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable, int srcOffset, int subsetWidth,
- int bpp)
+SkSwizzler::SkSwizzler(RowProc proc, const SkPMColor* ctable, int srcOffset, int srcWidth,
+ int dstOffset, int dstWidth, int srcBPP, int dstBPP)
: fRowProc(proc)
, fColorTable(ctable)
, fSrcOffset(srcOffset)
- , fX0(srcOffset)
- , fSubsetWidth(subsetWidth)
- , fDstWidth(subsetWidth)
+ , fDstOffset(dstOffset)
+ , fSrcOffsetUnits(srcOffset * srcBPP)
+ , fDstOffsetBytes(dstOffset * dstBPP)
+ , fSrcWidth(srcWidth)
+ , fDstWidth(dstWidth)
+ , fSwizzleWidth(srcWidth)
+ , fAllocatedWidth(dstWidth)
, fSampleX(1)
- , fBPP(bpp)
+ , fSrcBPP(srcBPP)
+ , fDstBPP(dstBPP)
{}
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) + fSrcOffset;
- fDstWidth = get_scaled_dimension(fSubsetWidth, sampleX);
+ fSrcOffsetUnits = (get_start_coord(sampleX) + fSrcOffset) * fSrcBPP;
+ fDstOffsetBytes = (fDstOffset / sampleX) * fDstBPP;
+ fSwizzleWidth = get_scaled_dimension(fSrcWidth, sampleX);
+ fAllocatedWidth = get_scaled_dimension(fDstWidth, sampleX);
- // check that fX0 is valid
- SkASSERT(fX0 >= 0);
- return fDstWidth;
+ return fAllocatedWidth;
}
SkSwizzler::ResultAlpha SkSwizzler::swizzle(void* dst, const uint8_t* SK_RESTRICT src) {
SkASSERT(nullptr != dst && nullptr != src);
- return fRowProc(dst, src, fDstWidth, fBPP, fSampleX * fBPP, fX0 * fBPP, fColorTable);
+ return fRowProc(SkTAddOffset<void>(dst, fDstOffsetBytes), src, fSwizzleWidth, fSrcBPP,
+ fSampleX * fSrcBPP, fSrcOffsetUnits, fColorTable);
}
diff --git a/src/codec/SkSwizzler.h b/src/codec/SkSwizzler.h
index 691dc77aa6..7f5bbc6209 100644
--- a/src/codec/SkSwizzler.h
+++ b/src/codec/SkSwizzler.h
@@ -126,11 +126,19 @@ public:
* @param options Indicates if dst is zero-initialized. The
* implementation may choose to skip writing zeroes
* if set to kYes_ZeroInitialized.
- * Contains subset information.
+ * Contains partial scanline information.
+ * @param frame Is non-NULL if the source pixels are part of an image
+ * frame that is a subset of the full image.
+ *
+ * Note that a deeper discussion of partial scanline subsets and image frame
+ * subsets is below. Currently, we do not support both simultaneously. If
+ * options->fSubset is non-NULL, frame must be NULL.
+ *
* @return A new SkSwizzler or nullptr on failure.
*/
static SkSwizzler* CreateSwizzler(SrcConfig, const SkPMColor* ctable,
- const SkImageInfo& dstInfo, const SkCodec::Options&);
+ const SkImageInfo& dstInfo, const SkCodec::Options&,
+ const SkIRect* frame = nullptr);
/**
* Swizzle a line. Generally this will be called height times, once
@@ -151,7 +159,7 @@ public:
*/
void fill(const SkImageInfo& info, void* dst, size_t rowBytes, uint32_t colorOrIndex,
SkCodec::ZeroInitialized zeroInit) override {
- const SkImageInfo fillInfo = info.makeWH(fDstWidth, info.height());
+ const SkImageInfo fillInfo = info.makeWH(fAllocatedWidth, info.height());
SkSampler::Fill(fillInfo, dst, rowBytes, colorOrIndex, zeroInit);
}
@@ -176,19 +184,93 @@ private:
const RowProc fRowProc;
const SkPMColor* fColorTable; // Unowned pointer
- const int fSrcOffset; // Offset of the src in pixels, allows for partial
- // scanline decodes.
- int fX0; // Start coordinate for the src, may be different than
- // fSrcOffset if we are sampling.
- const int fSubsetWidth; // Width of the subset of the source before any sampling.
- int fDstWidth; // Width of dst, which may differ with sampling.
- int fSampleX; // step between X samples
- const int fBPP; // if bitsPerPixel % 8 == 0
+
+ // Subset Swizzles
+ // There are two types of subset swizzles that we support. We do not
+ // support both at the same time.
+ // TODO: If we want to support partial scanlines for gifs (which may
+ // use frame subsets), we will need to support both subsetting
+ // modes at the same time.
+ // (1) Partial Scanlines
+ // The client only wants to write a subset of the source pixels
+ // to the destination. This subset is specified to CreateSwizzler
+ // using options->fSubset. We will store subset information in
+ // the following fields.
+ //
+ // fSrcOffset: The starting pixel of the source.
+ // fSrcOffsetUnits: Derived from fSrcOffset with two key
+ // differences:
+ // (1) This takes the size of source pixels into
+ // account by multiplying by fSrcBPP. This may
+ // be measured in bits or bytes depending on
+ // which is natural for the SrcConfig.
+ // (2) If we are sampling, this will be larger
+ // than fSrcOffset * fSrcBPP, since sampling
+ // implies that we will skip some pixels.
+ // fDstOffset: Will be zero. There is no destination offset
+ // for this type of subset.
+ // fDstOffsetBytes: Will be zero.
+ // fSrcWidth: The width of the desired subset of source
+ // pixels, before any sampling is performed.
+ // fDstWidth: Will be equal to fSrcWidth, since this is also
+ // calculated before any sampling is performed.
+ // For this type of subset, the destination width
+ // matches the desired subset of the source.
+ // fSwizzleWidth: The actual number of pixels that will be
+ // written by the RowProc. This is a scaled
+ // version of fSrcWidth/fDstWidth.
+ // fAllocatedWidth: Will be equal to fSwizzleWidth. For this type
+ // of subset, the number of pixels written is the
+ // same as the actual width of the destination.
+ // (2) Frame Subset
+ // The client will decode the entire width of the source into a
+ // subset of destination memory. This subset is specified to
+ // CreateSwizzler in the "frame" parameter. We store subset
+ // information in the following fields.
+ //
+ // fSrcOffset: Will be zero. The starting pixel of the source.
+ // fSrcOffsetUnits: Will only be non-zero if we are sampling,
+ // since sampling implies that we will skip some
+ // pixels. Note that this is measured in bits
+ // or bytes depending on which is natural for
+ // SrcConfig.
+ // fDstOffset: First pixel to write in destination.
+ // fDstOffsetBytes: fDstOffset * fDstBPP.
+ // fSrcWidth: The entire width of the source pixels, before
+ // any sampling is performed.
+ // fDstWidth: The entire width of the destination memory,
+ // before any sampling is performed.
+ // fSwizzleWidth: The actual number of pixels that will be
+ // written by the RowProc. This is a scaled
+ // version of fSrcWidth.
+ // fAllocatedWidth: The actual number of pixels in destination
+ // memory. This is a scaled version of
+ // fDstWidth.
+ //
+ // If we are not subsetting, these fields are more straightforward.
+ // fSrcOffset = fDstOffet = fDstOffsetBytes = 0
+ // fSrcOffsetUnits may be non-zero (we will skip the first few pixels when sampling)
+ // fSrcWidth = fDstWidth = Full original width
+ // fSwizzleWidth = fAllcoatedWidth = Scaled width (if we are sampling)
+ const int fSrcOffset;
+ const int fDstOffset;
+ int fSrcOffsetUnits;
+ int fDstOffsetBytes;
+ const int fSrcWidth;
+ const int fDstWidth;
+ int fSwizzleWidth;
+ int fAllocatedWidth;
+
+ int fSampleX; // Step between X samples
+ const int fSrcBPP; // Bits/bytes per pixel for the SrcConfig
+ // if bitsPerPixel % 8 == 0
// fBPP is bytesPerPixel
// else
// fBPP is bitsPerPixel
+ const int fDstBPP; // Bytes per pixel for the destination color type
- SkSwizzler(RowProc proc, const SkPMColor* ctable, int srcOffset, int subsetWidth, int bpp);
+ SkSwizzler(RowProc proc, const SkPMColor* ctable, int srcOffset, int srcWidth, int dstOffset,
+ int dstWidth, int srcBPP, int dstBPP);
int onSetSampleX(int) override;