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 |