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 "SkBmpCodec.h" | 8 #include "SkBmpCodec.h" |
| 9 #include "SkCodec.h" | 9 #include "SkCodec.h" |
| 10 #include "SkData.h" | 10 #include "SkData.h" |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 75 return NewFromStream(new SkMemoryStream(data)); | 75 return NewFromStream(new SkMemoryStream(data)); |
| 76 } | 76 } |
| 77 | 77 |
| 78 SkCodec::SkCodec(const SkImageInfo& info, SkStream* stream) | 78 SkCodec::SkCodec(const SkImageInfo& info, SkStream* stream) |
| 79 : fSrcInfo(info) | 79 : fSrcInfo(info) |
| 80 , fStream(stream) | 80 , fStream(stream) |
| 81 , fNeedsRewind(false) | 81 , fNeedsRewind(false) |
| 82 , fDstInfo() | 82 , fDstInfo() |
| 83 , fOptions() | 83 , fOptions() |
| 84 , fCurrScanline(-1) | 84 , fCurrScanline(-1) |
| 85 , fSubsetWidth(0) | |
| 85 {} | 86 {} |
| 86 | 87 |
| 87 SkCodec::~SkCodec() {} | 88 SkCodec::~SkCodec() {} |
| 88 | 89 |
| 89 bool SkCodec::rewindIfNeeded() { | 90 bool SkCodec::rewindIfNeeded() { |
| 90 if (!fStream) { | 91 if (!fStream) { |
| 91 // Some codecs do not have a stream, but they hold others that do. They | 92 // Some codecs do not have a stream, but they hold others that do. They |
| 92 // must handle rewinding themselves. | 93 // must handle rewinding themselves. |
| 93 return true; | 94 return true; |
| 94 } | 95 } |
| 95 | 96 |
| 96 // Store the value of fNeedsRewind so we can update it. Next read will | 97 // Store the value of fNeedsRewind so we can update it. Next read will |
| 97 // require a rewind. | 98 // require a rewind. |
| 98 const bool needsRewind = fNeedsRewind; | 99 const bool needsRewind = fNeedsRewind; |
| 99 fNeedsRewind = true; | 100 fNeedsRewind = true; |
| 100 if (!needsRewind) { | 101 if (!needsRewind) { |
| 101 return true; | 102 return true; |
| 102 } | 103 } |
| 103 | 104 |
| 104 // startScanlineDecode will need to be called before decoding scanlines. | 105 // startScanlineDecode will need to be called before decoding scanlines. |
| 105 fCurrScanline = -1; | 106 fCurrScanline = -1; |
| 107 fSubsetWidth = 0; | |
| 106 | 108 |
| 107 if (!fStream->rewind()) { | 109 if (!fStream->rewind()) { |
| 108 return false; | 110 return false; |
| 109 } | 111 } |
| 110 | 112 |
| 111 return this->onRewind(); | 113 return this->onRewind(); |
| 112 } | 114 } |
| 113 | 115 |
| 116 SkISize SkCodec::getScaledDimensions(float desiredScale) const { | |
| 117 // Negative and zero scales are errors. | |
| 118 SkASSERT(desiredScale > 0.0f); | |
| 119 if (desiredScale <= 0.0f) { | |
| 120 return SkISize::Make(0, 0); | |
| 121 } | |
| 122 | |
| 123 // Upscaling is not supported. Return the original size if the client | |
| 124 // requests an upscale. | |
| 125 if (desiredScale >= 1.0f) { | |
| 126 return this->getInfo().dimensions(); | |
| 127 } | |
| 128 return this->onGetScaledDimensions(desiredScale); | |
| 129 } | |
| 130 | |
| 131 bool SkCodec::getValidSubset(SkIRect* desiredSubset) const { | |
| 132 if (!desiredSubset) { | |
| 133 return false; | |
| 134 } | |
| 135 | |
| 136 if (!is_valid_subset(desiredSubset, this->getInfo().dimensions())) { | |
| 137 return false; | |
| 138 } | |
| 139 | |
| 140 return this->onGetValidSubset(desiredSubset); | |
| 141 } | |
| 142 | |
| 143 bool SkCodec::getScaledSubsetDimensions(float desiredScale, Options* options) co nst { | |
| 144 // Negative and zero scales are errors. | |
| 145 SkASSERT(desiredScale > 0.0f); | |
| 146 if (desiredScale <= 0.0f) { | |
| 147 return false; | |
| 148 } | |
| 149 | |
| 150 // Upscaling is not supported. We will suggest a full decode if | |
| 151 // upscaling is requested. | |
| 152 if (desiredScale >= 1.0f) { | |
| 153 desiredScale = 1.0f; | |
| 154 } | |
| 155 | |
| 156 // If the client is not requesting a subset decode, | |
| 157 // getScaledDimensions() should be used. | |
| 158 if (nullptr == options->fSubset) { | |
| 159 return false; | |
| 160 } | |
| 161 | |
| 162 if (!is_valid_subset(options->fSubset, this->getInfo().dimensions())) { | |
| 163 return false; | |
| 164 } | |
| 165 | |
| 166 return this->onGetScaledSubsetDimensions(desiredScale, options); | |
| 167 } | |
| 168 | |
| 114 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, | 169 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, |
| 115 const Options* options, SkPMColor ctable[], i nt* ctableCount) { | 170 const Options* options, SkPMColor ctable[], i nt* ctableCount) { |
| 116 if (kUnknown_SkColorType == info.colorType()) { | 171 if (kUnknown_SkColorType == info.colorType()) { |
| 117 return kInvalidConversion; | 172 return kInvalidConversion; |
| 118 } | 173 } |
| 119 if (nullptr == pixels) { | 174 if (nullptr == pixels) { |
| 120 return kInvalidParameters; | 175 return kInvalidParameters; |
| 121 } | 176 } |
| 122 if (rowBytes < info.minRowBytes()) { | 177 if (rowBytes < info.minRowBytes()) { |
| 123 return kInvalidParameters; | 178 return kInvalidParameters; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 175 } | 230 } |
| 176 | 231 |
| 177 return result; | 232 return result; |
| 178 } | 233 } |
| 179 | 234 |
| 180 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { | 235 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { |
| 181 return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr); | 236 return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr); |
| 182 } | 237 } |
| 183 | 238 |
| 184 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, | 239 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, |
| 185 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { | 240 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount, i nt subsetLeft, |
| 241 int subsetWidth) { | |
| 186 // Reset fCurrScanline in case of failure. | 242 // Reset fCurrScanline in case of failure. |
| 187 fCurrScanline = -1; | 243 fCurrScanline = -1; |
| 244 | |
| 245 // Ensure that the subset parameters are valid | |
| 246 if (0 > subsetLeft || subsetLeft >= dstInfo.width() || 0 > subsetWidth || | |
|
scroggo
2015/10/02 18:27:03
nit: I would lean towards separating these out log
| |
| 247 subsetLeft + subsetWidth > dstInfo.width()) { | |
| 248 return kInvalidParameters; | |
| 249 } | |
| 250 | |
| 188 // Ensure that valid color ptrs are passed in for kIndex8 color type | 251 // Ensure that valid color ptrs are passed in for kIndex8 color type |
| 189 if (kIndex_8_SkColorType == dstInfo.colorType()) { | 252 if (kIndex_8_SkColorType == dstInfo.colorType()) { |
| 190 if (nullptr == ctable || nullptr == ctableCount) { | 253 if (nullptr == ctable || nullptr == ctableCount) { |
| 191 return SkCodec::kInvalidParameters; | 254 return SkCodec::kInvalidParameters; |
| 192 } | 255 } |
| 193 } else { | 256 } else { |
| 194 if (ctableCount) { | 257 if (ctableCount) { |
| 195 *ctableCount = 0; | 258 *ctableCount = 0; |
| 196 } | 259 } |
| 197 ctableCount = nullptr; | 260 ctableCount = nullptr; |
| 198 ctable = nullptr; | 261 ctable = nullptr; |
| 199 } | 262 } |
| 200 | 263 |
| 201 if (!this->rewindIfNeeded()) { | 264 if (!this->rewindIfNeeded()) { |
| 202 return kCouldNotRewind; | 265 return kCouldNotRewind; |
| 203 } | 266 } |
| 204 | 267 |
| 205 // Set options. | 268 // Set options. |
| 206 Options optsStorage; | 269 Options optsStorage; |
| 207 if (nullptr == options) { | 270 if (nullptr == options) { |
| 208 options = &optsStorage; | 271 options = &optsStorage; |
| 209 } | 272 } |
| 210 | 273 |
| 211 const Result result = this->onStartScanlineDecode(dstInfo, *options, ctable, ctableCount); | 274 const Result result = this->onStartScanlineDecode(dstInfo, *options, ctable, ctableCount, |
| 275 subsetLeft, subsetWidth); | |
| 212 if (result != SkCodec::kSuccess) { | 276 if (result != SkCodec::kSuccess) { |
| 213 return result; | 277 return result; |
| 214 } | 278 } |
| 215 | 279 |
| 216 fCurrScanline = 0; | 280 fCurrScanline = 0; |
| 217 fDstInfo = dstInfo; | 281 fDstInfo = dstInfo; |
| 218 fOptions = *options; | 282 fOptions = *options; |
| 283 fSubsetWidth = subsetWidth; | |
| 219 return kSuccess; | 284 return kSuccess; |
| 220 } | 285 } |
| 221 | 286 |
| 287 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, | |
| 288 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { | |
| 289 return this->startScanlineDecode(dstInfo, options, ctable, ctableCount, 0, d stInfo.width()); | |
| 290 } | |
| 291 | |
| 222 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo) { | 292 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo) { |
| 223 return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr); | 293 return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr, 0, dstI nfo.width()); |
| 224 } | 294 } |
| 225 | 295 |
| 226 int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { | 296 int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { |
| 227 if (fCurrScanline < 0) { | 297 if (fCurrScanline < 0) { |
| 228 return 0; | 298 return 0; |
| 229 } | 299 } |
| 230 | 300 |
| 231 SkASSERT(!fDstInfo.isEmpty()); | 301 SkASSERT(!fDstInfo.isEmpty()); |
| 232 if ((rowBytes < fDstInfo.minRowBytes() && countLines > 1 ) || countLines <= 0 | 302 if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) { |
| 233 || fCurrScanline + countLines > fDstInfo.height()) { | |
| 234 return 0; | 303 return 0; |
| 235 } | 304 } |
| 236 | 305 |
| 237 const uint32_t linesDecoded = this->onGetScanlines(dst, countLines, rowBytes ); | 306 const uint32_t linesDecoded = this->onGetScanlines(dst, countLines, rowBytes ); |
| 238 if (linesDecoded < countLines) { | 307 if (linesDecoded < countLines) { |
| 239 this->fillIncompleteImage(this->dstInfo(), dst, rowBytes, this->options( ).fZeroInitialized, | 308 this->fillIncompleteImage(this->dstInfo(), dst, rowBytes, this->options( ).fZeroInitialized, |
| 240 countLines, linesDecoded); | 309 countLines, linesDecoded); |
| 241 } | 310 } |
| 242 fCurrScanline += linesDecoded; | 311 fCurrScanline += linesDecoded; |
| 243 return linesDecoded; | 312 return linesDecoded; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 275 return get_output_row_interlaced(inputScanline, this->getInfo().heig ht()); | 344 return get_output_row_interlaced(inputScanline, this->getInfo().heig ht()); |
| 276 } | 345 } |
| 277 } | 346 } |
| 278 | 347 |
| 279 void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t row Bytes, | 348 void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t row Bytes, |
| 280 ZeroInitialized zeroInit, int linesRequested, int linesDecoded) { | 349 ZeroInitialized zeroInit, int linesRequested, int linesDecoded) { |
| 281 void* fillDst; | 350 void* fillDst; |
| 282 SkImageInfo fillInfo; | 351 SkImageInfo fillInfo; |
| 283 const uint32_t fillValue = this->getFillValue(info.colorType(), info.alphaTy pe()); | 352 const uint32_t fillValue = this->getFillValue(info.colorType(), info.alphaTy pe()); |
| 284 const int linesRemaining = linesRequested - linesDecoded; | 353 const int linesRemaining = linesRequested - linesDecoded; |
| 354 const int fillWidth = fSubsetWidth ? fSubsetWidth : info.width(); | |
| 285 switch (this->getScanlineOrder()) { | 355 switch (this->getScanlineOrder()) { |
| 286 case kTopDown_SkScanlineOrder: | 356 case kTopDown_SkScanlineOrder: |
| 287 case kNone_SkScanlineOrder: | 357 case kNone_SkScanlineOrder: |
| 288 fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes); | 358 fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes); |
| 289 fillInfo = info.makeWH(info.width(), linesRemaining); | 359 fillInfo = info.makeWH(fillWidth, linesRemaining); |
| 290 SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroInit); | 360 SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroInit); |
| 291 break; | 361 break; |
| 292 case kBottomUp_SkScanlineOrder: | 362 case kBottomUp_SkScanlineOrder: |
| 293 fillDst = dst; | 363 fillDst = dst; |
| 294 fillInfo = info.makeWH(info.width(), linesRemaining); | 364 fillInfo = info.makeWH(fillWidth, linesRemaining); |
| 295 SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroInit); | 365 SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroInit); |
| 296 break; | 366 break; |
| 297 case kOutOfOrder_SkScanlineOrder: | 367 case kOutOfOrder_SkScanlineOrder: |
| 298 SkASSERT(1 == linesRequested || this->getInfo().height() == linesReq uested); | 368 SkASSERT(1 == linesRequested || this->getInfo().height() == linesReq uested); |
| 299 fillInfo = info.makeWH(info.width(), 1); | 369 fillInfo = info.makeWH(fillWidth, 1); |
| 300 for (int srcY = linesDecoded; srcY < linesRequested; srcY++) { | 370 for (int srcY = linesDecoded; srcY < linesRequested; srcY++) { |
| 301 fillDst = SkTAddOffset<void>(dst, this->outputScanline(srcY) * r owBytes); | 371 fillDst = SkTAddOffset<void>(dst, this->outputScanline(srcY) * r owBytes); |
| 302 SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroIni t); | 372 SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroIni t); |
| 303 } | 373 } |
| 304 break; | 374 break; |
| 305 } | 375 } |
| 306 } | 376 } |
| OLD | NEW |