Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(906)

Side by Side Diff: src/codec/SkCodec.cpp

Issue 1997703003: Make SkPngCodec decode progressively. (Closed) Base URL: https://skia.googlesource.com/skia.git@foil
Patch Set: rebase Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 // Store the value of fNeedsRewind so we can update it. Next read will 151 // Store the value of fNeedsRewind so we can update it. Next read will
152 // require a rewind. 152 // require a rewind.
153 const bool needsRewind = fNeedsRewind; 153 const bool needsRewind = fNeedsRewind;
154 fNeedsRewind = true; 154 fNeedsRewind = true;
155 if (!needsRewind) { 155 if (!needsRewind) {
156 return true; 156 return true;
157 } 157 }
158 158
159 // startScanlineDecode will need to be called before decoding scanlines. 159 // startScanlineDecode will need to be called before decoding scanlines.
160 fCurrScanline = -1; 160 fCurrScanline = -1;
161 // startIncrementalDecode will need to be called before incrementalDecode.
162 fStartedIncrementalDecode = false;
161 163
162 if (!fStream->rewind()) { 164 if (!fStream->rewind()) {
163 return false; 165 return false;
164 } 166 }
165 167
166 return this->onRewind(); 168 return this->onRewind();
167 } 169 }
168 170
171 #define CHECK_COLOR_TABLE \
172 if (kIndex_8_SkColorType == info.colorType()) { \
173 if (nullptr == ctable || nullptr == ctableCount) { \
174 return SkCodec::kInvalidParameters; \
175 } \
176 } else { \
177 if (ctableCount) { \
178 *ctableCount = 0; \
179 } \
180 ctableCount = nullptr; \
181 ctable = nullptr; \
182 }
183
184
169 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, 185 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
170 const Options* options, SkPMColor ctable[], i nt* ctableCount) { 186 const Options* options, SkPMColor ctable[], i nt* ctableCount) {
171 if (kUnknown_SkColorType == info.colorType()) { 187 if (kUnknown_SkColorType == info.colorType()) {
172 return kInvalidConversion; 188 return kInvalidConversion;
173 } 189 }
174 if (nullptr == pixels) { 190 if (nullptr == pixels) {
175 return kInvalidParameters; 191 return kInvalidParameters;
176 } 192 }
177 if (rowBytes < info.minRowBytes()) { 193 if (rowBytes < info.minRowBytes()) {
178 return kInvalidParameters; 194 return kInvalidParameters;
179 } 195 }
180 196
181 if (kIndex_8_SkColorType == info.colorType()) { 197 CHECK_COLOR_TABLE;
182 if (nullptr == ctable || nullptr == ctableCount) {
183 return kInvalidParameters;
184 }
185 } else {
186 if (ctableCount) {
187 *ctableCount = 0;
188 }
189 ctableCount = nullptr;
190 ctable = nullptr;
191 }
192 198
193 if (!this->rewindIfNeeded()) { 199 if (!this->rewindIfNeeded()) {
194 return kCouldNotRewind; 200 return kCouldNotRewind;
195 } 201 }
196 202
197 // Default options. 203 // Default options.
198 Options optsStorage; 204 Options optsStorage;
199 if (nullptr == options) { 205 if (nullptr == options) {
200 options = &optsStorage; 206 options = &optsStorage;
201 } else if (options->fSubset) { 207 } else if (options->fSubset) {
202 SkIRect subset(*options->fSubset); 208 SkIRect subset(*options->fSubset);
203 if (!this->onGetValidSubset(&subset) || subset != *options->fSubset) { 209 if (!this->onGetValidSubset(&subset) || subset != *options->fSubset) {
204 // FIXME: How to differentiate between not supporting subset at all 210 // FIXME: How to differentiate between not supporting subset at all
205 // and not supporting this particular subset? 211 // and not supporting this particular subset?
206 return kUnimplemented; 212 return kUnimplemented;
207 } 213 }
208 } 214 }
209 215
210 // FIXME: Support subsets somehow? Note that this works for SkWebpCodec 216 // FIXME: Support subsets somehow? Note that this works for SkWebpCodec
211 // because it supports arbitrary scaling/subset combinations. 217 // because it supports arbitrary scaling/subset combinations.
212 if (!this->dimensionsSupported(info.dimensions())) { 218 if (!this->dimensionsSupported(info.dimensions())) {
213 return kInvalidScale; 219 return kInvalidScale;
214 } 220 }
215 221
222 fDstInfo = info;
223 fOptions = *options;
224
216 // On an incomplete decode, the subclass will specify the number of scanline s that it decoded 225 // On an incomplete decode, the subclass will specify the number of scanline s that it decoded
217 // successfully. 226 // successfully.
218 int rowsDecoded = 0; 227 int rowsDecoded = 0;
219 const Result result = this->onGetPixels(info, pixels, rowBytes, *options, ct able, ctableCount, 228 const Result result = this->onGetPixels(info, pixels, rowBytes, *options, ct able, ctableCount,
220 &rowsDecoded); 229 &rowsDecoded);
221 230
222 if ((kIncompleteInput == result || kSuccess == result) && ctableCount) { 231 if ((kIncompleteInput == result || kSuccess == result) && ctableCount) {
223 SkASSERT(*ctableCount >= 0 && *ctableCount <= 256); 232 SkASSERT(*ctableCount >= 0 && *ctableCount <= 256);
224 } 233 }
225 234
226 // A return value of kIncompleteInput indicates a truncated image stream. 235 // A return value of kIncompleteInput indicates a truncated image stream.
227 // In this case, we will fill any uninitialized memory with a default value. 236 // In this case, we will fill any uninitialized memory with a default value.
228 // Some subclasses will take care of filling any uninitialized memory on 237 // Some subclasses will take care of filling any uninitialized memory on
229 // their own. They indicate that all of the memory has been filled by 238 // their own. They indicate that all of the memory has been filled by
230 // setting rowsDecoded equal to the height. 239 // setting rowsDecoded equal to the height.
231 if (kIncompleteInput == result && rowsDecoded != info.height()) { 240 if (kIncompleteInput == result && rowsDecoded != info.height()) {
232 this->fillIncompleteImage(info, pixels, rowBytes, options->fZeroInitiali zed, info.height(), 241 this->fillIncompleteImage(info, pixels, rowBytes, options->fZeroInitiali zed, info.height(),
233 rowsDecoded); 242 rowsDecoded);
234 } 243 }
235 244
236 return result; 245 return result;
237 } 246 }
238 247
239 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { 248 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
240 return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr); 249 return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr);
241 } 250 }
242 251
243 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, 252 SkCodec::Result SkCodec::startIncrementalDecode(const SkImageInfo& info, void* p ixels,
253 size_t rowBytes, const SkCodec::Options* options, SkPMColor* ctable, int * ctableCount) {
254 fStartedIncrementalDecode = false;
255
256 if (kUnknown_SkColorType == info.colorType()) {
257 return kInvalidConversion;
258 }
259 if (nullptr == pixels) {
260 return kInvalidParameters;
261 }
262
263 // Ensure that valid color ptrs are passed in for kIndex8 color type
264 CHECK_COLOR_TABLE;
265
266 // FIXME: If the rows come after the rows of a previous incremental decode,
267 // we might be able to skip the rewind, but only the implementation knows
268 // that. (e.g. PNG will always need to rewind, since we called longjmp, but
269 // a bottom-up BMP could skip rewinding if the new rows are above the old
270 // rows.)
271 if (!this->rewindIfNeeded()) {
272 return kCouldNotRewind;
273 }
274
275 // Set options.
276 Options optsStorage;
277 if (nullptr == options) {
278 options = &optsStorage;
279 } else if (options->fSubset) {
280 SkIRect size = SkIRect::MakeSize(info.dimensions());
281 if (!size.contains(*options->fSubset)) {
282 return kInvalidParameters;
283 }
284
285 const int top = options->fSubset->top();
286 const int bottom = options->fSubset->bottom();
287 if (top < 0 || top >= info.height() || top >= bottom || bottom > info.he ight()) {
288 return kInvalidParameters;
289 }
290 }
291
292 if (!this->dimensionsSupported(info.dimensions())) {
293 return kInvalidScale;
294 }
295
296 fDstInfo = info;
297 fOptions = *options;
298
299 const Result result = this->onStartIncrementalDecode(info, pixels, rowBytes,
300 fOptions, ctable, ctableCount);
301 if (kSuccess == result) {
302 fStartedIncrementalDecode = true;
303 } else if (kUnimplemented == result) {
304 // FIXME: This is temporarily necessary, until we transition SkCodec
305 // implementations from scanline decoding to incremental decoding.
306 // SkAndroidCodec will first attempt to use incremental decoding, but
307 // will fall back to scanline decoding if incremental returns
308 // kUnimplemented. rewindIfNeeded(), above, set fNeedsRewind to true
309 // (after potentially rewinding), but we do not want the next call to
310 // startScanlineDecode() to do a rewind.
311 fNeedsRewind = false;
312 }
313 return result;
314 }
315
316
317 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info,
244 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { 318 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) {
245 // Reset fCurrScanline in case of failure. 319 // Reset fCurrScanline in case of failure.
246 fCurrScanline = -1; 320 fCurrScanline = -1;
247 // Ensure that valid color ptrs are passed in for kIndex8 color type 321 // Ensure that valid color ptrs are passed in for kIndex8 color type
248 if (kIndex_8_SkColorType == dstInfo.colorType()) { 322 CHECK_COLOR_TABLE;
249 if (nullptr == ctable || nullptr == ctableCount) {
250 return SkCodec::kInvalidParameters;
251 }
252 } else {
253 if (ctableCount) {
254 *ctableCount = 0;
255 }
256 ctableCount = nullptr;
257 ctable = nullptr;
258 }
259 323
260 if (!this->rewindIfNeeded()) { 324 if (!this->rewindIfNeeded()) {
261 return kCouldNotRewind; 325 return kCouldNotRewind;
262 } 326 }
263 327
264 // Set options. 328 // Set options.
265 Options optsStorage; 329 Options optsStorage;
266 if (nullptr == options) { 330 if (nullptr == options) {
267 options = &optsStorage; 331 options = &optsStorage;
268 } else if (options->fSubset) { 332 } else if (options->fSubset) {
269 SkIRect size = SkIRect::MakeSize(dstInfo.dimensions()); 333 SkIRect size = SkIRect::MakeSize(info.dimensions());
270 if (!size.contains(*options->fSubset)) { 334 if (!size.contains(*options->fSubset)) {
271 return kInvalidInput; 335 return kInvalidInput;
272 } 336 }
273 337
274 // We only support subsetting in the x-dimension for scanline decoder. 338 // We only support subsetting in the x-dimension for scanline decoder.
275 // Subsetting in the y-dimension can be accomplished using skipScanlines (). 339 // Subsetting in the y-dimension can be accomplished using skipScanlines ().
276 if (options->fSubset->top() != 0 || options->fSubset->height() != dstInf o.height()) { 340 if (options->fSubset->top() != 0 || options->fSubset->height() != info.h eight()) {
277 return kInvalidInput; 341 return kInvalidInput;
278 } 342 }
279 } 343 }
280 344
281 // FIXME: Support subsets somehow? 345 // FIXME: Support subsets somehow?
282 if (!this->dimensionsSupported(dstInfo.dimensions())) { 346 if (!this->dimensionsSupported(info.dimensions())) {
283 return kInvalidScale; 347 return kInvalidScale;
284 } 348 }
285 349
286 const Result result = this->onStartScanlineDecode(dstInfo, *options, ctable, ctableCount); 350 const Result result = this->onStartScanlineDecode(info, *options, ctable, ct ableCount);
287 if (result != SkCodec::kSuccess) { 351 if (result != SkCodec::kSuccess) {
288 return result; 352 return result;
289 } 353 }
290 354
291 fCurrScanline = 0; 355 fCurrScanline = 0;
292 fDstInfo = dstInfo; 356 fDstInfo = info;
293 fOptions = *options; 357 fOptions = *options;
294 return kSuccess; 358 return kSuccess;
295 } 359 }
296 360
297 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo) { 361 #undef CHECK_COLOR_TABLE
298 return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr); 362
363 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& info) {
364 return this->startScanlineDecode(info, nullptr, nullptr, nullptr);
299 } 365 }
300 366
301 int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { 367 int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) {
302 if (fCurrScanline < 0) { 368 if (fCurrScanline < 0) {
303 return 0; 369 return 0;
304 } 370 }
305 371
306 SkASSERT(!fDstInfo.isEmpty()); 372 SkASSERT(!fDstInfo.isEmpty());
307 if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) { 373 if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) {
308 return 0; 374 return 0;
(...skipping 27 matching lines...) Expand all
336 } 402 }
337 403
338 int SkCodec::outputScanline(int inputScanline) const { 404 int SkCodec::outputScanline(int inputScanline) const {
339 SkASSERT(0 <= inputScanline && inputScanline < this->getInfo().height()); 405 SkASSERT(0 <= inputScanline && inputScanline < this->getInfo().height());
340 return this->onOutputScanline(inputScanline); 406 return this->onOutputScanline(inputScanline);
341 } 407 }
342 408
343 int SkCodec::onOutputScanline(int inputScanline) const { 409 int SkCodec::onOutputScanline(int inputScanline) const {
344 switch (this->getScanlineOrder()) { 410 switch (this->getScanlineOrder()) {
345 case kTopDown_SkScanlineOrder: 411 case kTopDown_SkScanlineOrder:
346 case kNone_SkScanlineOrder:
347 return inputScanline; 412 return inputScanline;
348 case kBottomUp_SkScanlineOrder: 413 case kBottomUp_SkScanlineOrder:
349 return this->getInfo().height() - inputScanline - 1; 414 return this->getInfo().height() - inputScanline - 1;
350 default: 415 default:
351 // This case indicates an interlaced gif and is implemented by SkGif Codec. 416 // This case indicates an interlaced gif and is implemented by SkGif Codec.
352 SkASSERT(false); 417 SkASSERT(false);
353 return 0; 418 return 0;
354 } 419 }
355 } 420 }
356 421
(...skipping 29 matching lines...) Expand all
386 const uint64_t fillValue = this->getFillValue(info); 451 const uint64_t fillValue = this->getFillValue(info);
387 const int linesRemaining = linesRequested - linesDecoded; 452 const int linesRemaining = linesRequested - linesDecoded;
388 SkSampler* sampler = this->getSampler(false); 453 SkSampler* sampler = this->getSampler(false);
389 454
390 int fillWidth = info.width(); 455 int fillWidth = info.width();
391 if (fOptions.fSubset) { 456 if (fOptions.fSubset) {
392 fillWidth = fOptions.fSubset->width(); 457 fillWidth = fOptions.fSubset->width();
393 } 458 }
394 459
395 switch (this->getScanlineOrder()) { 460 switch (this->getScanlineOrder()) {
396 case kTopDown_SkScanlineOrder: 461 case kTopDown_SkScanlineOrder: {
397 case kNone_SkScanlineOrder: {
398 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining); 462 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining);
399 fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes); 463 fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes);
400 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler) ; 464 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler) ;
401 break; 465 break;
402 } 466 }
403 case kBottomUp_SkScanlineOrder: { 467 case kBottomUp_SkScanlineOrder: {
404 fillDst = dst; 468 fillDst = dst;
405 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining); 469 const SkImageInfo fillInfo = info.makeWH(fillWidth, linesRemaining);
406 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler) ; 470 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, sampler) ;
407 break; 471 break;
408 } 472 }
409 case kOutOfOrder_SkScanlineOrder: { 473 case kOutOfOrder_SkScanlineOrder: {
410 SkASSERT(1 == linesRequested || this->getInfo().height() == linesReq uested); 474 SkASSERT(1 == linesRequested || this->getInfo().height() == linesReq uested);
411 const SkImageInfo fillInfo = info.makeWH(fillWidth, 1); 475 const SkImageInfo fillInfo = info.makeWH(fillWidth, 1);
412 for (int srcY = linesDecoded; srcY < linesRequested; srcY++) { 476 for (int srcY = linesDecoded; srcY < linesRequested; srcY++) {
413 fillDst = SkTAddOffset<void>(dst, this->outputScanline(srcY) * r owBytes); 477 fillDst = SkTAddOffset<void>(dst, this->outputScanline(srcY) * r owBytes);
414 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, samp ler); 478 fill_proc(fillInfo, fillDst, rowBytes, fillValue, zeroInit, samp ler);
415 } 479 }
416 break; 480 break;
417 } 481 }
418 } 482 }
419 } 483 }
OLDNEW
« no previous file with comments | « include/codec/SkCodec.h ('k') | src/codec/SkIcoCodec.h » ('j') | src/codec/SkSampler.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698