Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkCodec.h" | |
| 8 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
| 9 #include "SkScaledCodec.h" | 10 #include "SkScaledCodec.h" |
| 10 #include "SkStream.h" | 11 |
| 11 #include "SkWebpCodec.h" | 12 SkSampledCodec::SkSampledCodec(SkCodec* codec) |
| 12 | 13 : INHERITED(codec->getInfo()) |
| 13 | |
| 14 SkCodec* SkScaledCodec::NewFromStream(SkStream* stream) { | |
| 15 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromStream(stream)); | |
| 16 if (nullptr == codec) { | |
| 17 return nullptr; | |
| 18 } | |
| 19 | |
| 20 switch (codec->getEncodedFormat()) { | |
| 21 case kWEBP_SkEncodedFormat: | |
| 22 // Webp codec supports scaling and subsetting natively | |
| 23 return codec.detach(); | |
| 24 case kPNG_SkEncodedFormat: | |
| 25 case kJPEG_SkEncodedFormat: | |
| 26 // wrap in new SkScaledCodec | |
| 27 return new SkScaledCodec(codec.detach()); | |
| 28 default: | |
| 29 // FIXME: SkScaledCodec is temporarily disabled for other formats | |
| 30 // while focusing on the formats that are supported by | |
| 31 // BitmapRegionDecoder. | |
| 32 return nullptr; | |
| 33 } | |
| 34 } | |
| 35 | |
| 36 SkCodec* SkScaledCodec::NewFromData(SkData* data) { | |
| 37 if (!data) { | |
| 38 return nullptr; | |
| 39 } | |
| 40 return NewFromStream(new SkMemoryStream(data)); | |
| 41 } | |
| 42 | |
| 43 SkScaledCodec::SkScaledCodec(SkCodec* codec) | |
| 44 : INHERITED(codec->getInfo(), nullptr) | |
| 45 , fCodec(codec) | 14 , fCodec(codec) |
| 46 {} | 15 {} |
| 47 | 16 |
| 48 SkScaledCodec::~SkScaledCodec() {} | 17 static bool is_in_range(int coord, int offset, int length) { |
|
scroggo
2015/10/16 21:13:55
I still need to look over this file in more detail
| |
| 49 | 18 return coord >= offset && coord < offset + length; |
| 50 bool SkScaledCodec::onRewind() { | 19 } |
| 51 return fCodec->onRewind(); | 20 |
| 52 } | 21 SkISize SkSampledCodec::onGetSampledDimensions(int sampleSize) const { |
| 53 | 22 // Fast path for when we are not scaling. |
| 54 static SkISize best_scaled_dimensions(const SkISize& origDims, const SkISize& na tiveDims, | 23 if (1 == sampleSize) { |
| 55 const SkISize& scaledCodecDims, float desi redScale) { | 24 return fCodec->getInfo().dimensions(); |
| 56 if (nativeDims == scaledCodecDims) { | 25 } |
| 57 // does not matter which to return if equal. Return here to skip below c alculations | 26 |
| 58 return nativeDims; | 27 const int width = fCodec->getInfo().width(); |
| 59 } | 28 const int height = fCodec->getInfo().height(); |
| 60 float idealWidth = origDims.width() * desiredScale; | 29 |
| 61 float idealHeight = origDims.height() * desiredScale; | 30 // Check if the codec can provide the scaling natively. |
| 62 | 31 float scale = get_scale_from_sample_size(sampleSize); |
| 63 // calculate difference between native dimensions and ideal dimensions | 32 SkSize idealSize = SkSize::Make(scale * (float) width, scale * (float) heigh t); |
| 64 float nativeWDiff = SkTAbs(idealWidth - nativeDims.width()); | 33 SkISize nativeSize = fCodec->getScaledDimensions(scale); |
| 65 float nativeHDiff = SkTAbs(idealHeight - nativeDims.height()); | 34 float widthDiff = SkTAbs(((float) nativeSize.width()) - idealSize.width()); |
| 66 float nativeDiff = nativeWDiff + nativeHDiff; | 35 float heightDiff = SkTAbs(((float) nativeSize.height()) - idealSize.height() ); |
| 67 | 36 if (widthDiff < 1.0f && heightDiff < 1.0f) { |
| 68 // Native scaling is preferred to sampling. If we can scale natively to | 37 return nativeSize; |
| 69 // within one of the ideal value, we should choose to scale natively. | 38 } |
| 70 if (nativeWDiff < 1.0f && nativeHDiff < 1.0f) { | 39 |
| 71 return nativeDims; | 40 // Provide the scaling by sampling. |
| 72 } | 41 return SkISize::Make(get_scaled_dimension(width, sampleSize), |
| 73 | 42 get_scaled_dimension(height, sampleSize)); |
| 74 // calculate difference between scaledCodec dimensions and ideal dimensions | 43 } |
| 75 float scaledCodecWDiff = SkTAbs(idealWidth - scaledCodecDims.width()); | 44 |
| 76 float scaledCodecHDiff = SkTAbs(idealHeight - scaledCodecDims.height()); | 45 SkISize SkSampledCodec::onGetSampledSubsetDimensions(int sampleSize, const SkIRe ct& subset) const { |
|
scroggo
2015/10/19 20:03:20
Interesting - this function is no longer virtual (
msarett
2015/10/19 21:39:21
Yeah I agree that it makes sense but is a little w
| |
| 77 float scaledCodecDiff = scaledCodecWDiff + scaledCodecHDiff; | 46 // This call is less expensive than onGetSampledDimensions() because, regard less |
| 78 | 47 // of the scaling method, we are free to choose how many of the pixels that we |
| 79 // return dimensions closest to ideal dimensions. | 48 // want to clip. |
| 80 // If the differences are equal, return nativeDims, as native scaling is mor e efficient. | 49 // Alternatively, we could call onGetSampledDimensions(), calculate the scal e |
| 81 return nativeDiff > scaledCodecDiff ? scaledCodecDims : nativeDims; | 50 // as a float and do our best to apply an identical scale here. But I'm not |
| 82 } | 51 // sure that there is any added benefit to that approach. |
| 83 | 52 |
| 84 /* | 53 // We should, however, be sure that if the subset specifies the entire image , |
| 85 * Return a valid set of output dimensions for this decoder, given an input scal e | 54 // we will perform a full image decode. |
| 86 */ | 55 if (fCodec->getInfo().dimensions() == subset.size()) { |
| 87 SkISize SkScaledCodec::onGetScaledDimensions(float desiredScale) const { | 56 return onGetSampledDimensions(sampleSize); |
| 88 SkISize nativeDimensions = fCodec->getScaledDimensions(desiredScale); | 57 } |
| 89 // support scaling down by integer numbers. Ex: 1/2, 1/3, 1/4 ... | 58 |
| 90 SkISize scaledCodecDimensions; | 59 return SkISize::Make(get_scaled_dimension(subset.width(), sampleSize), |
| 91 if (desiredScale > 0.5f) { | 60 get_scaled_dimension(subset.height(), sampleSize)); |
| 92 // sampleSize = 1 | 61 } |
| 93 scaledCodecDimensions = fCodec->getInfo().dimensions(); | 62 |
| 94 } | 63 SkCodec::Result SkSampledCodec::onGetAndroidPixels(const SkImageInfo& info, void * pixels, |
| 95 // sampleSize determines the step size between samples | 64 size_t rowBytes, AndroidOptions& options) { |
| 96 // Ex: sampleSize = 2, sample every second pixel in x and y directions | 65 // Create an Options struct for the codec. |
| 97 int sampleSize = int ((1.0f / desiredScale) + 0.5f); | 66 SkCodec::Options codecOptions; |
| 98 | 67 codecOptions.fZeroInitialized = options.fZeroInitialized; |
| 99 int scaledWidth = get_scaled_dimension(this->getInfo().width(), sampleSize); | 68 |
| 100 int scaledHeight = get_scaled_dimension(this->getInfo().height(), sampleSize ); | 69 SkIRect* subset = options.fSubset; |
| 101 | 70 if (!subset || subset->size() == fCodec->getInfo().dimensions()) { |
| 102 // Return the calculated output dimensions for the given scale | 71 // Try to use the native codec to perform the decode. |
| 103 scaledCodecDimensions = SkISize::Make(scaledWidth, scaledHeight); | 72 SkCodec::Result result = fCodec->getPixels(info, pixels, rowBytes, &code cOptions, |
| 104 | 73 options.fColorPtr, options.fColorCount); |
| 105 return best_scaled_dimensions(this->getInfo().dimensions(), nativeDimensions , | 74 |
| 106 scaledCodecDimensions, desiredScale); | 75 if (SkCodec::kInvalidScale != result) { |
| 107 } | 76 return result; |
| 108 | 77 } |
| 109 // check if scaling to dstInfo size from srcInfo size using sampleSize is possib le | 78 |
| 110 static bool scaling_supported(const SkISize& dstDim, const SkISize& srcDim, | 79 // If the native codec does not support the requested scale, scale by sa mpling. |
| 111 int* sampleX, int* sampleY) { | 80 return sampledDecode(info, pixels, rowBytes, options); |
| 112 SkScaledCodec::ComputeSampleSize(dstDim, srcDim, sampleX, sampleY); | 81 } |
| 113 const int dstWidth = dstDim.width(); | 82 |
| 114 const int dstHeight = dstDim.height(); | 83 // We are performing a subset decode. |
| 115 const int srcWidth = srcDim.width(); | 84 // First attempt to use the native codec. The native codec needs to know th e scaled size |
| 116 const int srcHeight = srcDim.height(); | 85 // of the image and the subset. |
| 117 // only support down sampling, not up sampling | 86 int sampleSize = options.fSampleSize; |
| 118 if (dstWidth > srcWidth || dstHeight > srcHeight) { | 87 // FIXME: We already make this same function call in getAndroidPixels(). |
| 119 return false; | 88 SkISize scaledSize = this->onGetSampledDimensions(sampleSize); |
| 120 } | 89 int scaledSubsetX = subset->x() / sampleSize; |
| 121 // check that srcWidth is scaled down by an integer value | 90 int scaledSubsetY = subset->y() / sampleSize; |
| 122 if (get_scaled_dimension(srcWidth, *sampleX) != dstWidth) { | 91 int scaledSubsetWidth = info.width(); |
| 123 return false; | 92 int scaledSubsetHeight = info.height(); |
| 124 } | 93 |
| 125 // check that src height is scaled down by an integer value | 94 // The scanline decoder only needs to be aware of scaledSubsetX and scaledSu bestWidth. |
| 126 if (get_scaled_dimension(srcHeight, *sampleY) != dstHeight) { | 95 // We will handling subsetting in the y-dimension by skipping scanlines. |
| 127 return false; | 96 SkIRect scanlineSubset = SkIRect::MakeXYWH(scaledSubsetX, 0, scaledSubsetWid th, |
| 128 } | 97 scaledSize.height()); |
| 129 // sampleX and sampleY should be equal unless the original sampleSize reques ted was larger | 98 codecOptions.fSubset = &scanlineSubset; |
| 130 // than srcWidth or srcHeight. If so, the result of this is dstWidth or dstH eight = 1. | 99 SkCodec::Result result = fCodec->startScanlineDecode(info.makeWH(scaledSize. width(), |
| 131 // This functionality allows for tall thin images to still be scaled down by scaling factors. | 100 scaledSize.height()), &codecOptions, options.fColorPtr, options.fCol orCount); |
| 132 if (*sampleX != *sampleY){ | 101 switch (result) { |
| 133 if (1 != dstWidth && 1 != dstHeight) { | 102 case SkCodec::kSuccess: |
| 134 return false; | 103 break; |
| 135 } | 104 case SkCodec::kInvalidScale: |
| 136 } | 105 // If the native codec does not support the requested scale, scale b y sampling. |
| 137 return true; | 106 return sampledDecode(info, pixels, rowBytes, options); |
| 138 } | 107 default: |
| 139 | 108 return result; |
| 140 bool SkScaledCodec::onDimensionsSupported(const SkISize& dim) { | 109 } |
| 141 // Check with fCodec first. No need to call the non-virtual version, which | 110 |
| 142 // just checks if it matches the original, since a match means this method | 111 switch (fCodec->getScanlineOrder()) { |
| 143 // will not be called. | 112 case SkCodec::kTopDown_SkScanlineOrder: |
| 144 if (fCodec->onDimensionsSupported(dim)) { | 113 case SkCodec::kNone_SkScanlineOrder: { |
| 145 return true; | 114 if (!fCodec->skipScanlines(scaledSubsetY)) { |
| 146 } | 115 fCodec->fillIncompleteImage(info, pixels, rowBytes, options.fZer oInitialized, |
| 147 | 116 scaledSubsetHeight, 0); |
| 148 // FIXME: These variables are unused, but are needed by scaling_supported. | 117 return SkCodec::kIncompleteInput; |
| 149 // This class could also cache these values, and avoid calling this in | 118 } |
| 150 // onGetPixels (since getPixels already calls it). | 119 |
| 151 int sampleX; | 120 int decodedLines = fCodec->getScanlines(pixels, scaledSubsetHeight, rowBytes); |
| 152 int sampleY; | 121 if (decodedLines != scaledSubsetHeight) { |
| 153 return scaling_supported(dim, this->getInfo().dimensions(), &sampleX, &sampl eY); | 122 return SkCodec::kIncompleteInput; |
| 154 } | 123 } |
| 155 | 124 return SkCodec::kSuccess; |
| 156 // calculates sampleSize in x and y direction | 125 } |
| 157 void SkScaledCodec::ComputeSampleSize(const SkISize& dstDim, const SkISize& srcD im, | 126 case SkCodec::kBottomUp_SkScanlineOrder: |
| 158 int* sampleXPtr, int* sampleYPtr) { | 127 case SkCodec::kOutOfOrder_SkScanlineOrder: { |
| 159 int srcWidth = srcDim.width(); | 128 for (int y = 0; y < scaledSize.height(); y++) { |
| 160 int dstWidth = dstDim.width(); | 129 int dstY = fCodec->nextScanline(); |
| 161 int srcHeight = srcDim.height(); | 130 if (is_in_range(dstY, scaledSubsetY, scaledSubsetHeight)) { |
| 162 int dstHeight = dstDim.height(); | 131 void* pixelsPtr = SkTAddOffset<void>(pixels, rowBytes * (dst Y - scaledSubsetY)); |
| 163 | 132 if (1 != fCodec->getScanlines(pixelsPtr, 1, rowBytes)) { |
| 164 int sampleX = srcWidth / dstWidth; | 133 // FIXME: Fill incomplete images skbug.com/4428 |
| 165 int sampleY = srcHeight / dstHeight; | 134 return SkCodec::kIncompleteInput; |
| 166 | 135 } |
| 167 // only support down sampling, not up sampling | 136 } else { |
| 168 SkASSERT(dstWidth <= srcWidth); | 137 if (!fCodec->skipScanlines(1)) { |
| 169 SkASSERT(dstHeight <= srcHeight); | 138 // FIXME: Fill incomplete images skbug.com/4428 |
| 170 | 139 return SkCodec::kIncompleteInput; |
| 171 // sampleX and sampleY should be equal unless the original sampleSize reques ted was | 140 } |
| 172 // larger than srcWidth or srcHeight. | 141 } |
| 173 // If so, the result of this is dstWidth or dstHeight = 1. This functionalit y | 142 } |
| 174 // allows for tall thin images to still be scaled down by scaling factors. | 143 return SkCodec::kSuccess; |
| 175 | 144 } |
| 176 if (sampleX != sampleY){ | 145 default: |
| 177 if (1 != dstWidth && 1 != dstHeight) { | 146 SkASSERT(false); |
| 178 | 147 return SkCodec::kUnimplemented; |
| 179 // rounding during onGetScaledDimensions can cause different sampleS izes | 148 } |
| 180 // Ex: srcWidth = 79, srcHeight = 20, sampleSize = 10 | 149 } |
| 181 // dstWidth = 7, dstHeight = 2, sampleX = 79/7 = 11, sampleY = 20/2 = 10 | 150 |
| 182 // correct for this rounding by comparing width to sampleY and heigh t to sampleX | 151 |
| 183 | 152 SkCodec::Result SkSampledCodec::sampledDecode(const SkImageInfo& info, void* pix els, |
| 184 if (get_scaled_dimension(srcWidth, sampleY) == dstWidth) { | 153 size_t rowBytes, AndroidOptions& options) { |
| 185 sampleX = sampleY; | 154 // Create options struct for the codec. |
| 186 } else if (get_scaled_dimension(srcHeight, sampleX) == dstHeight) { | 155 SkCodec::Options sampledOptions; |
| 187 sampleY = sampleX; | 156 sampledOptions.fZeroInitialized = options.fZeroInitialized; |
| 188 } | 157 |
| 189 } | 158 // Check if there is a subset. |
| 190 } | 159 SkIRect subset; |
| 191 | 160 int subsetY = 0; |
| 192 if (sampleXPtr) { | 161 int subsetWidth = fCodec->getInfo().width(); |
| 193 *sampleXPtr = sampleX; | 162 int subsetHeight = fCodec->getInfo().height(); |
| 194 } | |
| 195 if (sampleYPtr) { | |
| 196 *sampleYPtr = sampleY; | |
| 197 } | |
| 198 } | |
| 199 | |
| 200 // TODO: Implement subsetting in onGetPixels which works when and when not sampl ing | |
| 201 | |
| 202 SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi d* dst, | |
| 203 size_t rowBytes, const Options& optio ns, | |
| 204 SkPMColor ctable[], int* ctableCount, | |
| 205 int* rowsDecoded) { | |
| 206 | |
| 207 if (options.fSubset) { | 163 if (options.fSubset) { |
| 208 // Subsets are not supported. | 164 // We will need to know about subsetting in the y-dimension in order to use the |
| 209 return kUnimplemented; | 165 // scanline decoder. |
| 210 } | 166 SkIRect* subsetPtr = options.fSubset; |
| 211 | 167 subsetY = subsetPtr->y(); |
| 212 if (fCodec->dimensionsSupported(requestedInfo.dimensions())) { | 168 subsetWidth = subsetPtr->width(); |
| 213 // Make sure that the parent class does not fill on an incomplete decode , since | 169 subsetHeight = subsetPtr->height(); |
| 214 // fCodec will take care of filling the uninitialized lines. | 170 |
| 215 *rowsDecoded = requestedInfo.height(); | 171 // The scanline decoder only needs to be aware of subsetting in the x-di mension. |
| 216 return fCodec->getPixels(requestedInfo, dst, rowBytes, &options, ctable, ctableCount); | 172 subset.setXYWH(subsetPtr->x(), 0, subsetWidth, fCodec->getInfo().height( )); |
| 217 } | 173 sampledOptions.fSubset = ⊂ |
| 218 | 174 } |
| 219 // scaling requested | 175 |
| 220 int sampleX; | 176 // Start the scanline decode. |
| 221 int sampleY; | 177 SkCodec::Result result = fCodec->startScanlineDecode( |
| 222 if (!scaling_supported(requestedInfo.dimensions(), fCodec->getInfo().dimensi ons(), | 178 info.makeWH(fCodec->getInfo().width(), fCodec->getInfo().height()), &sampledOptions, |
| 223 &sampleX, &sampleY)) { | 179 options.fColorPtr, options.fColorCount); |
| 224 // onDimensionsSupported would have returned false, meaning we should ne ver reach here. | 180 if (SkCodec::kSuccess != result) { |
| 225 SkASSERT(false); | 181 // If scaling is not supported, we should have caught the error |
| 226 return kInvalidScale; | 182 // in getAndroidPixels(). |
| 227 } | 183 SkASSERT(SkCodec::kInvalidScale != result); |
| 228 | |
| 229 // set first sample pixel in y direction | |
| 230 const int Y0 = get_start_coord(sampleY); | |
| 231 | |
| 232 const int dstHeight = requestedInfo.height(); | |
| 233 const int srcWidth = fCodec->getInfo().width(); | |
| 234 const int srcHeight = fCodec->getInfo().height(); | |
| 235 | |
| 236 const SkImageInfo info = requestedInfo.makeWH(srcWidth, srcHeight); | |
| 237 | |
| 238 Result result = fCodec->startScanlineDecode(info, &options, ctable, ctableCo unt); | |
| 239 | |
| 240 if (kSuccess != result) { | |
| 241 return result; | 184 return result; |
| 242 } | 185 } |
| 243 | 186 |
| 244 SkSampler* sampler = fCodec->getSampler(true); | 187 SkSampler* sampler = fCodec->getSampler(true); |
| 245 if (!sampler) { | 188 if (!sampler) { |
| 246 return kUnimplemented; | 189 return SkCodec::kUnimplemented; |
| 247 } | 190 } |
| 248 | 191 |
| 249 if (sampler->setSampleX(sampleX) != requestedInfo.width()) { | 192 // Since we guarantee that output dimensions are always at least one (even i f the sampleSize |
| 250 return kInvalidScale; | 193 // is greater than a given dimension), the input sampleSize is not always th e sampleSize that |
| 251 } | 194 // we use in practice. |
| 252 | 195 int sampleX = subsetWidth / info.width(); |
| 196 int sampleY = subsetHeight / info.height(); | |
| 197 if (sampler->setSampleX(sampleX) != info.width()) { | |
| 198 SkASSERT(false); | |
| 199 return SkCodec::kInvalidScale; | |
| 200 } | |
| 201 | |
| 202 int y0 = get_start_coord(sampleY); | |
| 203 int dstHeight = info.height(); | |
| 253 switch(fCodec->getScanlineOrder()) { | 204 switch(fCodec->getScanlineOrder()) { |
| 254 case SkCodec::kTopDown_SkScanlineOrder: { | 205 case SkCodec::kTopDown_SkScanlineOrder: { |
| 255 if (!fCodec->skipScanlines(Y0)) { | 206 if (!fCodec->skipScanlines(y0 + subsetY)) { |
| 256 *rowsDecoded = 0; | 207 fCodec->fillIncompleteImage(info, pixels, rowBytes, options.fZer oInitialized, |
| 257 return kIncompleteInput; | 208 dstHeight, 0); |
| 258 } | 209 return SkCodec::kIncompleteInput; |
| 210 } | |
| 211 void* pixelPtr = pixels; | |
| 259 for (int y = 0; y < dstHeight; y++) { | 212 for (int y = 0; y < dstHeight; y++) { |
| 260 if (1 != fCodec->getScanlines(dst, 1, rowBytes)) { | 213 if (1 != fCodec->getScanlines(pixelPtr, 1, rowBytes)) { |
| 261 // The failed call to getScanlines() will take care of | 214 fCodec->fillIncompleteImage(info, pixels, rowBytes, options. fZeroInitialized, |
| 262 // filling the failed row, so we indicate that we have | 215 dstHeight, y + 1); |
| 263 // decoded (y + 1) rows. | 216 return SkCodec::kIncompleteInput; |
| 264 *rowsDecoded = y + 1; | 217 } |
| 265 return kIncompleteInput; | 218 int linesToSkip = SkTMin(sampleY - 1, dstHeight - y - 1); |
| 266 } | 219 if (!fCodec->skipScanlines(linesToSkip)) { |
| 267 if (y < dstHeight - 1) { | 220 fCodec->fillIncompleteImage(info, pixels, rowBytes, options. fZeroInitialized, |
| 268 if (!fCodec->skipScanlines(sampleY - 1)) { | 221 dstHeight, y + 1); |
| 269 *rowsDecoded = y + 1; | 222 return SkCodec::kIncompleteInput; |
| 270 return kIncompleteInput; | 223 } |
| 271 } | 224 pixelPtr = SkTAddOffset<void>(pixelPtr, rowBytes); |
| 272 } | 225 } |
| 273 dst = SkTAddOffset<void>(dst, rowBytes); | 226 return SkCodec::kSuccess; |
| 274 } | |
| 275 return kSuccess; | |
| 276 } | 227 } |
| 277 case SkCodec::kBottomUp_SkScanlineOrder: | 228 case SkCodec::kBottomUp_SkScanlineOrder: |
| 278 case SkCodec::kOutOfOrder_SkScanlineOrder: { | 229 case SkCodec::kOutOfOrder_SkScanlineOrder: { |
| 279 Result result = kSuccess; | 230 SkCodec::Result result = SkCodec::kSuccess; |
| 280 int y; | 231 int y; |
| 281 for (y = 0; y < srcHeight; y++) { | 232 for (y = 0; y < fCodec->getInfo().height(); y++) { |
| 282 int srcY = fCodec->nextScanline(); | 233 int srcY = fCodec->nextScanline(); |
| 283 if (is_coord_necessary(srcY, sampleY, dstHeight)) { | 234 if (is_coord_necessary(srcY, sampleY, dstHeight, subsetY)) { |
| 284 void* dstPtr = SkTAddOffset<void>(dst, rowBytes * get_dst_co ord(srcY, sampleY)); | 235 void* pixelPtr = SkTAddOffset<void>(pixels, |
| 285 if (1 != fCodec->getScanlines(dstPtr, 1, rowBytes)) { | 236 rowBytes * get_dst_coord(srcY, sampleY)); |
| 286 result = kIncompleteInput; | 237 if (1 != fCodec->getScanlines(pixelPtr, 1, rowBytes)) { |
| 238 result = SkCodec::kIncompleteInput; | |
| 287 break; | 239 break; |
| 288 } | 240 } |
| 289 } else { | 241 } else { |
| 290 if (!fCodec->skipScanlines(1)) { | 242 if (!fCodec->skipScanlines(1)) { |
| 291 result = kIncompleteInput; | 243 result = SkCodec::kIncompleteInput; |
| 292 break; | 244 break; |
| 293 } | 245 } |
| 294 } | 246 } |
| 295 } | 247 } |
| 296 | 248 |
| 297 // We handle filling uninitialized memory here instead of in the par ent class. | 249 // We handle filling uninitialized memory here instead of using fCod ec. |
| 298 // The parent class does not know that we are sampling. | 250 // fCodec does not know that we are sampling. |
| 299 if (kIncompleteInput == result) { | 251 if (SkCodec::kIncompleteInput == result) { |
| 300 const uint32_t fillValue = fCodec->getFillValue(requestedInfo.co lorType(), | 252 const uint32_t fillValue = fCodec->getFillValue(info.colorType() , |
| 301 requestedInfo.alphaType()); | 253 info.alphaType()); |
| 302 for (; y < srcHeight; y++) { | 254 for (; y < fCodec->getInfo().height(); y++) { |
| 303 int srcY = fCodec->outputScanline(y); | 255 int srcY = fCodec->outputScanline(y); |
| 304 if (is_coord_necessary(srcY, sampleY, dstHeight)) { | 256 if (is_coord_necessary(srcY, sampleY, dstHeight, subsetY)) { |
| 305 void* dstRow = SkTAddOffset<void>(dst, | 257 void* pixelPtr = SkTAddOffset<void>(pixels, |
| 306 rowBytes * get_dst_coord(srcY, sampleY)); | 258 rowBytes * get_dst_coord(srcY, sampleY)); |
| 307 SkSampler::Fill(requestedInfo.makeWH(requestedInfo.width (), 1), dstRow, | 259 SkSampler::Fill(info.makeWH(info.width(), 1), pixelPtr, rowBytes, fillValue, |
| 308 rowBytes, fillValue, options.fZeroInitialized); | 260 options.fZeroInitialized); |
| 309 } | 261 } |
| 310 } | 262 } |
| 311 *rowsDecoded = dstHeight; | |
| 312 } | 263 } |
| 313 return result; | 264 return result; |
| 314 } | 265 } |
| 315 case SkCodec::kNone_SkScanlineOrder: { | 266 case SkCodec::kNone_SkScanlineOrder: { |
| 316 SkAutoMalloc storage(srcHeight * rowBytes); | 267 SkAutoMalloc storage((subsetHeight - y0) * rowBytes); |
| 317 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); | 268 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); |
| 318 int scanlines = fCodec->getScanlines(storagePtr, srcHeight, rowBytes ); | 269 if (!fCodec->skipScanlines(subsetY + y0)) { |
| 319 storagePtr += Y0 * rowBytes; | 270 fCodec->fillIncompleteImage(info, pixels, rowBytes, options.fZer oInitialized, |
| 320 scanlines -= Y0; | 271 dstHeight, 0); |
| 272 return SkCodec::kIncompleteInput; | |
| 273 } | |
| 274 int scanlines = fCodec->getScanlines(storagePtr, subsetHeight - y0, rowBytes); | |
| 321 int y = 0; | 275 int y = 0; |
| 322 while (y < dstHeight && scanlines > 0) { | 276 void* pixelPtr = pixels; |
| 323 memcpy(dst, storagePtr, rowBytes); | 277 while (y < dstHeight) { |
| 278 memcpy(pixelPtr, storagePtr, info.minRowBytes()); | |
| 324 storagePtr += sampleY * rowBytes; | 279 storagePtr += sampleY * rowBytes; |
| 325 dst = SkTAddOffset<void>(dst, rowBytes); | 280 pixelPtr = SkTAddOffset<void>(pixelPtr, rowBytes); |
| 326 scanlines -= sampleY; | |
| 327 y++; | 281 y++; |
| 328 } | 282 } |
| 329 if (y < dstHeight) { | 283 if (scanlines < dstHeight) { |
| 330 // fCodec has already handled filling uninitialized memory. | 284 // fCodec has already handled filling uninitialized memory. |
| 331 *rowsDecoded = dstHeight; | 285 return SkCodec::kIncompleteInput; |
| 332 return kIncompleteInput; | 286 } |
| 333 } | 287 return SkCodec::kSuccess; |
| 334 return kSuccess; | |
| 335 } | 288 } |
| 336 default: | 289 default: |
| 337 SkASSERT(false); | 290 SkASSERT(false); |
| 338 return kUnimplemented; | 291 return SkCodec::kUnimplemented; |
| 339 } | 292 } |
| 340 } | 293 } |
| 341 | |
| 342 uint32_t SkScaledCodec::onGetFillValue(SkColorType colorType, SkAlphaType alphaT ype) const { | |
| 343 return fCodec->onGetFillValue(colorType, alphaType); | |
| 344 } | |
| 345 | |
| 346 SkCodec::SkScanlineOrder SkScaledCodec::onGetScanlineOrder() const { | |
| 347 return fCodec->onGetScanlineOrder(); | |
| 348 } | |
| OLD | NEW |