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 "DMSrcSink.h" | 8 #include "DMSrcSink.h" |
9 #include "SamplePipeControllers.h" | 9 #include "SamplePipeControllers.h" |
10 #include "SkCodec.h" | 10 #include "SkCodec.h" |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
78 return flags.type != SinkFlags::kRaster | 78 return flags.type != SinkFlags::kRaster |
79 || flags.approach != SinkFlags::kDirect; | 79 || flags.approach != SinkFlags::kDirect; |
80 } | 80 } |
81 | 81 |
82 SkScanlineDecoder* start_scanline_decoder(SkData* encoded, const SkImageInfo& in fo, | 82 SkScanlineDecoder* start_scanline_decoder(SkData* encoded, const SkImageInfo& in fo, |
83 SkPMColor* colorPtr, int* colorCountPtr) { | 83 SkPMColor* colorPtr, int* colorCountPtr) { |
84 SkAutoTDelete<SkScanlineDecoder> scanlineDecoder(SkScanlineDecoder::NewFromD ata(encoded)); | 84 SkAutoTDelete<SkScanlineDecoder> scanlineDecoder(SkScanlineDecoder::NewFromD ata(encoded)); |
85 if (nullptr == scanlineDecoder) { | 85 if (nullptr == scanlineDecoder) { |
86 return nullptr; | 86 return nullptr; |
87 } | 87 } |
88 // DM scanline test assume kTopDown scanline ordering. Other orderings are | |
89 // tested from within SkScaledCodec. | |
90 // TODO (msarett): Redesign the CodecSrc tests to improve our coverage of Sk Codec and | |
91 // SkScanlineDecoder functionality. Maybe we should write c ode to explicitly | |
92 // test kNone, kOutOfOrder, and kBottomUp. | |
93 if (SkScanlineDecoder::kTopDown_SkScanlineOrder != scanlineDecoder->getScanl ineOrder()) { | |
94 return nullptr; | |
95 } | |
96 if (SkCodec::kSuccess != scanlineDecoder->start(info, NULL, colorPtr, colorC ountPtr)) { | 88 if (SkCodec::kSuccess != scanlineDecoder->start(info, NULL, colorPtr, colorC ountPtr)) { |
97 return nullptr; | 89 return nullptr; |
98 } | 90 } |
99 return scanlineDecoder.detach(); | 91 return scanlineDecoder.detach(); |
100 } | 92 } |
101 | 93 |
102 Error CodecSrc::draw(SkCanvas* canvas) const { | 94 Error CodecSrc::draw(SkCanvas* canvas) const { |
103 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); | 95 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); |
104 if (!encoded) { | 96 if (!encoded) { |
105 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); | 97 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); |
106 } | 98 } |
107 SkAutoTDelete<SkCodec> codec(SkScaledCodec::NewFromData(encoded)); | 99 SkAutoTDelete<SkCodec> codec(NULL); |
100 if (kScaledCodec_Mode == fMode) { | |
101 codec.reset(SkScaledCodec::NewFromData(encoded)); | |
102 // TODO (msarett): This should fall throught to a fatal error once we su pport scaled | |
scroggo
2015/08/31 19:35:24
nit: through*
msarett
2015/08/31 21:05:28
Done.
| |
103 // codecs for all image types. | |
104 if (nullptr == codec.get()) { | |
105 return Error::Nonfatal(SkStringPrintf("Couldn't create scaled codec for %s.", | |
106 fPath.c_str())); | |
107 } | |
108 } else { | |
109 codec.reset(SkCodec::NewFromData(encoded)); | |
110 } | |
108 if (nullptr == codec.get()) { | 111 if (nullptr == codec.get()) { |
109 // scaledCodec not supported, try normal codec | 112 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); |
110 codec.reset(SkCodec::NewFromData(encoded)); | |
111 if (nullptr == codec.get()) { | |
112 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str() ); | |
113 } | |
114 } | 113 } |
115 | 114 |
116 // Choose the color type to decode to | 115 // Choose the color type to decode to |
117 SkImageInfo decodeInfo = codec->getInfo(); | 116 SkImageInfo decodeInfo = codec->getInfo(); |
118 SkColorType canvasColorType = canvas->imageInfo().colorType(); | 117 SkColorType canvasColorType = canvas->imageInfo().colorType(); |
119 switch (fDstColorType) { | 118 switch (fDstColorType) { |
120 case kIndex8_Always_DstColorType: | 119 case kIndex8_Always_DstColorType: |
121 decodeInfo = codec->getInfo().makeColorType(kIndex_8_SkColorType); | 120 decodeInfo = codec->getInfo().makeColorType(kIndex_8_SkColorType); |
122 if (kRGB_565_SkColorType == canvasColorType) { | 121 if (kRGB_565_SkColorType == canvasColorType) { |
123 return Error::Nonfatal("Testing non-565 to 565 is uninteresting. "); | 122 return Error::Nonfatal("Testing non-565 to 565 is uninteresting. "); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
164 decodeInfo = decodeInfo.makeAlphaType(kPremul_SkAlphaType); | 163 decodeInfo = decodeInfo.makeAlphaType(kPremul_SkAlphaType); |
165 } | 164 } |
166 | 165 |
167 SkBitmap bitmap; | 166 SkBitmap bitmap; |
168 if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) { | 167 if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) { |
169 return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str( ), | 168 return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str( ), |
170 decodeInfo.width(), decodeInfo.height()); | 169 decodeInfo.width(), decodeInfo.height()); |
171 } | 170 } |
172 | 171 |
173 switch (fMode) { | 172 switch (fMode) { |
174 case kNormal_Mode: { | 173 case kScaledCodec_Mode: |
174 case kCodec_Mode: { | |
175 switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowB ytes(), nullptr, | 175 switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowB ytes(), nullptr, |
176 colorPtr, colorCountPtr)) { | 176 colorPtr, colorCountPtr)) { |
177 case SkCodec::kSuccess: | 177 case SkCodec::kSuccess: |
178 // We consider incomplete to be valid, since we should still decode what is | 178 // We consider incomplete to be valid, since we should still decode what is |
179 // available. | 179 // available. |
180 case SkCodec::kIncompleteInput: | 180 case SkCodec::kIncompleteInput: |
181 break; | 181 break; |
182 case SkCodec::kInvalidConversion: | 182 case SkCodec::kInvalidConversion: |
183 return Error::Nonfatal("Incompatible colortype conversion"); | 183 return Error::Nonfatal("Incompatible colortype conversion"); |
184 default: | 184 default: |
185 // Everything else is considered a failure. | 185 // Everything else is considered a failure. |
186 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str( )); | 186 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str( )); |
187 } | 187 } |
188 canvas->drawBitmap(bitmap, 0, 0); | 188 canvas->drawBitmap(bitmap, 0, 0); |
189 break; | 189 break; |
190 } | 190 } |
191 case kScanline_Mode: { | 191 case kScanline_Mode: { |
192 SkAutoTDelete<SkScanlineDecoder> scanlineDecoder( | 192 SkAutoTDelete<SkScanlineDecoder> scanlineDecoder( |
193 start_scanline_decoder(encoded.get(), decodeInfo, colorPtr, colorCountPtr)); | 193 start_scanline_decoder(encoded.get(), decodeInfo, colorPtr, colorCountPtr)); |
194 if (nullptr == scanlineDecoder) { | 194 if (nullptr == scanlineDecoder) { |
195 return Error::Nonfatal("Could not start top-down scanline decode r"); | 195 return Error::Nonfatal("Could not start scanline decoder"); |
196 } | 196 } |
197 | 197 |
198 const SkCodec::Result result = scanlineDecoder->getScanlines( | 198 const SkCodec::Result result = scanlineDecoder->getScanlines( |
199 bitmap.getAddr(0, 0), decodeInfo.height(), bitmap.rowBytes() ); | 199 bitmap.getAddr(0, 0), decodeInfo.height(), bitmap.rowBytes() ); |
200 switch (result) { | 200 switch (result) { |
201 case SkCodec::kSuccess: | 201 case SkCodec::kSuccess: |
202 case SkCodec::kIncompleteInput: | 202 case SkCodec::kIncompleteInput: |
203 break; | 203 break; |
204 default: | 204 default: |
205 return SkStringPrintf("%s failed with error message %d", | 205 return SkStringPrintf("%s failed with error message %d", |
206 fPath.c_str(), (int) result); | 206 fPath.c_str(), (int) result); |
207 } | 207 } |
208 canvas->drawBitmap(bitmap, 0, 0); | 208 canvas->drawBitmap(bitmap, 0, 0); |
209 break; | 209 break; |
210 } | 210 } |
211 case kScanline_Subset_Mode: { | 211 case kScanline_Subset_Mode: { |
msarett
2015/08/31 18:05:52
I'm wondering if maybe we should eliminate the sca
scroggo
2015/08/31 19:35:24
Yes, I think we should. This serves as a proof-of-
| |
212 //this mode decodes the image in divisor*divisor subsets, using a sc anline decoder | 212 //this mode decodes the image in divisor*divisor subsets, using a sc anline decoder |
213 const int divisor = 2; | 213 const int divisor = 2; |
214 const int w = decodeInfo.width(); | 214 const int w = decodeInfo.width(); |
215 const int h = decodeInfo.height(); | 215 const int h = decodeInfo.height(); |
216 if (divisor > w || divisor > h) { | 216 if (divisor > w || divisor > h) { |
217 return Error::Nonfatal(SkStringPrintf("Cannot decode subset: div isor %d is too big" | 217 return Error::Nonfatal(SkStringPrintf("Cannot decode subset: div isor %d is too big" |
218 "for %s with dimensions (%d x %d)", divisor, fPath.c_str (), w, h)); | 218 "for %s with dimensions (%d x %d)", divisor, fPath.c_str (), w, h)); |
219 } | 219 } |
220 const int subsetWidth = w/divisor; | 220 const int subsetWidth = w/divisor; |
221 const int subsetHeight = h/divisor; | 221 const int subsetHeight = h/divisor; |
222 // One of our subsets will be larger to contain any pixels that do n ot divide evenly. | 222 // One of our subsets will be larger to contain any pixels that do n ot divide evenly. |
223 const int extraX = w % divisor; | 223 const int extraX = w % divisor; |
224 const int extraY = h % divisor; | 224 const int extraY = h % divisor; |
225 /* | 225 /* |
226 * if w or h are not evenly divided by divisor need to adjust width a nd height of end | 226 * if w or h are not evenly divided by divisor need to adjust width a nd height of end |
227 * subsets to cover entire image. | 227 * subsets to cover entire image. |
228 * Add extraX and extraY to largestSubsetBm's width and height to adj ust width | 228 * Add extraX and extraY to largestSubsetBm's width and height to adj ust width |
229 * and height of end subsets. | 229 * and height of end subsets. |
230 * subsetBm is extracted from largestSubsetBm. | 230 * subsetBm is extracted from largestSubsetBm. |
231 * subsetBm's size is determined based on the current subset and may be larger for end | 231 * subsetBm's size is determined based on the current subset and may be larger for end |
232 * subsets. | 232 * subsets. |
233 */ | 233 */ |
234 SkImageInfo largestSubsetDecodeInfo = | 234 SkImageInfo largestSubsetDecodeInfo = |
235 decodeInfo.makeWH(subsetWidth + extraX, subsetHeight + extra Y); | 235 decodeInfo.makeWH(subsetWidth + extraX, subsetHeight + extra Y); |
236 SkBitmap largestSubsetBm; | 236 SkBitmap largestSubsetBm; |
237 if (!largestSubsetBm.tryAllocPixels(largestSubsetDecodeInfo, nullptr , colorTable.get())) { | 237 if (!largestSubsetBm.tryAllocPixels(largestSubsetDecodeInfo, nullptr , |
238 colorTable.get())) { | |
238 return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPat h.c_str(), | 239 return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPat h.c_str(), |
239 largestSubsetDecodeInfo.width(), largestSubsetDecodeInfo .height()); | 240 largestSubsetDecodeInfo.width(), largestSubsetDecodeInfo .height()); |
240 } | 241 } |
241 const size_t rowBytes = decodeInfo.minRowBytes(); | 242 const size_t rowBytes = decodeInfo.minRowBytes(); |
242 char* buffer = new char[largestSubsetDecodeInfo.height() * rowBytes] ; | 243 char* buffer = new char[largestSubsetDecodeInfo.height() * rowBytes] ; |
243 SkAutoTDeleteArray<char> lineDeleter(buffer); | 244 SkAutoTDeleteArray<char> lineDeleter(buffer); |
244 for (int col = 0; col < divisor; col++) { | 245 for (int col = 0; col < divisor; col++) { |
245 //currentSubsetWidth may be larger than subsetWidth for rightmos t subsets | 246 //currentSubsetWidth may be larger than subsetWidth for rightmos t subsets |
246 const int currentSubsetWidth = (col + 1 == divisor) ? | 247 const int currentSubsetWidth = (col + 1 == divisor) ? |
247 subsetWidth + extraX : subsetWidth; | 248 subsetWidth + extraX : subsetWidth; |
248 const int x = col * subsetWidth; | 249 const int x = col * subsetWidth; |
249 for (int row = 0; row < divisor; row++) { | 250 for (int row = 0; row < divisor; row++) { |
250 //currentSubsetHeight may be larger than subsetHeight for bo ttom subsets | 251 //currentSubsetHeight may be larger than subsetHeight for bo ttom subsets |
251 const int currentSubsetHeight = (row + 1 == divisor) ? | 252 const int currentSubsetHeight = (row + 1 == divisor) ? |
252 subsetHeight + extraY : subsetHeight; | 253 subsetHeight + extraY : subsetHeight; |
253 const int y = row * subsetHeight; | 254 const int y = row * subsetHeight; |
254 //create scanline decoder for each subset | 255 //create scanline decoder for each subset |
255 SkAutoTDelete<SkScanlineDecoder> subsetScanlineDecoder( | 256 SkAutoTDelete<SkScanlineDecoder> decoder(start_scanline_deco der(encoded.get(), |
256 start_scanline_decoder(encoded.get(), decodeInfo, | 257 decodeInfo, colorPtr, colorCountPtr)); |
257 colorPtr, colorCountPtr)); | 258 // TODO (msarett): Support this mode for all scanline orderi ngs. |
258 if (nullptr == subsetScanlineDecoder) { | 259 if (nullptr == decoder || SkScanlineDecoder::kTopDown_SkScan lineOrder != |
260 decoder->getScanlineOrder()) { | |
259 if (x == 0 && y == 0) { | 261 if (x == 0 && y == 0) { |
260 //first try, image may not be compatible | 262 //first try, image may not be compatible |
261 return Error::Nonfatal("Could not start top-down sca nline decoder"); | 263 return Error::Nonfatal("Could not start top-down sca nline decoder"); |
262 } else { | 264 } else { |
263 return "Error scanline decoder is nullptr"; | 265 return "Error scanline decoder is nullptr"; |
264 } | 266 } |
265 } | 267 } |
266 //skip to first line of subset | 268 //skip to first line of subset |
267 const SkCodec::Result skipResult = | 269 const SkCodec::Result skipResult = decoder->skipScanlines(y) ; |
268 subsetScanlineDecoder->skipScanlines(y); | |
269 switch (skipResult) { | 270 switch (skipResult) { |
270 case SkCodec::kSuccess: | 271 case SkCodec::kSuccess: |
271 case SkCodec::kIncompleteInput: | 272 case SkCodec::kIncompleteInput: |
272 break; | 273 break; |
273 default: | 274 default: |
274 return SkStringPrintf("%s failed after attempting to skip %d scanlines" | 275 return SkStringPrintf("%s failed after attempting to skip %d scanlines" |
275 "with error message %d", fPath.c_str(), y, ( int) skipResult); | 276 "with error message %d", fPath.c_str(), y, ( int) skipResult); |
276 } | 277 } |
277 //create and set size of subsetBm | 278 //create and set size of subsetBm |
278 SkBitmap subsetBm; | 279 SkBitmap subsetBm; |
279 SkIRect bounds = SkIRect::MakeWH(subsetWidth, subsetHeight); | 280 SkIRect bounds = SkIRect::MakeWH(subsetWidth, subsetHeight); |
280 bounds.setXYWH(0, 0, currentSubsetWidth, currentSubsetHeight ); | 281 bounds.setXYWH(0, 0, currentSubsetWidth, currentSubsetHeight ); |
281 SkAssertResult(largestSubsetBm.extractSubset(&subsetBm, boun ds)); | 282 SkAssertResult(largestSubsetBm.extractSubset(&subsetBm, boun ds)); |
282 SkAutoLockPixels autlockSubsetBm(subsetBm, true); | 283 SkAutoLockPixels autlockSubsetBm(subsetBm, true); |
283 const SkCodec::Result subsetResult = | 284 const SkCodec::Result subsetResult = |
284 subsetScanlineDecoder->getScanlines(buffer, currentSubse tHeight, rowBytes); | 285 decoder->getScanlines(buffer, currentSubsetHeight, r owBytes); |
285 switch (subsetResult) { | 286 switch (subsetResult) { |
286 case SkCodec::kSuccess: | 287 case SkCodec::kSuccess: |
287 case SkCodec::kIncompleteInput: | 288 case SkCodec::kIncompleteInput: |
288 break; | 289 break; |
289 default: | 290 default: |
290 return SkStringPrintf("%s failed with error message %d", | 291 return SkStringPrintf("%s failed with error message %d", |
291 fPath.c_str(), (int) subsetResult); | 292 fPath.c_str(), (int) subsetResult); |
292 } | 293 } |
293 const size_t bpp = decodeInfo.bytesPerPixel(); | 294 const size_t bpp = decodeInfo.bytesPerPixel(); |
294 /* | 295 /* |
(...skipping 21 matching lines...) Expand all Loading... | |
316 case kStripe_Mode: { | 317 case kStripe_Mode: { |
317 const int height = decodeInfo.height(); | 318 const int height = decodeInfo.height(); |
318 // This value is chosen arbitrarily. We exercise more cases by choo sing a value that | 319 // This value is chosen arbitrarily. We exercise more cases by choo sing a value that |
319 // does not align with image blocks. | 320 // does not align with image blocks. |
320 const int stripeHeight = 37; | 321 const int stripeHeight = 37; |
321 const int numStripes = (height + stripeHeight - 1) / stripeHeight; | 322 const int numStripes = (height + stripeHeight - 1) / stripeHeight; |
322 | 323 |
323 // Decode odd stripes | 324 // Decode odd stripes |
324 SkAutoTDelete<SkScanlineDecoder> decoder( | 325 SkAutoTDelete<SkScanlineDecoder> decoder( |
325 start_scanline_decoder(encoded.get(), decodeInfo, colorPtr, colorCountPtr)); | 326 start_scanline_decoder(encoded.get(), decodeInfo, colorPtr, colorCountPtr)); |
326 if (nullptr == decoder) { | 327 if (nullptr == decoder || |
328 SkScanlineDecoder::kTopDown_SkScanlineOrder != decoder->getS canlineOrder()) { | |
329 // This mode was designed to test the new skip scanlines API in libjpeg-turbo. | |
330 // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting | |
331 // to run this test for image types that do not have this scanli ne ordering. | |
327 return Error::Nonfatal("Could not start top-down scanline decode r"); | 332 return Error::Nonfatal("Could not start top-down scanline decode r"); |
328 } | 333 } |
329 for (int i = 0; i < numStripes; i += 2) { | 334 for (int i = 0; i < numStripes; i += 2) { |
330 // Skip a stripe | 335 // Skip a stripe |
331 const int linesToSkip = SkTMin(stripeHeight, height - i * stripe Height); | 336 const int linesToSkip = SkTMin(stripeHeight, height - i * stripe Height); |
332 SkCodec::Result result = decoder->skipScanlines(linesToSkip); | 337 SkCodec::Result result = decoder->skipScanlines(linesToSkip); |
333 switch (result) { | 338 switch (result) { |
334 case SkCodec::kSuccess: | 339 case SkCodec::kSuccess: |
335 case SkCodec::kIncompleteInput: | 340 case SkCodec::kIncompleteInput: |
336 break; | 341 break; |
(...skipping 13 matching lines...) Expand all Loading... | |
350 break; | 355 break; |
351 default: | 356 default: |
352 return SkStringPrintf("Cannot get scanlines for %s." , fPath.c_str()); | 357 return SkStringPrintf("Cannot get scanlines for %s." , fPath.c_str()); |
353 } | 358 } |
354 } | 359 } |
355 } | 360 } |
356 | 361 |
357 // Decode even stripes | 362 // Decode even stripes |
358 const SkCodec::Result startResult = decoder->start(decodeInfo, nullp tr, colorPtr, | 363 const SkCodec::Result startResult = decoder->start(decodeInfo, nullp tr, colorPtr, |
359 colorCountPtr); | 364 colorCountPtr); |
360 if (SkCodec::kSuccess != startResult) { | 365 if (SkCodec::kSuccess != startResult || |
366 SkScanlineDecoder::kTopDown_SkScanlineOrder != decoder->getS canlineOrder()) { | |
scroggo
2015/08/31 19:35:24
It seems like we should never reach here if kTopDo
msarett
2015/08/31 21:05:28
Not unless there is a bug in start(). I agree tha
| |
361 return "Failed to restart scanline decoder with same parameters. "; | 367 return "Failed to restart scanline decoder with same parameters. "; |
362 } | 368 } |
363 for (int i = 0; i < numStripes; i += 2) { | 369 for (int i = 0; i < numStripes; i += 2) { |
364 // Read a stripe | 370 // Read a stripe |
365 const int startY = i * stripeHeight; | 371 const int startY = i * stripeHeight; |
366 const int linesToRead = SkTMin(stripeHeight, height - startY); | 372 const int linesToRead = SkTMin(stripeHeight, height - startY); |
367 SkCodec::Result result = decoder->getScanlines(bitmap.getAddr(0, startY), | 373 SkCodec::Result result = decoder->getScanlines(bitmap.getAddr(0, startY), |
368 linesToRead, bitmap.rowBytes()); | 374 linesToRead, bitmap.rowBytes()); |
369 switch (result) { | 375 switch (result) { |
370 case SkCodec::kSuccess: | 376 case SkCodec::kSuccess: |
(...skipping 710 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1081 skr.visit<void>(i, drawsAsSingletonPictures); | 1087 skr.visit<void>(i, drawsAsSingletonPictures); |
1082 } | 1088 } |
1083 SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture()); | 1089 SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture()); |
1084 | 1090 |
1085 canvas->drawPicture(macroPic); | 1091 canvas->drawPicture(macroPic); |
1086 return ""; | 1092 return ""; |
1087 }); | 1093 }); |
1088 } | 1094 } |
1089 | 1095 |
1090 } // namespace DM | 1096 } // namespace DM |
OLD | NEW |