 Chromium Code Reviews
 Chromium Code Reviews Issue 1332053002:
  Fill incomplete images in SkCodec parent class  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master
    
  
    Issue 1332053002:
  Fill incomplete images in SkCodec parent class  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master| 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 "SkData.h" | 10 #include "SkData.h" | 
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 146 | 146 | 
| 147 if (!this->rewindIfNeeded()) { | 147 if (!this->rewindIfNeeded()) { | 
| 148 return kCouldNotRewind; | 148 return kCouldNotRewind; | 
| 149 } | 149 } | 
| 150 | 150 | 
| 151 // Default options. | 151 // Default options. | 
| 152 Options optsStorage; | 152 Options optsStorage; | 
| 153 if (nullptr == options) { | 153 if (nullptr == options) { | 
| 154 options = &optsStorage; | 154 options = &optsStorage; | 
| 155 } | 155 } | 
| 156 const Result result = this->onGetPixels(info, pixels, rowBytes, *options, ct able, ctableCount); | 156 | 
| 157 // On an incomplete decode, the subclass will specify the number of scanline s that it decoded | |
| 158 // successfully. | |
| 159 int rowsDecoded = 0; | |
| 160 const Result result = this->onGetPixels(info, pixels, rowBytes, *options, ct able, ctableCount, | |
| 161 &rowsDecoded); | |
| 157 | 162 | 
| 158 if ((kIncompleteInput == result || kSuccess == result) && ctableCount) { | 163 if ((kIncompleteInput == result || kSuccess == result) && ctableCount) { | 
| 159 SkASSERT(*ctableCount >= 0 && *ctableCount <= 256); | 164 SkASSERT(*ctableCount >= 0 && *ctableCount <= 256); | 
| 160 } | 165 } | 
| 166 | |
| 167 // A return value of kIncompleteInput indicates a truncated image stream. | |
| 168 // In this case, we will fill any uninitialized memory with a default value. | |
| 169 // Some subclasses will take care of filling any uninitialized memory on | |
| 170 // their own. They indicate that all of the memory has been filled by | |
| 171 // setting rowsDecoded equal to the height. | |
| 172 if (kIncompleteInput == result && rowsDecoded != info.height()) { | |
| 173 this->fillIncompleteImage(info, pixels, rowBytes, options->fZeroInitiali zed, | |
| 174 info.height(), rowsDecoded); | |
| 175 } | |
| 176 | |
| 161 return result; | 177 return result; | 
| 162 } | 178 } | 
| 163 | 179 | 
| 164 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { | 180 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { | 
| 165 return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr); | 181 return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr); | 
| 166 } | 182 } | 
| 167 | 183 | 
| 168 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, | 184 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, | 
| 169 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { | 185 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { | 
| 170 // Reset fCurrScanline in case of failure. | 186 // Reset fCurrScanline in case of failure. | 
| (...skipping 29 matching lines...) Expand all Loading... | |
| 200 fCurrScanline = 0; | 216 fCurrScanline = 0; | 
| 201 fDstInfo = dstInfo; | 217 fDstInfo = dstInfo; | 
| 202 fOptions = *options; | 218 fOptions = *options; | 
| 203 return kSuccess; | 219 return kSuccess; | 
| 204 } | 220 } | 
| 205 | 221 | 
| 206 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo) { | 222 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo) { | 
| 207 return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr); | 223 return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr); | 
| 208 } | 224 } | 
| 209 | 225 | 
| 210 SkCodec::Result SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes ) { | 226 uint32_t SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { | 
| 
scroggo
2015/10/01 14:48:31
If we wanted to, we could make getScanlines return
 
msarett
2015/10/01 18:14:14
It's fair to point out that this API change is no
 | |
| 211 if (fCurrScanline < 0) { | 227 if (fCurrScanline < 0) { | 
| 212 return kScanlineDecodingNotStarted; | 228 return 0; | 
| 
scroggo
2015/10/01 14:48:31
Do we still need this enum value?
 
msarett
2015/10/01 18:14:14
Looks like we don't.
 | |
| 213 } | 229 } | 
| 214 | 230 | 
| 215 SkASSERT(!fDstInfo.isEmpty()); | 231 SkASSERT(!fDstInfo.isEmpty()); | 
| 216 if ((rowBytes < fDstInfo.minRowBytes() && countLines > 1 ) || countLines <= 0 | 232 if ((rowBytes < fDstInfo.minRowBytes() && countLines > 1 ) || countLines <= 0 | 
| 217 || fCurrScanline + countLines > fDstInfo.height()) { | 233 || fCurrScanline + countLines > fDstInfo.height()) { | 
| 218 return kInvalidParameters; | 234 return 0; | 
| 219 } | 235 } | 
| 220 | 236 | 
| 221 const Result result = this->onGetScanlines(dst, countLines, rowBytes); | 237 const uint32_t linesDecoded = this->onGetScanlines(dst, countLines, rowBytes ); | 
| 222 fCurrScanline += countLines; | 238 if (linesDecoded < countLines) { | 
| 223 return result; | 239 this->fillIncompleteImage(this->dstInfo(), dst, rowBytes, this->options( ).fZeroInitialized, | 
| 240 countLines, linesDecoded); | |
| 241 } | |
| 242 fCurrScanline += linesDecoded; | |
| 243 return linesDecoded; | |
| 224 } | 244 } | 
| 225 | 245 | 
| 226 SkCodec::Result SkCodec::skipScanlines(int countLines) { | 246 bool SkCodec::skipScanlines(int countLines) { | 
| 227 if (fCurrScanline < 0) { | 247 if (fCurrScanline < 0) { | 
| 228 return kScanlineDecodingNotStarted; | 248 return false; | 
| 229 } | 249 } | 
| 230 | 250 | 
| 231 SkASSERT(!fDstInfo.isEmpty()); | 251 SkASSERT(!fDstInfo.isEmpty()); | 
| 232 if (fCurrScanline + countLines > fDstInfo.height()) { | 252 if (fCurrScanline + countLines > fDstInfo.height()) { | 
| 233 // Arguably, we could just skip the scanlines which are remaining, | 253 // Arguably, we could just skip the scanlines which are remaining, | 
| 234 // and return kSuccess. We choose to return invalid so the client | 254 // and return true. We choose to return false so the client | 
| 235 // can catch their bug. | 255 // can catch their bug. | 
| 236 return SkCodec::kInvalidParameters; | 256 return false; | 
| 237 } | 257 } | 
| 238 | 258 | 
| 239 const Result result = this->onSkipScanlines(countLines); | 259 if (!this->onSkipScanlines(countLines)) { | 
| 260 return false; | |
| 261 } | |
| 240 fCurrScanline += countLines; | 262 fCurrScanline += countLines; | 
| 241 return result; | 263 return true; | 
| 242 } | 264 } | 
| 265 | |
| 266 int SkCodec::nextScanline(int srcY) const { | |
| 267 SkASSERT(0 <= srcY && srcY < this->getInfo().height()); | |
| 268 switch (this->getScanlineOrder()) { | |
| 269 case kTopDown_SkScanlineOrder: | |
| 270 case kNone_SkScanlineOrder: | |
| 271 return srcY; | |
| 272 case kBottomUp_SkScanlineOrder: | |
| 273 return this->dstInfo().height() - srcY - 1; | |
| 274 case kOutOfOrder_SkScanlineOrder: | |
| 275 return get_output_row_interlaced(srcY, this->getInfo().height()); | |
| 
scroggo
2015/10/01 14:48:31
It's odd to me that kBottomUp takes the dstInfo in
 
msarett
2015/10/01 18:14:14
We can use getInfo() in both places.  This is prob
 | |
| 276 } | |
| 277 } | |
| 278 | |
| 279 void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t row Bytes, | |
| 280 ZeroInitialized zeroInit, int linesRequested, int linesDecoded) { | |
| 281 void* fillDst; | |
| 282 SkImageInfo fillInfo; | |
| 283 const uint32_t fillValue = this->getFillValue(info.colorType(), info.alphaTy pe()); | |
| 284 const int linesRemaining = linesRequested - linesDecoded; | |
| 285 switch (this->getScanlineOrder()) { | |
| 286 case kTopDown_SkScanlineOrder: | |
| 287 case kNone_SkScanlineOrder: | |
| 288 fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes); | |
| 289 fillInfo = info.makeWH(info.width(), linesRemaining); | |
| 290 SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroInit); | |
| 291 break; | |
| 292 case kBottomUp_SkScanlineOrder: | |
| 293 fillDst = dst; | |
| 294 fillInfo = info.makeWH(info.width(), linesRemaining); | |
| 295 SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroInit); | |
| 296 break; | |
| 297 case kOutOfOrder_SkScanlineOrder: | |
| 298 SkASSERT(1 == linesRequested || this->getInfo().height() == linesReq uested); | |
| 
scroggo
2015/10/01 14:48:31
Do you need the second half? It seems like if it's
 
msarett
2015/10/01 18:14:13
I don't understand.  linesRequested can be 1 or th
 
scroggo
2015/10/01 20:48:57
Oh, I think I was confused. This is just to discou
 
msarett
2015/10/01 22:34:51
Yes!
 | |
| 299 fillInfo = info.makeWH(info.width(), 1); | |
| 300 for (int srcY = linesDecoded; srcY < linesRequested; srcY++) { | |
| 301 fillDst = SkTAddOffset<void>(dst, this->nextScanline(srcY) * row Bytes); | |
| 302 SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroIni t); | |
| 303 } | |
| 304 break; | |
| 305 } | |
| 306 } | |
| OLD | NEW |