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