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 "SkAndroidCodec.h" | |
10 #include "SkCodec.h" | 11 #include "SkCodec.h" |
11 #include "SkCodecTools.h" | 12 #include "SkCodecTools.h" |
12 #include "SkCommonFlags.h" | 13 #include "SkCommonFlags.h" |
13 #include "SkData.h" | 14 #include "SkData.h" |
14 #include "SkDocument.h" | 15 #include "SkDocument.h" |
15 #include "SkError.h" | 16 #include "SkError.h" |
16 #include "SkFunction.h" | 17 #include "SkFunction.h" |
17 #include "SkImageGenerator.h" | 18 #include "SkImageGenerator.h" |
18 #include "SkMultiPictureDraw.h" | 19 #include "SkMultiPictureDraw.h" |
19 #include "SkNullCanvas.h" | 20 #include "SkNullCanvas.h" |
20 #include "SkOSFile.h" | 21 #include "SkOSFile.h" |
21 #include "SkPictureData.h" | 22 #include "SkPictureData.h" |
22 #include "SkPictureRecorder.h" | 23 #include "SkPictureRecorder.h" |
23 #include "SkRandom.h" | 24 #include "SkRandom.h" |
24 #include "SkRecordDraw.h" | 25 #include "SkRecordDraw.h" |
25 #include "SkRecorder.h" | 26 #include "SkRecorder.h" |
26 #include "SkRemote.h" | 27 #include "SkRemote.h" |
27 #include "SkSVGCanvas.h" | 28 #include "SkSVGCanvas.h" |
28 #include "SkScaledCodec.h" | |
29 #include "SkStream.h" | 29 #include "SkStream.h" |
30 #include "SkTLogic.h" | 30 #include "SkTLogic.h" |
31 #include "SkXMLWriter.h" | 31 #include "SkXMLWriter.h" |
32 #include "SkScaledCodec.h" | |
33 #include "SkSwizzler.h" | 32 #include "SkSwizzler.h" |
34 | 33 |
35 DEFINE_bool(multiPage, false, "For document-type backends, render the source" | 34 DEFINE_bool(multiPage, false, "For document-type backends, render the source" |
36 " into multiple pages"); | 35 " into multiple pages"); |
37 | 36 |
38 static bool lazy_decode_bitmap(const void* src, size_t size, SkBitmap* dst) { | 37 static bool lazy_decode_bitmap(const void* src, size_t size, SkBitmap* dst) { |
39 SkAutoTUnref<SkData> encoded(SkData::NewWithCopy(src, size)); | 38 SkAutoTUnref<SkData> encoded(SkData::NewWithCopy(src, size)); |
40 return encoded && SkDEPRECATED_InstallDiscardablePixelRef(encoded, dst); | 39 return encoded && SkDEPRECATED_InstallDiscardablePixelRef(encoded, dst); |
41 } | 40 } |
42 | 41 |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
237 {} | 236 {} |
238 | 237 |
239 bool CodecSrc::veto(SinkFlags flags) const { | 238 bool CodecSrc::veto(SinkFlags flags) const { |
240 // No need to test decoding to non-raster or indirect backend. | 239 // No need to test decoding to non-raster or indirect backend. |
241 // TODO: Once we implement GPU paths (e.g. JPEG YUV), we should use a deferr ed decode to | 240 // TODO: Once we implement GPU paths (e.g. JPEG YUV), we should use a deferr ed decode to |
242 // let the GPU handle it. | 241 // let the GPU handle it. |
243 return flags.type != SinkFlags::kRaster | 242 return flags.type != SinkFlags::kRaster |
244 || flags.approach != SinkFlags::kDirect; | 243 || flags.approach != SinkFlags::kDirect; |
245 } | 244 } |
246 | 245 |
246 bool get_decode_info(SkImageInfo* decodeInfo, const SkImageInfo& defaultInfo, | |
247 SkColorType canvasColorType, CodecSrc::DstColorType dstColorType) { | |
248 switch (dstColorType) { | |
249 case CodecSrc::kIndex8_Always_DstColorType: | |
250 if (kRGB_565_SkColorType == canvasColorType) { | |
251 return false; | |
252 } | |
253 *decodeInfo = defaultInfo.makeColorType(kIndex_8_SkColorType); | |
254 break; | |
255 case CodecSrc::kGrayscale_Always_DstColorType: | |
256 if (kRGB_565_SkColorType == canvasColorType) { | |
257 return false; | |
258 } | |
259 *decodeInfo = defaultInfo.makeColorType(kGray_8_SkColorType); | |
260 break; | |
261 default: | |
262 *decodeInfo = defaultInfo.makeColorType(canvasColorType); | |
263 break; | |
264 } | |
265 | |
266 // FIXME: Currently we cannot draw unpremultiplied sources. | |
267 if (decodeInfo->alphaType() == kUnpremul_SkAlphaType) { | |
268 decodeInfo->makeAlphaType(kPremul_SkAlphaType); | |
269 } | |
270 return true; | |
271 } | |
272 | |
247 Error CodecSrc::draw(SkCanvas* canvas) const { | 273 Error CodecSrc::draw(SkCanvas* canvas) const { |
248 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); | 274 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); |
249 if (!encoded) { | 275 if (!encoded) { |
250 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); | 276 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); |
251 } | 277 } |
252 SkAutoTDelete<SkCodec> codec(NULL); | 278 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); |
253 if (kScaledCodec_Mode == fMode) { | |
254 codec.reset(SkScaledCodec::NewFromData(encoded)); | |
255 // TODO (msarett): This should fall through to a fatal error once we sup port scaled | |
256 // codecs for all image types. | |
257 if (nullptr == codec.get()) { | |
258 return Error::Nonfatal(SkStringPrintf("Couldn't create scaled codec for %s.", | |
259 fPath.c_str())); | |
260 } | |
261 } else { | |
262 codec.reset(SkCodec::NewFromData(encoded)); | |
263 } | |
264 if (nullptr == codec.get()) { | 279 if (nullptr == codec.get()) { |
265 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); | 280 return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); |
266 } | 281 } |
267 | 282 |
268 // Choose the color type to decode to | 283 SkImageInfo decodeInfo; |
269 SkImageInfo decodeInfo = codec->getInfo(); | 284 if (!get_decode_info(&decodeInfo, codec->getInfo(), canvas->imageInfo().colo rType(), |
270 SkColorType canvasColorType = canvas->imageInfo().colorType(); | 285 fDstColorType)) { |
271 switch (fDstColorType) { | 286 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); |
272 case kIndex8_Always_DstColorType: | |
273 decodeInfo = codec->getInfo().makeColorType(kIndex_8_SkColorType); | |
274 if (kRGB_565_SkColorType == canvasColorType) { | |
275 return Error::Nonfatal("Testing non-565 to 565 is uninteresting. "); | |
276 } | |
277 break; | |
278 case kGrayscale_Always_DstColorType: | |
279 decodeInfo = codec->getInfo().makeColorType(kGray_8_SkColorType); | |
280 if (kRGB_565_SkColorType == canvasColorType) { | |
281 return Error::Nonfatal("Testing non-565 to 565 is uninteresting. "); | |
282 } | |
283 break; | |
284 default: | |
285 decodeInfo = decodeInfo.makeColorType(canvasColorType); | |
286 break; | |
287 } | 287 } |
288 | 288 |
289 // Try to scale the image if it is desired | 289 // Try to scale the image if it is desired |
290 SkISize size = codec->getScaledDimensions(fScale); | 290 SkISize size = codec->getScaledDimensions(fScale); |
291 if (size == decodeInfo.dimensions() && 1.0f != fScale) { | 291 if (size == decodeInfo.dimensions() && 1.0f != fScale) { |
292 return Error::Nonfatal("Test without scaling is uninteresting."); | 292 return Error::Nonfatal("Test without scaling is uninteresting."); |
293 } | 293 } |
294 | 294 |
295 // Visually inspecting very small output images is not necessary. We will | 295 // Visually inspecting very small output images is not necessary. We will |
296 // cover these cases in unit testing. | 296 // cover these cases in unit testing. |
297 if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) { | 297 if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) { |
298 return Error::Nonfatal("Scaling very small images is uninteresting."); | 298 return Error::Nonfatal("Scaling very small images is uninteresting."); |
299 } | 299 } |
300 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); | 300 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); |
301 | 301 |
302 // Construct a color table for the decode if necessary | 302 // Construct a color table for the decode if necessary |
303 SkAutoTUnref<SkColorTable> colorTable(nullptr); | 303 SkAutoTUnref<SkColorTable> colorTable(nullptr); |
304 SkPMColor* colorPtr = nullptr; | 304 SkPMColor* colorPtr = nullptr; |
305 int* colorCountPtr = nullptr; | 305 int* colorCountPtr = nullptr; |
306 int maxColors = 256; | 306 int maxColors = 256; |
307 if (kIndex_8_SkColorType == decodeInfo.colorType()) { | 307 if (kIndex_8_SkColorType == decodeInfo.colorType()) { |
308 SkPMColor colors[256]; | 308 SkPMColor colors[256]; |
309 colorTable.reset(new SkColorTable(colors, maxColors)); | 309 colorTable.reset(new SkColorTable(colors, maxColors)); |
310 colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); | 310 colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); |
311 colorCountPtr = &maxColors; | 311 colorCountPtr = &maxColors; |
312 } | 312 } |
313 | 313 |
314 // FIXME: Currently we cannot draw unpremultiplied sources. | |
315 if (decodeInfo.alphaType() == kUnpremul_SkAlphaType) { | |
316 decodeInfo = decodeInfo.makeAlphaType(kPremul_SkAlphaType); | |
317 } | |
318 | |
319 SkBitmap bitmap; | 314 SkBitmap bitmap; |
320 if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) { | 315 if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) { |
321 return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str( ), | 316 return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str( ), |
322 decodeInfo.width(), decodeInfo.height()); | 317 decodeInfo.width(), decodeInfo.height()); |
323 } | 318 } |
324 | 319 |
325 switch (fMode) { | 320 switch (fMode) { |
326 case kScaledCodec_Mode: | |
327 case kCodec_Mode: { | 321 case kCodec_Mode: { |
328 switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowB ytes(), nullptr, | 322 switch (codec->getPixels(decodeInfo, bitmap.getPixels(), bitmap.rowB ytes(), nullptr, |
329 colorPtr, colorCountPtr)) { | 323 colorPtr, colorCountPtr)) { |
330 case SkCodec::kSuccess: | 324 case SkCodec::kSuccess: |
331 // We consider incomplete to be valid, since we should still decode what is | 325 // We consider incomplete to be valid, since we should still decode what is |
332 // available. | 326 // available. |
333 case SkCodec::kIncompleteInput: | 327 case SkCodec::kIncompleteInput: |
334 break; | 328 break; |
335 case SkCodec::kInvalidConversion: | 329 case SkCodec::kInvalidConversion: |
336 return Error::Nonfatal("Incompatible colortype conversion"); | 330 return Error::Nonfatal("Incompatible colortype conversion"); |
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
578 left += decodeInfo.width(); | 572 left += decodeInfo.width(); |
579 } | 573 } |
580 return ""; | 574 return ""; |
581 } | 575 } |
582 } | 576 } |
583 return ""; | 577 return ""; |
584 } | 578 } |
585 | 579 |
586 SkISize CodecSrc::size() const { | 580 SkISize CodecSrc::size() const { |
587 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); | 581 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); |
588 SkAutoTDelete<SkCodec> codec(nullptr); | 582 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(encoded)); |
589 | |
590 if (kScaledCodec_Mode == fMode) { | |
591 codec.reset(SkScaledCodec::NewFromData(encoded)); | |
592 } else { | |
593 codec.reset(SkCodec::NewFromData(encoded)); | |
594 } | |
595 | |
596 if (nullptr == codec) { | 583 if (nullptr == codec) { |
597 return SkISize::Make(0, 0); | 584 return SkISize::Make(0, 0); |
598 } | 585 } |
599 return codec->getScaledDimensions(fScale); | 586 return codec->getScaledDimensions(fScale); |
600 } | 587 } |
601 | 588 |
602 Name CodecSrc::name() const { | 589 Name CodecSrc::name() const { |
603 if (1.0f == fScale) { | 590 if (1.0f == fScale) { |
604 return SkOSPath::Basename(fPath.c_str()); | 591 return SkOSPath::Basename(fPath.c_str()); |
605 } | 592 } |
606 return get_scaled_name(fPath, fScale); | 593 return get_scaled_name(fPath, fScale); |
607 } | 594 } |
608 | 595 |
609 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~*/ | 596 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~*/ |
610 | 597 |
598 AndroidCodecSrc::AndroidCodecSrc(Path path, Mode mode, CodecSrc::DstColorType ds tColorType, | |
599 int sampleSize) | |
600 : fPath(path) | |
601 , fMode(mode) | |
602 , fDstColorType(dstColorType) | |
603 , fSampleSize(sampleSize) | |
604 {} | |
605 | |
606 bool AndroidCodecSrc::veto(SinkFlags flags) const { | |
607 // No need to test decoding to non-raster or indirect backend. | |
608 // TODO: Once we implement GPU paths (e.g. JPEG YUV), we should use a deferr ed decode to | |
609 // let the GPU handle it. | |
610 return flags.type != SinkFlags::kRaster | |
611 || flags.approach != SinkFlags::kDirect; | |
612 } | |
613 | |
614 Error AndroidCodecSrc::draw(SkCanvas* canvas) const { | |
scroggo
2015/10/20 13:51:59
Any thoughts on consolidating this code with Codec
msarett
2015/10/20 14:47:27
I'm guessing you are referring to sharing code bet
| |
615 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); | |
616 if (!encoded) { | |
617 return SkStringPrintf("Couldn't read %s.", fPath.c_str()); | |
618 } | |
619 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded)); | |
620 if (nullptr == codec.get()) { | |
621 return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_s tr()); | |
622 } | |
623 | |
624 SkImageInfo decodeInfo; | |
625 if (!get_decode_info(&decodeInfo, codec->getInfo(), canvas->imageInfo().colo rType(), | |
626 fDstColorType)) { | |
627 return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); | |
628 } | |
629 | |
630 // Scale the image if it is desired. | |
631 SkISize size = codec->getSampledDimensions(fSampleSize); | |
632 | |
633 // Visually inspecting very small output images is not necessary. We will | |
634 // cover these cases in unit testing. | |
635 if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) { | |
636 return Error::Nonfatal("Scaling very small images is uninteresting."); | |
637 } | |
638 decodeInfo = decodeInfo.makeWH(size.width(), size.height()); | |
639 | |
640 // Construct a color table for the decode if necessary | |
641 SkAutoTUnref<SkColorTable> colorTable(nullptr); | |
642 SkPMColor* colorPtr = nullptr; | |
643 int* colorCountPtr = nullptr; | |
644 int maxColors = 256; | |
645 if (kIndex_8_SkColorType == decodeInfo.colorType()) { | |
646 SkPMColor colors[256]; | |
647 colorTable.reset(new SkColorTable(colors, maxColors)); | |
648 colorPtr = const_cast<SkPMColor*>(colorTable->readColors()); | |
649 colorCountPtr = &maxColors; | |
650 } | |
651 | |
652 SkBitmap bitmap; | |
653 if (!bitmap.tryAllocPixels(decodeInfo, nullptr, colorTable.get())) { | |
654 return SkStringPrintf("Image(%s) is too large (%d x %d)\n", fPath.c_str( ), | |
655 decodeInfo.width(), decodeInfo.height()); | |
656 } | |
657 | |
658 // Create options for the codec. | |
659 SkAndroidCodec::AndroidOptions options; | |
660 options.fColorPtr = colorPtr; | |
661 options.fColorCount = colorCountPtr; | |
662 options.fSampleSize = fSampleSize; | |
663 | |
664 switch (fMode) { | |
665 case kFullImage_Mode: { | |
666 switch (codec->getAndroidPixels(decodeInfo, bitmap.getPixels(), bitm ap.rowBytes(), | |
667 &options)) { | |
668 case SkCodec::kSuccess: | |
669 case SkCodec::kIncompleteInput: | |
670 break; | |
671 case SkCodec::kInvalidConversion: | |
672 return Error::Nonfatal("Cannot convert to requested color ty pe.\n"); | |
673 default: | |
674 return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str( )); | |
675 } | |
676 canvas->drawBitmap(bitmap, 0, 0); | |
677 return ""; | |
678 } | |
679 case kDivisor_Mode: { | |
680 const int width = codec->getInfo().width(); | |
681 const int height = codec->getInfo().height(); | |
682 const int divisor = 2; | |
683 if (width < divisor || height < divisor) { | |
684 return Error::Nonfatal("Divisor is larger than image dimension.\ n"); | |
685 } | |
686 | |
687 // Rounding the size of the subsets may leave some pixels uninitiali zed on the bottom | |
688 // and right edges of the bitmap. | |
689 bitmap.eraseColor(0); | |
scroggo
2015/10/20 13:51:59
How will we handle this in BRD? Or is this a resul
msarett
2015/10/20 14:47:27
The second one. As Mike noted, we potentially run
| |
690 for (uint32_t x = 0; x < divisor; x++) { | |
scroggo
2015/10/20 13:51:59
Why are x and y uint32_t when divisor is an int? (
msarett
2015/10/20 14:47:27
Thanks, my mistake.
| |
691 for (uint32_t y = 0; y < divisor; y++) { | |
692 // Calculate the subset dimensions | |
693 int subsetWidth = width / divisor; | |
694 int subsetHeight = height / divisor; | |
695 const int left = x * subsetWidth; | |
696 const int top = y * subsetHeight; | |
697 | |
698 // Increase the size of the last subset in each row or colum n, when the | |
699 // divisor does not divide evenly into the image dimensions | |
700 subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0; | |
701 subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0; | |
702 SkIRect subset = SkIRect::MakeXYWH(left, top, subsetWidth, s ubsetHeight); | |
703 if (!codec->getSupportedSubset(&subset)) { | |
704 return "Could not get supported subset to decode.\n"; | |
705 } | |
706 options.fSubset = ⊂ | |
707 void* pixels = bitmap.getAddr(subset.left() / fSampleSize, | |
708 subset.top() / fSampleSize); | |
709 SkISize scaledSubsetSize = codec->getSampledSubsetDimensions (fSampleSize, | |
710 subset); | |
711 SkImageInfo subsetDecodeInfo = decodeInfo.makeWH(scaledSubse tSize.width(), | |
712 scaledSubsetSize.height()); | |
713 | |
714 switch (codec->getAndroidPixels(subsetDecodeInfo, pixels, bi tmap.rowBytes(), | |
715 &options)) { | |
716 case SkCodec::kSuccess: | |
717 case SkCodec::kIncompleteInput: | |
718 break; | |
719 case SkCodec::kInvalidConversion: | |
720 return Error::Nonfatal("Cannot convert to requested color type.\n"); | |
721 default: | |
722 return SkStringPrintf("Couldn't getPixels %s.", fPat h.c_str()); | |
723 } | |
724 } | |
725 } | |
726 canvas->drawBitmap(bitmap, 0, 0); | |
727 return ""; | |
728 } | |
729 default: | |
730 SkASSERT(false); | |
731 return "Error: Should not be reached.\n"; | |
732 } | |
733 } | |
734 | |
735 SkISize AndroidCodecSrc::size() const { | |
736 SkAutoTUnref<SkData> encoded(SkData::NewFromFileName(fPath.c_str())); | |
737 SkAutoTDelete<SkAndroidCodec> codec(SkAndroidCodec::NewFromData(encoded)); | |
738 if (nullptr == codec) { | |
739 return SkISize::Make(0, 0); | |
740 } | |
741 return codec->getSampledDimensions(fSampleSize); | |
742 } | |
743 | |
744 Name AndroidCodecSrc::name() const { | |
745 // We will replicate the names used by CodecSrc so that images can | |
746 // be compared in Gold. | |
747 if (1 == fSampleSize) { | |
748 return SkOSPath::Basename(fPath.c_str()); | |
749 } | |
750 return get_scaled_name(fPath, get_scale_from_sample_size(fSampleSize)); | |
751 } | |
752 | |
753 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~*/ | |
754 | |
611 ImageSrc::ImageSrc(Path path, int divisor) : fPath(path), fDivisor(divisor) {} | 755 ImageSrc::ImageSrc(Path path, int divisor) : fPath(path), fDivisor(divisor) {} |
612 | 756 |
613 bool ImageSrc::veto(SinkFlags flags) const { | 757 bool ImageSrc::veto(SinkFlags flags) const { |
614 // No need to test decoding to non-raster or indirect backend. | 758 // No need to test decoding to non-raster or indirect backend. |
615 // TODO: Instead, use lazy decoding to allow the GPU to handle cases like YU V. | 759 // TODO: Instead, use lazy decoding to allow the GPU to handle cases like YU V. |
616 return flags.type != SinkFlags::kRaster | 760 return flags.type != SinkFlags::kRaster |
617 || flags.approach != SinkFlags::kDirect; | 761 || flags.approach != SinkFlags::kDirect; |
618 } | 762 } |
619 | 763 |
620 Error ImageSrc::draw(SkCanvas* canvas) const { | 764 Error ImageSrc::draw(SkCanvas* canvas) const { |
(...skipping 590 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1211 skr.visit<void>(i, drawsAsSingletonPictures); | 1355 skr.visit<void>(i, drawsAsSingletonPictures); |
1212 } | 1356 } |
1213 SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture()); | 1357 SkAutoTUnref<SkPicture> macroPic(macroRec.endRecordingAsPicture()); |
1214 | 1358 |
1215 canvas->drawPicture(macroPic); | 1359 canvas->drawPicture(macroPic); |
1216 return ""; | 1360 return ""; |
1217 }); | 1361 }); |
1218 } | 1362 } |
1219 | 1363 |
1220 } // namespace DM | 1364 } // namespace DM |
OLD | NEW |