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 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
75 return NewFromStream(new SkMemoryStream(data)); | 75 return NewFromStream(new SkMemoryStream(data)); |
76 } | 76 } |
77 | 77 |
78 SkCodec::SkCodec(const SkImageInfo& info, SkStream* stream) | 78 SkCodec::SkCodec(const SkImageInfo& info, SkStream* stream) |
79 : fSrcInfo(info) | 79 : fSrcInfo(info) |
80 , fStream(stream) | 80 , fStream(stream) |
81 , fNeedsRewind(false) | 81 , fNeedsRewind(false) |
82 , fDstInfo() | 82 , fDstInfo() |
83 , fOptions() | 83 , fOptions() |
84 , fCurrScanline(-1) | 84 , fCurrScanline(-1) |
85 , fSubsetWidth(0) | |
85 {} | 86 {} |
86 | 87 |
87 SkCodec::~SkCodec() {} | 88 SkCodec::~SkCodec() {} |
88 | 89 |
89 bool SkCodec::rewindIfNeeded() { | 90 bool SkCodec::rewindIfNeeded() { |
90 if (!fStream) { | 91 if (!fStream) { |
91 // Some codecs do not have a stream, but they hold others that do. They | 92 // Some codecs do not have a stream, but they hold others that do. They |
92 // must handle rewinding themselves. | 93 // must handle rewinding themselves. |
93 return true; | 94 return true; |
94 } | 95 } |
95 | 96 |
96 // Store the value of fNeedsRewind so we can update it. Next read will | 97 // Store the value of fNeedsRewind so we can update it. Next read will |
97 // require a rewind. | 98 // require a rewind. |
98 const bool needsRewind = fNeedsRewind; | 99 const bool needsRewind = fNeedsRewind; |
99 fNeedsRewind = true; | 100 fNeedsRewind = true; |
100 if (!needsRewind) { | 101 if (!needsRewind) { |
101 return true; | 102 return true; |
102 } | 103 } |
103 | 104 |
104 // startScanlineDecode will need to be called before decoding scanlines. | 105 // startScanlineDecode will need to be called before decoding scanlines. |
105 fCurrScanline = -1; | 106 fCurrScanline = -1; |
107 fSubsetWidth = 0; | |
106 | 108 |
107 if (!fStream->rewind()) { | 109 if (!fStream->rewind()) { |
108 return false; | 110 return false; |
109 } | 111 } |
110 | 112 |
111 return this->onRewind(); | 113 return this->onRewind(); |
112 } | 114 } |
113 | 115 |
116 SkISize SkCodec::getScaledDimensions(float desiredScale) const { | |
117 // Negative and zero scales are errors. | |
118 SkASSERT(desiredScale > 0.0f); | |
119 if (desiredScale <= 0.0f) { | |
120 return SkISize::Make(0, 0); | |
121 } | |
122 | |
123 // Upscaling is not supported. Return the original size if the client | |
124 // requests an upscale. | |
125 if (desiredScale >= 1.0f) { | |
126 return this->getInfo().dimensions(); | |
127 } | |
128 return this->onGetScaledDimensions(desiredScale); | |
129 } | |
130 | |
131 bool SkCodec::getValidSubset(SkIRect* desiredSubset) const { | |
132 if (!desiredSubset) { | |
133 return false; | |
134 } | |
135 | |
136 if (!is_valid_subset(desiredSubset, this->getInfo().dimensions())) { | |
137 return false; | |
138 } | |
139 | |
140 return this->onGetValidSubset(desiredSubset); | |
141 } | |
142 | |
143 bool SkCodec::getScaledSubsetDimensions(float desiredScale, Options* options) co nst { | |
144 // Negative and zero scales are errors. | |
145 SkASSERT(desiredScale > 0.0f); | |
146 if (desiredScale <= 0.0f) { | |
147 return false; | |
148 } | |
149 | |
150 // Upscaling is not supported. We will suggest a full decode if | |
151 // upscaling is requested. | |
152 if (desiredScale >= 1.0f) { | |
153 desiredScale = 1.0f; | |
154 } | |
155 | |
156 // If the client is not requesting a subset decode, | |
157 // getScaledDimensions() should be used. | |
158 if (nullptr == options->fSubset) { | |
159 return false; | |
160 } | |
161 | |
162 if (!is_valid_subset(options->fSubset, this->getInfo().dimensions())) { | |
163 return false; | |
164 } | |
165 | |
166 return this->onGetScaledSubsetDimensions(desiredScale, options); | |
167 } | |
168 | |
114 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, | 169 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, |
115 const Options* options, SkPMColor ctable[], i nt* ctableCount) { | 170 const Options* options, SkPMColor ctable[], i nt* ctableCount) { |
116 if (kUnknown_SkColorType == info.colorType()) { | 171 if (kUnknown_SkColorType == info.colorType()) { |
117 return kInvalidConversion; | 172 return kInvalidConversion; |
118 } | 173 } |
119 if (nullptr == pixels) { | 174 if (nullptr == pixels) { |
120 return kInvalidParameters; | 175 return kInvalidParameters; |
121 } | 176 } |
122 if (rowBytes < info.minRowBytes()) { | 177 if (rowBytes < info.minRowBytes()) { |
123 return kInvalidParameters; | 178 return kInvalidParameters; |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
175 } | 230 } |
176 | 231 |
177 return result; | 232 return result; |
178 } | 233 } |
179 | 234 |
180 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { | 235 SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { |
181 return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr); | 236 return this->getPixels(info, pixels, rowBytes, nullptr, nullptr, nullptr); |
182 } | 237 } |
183 | 238 |
184 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, | 239 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, |
185 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { | 240 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount, i nt subsetLeft, |
241 int subsetWidth) { | |
186 // Reset fCurrScanline in case of failure. | 242 // Reset fCurrScanline in case of failure. |
187 fCurrScanline = -1; | 243 fCurrScanline = -1; |
244 | |
245 // Ensure that the subset parameters are valid | |
246 if (0 > subsetLeft || subsetLeft >= dstInfo.width() || 0 > subsetWidth || | |
scroggo
2015/10/02 18:27:03
nit: I would lean towards separating these out log
| |
247 subsetLeft + subsetWidth > dstInfo.width()) { | |
248 return kInvalidParameters; | |
249 } | |
250 | |
188 // Ensure that valid color ptrs are passed in for kIndex8 color type | 251 // Ensure that valid color ptrs are passed in for kIndex8 color type |
189 if (kIndex_8_SkColorType == dstInfo.colorType()) { | 252 if (kIndex_8_SkColorType == dstInfo.colorType()) { |
190 if (nullptr == ctable || nullptr == ctableCount) { | 253 if (nullptr == ctable || nullptr == ctableCount) { |
191 return SkCodec::kInvalidParameters; | 254 return SkCodec::kInvalidParameters; |
192 } | 255 } |
193 } else { | 256 } else { |
194 if (ctableCount) { | 257 if (ctableCount) { |
195 *ctableCount = 0; | 258 *ctableCount = 0; |
196 } | 259 } |
197 ctableCount = nullptr; | 260 ctableCount = nullptr; |
198 ctable = nullptr; | 261 ctable = nullptr; |
199 } | 262 } |
200 | 263 |
201 if (!this->rewindIfNeeded()) { | 264 if (!this->rewindIfNeeded()) { |
202 return kCouldNotRewind; | 265 return kCouldNotRewind; |
203 } | 266 } |
204 | 267 |
205 // Set options. | 268 // Set options. |
206 Options optsStorage; | 269 Options optsStorage; |
207 if (nullptr == options) { | 270 if (nullptr == options) { |
208 options = &optsStorage; | 271 options = &optsStorage; |
209 } | 272 } |
210 | 273 |
211 const Result result = this->onStartScanlineDecode(dstInfo, *options, ctable, ctableCount); | 274 const Result result = this->onStartScanlineDecode(dstInfo, *options, ctable, ctableCount, |
275 subsetLeft, subsetWidth); | |
212 if (result != SkCodec::kSuccess) { | 276 if (result != SkCodec::kSuccess) { |
213 return result; | 277 return result; |
214 } | 278 } |
215 | 279 |
216 fCurrScanline = 0; | 280 fCurrScanline = 0; |
217 fDstInfo = dstInfo; | 281 fDstInfo = dstInfo; |
218 fOptions = *options; | 282 fOptions = *options; |
283 fSubsetWidth = subsetWidth; | |
219 return kSuccess; | 284 return kSuccess; |
220 } | 285 } |
221 | 286 |
287 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo, | |
288 const SkCodec::Options* options, SkPMColor ctable[], int* ctableCount) { | |
289 return this->startScanlineDecode(dstInfo, options, ctable, ctableCount, 0, d stInfo.width()); | |
290 } | |
291 | |
222 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo) { | 292 SkCodec::Result SkCodec::startScanlineDecode(const SkImageInfo& dstInfo) { |
223 return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr); | 293 return this->startScanlineDecode(dstInfo, nullptr, nullptr, nullptr, 0, dstI nfo.width()); |
224 } | 294 } |
225 | 295 |
226 int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { | 296 int SkCodec::getScanlines(void* dst, int countLines, size_t rowBytes) { |
227 if (fCurrScanline < 0) { | 297 if (fCurrScanline < 0) { |
228 return 0; | 298 return 0; |
229 } | 299 } |
230 | 300 |
231 SkASSERT(!fDstInfo.isEmpty()); | 301 SkASSERT(!fDstInfo.isEmpty()); |
232 if ((rowBytes < fDstInfo.minRowBytes() && countLines > 1 ) || countLines <= 0 | 302 if (countLines <= 0 || fCurrScanline + countLines > fDstInfo.height()) { |
233 || fCurrScanline + countLines > fDstInfo.height()) { | |
234 return 0; | 303 return 0; |
235 } | 304 } |
236 | 305 |
237 const uint32_t linesDecoded = this->onGetScanlines(dst, countLines, rowBytes ); | 306 const uint32_t linesDecoded = this->onGetScanlines(dst, countLines, rowBytes ); |
238 if (linesDecoded < countLines) { | 307 if (linesDecoded < countLines) { |
239 this->fillIncompleteImage(this->dstInfo(), dst, rowBytes, this->options( ).fZeroInitialized, | 308 this->fillIncompleteImage(this->dstInfo(), dst, rowBytes, this->options( ).fZeroInitialized, |
240 countLines, linesDecoded); | 309 countLines, linesDecoded); |
241 } | 310 } |
242 fCurrScanline += linesDecoded; | 311 fCurrScanline += linesDecoded; |
243 return linesDecoded; | 312 return linesDecoded; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
275 return get_output_row_interlaced(inputScanline, this->getInfo().heig ht()); | 344 return get_output_row_interlaced(inputScanline, this->getInfo().heig ht()); |
276 } | 345 } |
277 } | 346 } |
278 | 347 |
279 void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t row Bytes, | 348 void SkCodec::fillIncompleteImage(const SkImageInfo& info, void* dst, size_t row Bytes, |
280 ZeroInitialized zeroInit, int linesRequested, int linesDecoded) { | 349 ZeroInitialized zeroInit, int linesRequested, int linesDecoded) { |
281 void* fillDst; | 350 void* fillDst; |
282 SkImageInfo fillInfo; | 351 SkImageInfo fillInfo; |
283 const uint32_t fillValue = this->getFillValue(info.colorType(), info.alphaTy pe()); | 352 const uint32_t fillValue = this->getFillValue(info.colorType(), info.alphaTy pe()); |
284 const int linesRemaining = linesRequested - linesDecoded; | 353 const int linesRemaining = linesRequested - linesDecoded; |
354 const int fillWidth = fSubsetWidth ? fSubsetWidth : info.width(); | |
285 switch (this->getScanlineOrder()) { | 355 switch (this->getScanlineOrder()) { |
286 case kTopDown_SkScanlineOrder: | 356 case kTopDown_SkScanlineOrder: |
287 case kNone_SkScanlineOrder: | 357 case kNone_SkScanlineOrder: |
288 fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes); | 358 fillDst = SkTAddOffset<void>(dst, linesDecoded * rowBytes); |
289 fillInfo = info.makeWH(info.width(), linesRemaining); | 359 fillInfo = info.makeWH(fillWidth, linesRemaining); |
290 SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroInit); | 360 SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroInit); |
291 break; | 361 break; |
292 case kBottomUp_SkScanlineOrder: | 362 case kBottomUp_SkScanlineOrder: |
293 fillDst = dst; | 363 fillDst = dst; |
294 fillInfo = info.makeWH(info.width(), linesRemaining); | 364 fillInfo = info.makeWH(fillWidth, linesRemaining); |
295 SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroInit); | 365 SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroInit); |
296 break; | 366 break; |
297 case kOutOfOrder_SkScanlineOrder: | 367 case kOutOfOrder_SkScanlineOrder: |
298 SkASSERT(1 == linesRequested || this->getInfo().height() == linesReq uested); | 368 SkASSERT(1 == linesRequested || this->getInfo().height() == linesReq uested); |
299 fillInfo = info.makeWH(info.width(), 1); | 369 fillInfo = info.makeWH(fillWidth, 1); |
300 for (int srcY = linesDecoded; srcY < linesRequested; srcY++) { | 370 for (int srcY = linesDecoded; srcY < linesRequested; srcY++) { |
301 fillDst = SkTAddOffset<void>(dst, this->outputScanline(srcY) * r owBytes); | 371 fillDst = SkTAddOffset<void>(dst, this->outputScanline(srcY) * r owBytes); |
302 SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroIni t); | 372 SkSwizzler::Fill(fillDst, fillInfo, rowBytes, fillValue, zeroIni t); |
303 } | 373 } |
304 break; | 374 break; |
305 } | 375 } |
306 } | 376 } |
OLD | NEW |