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) { | |
msarett
2016/05/26 16:45:22
This code is temporary, right? Until we finish im
scroggo
2016/05/26 19:08:56
It is only temporarily necessary. It's not necessa
| |
287 // No need to rewind after this failure, since none of the stream was | |
288 // read. | |
289 fNeedsRewind = false; | |
290 } | |
291 return result; | |
292 } | |
293 | |
294 | |
295 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info, | |
232 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { | 296 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { |
233 // Reset fCurrScanline in case of failure. | 297 // Reset fCurrScanline in case of failure. |
234 fCurrScanline = -1; | 298 fCurrScanline = -1; |
235 // Ensure that valid color ptrs are passed in for kIndex8 color type | 299 // Ensure that valid color ptrs are passed in for kIndex8 color type |
236 if (kIndex_8_SkColorType == dstInfo.colorType()) { | 300 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 | 301 |
248 if (!this->rewindIfNeeded()) { | 302 if (!this->rewindIfNeeded()) { |
249 return kCouldNotRewind; | 303 return kCouldNotRewind; |
250 } | 304 } |
251 | 305 |
252 // Set options. | 306 // Set options. |
253 Options optsStorage; | 307 Options optsStorage; |
254 if (nullptr == options) { | 308 if (nullptr == options) { |
255 options = &optsStorage; | 309 options = &optsStorage; |
256 } else if (options->fSubset) { | 310 } else if (options->fSubset) { |
257 SkIRect size = SkIRect::MakeSize(dstInfo.dimensions()); | 311 SkIRect size = SkIRect::MakeSize(info.dimensions()); |
258 if (!size.contains(*options->fSubset)) { | 312 if (!size.contains(*options->fSubset)) { |
259 return kInvalidInput; | 313 return kInvalidInput; |
260 } | 314 } |
261 | 315 |
262 // We only support subsetting in the x-dimension for scanline decoder. | 316 // We only support subsetting in the x-dimension for scanline decoder. |
263 // Subsetting in the y-dimension can be accomplished using skipScanlines (). | 317 // Subsetting in the y-dimension can be accomplished using skipScanlines (). |
264 if (options->fSubset->top() != 0 || options->fSubset->height() != dstInf o.height()) { | 318 if (options->fSubset->top() != 0 || options->fSubset->height() != info.h eight()) { |
265 return kInvalidInput; | 319 return kInvalidInput; |
266 } | 320 } |
267 } | 321 } |
268 | 322 |
269 // FIXME: Support subsets somehow? | 323 // FIXME: Support subsets somehow? |
270 if (!this->dimensionsSupported(dstInfo.dimensions())) { | 324 if (!this->dimensionsSupported(info.dimensions())) { |
271 return kInvalidScale; | 325 return kInvalidScale; |
272 } | 326 } |
273 | 327 |
274 const Result result = this->onStartScanlineDecode(dstInfo, *options, ctable, ctableCount); | 328 const Result result = this->onStartScanlineDecode(info, *options, ctable, ct ableCount); |
275 if (result != SkCodec::kSuccess) { | 329 if (result != SkCodec::kSuccess) { |
276 return result; | 330 return result; |
277 } | 331 } |
278 | 332 |
279 fCurrScanline = 0; | 333 fCurrScanline = 0; |
280 fDstInfo = dstInfo; | 334 fDstInfo = info; |
281 fOptions = *options; | 335 fOptions = *options; |
282 return kSuccess; | 336 return kSuccess; |
283 } | 337 } |
284 | 338 |
285 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo) { | 339 #undef CHECK_COLOR_TABLE |
286 return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr); | 340 |
341 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info) { | |
342 return this->startScanlineDecode(info, nullptr, nullptr, nullptr); | |
287 } | 343 } |
288 | 344 |
289 int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { | 345 int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { |
290 if (fCurrScanline < 0) { | 346 if (fCurrScanline < 0) { |
291 return 0; | 347 return 0; |
292 } | 348 } |
293 | 349 |
294 SkASSERT(!fDstInfo.isEmpty()); | 350 SkASSERT(!fDstInfo.isEmpty()); |
295 if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) { | 351 if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) { |
296 return 0; | 352 return 0; |
(...skipping 27 matching lines...) Expand all Loading... | |
324 } | 380 } |
325 | 381 |
326 int SkCodec::outputScanline(int inputScanline) const { | 382 int SkCodec::outputScanline(int inputScanline) const { |
327 SkASSERT(0 <= inputScanline && inputScanline < this->getInfo().height()); | 383 SkASSERT(0 <= inputScanline && inputScanline < this->getInfo().height()); |
328 return this->onOutputScanline(inputScanline); | 384 return this->onOutputScanline(inputScanline); |
329 } | 385 } |
330 | 386 |
331 int SkCodec::onOutputScanline(int inputScanline) const { | 387 int SkCodec::onOutputScanline(int inputScanline) const { |
332 switch (this->getScanlineOrder()) { | 388 switch (this->getScanlineOrder()) { |
333 case kTopDown_SkScanlineOrder: | 389 case kTopDown_SkScanlineOrder: |
334 case kNone_SkScanlineOrder: | |
335 return inputScanline; | 390 return inputScanline; |
336 case kBottomUp_SkScanlineOrder: | 391 case kBottomUp_SkScanlineOrder: |
337 return this->getInfo().height() - inputScanline - 1; | 392 return this->getInfo().height() - inputScanline - 1; |
338 default: | 393 default: |
339 // This case indicates an interlaced gif and is implemented by SkGif Codec. | 394 // This case indicates an interlaced gif and is implemented by SkGif Codec. |
340 SkASSERT(false); | 395 SkASSERT(false); |
341 return 0; | 396 return 0; |
342 } | 397 } |
343 } | 398 } |
344 | 399 |
(...skipping 13 matching lines...) Expand all Loading... | |
358 const uint32_t fillValue = this->getFillValue(info.colorType()); | 413 const uint32_t fillValue = this->getFillValue(info.colorType()); |
359 const int linesRemaining = linesRequested - linesDecoded; | 414 const int linesRemaining = linesRequested - linesDecoded; |
360 SkSampler* sampler = this->getSampler(false); | 415 SkSampler* sampler = this->getSampler(false); |
361 | 416 |
362 int fillWidth = info.width(); | 417 int fillWidth = info.width(); |
363 if (fOptions.fSubset) { | 418 if (fOptions.fSubset) { |
364 fillWidth = fOptions.fSubset->width(); | 419 fillWidth = fOptions.fSubset->width(); |
365 } | 420 } |
366 | 421 |
367 switch (this->getScanlineOrder()) { | 422 switch (this->getScanlineOrder()) { |
368 case kTopDown_SkScanlineOrder: | 423 case kTopDown_SkScanlineOrder: { |
369 case kNone_SkScanlineOrder: { | |
370 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining); | 424 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining); |
371 fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes); | 425 fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes); |
372 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler) ; | 426 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler) ; |
373 break; | 427 break; |
374 } | 428 } |
375 case kBottomUp_SkScanlineOrder: { | 429 case kBottomUp_SkScanlineOrder: { |
376 fillDst = dst; | 430 fillDst = dst; |
377 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining); | 431 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining); |
378 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler) ; | 432 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler) ; |
379 break; | 433 break; |
380 } | 434 } |
381 case kOutOfOrder_SkScanlineOrder: { | 435 case kOutOfOrder_SkScanlineOrder: { |
382 SkASSERT(1 == linesRequested || this->getInfo().height() == linesReq uested); | 436 SkASSERT(1 == linesRequested || this->getInfo().height() == linesReq uested); |
383 const SkImageInfo fillInfo = info.makeWH(fillWidth, 1); | 437 const SkImageInfo fillInfo = info.makeWH(fillWidth, 1); |
384 for (int srcY = linesDecoded; srcY < linesRequested; srcY++) { | 438 for (int srcY = linesDecoded; srcY < linesRequested; srcY++) { |
385 fillDst = SkTAddOffset<void>(dst, this->outputScanline(srcY) * r owBytes); | 439 fillDst = SkTAddOffset<void>(dst, this->outputScanline(srcY) * r owBytes); |
386 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, samp ler); | 440 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, samp ler); |
387 } | 441 } |
388 break; | 442 break; |
389 } | 443 } |
390 } | 444 } |
391 } | 445 } |
OLD | NEW |