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 { |
| 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); |
| 690 for (int x = 0; x < divisor; x++) { |
| 691 for (int 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 |