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

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

Powered by Google App Engine
This is Rietveld 408576698