| 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 "SkCodecPriv.h" | 8 #include "SkCodecPriv.h" |
| 9 #include "SkScaledCodec.h" | 9 #include "SkScaledCodec.h" |
| 10 #include "SkStream.h" | 10 #include "SkStream.h" |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 int scaledHeight = get_scaled_dimension(this->getInfo().height(), sampleSize
); | 93 int scaledHeight = get_scaled_dimension(this->getInfo().height(), sampleSize
); |
| 94 | 94 |
| 95 // Return the calculated output dimensions for the given scale | 95 // Return the calculated output dimensions for the given scale |
| 96 scaledCodecDimensions = SkISize::Make(scaledWidth, scaledHeight); | 96 scaledCodecDimensions = SkISize::Make(scaledWidth, scaledHeight); |
| 97 | 97 |
| 98 return best_scaled_dimensions(this->getInfo().dimensions(), nativeDimensions
, | 98 return best_scaled_dimensions(this->getInfo().dimensions(), nativeDimensions
, |
| 99 scaledCodecDimensions, desiredScale); | 99 scaledCodecDimensions, desiredScale); |
| 100 } | 100 } |
| 101 | 101 |
| 102 // check if scaling to dstInfo size from srcInfo size using sampleSize is possib
le | 102 // check if scaling to dstInfo size from srcInfo size using sampleSize is possib
le |
| 103 static bool scaling_supported(const SkImageInfo& dstInfo, const SkImageInfo& src
Info, | 103 static bool scaling_supported(const SkISize& dstDim, const SkISize& srcDim, |
| 104 int* sampleX, int* sampleY) { | 104 int* sampleX, int* sampleY) { |
| 105 SkScaledCodec::ComputeSampleSize(dstInfo, srcInfo, sampleX, sampleY); | 105 SkScaledCodec::ComputeSampleSize(dstDim, srcDim, sampleX, sampleY); |
| 106 const int dstWidth = dstInfo.width(); | 106 const int dstWidth = dstDim.width(); |
| 107 const int dstHeight = dstInfo.height(); | 107 const int dstHeight = dstDim.height(); |
| 108 const int srcWidth = srcInfo.width(); | 108 const int srcWidth = srcDim.width(); |
| 109 const int srcHeight = srcInfo.height(); | 109 const int srcHeight = srcDim.height(); |
| 110 // only support down sampling, not up sampling | 110 // only support down sampling, not up sampling |
| 111 if (dstWidth > srcWidth || dstHeight > srcHeight) { | 111 if (dstWidth > srcWidth || dstHeight > srcHeight) { |
| 112 return false; | 112 return false; |
| 113 } | 113 } |
| 114 // check that srcWidth is scaled down by an integer value | 114 // check that srcWidth is scaled down by an integer value |
| 115 if (get_scaled_dimension(srcWidth, *sampleX) != dstWidth) { | 115 if (get_scaled_dimension(srcWidth, *sampleX) != dstWidth) { |
| 116 return false; | 116 return false; |
| 117 } | 117 } |
| 118 // check that src height is scaled down by an integer value | 118 // check that src height is scaled down by an integer value |
| 119 if (get_scaled_dimension(srcHeight, *sampleY) != dstHeight) { | 119 if (get_scaled_dimension(srcHeight, *sampleY) != dstHeight) { |
| 120 return false; | 120 return false; |
| 121 } | 121 } |
| 122 // sampleX and sampleY should be equal unless the original sampleSize reques
ted was larger | 122 // sampleX and sampleY should be equal unless the original sampleSize reques
ted was larger |
| 123 // than srcWidth or srcHeight. If so, the result of this is dstWidth or dstH
eight = 1. | 123 // than srcWidth or srcHeight. If so, the result of this is dstWidth or dstH
eight = 1. |
| 124 // This functionality allows for tall thin images to still be scaled down by
scaling factors. | 124 // This functionality allows for tall thin images to still be scaled down by
scaling factors. |
| 125 if (*sampleX != *sampleY){ | 125 if (*sampleX != *sampleY){ |
| 126 if (1 != dstWidth && 1 != dstHeight) { | 126 if (1 != dstWidth && 1 != dstHeight) { |
| 127 return false; | 127 return false; |
| 128 } | 128 } |
| 129 } | 129 } |
| 130 return true; | 130 return true; |
| 131 } | 131 } |
| 132 | 132 |
| 133 bool SkScaledCodec::onDimensionsSupported(const SkISize& dim) { |
| 134 // Check with fCodec first. No need to call the non-virtual version, which |
| 135 // just checks if it matches the original, since a match means this method |
| 136 // will not be called. |
| 137 if (fCodec->onDimensionsSupported(dim)) { |
| 138 return true; |
| 139 } |
| 140 |
| 141 // FIXME: These variables are unused, but are needed by scaling_supported. |
| 142 // This class could also cache these values, and avoid calling this in |
| 143 // onGetPixels (since getPixels already calls it). |
| 144 int sampleX; |
| 145 int sampleY; |
| 146 return scaling_supported(dim, this->getInfo().dimensions(), &sampleX, &sampl
eY); |
| 147 } |
| 148 |
| 133 // calculates sampleSize in x and y direction | 149 // calculates sampleSize in x and y direction |
| 134 void SkScaledCodec::ComputeSampleSize(const SkImageInfo& dstInfo, const SkImageI
nfo& srcInfo, | 150 void SkScaledCodec::ComputeSampleSize(const SkISize& dstDim, const SkISize& srcD
im, |
| 135 int* sampleXPtr, int* sampleYPtr) { | 151 int* sampleXPtr, int* sampleYPtr) { |
| 136 int srcWidth = srcInfo.width(); | 152 int srcWidth = srcDim.width(); |
| 137 int dstWidth = dstInfo.width(); | 153 int dstWidth = dstDim.width(); |
| 138 int srcHeight = srcInfo.height(); | 154 int srcHeight = srcDim.height(); |
| 139 int dstHeight = dstInfo.height(); | 155 int dstHeight = dstDim.height(); |
| 140 | 156 |
| 141 int sampleX = srcWidth / dstWidth; | 157 int sampleX = srcWidth / dstWidth; |
| 142 int sampleY = srcHeight / dstHeight; | 158 int sampleY = srcHeight / dstHeight; |
| 143 | 159 |
| 144 // only support down sampling, not up sampling | 160 // only support down sampling, not up sampling |
| 145 SkASSERT(dstWidth <= srcWidth); | 161 SkASSERT(dstWidth <= srcWidth); |
| 146 SkASSERT(dstHeight <= srcHeight); | 162 SkASSERT(dstHeight <= srcHeight); |
| 147 | 163 |
| 148 // sampleX and sampleY should be equal unless the original sampleSize reques
ted was | 164 // sampleX and sampleY should be equal unless the original sampleSize reques
ted was |
| 149 // larger than srcWidth or srcHeight. | 165 // larger than srcWidth or srcHeight. |
| (...skipping 26 matching lines...) Expand all Loading... |
| 176 | 192 |
| 177 // TODO: Implement subsetting in onGetPixels which works when and when not sampl
ing | 193 // TODO: Implement subsetting in onGetPixels which works when and when not sampl
ing |
| 178 | 194 |
| 179 SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi
d* dst, | 195 SkCodec::Result SkScaledCodec::onGetPixels(const SkImageInfo& requestedInfo, voi
d* dst, |
| 180 size_t rowBytes, const Options& optio
ns, | 196 size_t rowBytes, const Options& optio
ns, |
| 181 SkPMColor ctable[], int* ctableCount)
{ | 197 SkPMColor ctable[], int* ctableCount)
{ |
| 182 | 198 |
| 183 if (options.fSubset) { | 199 if (options.fSubset) { |
| 184 // Subsets are not supported. | 200 // Subsets are not supported. |
| 185 return kUnimplemented; | 201 return kUnimplemented; |
| 186 } | |
| 187 | |
| 188 // FIXME: If no scaling/subsets are requested, we can call fCodec->getPixels
. | |
| 189 Result result = fCodec->startScanlineDecode(requestedInfo, &options, ctable,
ctableCount); | |
| 190 if (kSuccess == result) { | |
| 191 // native decode supported | |
| 192 switch (fCodec->getScanlineOrder()) { | |
| 193 case SkCodec::kTopDown_SkScanlineOrder: | |
| 194 case SkCodec::kBottomUp_SkScanlineOrder: | |
| 195 case SkCodec::kNone_SkScanlineOrder: | |
| 196 return fCodec->getScanlines(dst, requestedInfo.height(), rowByte
s); | |
| 197 case SkCodec::kOutOfOrder_SkScanlineOrder: { | |
| 198 for (int y = 0; y < requestedInfo.height(); y++) { | |
| 199 int dstY = fCodec->nextScanline(); | |
| 200 void* dstPtr = SkTAddOffset<void>(dst, rowBytes * dstY); | |
| 201 result = fCodec->getScanlines(dstPtr, 1, rowBytes); | |
| 202 // FIXME (msarett): Make the SkCodec base class take care of
filling | |
| 203 // uninitialized pixels so we can return immediately on kInc
ompleteInput. | |
| 204 if (kSuccess != result && kIncompleteInput != result) { | |
| 205 return result; | |
| 206 } | |
| 207 } | |
| 208 return result; | |
| 209 } | |
| 210 } | |
| 211 } | 202 } |
| 212 | 203 |
| 213 if (kInvalidScale != result) { | 204 if (fCodec->dimensionsSupported(requestedInfo.dimensions())) { |
| 214 // no scaling requested | 205 return fCodec->getPixels(requestedInfo, dst, rowBytes, &options, ctable,
ctableCount); |
| 215 return result; | |
| 216 } | 206 } |
| 217 | 207 |
| 218 // scaling requested | 208 // scaling requested |
| 219 int sampleX; | 209 int sampleX; |
| 220 int sampleY; | 210 int sampleY; |
| 221 if (!scaling_supported(requestedInfo, fCodec->getInfo(), &sampleX, &sampleY)
) { | 211 if (!scaling_supported(requestedInfo.dimensions(), fCodec->getInfo().dimensi
ons(), |
| 212 &sampleX, &sampleY)) { |
| 213 // onDimensionsSupported would have returned false, meaning we should ne
ver reach here. |
| 214 SkASSERT(false); |
| 222 return kInvalidScale; | 215 return kInvalidScale; |
| 223 } | 216 } |
| 217 |
| 224 // set first sample pixel in y direction | 218 // set first sample pixel in y direction |
| 225 int Y0 = get_start_coord(sampleY); | 219 const int Y0 = get_start_coord(sampleY); |
| 226 | 220 |
| 227 int dstHeight = requestedInfo.height(); | 221 const int dstHeight = requestedInfo.height(); |
| 228 int srcHeight = fCodec->getInfo().height(); | 222 const int srcWidth = fCodec->getInfo().width(); |
| 229 | 223 const int srcHeight = fCodec->getInfo().height(); |
| 230 SkImageInfo info = requestedInfo; | |
| 231 // use original height as codec does not support y sampling natively | |
| 232 info = info.makeWH(requestedInfo.width(), srcHeight); | |
| 233 | 224 |
| 234 // update codec with new info | 225 const SkImageInfo info = requestedInfo.makeWH(srcWidth, srcHeight); |
| 235 // FIXME: The previous call to start returned kInvalidScale. This call may | 226 |
| 236 // require a rewind. (skbug.com/4284) | 227 Result result = fCodec->startScanlineDecode(info, &options, ctable, ctableCo
unt); |
| 237 result = fCodec->startScanlineDecode(info, &options, ctable, ctableCount); | 228 |
| 238 if (kSuccess != result) { | 229 if (kSuccess != result) { |
| 239 return result; | 230 return result; |
| 240 } | 231 } |
| 241 | 232 |
| 233 SkSampler* sampler = fCodec->getSampler(); |
| 234 if (!sampler) { |
| 235 return kUnimplemented; |
| 236 } |
| 237 |
| 238 if (sampler->setSampleX(sampleX) != requestedInfo.width()) { |
| 239 return kInvalidScale; |
| 240 } |
| 241 |
| 242 switch(fCodec->getScanlineOrder()) { | 242 switch(fCodec->getScanlineOrder()) { |
| 243 case SkCodec::kTopDown_SkScanlineOrder: { | 243 case SkCodec::kTopDown_SkScanlineOrder: { |
| 244 result = fCodec->skipScanlines(Y0); | 244 result = fCodec->skipScanlines(Y0); |
| 245 if (kSuccess != result && kIncompleteInput != result) { | 245 if (kSuccess != result && kIncompleteInput != result) { |
| 246 return result; | 246 return result; |
| 247 } | 247 } |
| 248 for (int y = 0; y < dstHeight; y++) { | 248 for (int y = 0; y < dstHeight; y++) { |
| 249 result = fCodec->getScanlines(dst, 1, rowBytes); | 249 result = fCodec->getScanlines(dst, 1, rowBytes); |
| 250 if (kSuccess != result && kIncompleteInput != result) { | 250 if (kSuccess != result && kIncompleteInput != result) { |
| 251 return result; | 251 return result; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 292 storagePtr += sampleY * rowBytes; | 292 storagePtr += sampleY * rowBytes; |
| 293 dst = SkTAddOffset<void>(dst, rowBytes); | 293 dst = SkTAddOffset<void>(dst, rowBytes); |
| 294 } | 294 } |
| 295 return result; | 295 return result; |
| 296 } | 296 } |
| 297 default: | 297 default: |
| 298 SkASSERT(false); | 298 SkASSERT(false); |
| 299 return kUnimplemented; | 299 return kUnimplemented; |
| 300 } | 300 } |
| 301 } | 301 } |
| OLD | NEW |