| 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 "SkCodecPriv.h" | 10 #include "SkCodecPriv.h" |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 // startScanlineDecode will need to be called before decoding scanlines. | 147 // startScanlineDecode will need to be called before decoding scanlines. |
| 148 fCurrScanline = -1; | 148 fCurrScanline = -1; |
| 149 | 149 |
| 150 if (!fStream->rewind()) { | 150 if (!fStream->rewind()) { |
| 151 return false; | 151 return false; |
| 152 } | 152 } |
| 153 | 153 |
| 154 return this->onRewind(); | 154 return this->onRewind(); |
| 155 } | 155 } |
| 156 | 156 |
| 157 #define CHECK_COLOR_TABLE \ |
| 158 if (kIndex_8_SkColorType == info.colorType()) { \ |
| 159 if (nullptr == ctable || nullptr == ctableCount) { \ |
| 160 return SkCodec::kInvalidParameters; \ |
| 161 } \ |
| 162 } else { \ |
| 163 if (ctableCount) { \ |
| 164 *ctableCount = 0; \ |
| 165 } \ |
| 166 ctableCount = nullptr; \ |
| 167 ctable = nullptr; \ |
| 168 } |
| 169 |
| 170 |
| 157 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t
rowBytes, | 171 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t
rowBytes, |
| 158 const Options* options, SkPMColor ctable[], i
nt* ctableCount) { | 172 const Options* options, SkPMColor ctable[], i
nt* ctableCount) { |
| 159 if (kUnknown_SkColorType == info.colorType()) { | 173 if (kUnknown_SkColorType == info.colorType()) { |
| 160 return kInvalidConversion; | 174 return kInvalidConversion; |
| 161 } | 175 } |
| 162 if (nullptr == pixels) { | 176 if (nullptr == pixels) { |
| 163 return kInvalidParameters; | 177 return kInvalidParameters; |
| 164 } | 178 } |
| 165 if (rowBytes < info.minRowBytes()) { | 179 if (rowBytes < info.minRowBytes()) { |
| 166 return kInvalidParameters; | 180 return kInvalidParameters; |
| 167 } | 181 } |
| 168 | 182 |
| 169 if (kIndex_8_SkColorType == info.colorType()) { | 183 CHECK_COLOR_TABLE; |
| 170 if (nullptr == ctable || nullptr == ctableCount) { | |
| 171 return kInvalidParameters; | |
| 172 } | |
| 173 } else { | |
| 174 if (ctableCount) { | |
| 175 *ctableCount = 0; | |
| 176 } | |
| 177 ctableCount = nullptr; | |
| 178 ctable = nullptr; | |
| 179 } | |
| 180 | 184 |
| 181 if (!this->rewindIfNeeded()) { | 185 if (!this->rewindIfNeeded()) { |
| 182 return kCouldNotRewind; | 186 return kCouldNotRewind; |
| 183 } | 187 } |
| 184 | 188 |
| 185 // Default options. | 189 // Default options. |
| 186 Options optsStorage; | 190 Options optsStorage; |
| 187 if (nullptr == options) { | 191 if (nullptr == options) { |
| 188 options = &optsStorage; | 192 options = &optsStorage; |
| 189 } else if (options->fSubset) { | 193 } else if (options->fSubset) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 rowsDecoded); | 225 rowsDecoded); |
| 222 } | 226 } |
| 223 | 227 |
| 224 return result; | 228 return result; |
| 225 } | 229 } |
| 226 | 230 |
| 227 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t
rowBytes) { | 231 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t
rowBytes) { |
| 228 return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr); | 232 return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr); |
| 229 } | 233 } |
| 230 | 234 |
| 231 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, | 235 SkCodec::Result SkCodec::startIncrementalDecode(const SkImageInfo& info, void* p
ixels, |
| 236 size_t rowBytes, const SkCodec::Options* options, SkPMColor* ctable, int
* ctableCount) { |
| 237 fStartedIncrementalDecode = false; |
| 238 |
| 239 if (kUnknown_SkColorType == info.colorType()) { |
| 240 return kInvalidConversion; |
| 241 } |
| 242 if (nullptr == pixels) { |
| 243 return kInvalidParameters; |
| 244 } |
| 245 |
| 246 // Ensure that valid color ptrs are passed in for kIndex8 color type |
| 247 CHECK_COLOR_TABLE; |
| 248 |
| 249 // FIXME: If the rows come after the rows of a previous incremental decode, |
| 250 // we might be able to skip the rewind, but only the implementation knows |
| 251 // that. (e.g. PNG will always need to rewind, since we called longjmp, but |
| 252 // a bottom-up BMP could skip rewinding if the new rows are above the old |
| 253 // rows.) |
| 254 if (!this->rewindIfNeeded()) { |
| 255 return kCouldNotRewind; |
| 256 } |
| 257 |
| 258 // Set options. |
| 259 Options optsStorage; |
| 260 if (nullptr == options) { |
| 261 options = &optsStorage; |
| 262 } else if (options->fSubset) { |
| 263 SkIRect size = SkIRect::MakeSize(info.dimensions()); |
| 264 if (!size.contains(*options->fSubset)) { |
| 265 return kInvalidParameters; |
| 266 } |
| 267 |
| 268 const int top = options->fSubset->top(); |
| 269 const int bottom = options->fSubset->bottom(); |
| 270 if (top < 0 || top >= info.height() || top >= bottom || bottom > info.he
ight()) { |
| 271 return kInvalidParameters; |
| 272 } |
| 273 } |
| 274 |
| 275 if (!this->dimensionsSupported(info.dimensions())) { |
| 276 return kInvalidScale; |
| 277 } |
| 278 |
| 279 fDstInfo = info; |
| 280 fOptions = *options; |
| 281 |
| 282 const Result result = this->onStartIncrementalDecode(info, pixels, rowBytes, |
| 283 fOptions, ctable, ctableCount); |
| 284 if (kSuccess == result) { |
| 285 fStartedIncrementalDecode = true; |
| 286 } else if (kUnimplemented == result) { |
| 287 // FIXME: This is temporarily necessary, until we transition SkCodec |
| 288 // implementations from scanline decoding to incremental decoding. |
| 289 // SkAndroidCodec will first attempt to use incremental decoding, but |
| 290 // will fall back to scanline decoding if incremental returns |
| 291 // kUnimplemented. rewindIfNeeded(), above, set fNeedsRewind to true |
| 292 // (after potentially rewinding), but we do not want the next call to |
| 293 // startScanlineDecode() to do a rewind. |
| 294 fNeedsRewind = false; |
| 295 } |
| 296 return result; |
| 297 } |
| 298 |
| 299 |
| 300 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info, |
| 232 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { | 301 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { |
| 233 // Reset fCurrScanline in case of failure. | 302 // Reset fCurrScanline in case of failure. |
| 234 fCurrScanline = -1; | 303 fCurrScanline = -1; |
| 235 // Ensure that valid color ptrs are passed in for kIndex8 color type | 304 // Ensure that valid color ptrs are passed in for kIndex8 color type |
| 236 if (kIndex_8_SkColorType == dstInfo.colorType()) { | 305 CHECK_COLOR_TABLE; |
| 237 if (nullptr == ctable || nullptr == ctableCount) { | |
| 238 return SkCodec::kInvalidParameters; | |
| 239 } | |
| 240 } else { | |
| 241 if (ctableCount) { | |
| 242 *ctableCount = 0; | |
| 243 } | |
| 244 ctableCount = nullptr; | |
| 245 ctable = nullptr; | |
| 246 } | |
| 247 | 306 |
| 248 if (!this->rewindIfNeeded()) { | 307 if (!this->rewindIfNeeded()) { |
| 249 return kCouldNotRewind; | 308 return kCouldNotRewind; |
| 250 } | 309 } |
| 251 | 310 |
| 252 // Set options. | 311 // Set options. |
| 253 Options optsStorage; | 312 Options optsStorage; |
| 254 if (nullptr == options) { | 313 if (nullptr == options) { |
| 255 options = &optsStorage; | 314 options = &optsStorage; |
| 256 } else if (options->fSubset) { | 315 } else if (options->fSubset) { |
| 257 SkIRect size = SkIRect::MakeSize(dstInfo.dimensions()); | 316 SkIRect size = SkIRect::MakeSize(info.dimensions()); |
| 258 if (!size.contains(*options->fSubset)) { | 317 if (!size.contains(*options->fSubset)) { |
| 259 return kInvalidInput; | 318 return kInvalidInput; |
| 260 } | 319 } |
| 261 | 320 |
| 262 // We only support subsetting in the x-dimension for scanline decoder. | 321 // We only support subsetting in the x-dimension for scanline decoder. |
| 263 // Subsetting in the y-dimension can be accomplished using skipScanlines
(). | 322 // Subsetting in the y-dimension can be accomplished using skipScanlines
(). |
| 264 if (options->fSubset->top() != 0 || options->fSubset->height() != dstInf
o.height()) { | 323 if (options->fSubset->top() != 0 || options->fSubset->height() != info.h
eight()) { |
| 265 return kInvalidInput; | 324 return kInvalidInput; |
| 266 } | 325 } |
| 267 } | 326 } |
| 268 | 327 |
| 269 // FIXME: Support subsets somehow? | 328 // FIXME: Support subsets somehow? |
| 270 if (!this->dimensionsSupported(dstInfo.dimensions())) { | 329 if (!this->dimensionsSupported(info.dimensions())) { |
| 271 return kInvalidScale; | 330 return kInvalidScale; |
| 272 } | 331 } |
| 273 | 332 |
| 274 const Result result = this->onStartScanlineDecode(dstInfo, *options, ctable,
ctableCount); | 333 const Result result = this->onStartScanlineDecode(info, *options, ctable, ct
ableCount); |
| 275 if (result != SkCodec::kSuccess) { | 334 if (result != SkCodec::kSuccess) { |
| 276 return result; | 335 return result; |
| 277 } | 336 } |
| 278 | 337 |
| 279 fCurrScanline = 0; | 338 fCurrScanline = 0; |
| 280 fDstInfo = dstInfo; | 339 fDstInfo = info; |
| 281 fOptions = *options; | 340 fOptions = *options; |
| 282 return kSuccess; | 341 return kSuccess; |
| 283 } | 342 } |
| 284 | 343 |
| 285 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo) { | 344 #undef CHECK_COLOR_TABLE |
| 286 return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr); | 345 |
| 346 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info) { |
| 347 return this->startScanlineDecode(info, nullptr, nullptr, nullptr); |
| 287 } | 348 } |
| 288 | 349 |
| 289 int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { | 350 int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { |
| 290 if (fCurrScanline < 0) { | 351 if (fCurrScanline < 0) { |
| 291 return 0; | 352 return 0; |
| 292 } | 353 } |
| 293 | 354 |
| 294 SkASSERT(!fDstInfo.isEmpty()); | 355 SkASSERT(!fDstInfo.isEmpty()); |
| 295 if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) { | 356 if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) { |
| 296 return 0; | 357 return 0; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 324 } | 385 } |
| 325 | 386 |
| 326 int SkCodec::outputScanline(int inputScanline) const { | 387 int SkCodec::outputScanline(int inputScanline) const { |
| 327 SkASSERT(0 <= inputScanline && inputScanline < this->getInfo().height()); | 388 SkASSERT(0 <= inputScanline && inputScanline < this->getInfo().height()); |
| 328 return this->onOutputScanline(inputScanline); | 389 return this->onOutputScanline(inputScanline); |
| 329 } | 390 } |
| 330 | 391 |
| 331 int SkCodec::onOutputScanline(int inputScanline) const { | 392 int SkCodec::onOutputScanline(int inputScanline) const { |
| 332 switch (this->getScanlineOrder()) { | 393 switch (this->getScanlineOrder()) { |
| 333 case kTopDown_SkScanlineOrder: | 394 case kTopDown_SkScanlineOrder: |
| 334 case kNone_SkScanlineOrder: | |
| 335 return inputScanline; | 395 return inputScanline; |
| 336 case kBottomUp_SkScanlineOrder: | 396 case kBottomUp_SkScanlineOrder: |
| 337 return this->getInfo().height() - inputScanline - 1; | 397 return this->getInfo().height() - inputScanline - 1; |
| 338 default: | 398 default: |
| 339 // This case indicates an interlaced gif and is implemented by SkGif
Codec. | 399 // This case indicates an interlaced gif and is implemented by SkGif
Codec. |
| 340 SkASSERT(false); | 400 SkASSERT(false); |
| 341 return 0; | 401 return 0; |
| 342 } | 402 } |
| 343 } | 403 } |
| 344 | 404 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 358 const uint32_t fillValue = this->getFillValue(info.colorType()); | 418 const uint32_t fillValue = this->getFillValue(info.colorType()); |
| 359 const int linesRemaining = linesRequested - linesDecoded; | 419 const int linesRemaining = linesRequested - linesDecoded; |
| 360 SkSampler* sampler = this->getSampler(false); | 420 SkSampler* sampler = this->getSampler(false); |
| 361 | 421 |
| 362 int fillWidth = info.width(); | 422 int fillWidth = info.width(); |
| 363 if (fOptions.fSubset) { | 423 if (fOptions.fSubset) { |
| 364 fillWidth = fOptions.fSubset->width(); | 424 fillWidth = fOptions.fSubset->width(); |
| 365 } | 425 } |
| 366 | 426 |
| 367 switch (this->getScanlineOrder()) { | 427 switch (this->getScanlineOrder()) { |
| 368 case kTopDown_SkScanlineOrder: | 428 case kTopDown_SkScanlineOrder: { |
| 369 case kNone_SkScanlineOrder: { | |
| 370 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining); | 429 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining); |
| 371 fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes); | 430 fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes); |
| 372 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler)
; | 431 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler)
; |
| 373 break; | 432 break; |
| 374 } | 433 } |
| 375 case kBottomUp_SkScanlineOrder: { | 434 case kBottomUp_SkScanlineOrder: { |
| 376 fillDst = dst; | 435 fillDst = dst; |
| 377 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining); | 436 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining); |
| 378 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler)
; | 437 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler)
; |
| 379 break; | 438 break; |
| 380 } | 439 } |
| 381 case kOutOfOrder_SkScanlineOrder: { | 440 case kOutOfOrder_SkScanlineOrder: { |
| 382 SkASSERT(1 == linesRequested || this->getInfo().height() == linesReq
uested); | 441 SkASSERT(1 == linesRequested || this->getInfo().height() == linesReq
uested); |
| 383 const SkImageInfo fillInfo = info.makeWH(fillWidth, 1); | 442 const SkImageInfo fillInfo = info.makeWH(fillWidth, 1); |
| 384 for (int srcY = linesDecoded; srcY < linesRequested; srcY++) { | 443 for (int srcY = linesDecoded; srcY < linesRequested; srcY++) { |
| 385 fillDst = SkTAddOffset<void>(dst, this->outputScanline(srcY) * r
owBytes); | 444 fillDst = SkTAddOffset<void>(dst, this->outputScanline(srcY) * r
owBytes); |
| 386 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, samp
ler); | 445 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, samp
ler); |
| 387 } | 446 } |
| 388 break; | 447 break; |
| 389 } | 448 } |
| 390 } | 449 } |
| 391 } | 450 } |
| OLD | NEW |