| scroggo | 478652e | 2015-03-25 07:11:02 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright 2015 Google Inc. | 
|  | 3 | * | 
|  | 4 | * Use of this source code is governed by a BSD-style license that can be | 
|  | 5 | * found in the LICENSE file. | 
|  | 6 | */ | 
|  | 7 |  | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 8 | #include "DMSrcSink.h" | 
| Brian Salomon | f865b05 | 2018-03-09 09:01:53 -0500 | [diff] [blame] | 9 | #include <cmath> | 
|  | 10 | #include <functional> | 
|  | 11 | #include "../src/jumper/SkJumper.h" | 
| msarett | 9876ac5 | 2016-06-01 14:47:18 -0700 | [diff] [blame] | 12 | #include "Resources.h" | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 13 | #include "SkAndroidCodec.h" | 
| Hal Canary | 95e3c05 | 2017-01-11 12:44:43 -0500 | [diff] [blame] | 14 | #include "SkAutoMalloc.h" | 
| Brian Osman | e5756ec | 2017-09-06 17:08:30 -0400 | [diff] [blame] | 15 | #include "SkBase64.h" | 
| scroggo | f24f224 | 2015-03-03 08:59:20 -0800 | [diff] [blame] | 16 | #include "SkCodec.h" | 
| msarett | b714fb0 | 2016-01-22 14:46:42 -0800 | [diff] [blame] | 17 | #include "SkCodecImageGenerator.h" | 
| msarett | 888dc16 | 2016-05-23 10:21:17 -0700 | [diff] [blame] | 18 | #include "SkColorSpace.h" | 
| Kevin Lubick | c456b73 | 2017-01-11 17:21:57 +0000 | [diff] [blame] | 19 | #include "SkColorSpaceXform.h" | 
| Mike Klein | 841101d | 2017-03-10 09:55:51 -0500 | [diff] [blame] | 20 | #include "SkColorSpaceXformCanvas.h" | 
| Hal Canary | 95e3c05 | 2017-01-11 12:44:43 -0500 | [diff] [blame] | 21 | #include "SkColorSpace_XYZ.h" | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 22 | #include "SkCommonFlags.h" | 
| Chris Dalton | 040238b | 2017-12-18 14:22:34 -0700 | [diff] [blame] | 23 | #include "SkCommonFlagsGpu.h" | 
| mtklein | b3e5e4d | 2015-03-25 13:13:43 -0700 | [diff] [blame] | 24 | #include "SkData.h" | 
| Hal Canary | 85c7fe8 | 2016-10-25 10:33:27 -0400 | [diff] [blame] | 25 | #include "SkDebugCanvas.h" | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 26 | #include "SkDeferredDisplayListRecorder.h" | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 27 | #include "SkDocument.h" | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 28 | #include "SkExecutor.h" | 
| mtklein | b3e5e4d | 2015-03-25 13:13:43 -0700 | [diff] [blame] | 29 | #include "SkImageGenerator.h" | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 30 | #include "SkImageGeneratorCG.h" | 
| msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 31 | #include "SkImageGeneratorWIC.h" | 
| Mike Reed | 7fcfb62 | 2018-02-09 13:26:46 -0500 | [diff] [blame] | 32 | #include "SkImageInfoPriv.h" | 
| mtklein | 8bbbb69 | 2016-08-15 12:56:00 -0700 | [diff] [blame] | 33 | #include "SkLiteDL.h" | 
|  | 34 | #include "SkLiteRecorder.h" | 
| mtklein | c8be09a | 2016-01-04 18:56:57 -0800 | [diff] [blame] | 35 | #include "SkMallocPixelRef.h" | 
| Hal Canary | 45cde31 | 2017-04-03 16:06:42 -0400 | [diff] [blame] | 36 | #include "SkMultiPictureDocumentPriv.h" | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 37 | #include "SkMultiPictureDraw.h" | 
| mtklein | ad66f9b | 2015-02-13 15:11:10 -0800 | [diff] [blame] | 38 | #include "SkNullCanvas.h" | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 39 | #include "SkOSFile.h" | 
| Ben Wagner | bf111d7 | 2016-11-07 18:05:29 -0500 | [diff] [blame] | 40 | #include "SkOSPath.h" | 
| msarett | 9e9444c | 2016-02-03 12:39:10 -0800 | [diff] [blame] | 41 | #include "SkOpts.h" | 
| Mike Reed | e7a5832 | 2017-12-20 14:09:20 -0500 | [diff] [blame] | 42 | #include "SkPictureCommon.h" | 
| mtklein | ffa901a | 2015-03-16 10:38:07 -0700 | [diff] [blame] | 43 | #include "SkPictureData.h" | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 44 | #include "SkPictureRecorder.h" | 
| reed | 54dc487 | 2016-09-13 08:09:45 -0700 | [diff] [blame] | 45 | #include "SkPipe.h" | 
| Brian Osman | e5756ec | 2017-09-06 17:08:30 -0400 | [diff] [blame] | 46 | #include "SkPngEncoder.h" | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 47 | #include "SkRandom.h" | 
| mtklein | d31c13d | 2015-05-05 12:59:56 -0700 | [diff] [blame] | 48 | #include "SkRecordDraw.h" | 
|  | 49 | #include "SkRecorder.h" | 
| fmalita | 2aafe6f | 2015-02-06 12:51:10 -0800 | [diff] [blame] | 50 | #include "SkSVGCanvas.h" | 
| scroggo | a1193e4 | 2015-01-21 12:09:53 -0800 | [diff] [blame] | 51 | #include "SkStream.h" | 
| Brian Salomon | f865b05 | 2018-03-09 09:01:53 -0500 | [diff] [blame] | 52 | #include "SkSurfaceCharacterization.h" | 
| Kevin Lubick | c456b73 | 2017-01-11 17:21:57 +0000 | [diff] [blame] | 53 | #include "SkSwizzler.h" | 
| Brian Salomon | f865b05 | 2018-03-09 09:01:53 -0500 | [diff] [blame] | 54 | #include "SkTLogic.h" | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 55 | #include "SkTaskGroup.h" | 
| Yuqian Li | b8b6253 | 2018-02-23 14:13:36 +0800 | [diff] [blame] | 56 | #include "SkThreadedBMPDevice.h" | 
| msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 57 | #if defined(SK_BUILD_FOR_WIN) | 
|  | 58 | #include "SkAutoCoInitialize.h" | 
| Hal Canary | 5e221e7 | 2017-02-06 09:51:42 -0500 | [diff] [blame] | 59 | #include "SkHRESULT.h" | 
|  | 60 | #include "SkTScopedComPtr.h" | 
|  | 61 | #include <XpsObjectModel.h> | 
| msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 62 | #endif | 
|  | 63 |  | 
| Florin Malita | 124d5af | 2017-12-31 17:02:26 -0500 | [diff] [blame] | 64 | #if !defined(SK_BUILD_FOR_GOOGLE3) | 
| Florin Malita | 54f65c4 | 2018-01-16 17:04:30 -0500 | [diff] [blame] | 65 | #include "Skottie.h" | 
| Florin Malita | 124d5af | 2017-12-31 17:02:26 -0500 | [diff] [blame] | 66 | #endif | 
|  | 67 |  | 
| fmalita | 718df0a | 2016-07-15 10:33:29 -0700 | [diff] [blame] | 68 | #if defined(SK_XML) | 
| fmalita | a48f0e3 | 2016-08-04 06:26:05 -0700 | [diff] [blame] | 69 | #include "SkSVGDOM.h" | 
| fmalita | 718df0a | 2016-07-15 10:33:29 -0700 | [diff] [blame] | 70 | #include "SkXMLWriter.h" | 
|  | 71 | #endif | 
|  | 72 |  | 
| Robert Phillips | 0c4b7b1 | 2018-03-06 08:20:37 -0500 | [diff] [blame] | 73 | #if SK_SUPPORT_GPU | 
| Brian Salomon | f865b05 | 2018-03-09 09:01:53 -0500 | [diff] [blame] | 74 | #include "GrBackendSurface.h" | 
| Robert Phillips | 0c4b7b1 | 2018-03-06 08:20:37 -0500 | [diff] [blame] | 75 | #include "GrContextPriv.h" | 
| Brian Salomon | f865b05 | 2018-03-09 09:01:53 -0500 | [diff] [blame] | 76 | #include "GrGpu.h" | 
| Robert Phillips | 0c4b7b1 | 2018-03-06 08:20:37 -0500 | [diff] [blame] | 77 | #endif | 
|  | 78 |  | 
| halcanary | 7e79818 | 2015-04-14 14:06:18 -0700 | [diff] [blame] | 79 | DEFINE_bool(multiPage, false, "For document-type backends, render the source" | 
|  | 80 | " into multiple pages"); | 
| scroggo | 3ac66e9 | 2016-02-08 15:09:48 -0800 | [diff] [blame] | 81 | DEFINE_bool(RAW_threading, true, "Allow RAW decodes to run on multiple threads?"); | 
| halcanary | 7e79818 | 2015-04-14 14:06:18 -0700 | [diff] [blame] | 82 |  | 
| bsalomon | 3724e57 | 2016-03-30 18:56:19 -0700 | [diff] [blame] | 83 | using sk_gpu_test::GrContextFactory; | 
|  | 84 |  | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 85 | namespace DM { | 
|  | 86 |  | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 87 | GMSrc::GMSrc(skiagm::GMRegistry::Factory factory) : fFactory(factory) {} | 
|  | 88 |  | 
|  | 89 | Error GMSrc::draw(SkCanvas* canvas) const { | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 90 | std::unique_ptr<skiagm::GM> gm(fFactory(nullptr)); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 91 | gm->draw(canvas); | 
|  | 92 | return ""; | 
|  | 93 | } | 
|  | 94 |  | 
|  | 95 | SkISize GMSrc::size() const { | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 96 | std::unique_ptr<skiagm::GM> gm(fFactory(nullptr)); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 97 | return gm->getISize(); | 
|  | 98 | } | 
|  | 99 |  | 
|  | 100 | Name GMSrc::name() const { | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 101 | std::unique_ptr<skiagm::GM> gm(fFactory(nullptr)); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 102 | return gm->getName(); | 
|  | 103 | } | 
|  | 104 |  | 
| bsalomon | 4ee6bd8 | 2015-05-27 13:23:23 -0700 | [diff] [blame] | 105 | void GMSrc::modifyGrContextOptions(GrContextOptions* options) const { | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 106 | std::unique_ptr<skiagm::GM> gm(fFactory(nullptr)); | 
| bsalomon | 4ee6bd8 | 2015-05-27 13:23:23 -0700 | [diff] [blame] | 107 | gm->modifyGrContextOptions(options); | 
|  | 108 | } | 
|  | 109 |  | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 110 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 111 |  | 
| msarett | d1227a7 | 2016-05-18 06:23:57 -0700 | [diff] [blame] | 112 | BRDSrc::BRDSrc(Path path, Mode mode, CodecSrc::DstColorType dstColorType, uint32_t sampleSize) | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 113 | : fPath(path) | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 114 | , fMode(mode) | 
|  | 115 | , fDstColorType(dstColorType) | 
|  | 116 | , fSampleSize(sampleSize) | 
|  | 117 | {} | 
|  | 118 |  | 
|  | 119 | bool BRDSrc::veto(SinkFlags flags) const { | 
|  | 120 | // No need to test to non-raster or indirect backends. | 
|  | 121 | return flags.type != SinkFlags::kRaster | 
|  | 122 | || flags.approach != SinkFlags::kDirect; | 
|  | 123 | } | 
|  | 124 |  | 
| msarett | d1227a7 | 2016-05-18 06:23:57 -0700 | [diff] [blame] | 125 | static SkBitmapRegionDecoder* create_brd(Path path) { | 
| bungeman | 38d909e | 2016-08-02 14:40:46 -0700 | [diff] [blame] | 126 | sk_sp<SkData> encoded(SkData::MakeFromFileName(path.c_str())); | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 127 | if (!encoded) { | 
| Ben Wagner | a93a14a | 2017-08-28 10:34:05 -0400 | [diff] [blame] | 128 | return nullptr; | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 129 | } | 
| reed | 42943c8 | 2016-09-12 12:01:44 -0700 | [diff] [blame] | 130 | return SkBitmapRegionDecoder::Create(encoded, SkBitmapRegionDecoder::kAndroidCodec_Strategy); | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 131 | } | 
|  | 132 |  | 
| Matt Sarett | 334df3a | 2016-12-15 18:17:33 -0500 | [diff] [blame] | 133 | static inline void alpha8_to_gray8(SkBitmap* bitmap) { | 
|  | 134 | // Android requires kGray8 bitmaps to be tagged as kAlpha8.  Here we convert | 
|  | 135 | // them back to kGray8 so our test framework can draw them correctly. | 
|  | 136 | if (kAlpha_8_SkColorType == bitmap->info().colorType()) { | 
|  | 137 | SkImageInfo newInfo = bitmap->info().makeColorType(kGray_8_SkColorType) | 
|  | 138 | .makeAlphaType(kOpaque_SkAlphaType); | 
|  | 139 | *const_cast<SkImageInfo*>(&bitmap->info()) = newInfo; | 
|  | 140 | } | 
|  | 141 | } | 
|  | 142 |  | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 143 | Error BRDSrc::draw(SkCanvas* canvas) const { | 
| Matt Sarett | a40d9c8 | 2017-05-19 15:21:05 -0400 | [diff] [blame] | 144 | if (canvas->imageInfo().colorSpace() && | 
|  | 145 | kRGBA_F16_SkColorType != canvas->imageInfo().colorType()) { | 
|  | 146 | // SkAndroidCodec uses legacy premultiplication and blending.  Therefore, we only | 
|  | 147 | // run these tests on legacy canvases. | 
|  | 148 | // We allow an exception for F16, since Android uses F16. | 
|  | 149 | return Error::Nonfatal("Skip testing to color correct canvas."); | 
|  | 150 | } | 
|  | 151 |  | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 152 | SkColorType colorType = canvas->imageInfo().colorType(); | 
|  | 153 | if (kRGB_565_SkColorType == colorType && | 
|  | 154 | CodecSrc::kGetFromCanvas_DstColorType != fDstColorType) { | 
|  | 155 | return Error::Nonfatal("Testing non-565 to 565 is uninteresting."); | 
|  | 156 | } | 
|  | 157 | switch (fDstColorType) { | 
|  | 158 | case CodecSrc::kGetFromCanvas_DstColorType: | 
|  | 159 | break; | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 160 | case CodecSrc::kGrayscale_Always_DstColorType: | 
|  | 161 | colorType = kGray_8_SkColorType; | 
|  | 162 | break; | 
| msarett | 34e0ec4 | 2016-04-22 16:27:24 -0700 | [diff] [blame] | 163 | default: | 
|  | 164 | SkASSERT(false); | 
|  | 165 | break; | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 166 | } | 
|  | 167 |  | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 168 | std::unique_ptr<SkBitmapRegionDecoder> brd(create_brd(fPath)); | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 169 | if (nullptr == brd.get()) { | 
|  | 170 | return Error::Nonfatal(SkStringPrintf("Could not create brd for %s.", fPath.c_str())); | 
|  | 171 | } | 
|  | 172 |  | 
| Leon Scroggins III | 0118e97 | 2018-03-13 11:14:33 -0400 | [diff] [blame] | 173 | auto recommendedCT = brd->computeOutputColorType(colorType); | 
|  | 174 | if (kRGB_565_SkColorType == colorType && recommendedCT != colorType) { | 
|  | 175 | return Error::Nonfatal("Skip decoding non-opaque to 565."); | 
| Leon Scroggins III | 1dc8ecb | 2017-08-17 13:42:48 -0400 | [diff] [blame] | 176 | } | 
| Leon Scroggins III | 0118e97 | 2018-03-13 11:14:33 -0400 | [diff] [blame] | 177 | colorType = recommendedCT; | 
|  | 178 |  | 
|  | 179 | auto colorSpace = brd->computeOutputColorSpace(colorType, nullptr); | 
| Leon Scroggins III | 1dc8ecb | 2017-08-17 13:42:48 -0400 | [diff] [blame] | 180 |  | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 181 | const uint32_t width = brd->width(); | 
|  | 182 | const uint32_t height = brd->height(); | 
|  | 183 | // Visually inspecting very small output images is not necessary. | 
|  | 184 | if ((width / fSampleSize <= 10 || height / fSampleSize <= 10) && 1 != fSampleSize) { | 
|  | 185 | return Error::Nonfatal("Scaling very small images is uninteresting."); | 
|  | 186 | } | 
|  | 187 | switch (fMode) { | 
|  | 188 | case kFullImage_Mode: { | 
| msarett | 35e5d1b | 2015-10-27 12:50:25 -0700 | [diff] [blame] | 189 | SkBitmap bitmap; | 
|  | 190 | if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(0, 0, width, height), | 
| Leon Scroggins III | 0118e97 | 2018-03-13 11:14:33 -0400 | [diff] [blame] | 191 | fSampleSize, colorType, false, colorSpace)) { | 
| mtklein | 9b43915 | 2015-12-09 13:02:26 -0800 | [diff] [blame] | 192 | return "Cannot decode (full) region."; | 
| msarett | 35e5d1b | 2015-10-27 12:50:25 -0700 | [diff] [blame] | 193 | } | 
| Matt Sarett | 334df3a | 2016-12-15 18:17:33 -0500 | [diff] [blame] | 194 | alpha8_to_gray8(&bitmap); | 
| Matt Sarett | 8db74f1 | 2017-06-14 13:02:05 +0000 | [diff] [blame] | 195 |  | 
| msarett | 35e5d1b | 2015-10-27 12:50:25 -0700 | [diff] [blame] | 196 | canvas->drawBitmap(bitmap, 0, 0); | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 197 | return ""; | 
|  | 198 | } | 
|  | 199 | case kDivisor_Mode: { | 
|  | 200 | const uint32_t divisor = 2; | 
|  | 201 | if (width < divisor || height < divisor) { | 
| mtklein | 9b43915 | 2015-12-09 13:02:26 -0800 | [diff] [blame] | 202 | return Error::Nonfatal("Divisor is larger than image dimension."); | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 203 | } | 
|  | 204 |  | 
|  | 205 | // Use a border to test subsets that extend outside the image. | 
|  | 206 | // We will not allow the border to be larger than the image dimensions.  Allowing | 
|  | 207 | // these large borders causes off by one errors that indicate a problem with the | 
|  | 208 | // test suite, not a problem with the implementation. | 
|  | 209 | const uint32_t maxBorder = SkTMin(width, height) / (fSampleSize * divisor); | 
|  | 210 | const uint32_t scaledBorder = SkTMin(5u, maxBorder); | 
|  | 211 | const uint32_t unscaledBorder = scaledBorder * fSampleSize; | 
|  | 212 |  | 
|  | 213 | // We may need to clear the canvas to avoid uninitialized memory. | 
|  | 214 | // Assume we are scaling a 780x780 image with sampleSize = 8. | 
|  | 215 | // The output image should be 97x97. | 
|  | 216 | // Each subset will be 390x390. | 
|  | 217 | // Each scaled subset be 48x48. | 
|  | 218 | // Four scaled subsets will only fill a 96x96 image. | 
|  | 219 | // The bottom row and last column will not be touched. | 
|  | 220 | // This is an unfortunate result of our rounding rules when scaling. | 
|  | 221 | // Maybe we need to consider testing scaled subsets without trying to | 
|  | 222 | // combine them to match the full scaled image?  Or maybe this is the | 
|  | 223 | // best we can do? | 
|  | 224 | canvas->clear(0); | 
|  | 225 |  | 
|  | 226 | for (uint32_t x = 0; x < divisor; x++) { | 
|  | 227 | for (uint32_t y = 0; y < divisor; y++) { | 
|  | 228 | // Calculate the subset dimensions | 
|  | 229 | uint32_t subsetWidth = width / divisor; | 
|  | 230 | uint32_t subsetHeight = height / divisor; | 
|  | 231 | const int left = x * subsetWidth; | 
|  | 232 | const int top = y * subsetHeight; | 
|  | 233 |  | 
|  | 234 | // Increase the size of the last subset in each row or column, when the | 
|  | 235 | // divisor does not divide evenly into the image dimensions | 
|  | 236 | subsetWidth += (x + 1 == divisor) ? (width % divisor) : 0; | 
|  | 237 | subsetHeight += (y + 1 == divisor) ? (height % divisor) : 0; | 
|  | 238 |  | 
|  | 239 | // Increase the size of the subset in order to have a border on each side | 
|  | 240 | const int decodeLeft = left - unscaledBorder; | 
|  | 241 | const int decodeTop = top - unscaledBorder; | 
|  | 242 | const uint32_t decodeWidth = subsetWidth + unscaledBorder * 2; | 
|  | 243 | const uint32_t decodeHeight = subsetHeight + unscaledBorder * 2; | 
| msarett | 35e5d1b | 2015-10-27 12:50:25 -0700 | [diff] [blame] | 244 | SkBitmap bitmap; | 
|  | 245 | if (!brd->decodeRegion(&bitmap, nullptr, SkIRect::MakeXYWH(decodeLeft, | 
| Matt Sarett | 68feef4 | 2017-04-11 09:51:32 -0400 | [diff] [blame] | 246 | decodeTop, decodeWidth, decodeHeight), fSampleSize, colorType, false, | 
| Leon Scroggins III | 0118e97 | 2018-03-13 11:14:33 -0400 | [diff] [blame] | 247 | colorSpace)) { | 
| mtklein | 9b43915 | 2015-12-09 13:02:26 -0800 | [diff] [blame] | 248 | return "Cannot decode region."; | 
| msarett | 35e5d1b | 2015-10-27 12:50:25 -0700 | [diff] [blame] | 249 | } | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 250 |  | 
| Matt Sarett | 334df3a | 2016-12-15 18:17:33 -0500 | [diff] [blame] | 251 | alpha8_to_gray8(&bitmap); | 
| msarett | 35e5d1b | 2015-10-27 12:50:25 -0700 | [diff] [blame] | 252 | canvas->drawBitmapRect(bitmap, | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 253 | SkRect::MakeXYWH((SkScalar) scaledBorder, (SkScalar) scaledBorder, | 
|  | 254 | (SkScalar) (subsetWidth / fSampleSize), | 
|  | 255 | (SkScalar) (subsetHeight / fSampleSize)), | 
|  | 256 | SkRect::MakeXYWH((SkScalar) (left / fSampleSize), | 
|  | 257 | (SkScalar) (top / fSampleSize), | 
|  | 258 | (SkScalar) (subsetWidth / fSampleSize), | 
|  | 259 | (SkScalar) (subsetHeight / fSampleSize)), | 
|  | 260 | nullptr); | 
|  | 261 | } | 
|  | 262 | } | 
|  | 263 | return ""; | 
|  | 264 | } | 
|  | 265 | default: | 
|  | 266 | SkASSERT(false); | 
| mtklein | 9b43915 | 2015-12-09 13:02:26 -0800 | [diff] [blame] | 267 | return "Error: Should not be reached."; | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 268 | } | 
|  | 269 | } | 
|  | 270 |  | 
|  | 271 | SkISize BRDSrc::size() const { | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 272 | std::unique_ptr<SkBitmapRegionDecoder> brd(create_brd(fPath)); | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 273 | if (brd) { | 
| Hal Canary | fafe135 | 2017-04-11 12:12:02 -0400 | [diff] [blame] | 274 | return {SkTMax(1, brd->width() / (int)fSampleSize), | 
|  | 275 | SkTMax(1, brd->height() / (int)fSampleSize)}; | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 276 | } | 
| Hal Canary | fafe135 | 2017-04-11 12:12:02 -0400 | [diff] [blame] | 277 | return {0, 0}; | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 278 | } | 
|  | 279 |  | 
|  | 280 | static SkString get_scaled_name(const Path& path, float scale) { | 
|  | 281 | return SkStringPrintf("%s_%.3f", SkOSPath::Basename(path.c_str()).c_str(), scale); | 
|  | 282 | } | 
|  | 283 |  | 
|  | 284 | Name BRDSrc::name() const { | 
|  | 285 | // We will replicate the names used by CodecSrc so that images can | 
|  | 286 | // be compared in Gold. | 
|  | 287 | if (1 == fSampleSize) { | 
|  | 288 | return SkOSPath::Basename(fPath.c_str()); | 
|  | 289 | } | 
| msarett | 4b0778e | 2015-11-13 09:59:11 -0800 | [diff] [blame] | 290 | return get_scaled_name(fPath, 1.0f / (float) fSampleSize); | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 291 | } | 
|  | 292 |  | 
|  | 293 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 294 |  | 
| scroggo | 3ac66e9 | 2016-02-08 15:09:48 -0800 | [diff] [blame] | 295 | static bool serial_from_path_name(const SkString& path) { | 
|  | 296 | if (!FLAGS_RAW_threading) { | 
|  | 297 | static const char* const exts[] = { | 
|  | 298 | "arw", "cr2", "dng", "nef", "nrw", "orf", "raf", "rw2", "pef", "srw", | 
|  | 299 | "ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "RAF", "RW2", "PEF", "SRW", | 
|  | 300 | }; | 
|  | 301 | const char* actualExt = strrchr(path.c_str(), '.'); | 
|  | 302 | if (actualExt) { | 
|  | 303 | actualExt++; | 
|  | 304 | for (auto* ext : exts) { | 
|  | 305 | if (0 == strcmp(ext, actualExt)) { | 
|  | 306 | return true; | 
|  | 307 | } | 
|  | 308 | } | 
|  | 309 | } | 
|  | 310 | } | 
|  | 311 | return false; | 
|  | 312 | } | 
|  | 313 |  | 
| scroggo | c5560be | 2016-02-03 09:42:42 -0800 | [diff] [blame] | 314 | CodecSrc::CodecSrc(Path path, Mode mode, DstColorType dstColorType, SkAlphaType dstAlphaType, | 
|  | 315 | float scale) | 
| msarett | 438b2ad | 2015-04-09 12:43:10 -0700 | [diff] [blame] | 316 | : fPath(path) | 
|  | 317 | , fMode(mode) | 
|  | 318 | , fDstColorType(dstColorType) | 
| scroggo | c5560be | 2016-02-03 09:42:42 -0800 | [diff] [blame] | 319 | , fDstAlphaType(dstAlphaType) | 
| msarett | 0a24297 | 2015-06-11 14:27:27 -0700 | [diff] [blame] | 320 | , fScale(scale) | 
| scroggo | 3ac66e9 | 2016-02-08 15:09:48 -0800 | [diff] [blame] | 321 | , fRunSerially(serial_from_path_name(path)) | 
| msarett | 438b2ad | 2015-04-09 12:43:10 -0700 | [diff] [blame] | 322 | {} | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 323 |  | 
| mtklein | 99cab4e | 2015-07-31 06:43:04 -0700 | [diff] [blame] | 324 | bool CodecSrc::veto(SinkFlags flags) const { | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 325 | // Test to direct raster backends (8888 and 565). | 
| msarett | b714fb0 | 2016-01-22 14:46:42 -0800 | [diff] [blame] | 326 | return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect; | 
| mtklein | e0effd6 | 2015-07-29 06:37:28 -0700 | [diff] [blame] | 327 | } | 
| scroggo | 9b77ddd | 2015-03-19 06:03:39 -0700 | [diff] [blame] | 328 |  | 
| msarett | 34e0ec4 | 2016-04-22 16:27:24 -0700 | [diff] [blame] | 329 | // Allows us to test decodes to non-native 8888. | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 330 | static void swap_rb_if_necessary(SkBitmap& bitmap, CodecSrc::DstColorType dstColorType) { | 
| msarett | 34e0ec4 | 2016-04-22 16:27:24 -0700 | [diff] [blame] | 331 | if (CodecSrc::kNonNative8888_Always_DstColorType != dstColorType) { | 
|  | 332 | return; | 
|  | 333 | } | 
|  | 334 |  | 
|  | 335 | for (int y = 0; y < bitmap.height(); y++) { | 
|  | 336 | uint32_t* row = (uint32_t*) bitmap.getAddr(0, y); | 
|  | 337 | SkOpts::RGBA_to_BGRA(row, row, bitmap.width()); | 
|  | 338 | } | 
|  | 339 | } | 
|  | 340 |  | 
| msarett | 9e9444c | 2016-02-03 12:39:10 -0800 | [diff] [blame] | 341 | // FIXME: Currently we cannot draw unpremultiplied sources. skbug.com/3338 and skbug.com/3339. | 
|  | 342 | // This allows us to still test unpremultiplied decodes. | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 343 | static void premultiply_if_necessary(SkBitmap& bitmap) { | 
| msarett | 9e9444c | 2016-02-03 12:39:10 -0800 | [diff] [blame] | 344 | if (kUnpremul_SkAlphaType != bitmap.alphaType()) { | 
|  | 345 | return; | 
|  | 346 | } | 
|  | 347 |  | 
|  | 348 | switch (bitmap.colorType()) { | 
| Mike Klein | 45c16fa | 2017-07-18 18:15:13 -0400 | [diff] [blame] | 349 | case kRGBA_F16_SkColorType: { | 
|  | 350 | SkJumper_MemoryCtx ctx = { bitmap.getAddr(0,0), bitmap.rowBytesAsPixels() }; | 
|  | 351 | SkRasterPipeline_<256> p; | 
|  | 352 | p.append(SkRasterPipeline::load_f16, &ctx); | 
|  | 353 | p.append(SkRasterPipeline::premul); | 
|  | 354 | p.append(SkRasterPipeline::store_f16, &ctx); | 
|  | 355 | p.run(0,0, bitmap.width(), bitmap.height()); | 
|  | 356 | } | 
| Leon Scroggins III | eceee04 | 2017-05-23 16:58:09 -0400 | [diff] [blame] | 357 | break; | 
| msarett | 9e9444c | 2016-02-03 12:39:10 -0800 | [diff] [blame] | 358 | case kN32_SkColorType: | 
|  | 359 | for (int y = 0; y < bitmap.height(); y++) { | 
|  | 360 | uint32_t* row = (uint32_t*) bitmap.getAddr(0, y); | 
|  | 361 | SkOpts::RGBA_to_rgbA(row, row, bitmap.width()); | 
|  | 362 | } | 
|  | 363 | break; | 
| msarett | 9e9444c | 2016-02-03 12:39:10 -0800 | [diff] [blame] | 364 | default: | 
|  | 365 | // No need to premultiply kGray or k565 outputs. | 
|  | 366 | break; | 
|  | 367 | } | 
| msarett | e1daa48 | 2016-02-03 15:31:18 -0800 | [diff] [blame] | 368 |  | 
|  | 369 | // In the kIndex_8 case, the canvas won't even try to draw unless we mark the | 
|  | 370 | // bitmap as kPremul. | 
|  | 371 | bitmap.setAlphaType(kPremul_SkAlphaType); | 
| msarett | 9e9444c | 2016-02-03 12:39:10 -0800 | [diff] [blame] | 372 | } | 
|  | 373 |  | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 374 | static bool get_decode_info(SkImageInfo* decodeInfo, SkColorType canvasColorType, | 
| scroggo | ba58489 | 2016-05-20 13:56:13 -0700 | [diff] [blame] | 375 | CodecSrc::DstColorType dstColorType, SkAlphaType dstAlphaType) { | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 376 | switch (dstColorType) { | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 377 | case CodecSrc::kGrayscale_Always_DstColorType: | 
| scroggo | 1a36192 | 2016-05-20 14:27:16 -0700 | [diff] [blame] | 378 | if (kRGB_565_SkColorType == canvasColorType) { | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 379 | return false; | 
|  | 380 | } | 
| scroggo | c5560be | 2016-02-03 09:42:42 -0800 | [diff] [blame] | 381 | *decodeInfo = decodeInfo->makeColorType(kGray_8_SkColorType); | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 382 | break; | 
| msarett | 34e0ec4 | 2016-04-22 16:27:24 -0700 | [diff] [blame] | 383 | case CodecSrc::kNonNative8888_Always_DstColorType: | 
| Leon Scroggins III | 557fbbe | 2017-05-23 09:37:21 -0400 | [diff] [blame] | 384 | if (kRGB_565_SkColorType == canvasColorType | 
|  | 385 | || kRGBA_F16_SkColorType == canvasColorType) { | 
| msarett | 34e0ec4 | 2016-04-22 16:27:24 -0700 | [diff] [blame] | 386 | return false; | 
|  | 387 | } | 
|  | 388 | #ifdef SK_PMCOLOR_IS_RGBA | 
|  | 389 | *decodeInfo = decodeInfo->makeColorType(kBGRA_8888_SkColorType); | 
|  | 390 | #else | 
|  | 391 | *decodeInfo = decodeInfo->makeColorType(kRGBA_8888_SkColorType); | 
|  | 392 | #endif | 
|  | 393 | break; | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 394 | default: | 
| msarett | 55f7bdd | 2016-02-16 13:24:54 -0800 | [diff] [blame] | 395 | if (kRGB_565_SkColorType == canvasColorType && | 
|  | 396 | kOpaque_SkAlphaType != decodeInfo->alphaType()) { | 
|  | 397 | return false; | 
|  | 398 | } | 
| Matt Sarett | 09a1c08 | 2017-02-01 15:34:22 -0800 | [diff] [blame] | 399 |  | 
|  | 400 | if (kRGBA_F16_SkColorType == canvasColorType) { | 
| Brian Osman | 36703d9 | 2017-12-12 14:09:31 -0500 | [diff] [blame] | 401 | sk_sp<SkColorSpace> linearSpace = decodeInfo->colorSpace()->makeLinearGamma(); | 
| Matt Sarett | 09a1c08 | 2017-02-01 15:34:22 -0800 | [diff] [blame] | 402 | *decodeInfo = decodeInfo->makeColorSpace(std::move(linearSpace)); | 
|  | 403 | } | 
|  | 404 |  | 
| scroggo | c5560be | 2016-02-03 09:42:42 -0800 | [diff] [blame] | 405 | *decodeInfo = decodeInfo->makeColorType(canvasColorType); | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 406 | break; | 
|  | 407 | } | 
|  | 408 |  | 
| scroggo | ba58489 | 2016-05-20 13:56:13 -0700 | [diff] [blame] | 409 | *decodeInfo = decodeInfo->makeAlphaType(dstAlphaType); | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 410 | return true; | 
|  | 411 | } | 
|  | 412 |  | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 413 | static void draw_to_canvas(SkCanvas* canvas, const SkImageInfo& info, void* pixels, size_t rowBytes, | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 414 | CodecSrc::DstColorType dstColorType, | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 415 | SkScalar left = 0, SkScalar top = 0) { | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 416 | SkBitmap bitmap; | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 417 | bitmap.installPixels(info, pixels, rowBytes); | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 418 | premultiply_if_necessary(bitmap); | 
|  | 419 | swap_rb_if_necessary(bitmap, dstColorType); | 
|  | 420 | canvas->drawBitmap(bitmap, left, top); | 
|  | 421 | } | 
|  | 422 |  | 
| Matt Sarett | f485cf9 | 2017-05-26 08:58:03 -0400 | [diff] [blame] | 423 | // For codec srcs, we want the "draw" step to be a memcpy.  Any interesting color space or | 
|  | 424 | // color format conversions should be performed by the codec.  Sometimes the output of the | 
|  | 425 | // decode will be in an interesting color space.  On our srgb and f16 backends, we need to | 
|  | 426 | // "pretend" that the color space is standard sRGB to avoid triggering color conversion | 
|  | 427 | // at draw time. | 
|  | 428 | static void set_bitmap_color_space(SkImageInfo* info) { | 
|  | 429 | if (kRGBA_F16_SkColorType == info->colorType()) { | 
|  | 430 | *info = info->makeColorSpace(SkColorSpace::MakeSRGBLinear()); | 
|  | 431 | } else { | 
|  | 432 | *info = info->makeColorSpace(SkColorSpace::MakeSRGB()); | 
|  | 433 | } | 
|  | 434 | } | 
|  | 435 |  | 
| mtklein | e0effd6 | 2015-07-29 06:37:28 -0700 | [diff] [blame] | 436 | Error CodecSrc::draw(SkCanvas* canvas) const { | 
| bungeman | 38d909e | 2016-08-02 14:40:46 -0700 | [diff] [blame] | 437 | sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 438 | if (!encoded) { | 
|  | 439 | return SkStringPrintf("Couldn't read %s.", fPath.c_str()); | 
|  | 440 | } | 
| msarett | b714fb0 | 2016-01-22 14:46:42 -0800 | [diff] [blame] | 441 |  | 
| Mike Reed | ede7bac | 2017-07-23 15:30:02 -0400 | [diff] [blame] | 442 | std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded)); | 
| msarett | 9e707a0 | 2015-09-01 14:57:57 -0700 | [diff] [blame] | 443 | if (nullptr == codec.get()) { | 
|  | 444 | return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); | 
| scroggo | 9b77ddd | 2015-03-19 06:03:39 -0700 | [diff] [blame] | 445 | } | 
|  | 446 |  | 
| scroggo | ba58489 | 2016-05-20 13:56:13 -0700 | [diff] [blame] | 447 | SkImageInfo decodeInfo = codec->getInfo(); | 
|  | 448 | if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType, | 
|  | 449 | fDstAlphaType)) { | 
| Matt Sarett | ea518f0 | 2017-02-03 11:58:59 -0800 | [diff] [blame] | 450 | return Error::Nonfatal("Skipping uninteresting test."); | 
| msarett | 438b2ad | 2015-04-09 12:43:10 -0700 | [diff] [blame] | 451 | } | 
|  | 452 |  | 
| msarett | 0a24297 | 2015-06-11 14:27:27 -0700 | [diff] [blame] | 453 | // Try to scale the image if it is desired | 
|  | 454 | SkISize size = codec->getScaledDimensions(fScale); | 
|  | 455 | if (size == decodeInfo.dimensions() && 1.0f != fScale) { | 
|  | 456 | return Error::Nonfatal("Test without scaling is uninteresting."); | 
|  | 457 | } | 
| msarett | b32758a | 2015-08-18 13:22:46 -0700 | [diff] [blame] | 458 |  | 
|  | 459 | // Visually inspecting very small output images is not necessary.  We will | 
|  | 460 | // cover these cases in unit testing. | 
|  | 461 | if ((size.width() <= 10 || size.height() <= 10) && 1.0f != fScale) { | 
|  | 462 | return Error::Nonfatal("Scaling very small images is uninteresting."); | 
|  | 463 | } | 
| msarett | 0a24297 | 2015-06-11 14:27:27 -0700 | [diff] [blame] | 464 | decodeInfo = decodeInfo.makeWH(size.width(), size.height()); | 
|  | 465 |  | 
| Mike Reed | 7fcfb62 | 2018-02-09 13:26:46 -0500 | [diff] [blame] | 466 | const int bpp = decodeInfo.bytesPerPixel(); | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 467 | const size_t rowBytes = size.width() * bpp; | 
| Mike Reed | f0ffb89 | 2017-10-03 14:47:21 -0400 | [diff] [blame] | 468 | const size_t safeSize = decodeInfo.computeByteSize(rowBytes); | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 469 | SkAutoMalloc pixels(safeSize); | 
| msarett | 438b2ad | 2015-04-09 12:43:10 -0700 | [diff] [blame] | 470 |  | 
| msarett | bb25b53 | 2016-01-13 09:31:39 -0800 | [diff] [blame] | 471 | SkCodec::Options options; | 
| Matt Sarett | a40d9c8 | 2017-05-19 15:21:05 -0400 | [diff] [blame] | 472 | options.fPremulBehavior = canvas->imageInfo().colorSpace() ? | 
|  | 473 | SkTransferFunctionBehavior::kRespect : SkTransferFunctionBehavior::kIgnore; | 
| msarett | bb25b53 | 2016-01-13 09:31:39 -0800 | [diff] [blame] | 474 | if (kCodecZeroInit_Mode == fMode) { | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 475 | memset(pixels.get(), 0, size.height() * rowBytes); | 
| msarett | bb25b53 | 2016-01-13 09:31:39 -0800 | [diff] [blame] | 476 | options.fZeroInitialized = SkCodec::kYes_ZeroInitialized; | 
|  | 477 | } | 
| msarett | 34e0ec4 | 2016-04-22 16:27:24 -0700 | [diff] [blame] | 478 |  | 
|  | 479 | SkImageInfo bitmapInfo = decodeInfo; | 
| Matt Sarett | f485cf9 | 2017-05-26 08:58:03 -0400 | [diff] [blame] | 480 | set_bitmap_color_space(&bitmapInfo); | 
| msarett | 34e0ec4 | 2016-04-22 16:27:24 -0700 | [diff] [blame] | 481 | if (kRGBA_8888_SkColorType == decodeInfo.colorType() || | 
|  | 482 | kBGRA_8888_SkColorType == decodeInfo.colorType()) { | 
|  | 483 | bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); | 
|  | 484 | } | 
| scroggo | 9b77ddd | 2015-03-19 06:03:39 -0700 | [diff] [blame] | 485 |  | 
| scroggo | 9c59ebc | 2015-03-25 13:48:49 -0700 | [diff] [blame] | 486 | switch (fMode) { | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 487 | case kAnimated_Mode: { | 
|  | 488 | std::vector<SkCodec::FrameInfo> frameInfos = codec->getFrameInfo(); | 
|  | 489 | if (frameInfos.size() <= 1) { | 
|  | 490 | return SkStringPrintf("%s is not an animated image.", fPath.c_str()); | 
|  | 491 | } | 
|  | 492 |  | 
| scroggo | 90e971a | 2016-10-25 06:11:01 -0700 | [diff] [blame] | 493 | // As in CodecSrc::size(), compute a roughly square grid to draw the frames | 
|  | 494 | // into. "factor" is the number of frames to draw on one row. There will be | 
|  | 495 | // up to "factor" rows as well. | 
|  | 496 | const float root = sqrt((float) frameInfos.size()); | 
|  | 497 | const int factor = sk_float_ceil2int(root); | 
|  | 498 |  | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 499 | // Used to cache a frame that future frames will depend on. | 
|  | 500 | SkAutoMalloc priorFramePixels; | 
| Leon Scroggins III | 249b8e3 | 2017-04-17 12:46:33 -0400 | [diff] [blame] | 501 | int cachedFrame = SkCodec::kNone; | 
|  | 502 | for (int i = 0; static_cast<size_t>(i) < frameInfos.size(); i++) { | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 503 | options.fFrameIndex = i; | 
|  | 504 | // Check for a prior frame | 
| Leon Scroggins III | 249b8e3 | 2017-04-17 12:46:33 -0400 | [diff] [blame] | 505 | const int reqFrame = frameInfos[i].fRequiredFrame; | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 506 | if (reqFrame != SkCodec::kNone && reqFrame == cachedFrame | 
|  | 507 | && priorFramePixels.get()) { | 
|  | 508 | // Copy into pixels | 
|  | 509 | memcpy(pixels.get(), priorFramePixels.get(), safeSize); | 
| Leon Scroggins III | 33deb7e | 2017-06-07 12:31:51 -0400 | [diff] [blame] | 510 | options.fPriorFrame = reqFrame; | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 511 | } else { | 
| Leon Scroggins III | 33deb7e | 2017-06-07 12:31:51 -0400 | [diff] [blame] | 512 | options.fPriorFrame = SkCodec::kNone; | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 513 | } | 
| Leon Scroggins III | 3fc97d7 | 2016-12-09 16:39:33 -0500 | [diff] [blame] | 514 | SkCodec::Result result = codec->getPixels(decodeInfo, pixels.get(), | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 515 | rowBytes, &options); | 
| Leon Scroggins III | 3fc97d7 | 2016-12-09 16:39:33 -0500 | [diff] [blame] | 516 | if (SkCodec::kInvalidInput == result && i > 0) { | 
|  | 517 | // Some of our test images have truncated later frames. Treat that | 
|  | 518 | // the same as incomplete. | 
|  | 519 | result = SkCodec::kIncompleteInput; | 
|  | 520 | } | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 521 | switch (result) { | 
|  | 522 | case SkCodec::kSuccess: | 
| Leon Scroggins III | 674a184 | 2017-07-06 12:26:09 -0400 | [diff] [blame] | 523 | case SkCodec::kErrorInInput: | 
| scroggo | 90e971a | 2016-10-25 06:11:01 -0700 | [diff] [blame] | 524 | case SkCodec::kIncompleteInput: { | 
| Leon Scroggins III | 557fbbe | 2017-05-23 09:37:21 -0400 | [diff] [blame] | 525 | // If the next frame depends on this one, store it in priorFrame. | 
|  | 526 | // It is possible that we may discard a frame that future frames depend on, | 
|  | 527 | // but the codec will simply redecode the discarded frame. | 
|  | 528 | // Do this before calling draw_to_canvas, which premultiplies in place. If | 
|  | 529 | // we're decoding to unpremul, we want to pass the unmodified frame to the | 
|  | 530 | // codec for decoding the next frame. | 
|  | 531 | if (static_cast<size_t>(i+1) < frameInfos.size() | 
|  | 532 | && frameInfos[i+1].fRequiredFrame == i) { | 
|  | 533 | memcpy(priorFramePixels.reset(safeSize), pixels.get(), safeSize); | 
|  | 534 | cachedFrame = i; | 
|  | 535 | } | 
|  | 536 |  | 
| scroggo | 90e971a | 2016-10-25 06:11:01 -0700 | [diff] [blame] | 537 | SkAutoCanvasRestore acr(canvas, true); | 
|  | 538 | const int xTranslate = (i % factor) * decodeInfo.width(); | 
|  | 539 | const int yTranslate = (i / factor) * decodeInfo.height(); | 
|  | 540 | canvas->translate(SkIntToScalar(xTranslate), SkIntToScalar(yTranslate)); | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 541 | draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType); | 
| Leon Scroggins III | 674a184 | 2017-07-06 12:26:09 -0400 | [diff] [blame] | 542 | if (result != SkCodec::kSuccess) { | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 543 | return ""; | 
|  | 544 | } | 
|  | 545 | break; | 
| scroggo | 90e971a | 2016-10-25 06:11:01 -0700 | [diff] [blame] | 546 | } | 
| scroggo | 53f63b6 | 2016-10-27 08:29:13 -0700 | [diff] [blame] | 547 | case SkCodec::kInvalidConversion: | 
| Mike Reed | 304a07c | 2017-07-12 15:10:28 -0400 | [diff] [blame] | 548 | if (i > 0 && (decodeInfo.colorType() == kRGB_565_SkColorType)) { | 
| scroggo | 53f63b6 | 2016-10-27 08:29:13 -0700 | [diff] [blame] | 549 | return Error::Nonfatal(SkStringPrintf( | 
| Mike Reed | 304a07c | 2017-07-12 15:10:28 -0400 | [diff] [blame] | 550 | "Cannot decode frame %i to 565 (%s).", i, fPath.c_str())); | 
| scroggo | 53f63b6 | 2016-10-27 08:29:13 -0700 | [diff] [blame] | 551 | } | 
|  | 552 | // Fall through. | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 553 | default: | 
|  | 554 | return SkStringPrintf("Couldn't getPixels for frame %i in %s.", | 
|  | 555 | i, fPath.c_str()); | 
|  | 556 | } | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 557 | } | 
|  | 558 | break; | 
|  | 559 | } | 
| msarett | bb25b53 | 2016-01-13 09:31:39 -0800 | [diff] [blame] | 560 | case kCodecZeroInit_Mode: | 
| msarett | 9e707a0 | 2015-09-01 14:57:57 -0700 | [diff] [blame] | 561 | case kCodec_Mode: { | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 562 | switch (codec->getPixels(decodeInfo, pixels.get(), rowBytes, &options)) { | 
| scroggo | eb602a5 | 2015-07-09 08:16:03 -0700 | [diff] [blame] | 563 | case SkCodec::kSuccess: | 
| Leon Scroggins III | 674a184 | 2017-07-06 12:26:09 -0400 | [diff] [blame] | 564 | // We consider these to be valid, since we should still decode what is | 
| scroggo | 9c59ebc | 2015-03-25 13:48:49 -0700 | [diff] [blame] | 565 | // available. | 
| Leon Scroggins III | 674a184 | 2017-07-06 12:26:09 -0400 | [diff] [blame] | 566 | case SkCodec::kErrorInInput: | 
| scroggo | eb602a5 | 2015-07-09 08:16:03 -0700 | [diff] [blame] | 567 | case SkCodec::kIncompleteInput: | 
| scroggo | 9c59ebc | 2015-03-25 13:48:49 -0700 | [diff] [blame] | 568 | break; | 
| scroggo | 9c59ebc | 2015-03-25 13:48:49 -0700 | [diff] [blame] | 569 | default: | 
|  | 570 | // Everything else is considered a failure. | 
|  | 571 | return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); | 
|  | 572 | } | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 573 |  | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 574 | draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType); | 
| scroggo | 9c59ebc | 2015-03-25 13:48:49 -0700 | [diff] [blame] | 575 | break; | 
| emmaleer | 0a4c3cb | 2015-06-22 10:40:21 -0700 | [diff] [blame] | 576 | } | 
| scroggo | 9c59ebc | 2015-03-25 13:48:49 -0700 | [diff] [blame] | 577 | case kScanline_Mode: { | 
| scroggo | d8d6855 | 2016-06-06 11:26:17 -0700 | [diff] [blame] | 578 | void* dst = pixels.get(); | 
|  | 579 | uint32_t height = decodeInfo.height(); | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 580 | const bool useIncremental = [this]() { | 
|  | 581 | auto exts = { "png", "PNG", "gif", "GIF" }; | 
|  | 582 | for (auto ext : exts) { | 
|  | 583 | if (fPath.endsWith(ext)) { | 
|  | 584 | return true; | 
|  | 585 | } | 
|  | 586 | } | 
|  | 587 | return false; | 
|  | 588 | }(); | 
|  | 589 | // ico may use the old scanline method or the new one, depending on whether it | 
|  | 590 | // internally holds a bmp or a png. | 
| scroggo | 8e6c7ad | 2016-09-16 08:20:38 -0700 | [diff] [blame] | 591 | const bool ico = fPath.endsWith("ico"); | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 592 | bool useOldScanlineMethod = !useIncremental && !ico; | 
|  | 593 | if (useIncremental || ico) { | 
| scroggo | 8e6c7ad | 2016-09-16 08:20:38 -0700 | [diff] [blame] | 594 | if (SkCodec::kSuccess == codec->startIncrementalDecode(decodeInfo, dst, | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 595 | rowBytes, &options)) { | 
| scroggo | 8e6c7ad | 2016-09-16 08:20:38 -0700 | [diff] [blame] | 596 | int rowsDecoded; | 
| Leon Scroggins III | 674a184 | 2017-07-06 12:26:09 -0400 | [diff] [blame] | 597 | auto result = codec->incrementalDecode(&rowsDecoded); | 
|  | 598 | if (SkCodec::kIncompleteInput == result || SkCodec::kErrorInInput == result) { | 
| scroggo | 8e6c7ad | 2016-09-16 08:20:38 -0700 | [diff] [blame] | 599 | codec->fillIncompleteImage(decodeInfo, dst, rowBytes, | 
|  | 600 | SkCodec::kNo_ZeroInitialized, height, | 
|  | 601 | rowsDecoded); | 
| scroggo | 6fb2391 | 2016-06-02 14:16:43 -0700 | [diff] [blame] | 602 | } | 
| scroggo | 8e6c7ad | 2016-09-16 08:20:38 -0700 | [diff] [blame] | 603 | } else { | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 604 | if (useIncremental) { | 
|  | 605 | // Error: These should support incremental decode. | 
| scroggo | 8e6c7ad | 2016-09-16 08:20:38 -0700 | [diff] [blame] | 606 | return "Could not start incremental decode"; | 
|  | 607 | } | 
|  | 608 | // Otherwise, this is an ICO. Since incremental failed, it must contain a BMP, | 
|  | 609 | // which should work via startScanlineDecode | 
|  | 610 | useOldScanlineMethod = true; | 
|  | 611 | } | 
|  | 612 | } | 
|  | 613 |  | 
|  | 614 | if (useOldScanlineMethod) { | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 615 | if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo)) { | 
| scroggo | 8e6c7ad | 2016-09-16 08:20:38 -0700 | [diff] [blame] | 616 | return "Could not start scanline decoder"; | 
|  | 617 | } | 
|  | 618 |  | 
|  | 619 | switch (codec->getScanlineOrder()) { | 
|  | 620 | case SkCodec::kTopDown_SkScanlineOrder: | 
|  | 621 | case SkCodec::kBottomUp_SkScanlineOrder: | 
|  | 622 | // We do not need to check the return value.  On an incomplete | 
|  | 623 | // image, memory will be filled with a default value. | 
|  | 624 | codec->getScanlines(dst, height, rowBytes); | 
|  | 625 | break; | 
| msarett | 10522ff | 2015-09-07 08:54:01 -0700 | [diff] [blame] | 626 | } | 
|  | 627 | } | 
|  | 628 |  | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 629 | draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, fDstColorType); | 
| emmaleer | 9700206 | 2015-05-27 12:36:10 -0700 | [diff] [blame] | 630 | break; | 
|  | 631 | } | 
| msarett | 0a24297 | 2015-06-11 14:27:27 -0700 | [diff] [blame] | 632 | case kStripe_Mode: { | 
|  | 633 | const int height = decodeInfo.height(); | 
|  | 634 | // This value is chosen arbitrarily.  We exercise more cases by choosing a value that | 
|  | 635 | // does not align with image blocks. | 
|  | 636 | const int stripeHeight = 37; | 
|  | 637 | const int numStripes = (height + stripeHeight - 1) / stripeHeight; | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 638 | void* dst = pixels.get(); | 
| msarett | 0a24297 | 2015-06-11 14:27:27 -0700 | [diff] [blame] | 639 |  | 
|  | 640 | // Decode odd stripes | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 641 | if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options)) { | 
| msarett | b65e604 | 2016-02-23 05:37:25 -0800 | [diff] [blame] | 642 | return "Could not start scanline decoder"; | 
|  | 643 | } | 
|  | 644 |  | 
|  | 645 | // This mode was designed to test the new skip scanlines API in libjpeg-turbo. | 
|  | 646 | // Jpegs have kTopDown_SkScanlineOrder, and at this time, it is not interesting | 
|  | 647 | // to run this test for image types that do not have this scanline ordering. | 
| scroggo | 12e2f50 | 2016-05-16 09:04:18 -0700 | [diff] [blame] | 648 | // We only run this on Jpeg, which is always kTopDown. | 
|  | 649 | SkASSERT(SkCodec::kTopDown_SkScanlineOrder == codec->getScanlineOrder()); | 
| msarett | e6dd004 | 2015-10-09 11:07:34 -0700 | [diff] [blame] | 650 |  | 
| msarett | 0a24297 | 2015-06-11 14:27:27 -0700 | [diff] [blame] | 651 | for (int i = 0; i < numStripes; i += 2) { | 
|  | 652 | // Skip a stripe | 
|  | 653 | const int linesToSkip = SkTMin(stripeHeight, height - i * stripeHeight); | 
| msarett | e6dd004 | 2015-10-09 11:07:34 -0700 | [diff] [blame] | 654 | codec->skipScanlines(linesToSkip); | 
| msarett | 0a24297 | 2015-06-11 14:27:27 -0700 | [diff] [blame] | 655 |  | 
|  | 656 | // Read a stripe | 
|  | 657 | const int startY = (i + 1) * stripeHeight; | 
|  | 658 | const int linesToRead = SkTMin(stripeHeight, height - startY); | 
|  | 659 | if (linesToRead > 0) { | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 660 | codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead, | 
|  | 661 | rowBytes); | 
| msarett | 0a24297 | 2015-06-11 14:27:27 -0700 | [diff] [blame] | 662 | } | 
|  | 663 | } | 
|  | 664 |  | 
|  | 665 | // Decode even stripes | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 666 | const SkCodec::Result startResult = codec->startScanlineDecode(decodeInfo); | 
| scroggo | 1c005e4 | 2015-08-04 09:24:45 -0700 | [diff] [blame] | 667 | if (SkCodec::kSuccess != startResult) { | 
|  | 668 | return "Failed to restart scanline decoder with same parameters."; | 
| msarett | 0a24297 | 2015-06-11 14:27:27 -0700 | [diff] [blame] | 669 | } | 
|  | 670 | for (int i = 0; i < numStripes; i += 2) { | 
|  | 671 | // Read a stripe | 
|  | 672 | const int startY = i * stripeHeight; | 
|  | 673 | const int linesToRead = SkTMin(stripeHeight, height - startY); | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 674 | codec->getScanlines(SkTAddOffset<void>(dst, rowBytes * startY), linesToRead, | 
|  | 675 | rowBytes); | 
| msarett | 0a24297 | 2015-06-11 14:27:27 -0700 | [diff] [blame] | 676 |  | 
|  | 677 | // Skip a stripe | 
| msarett | f6db27e | 2015-06-12 09:34:04 -0700 | [diff] [blame] | 678 | const int linesToSkip = SkTMin(stripeHeight, height - (i + 1) * stripeHeight); | 
|  | 679 | if (linesToSkip > 0) { | 
| msarett | e6dd004 | 2015-10-09 11:07:34 -0700 | [diff] [blame] | 680 | codec->skipScanlines(linesToSkip); | 
| msarett | 0a24297 | 2015-06-11 14:27:27 -0700 | [diff] [blame] | 681 | } | 
|  | 682 | } | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 683 |  | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 684 | draw_to_canvas(canvas, bitmapInfo, dst, rowBytes, fDstColorType); | 
| emmaleer | 0a4c3cb | 2015-06-22 10:40:21 -0700 | [diff] [blame] | 685 | break; | 
| msarett | 0a24297 | 2015-06-11 14:27:27 -0700 | [diff] [blame] | 686 | } | 
| msarett | 91c22b2 | 2016-02-22 12:27:46 -0800 | [diff] [blame] | 687 | case kCroppedScanline_Mode: { | 
|  | 688 | const int width = decodeInfo.width(); | 
|  | 689 | const int height = decodeInfo.height(); | 
|  | 690 | // This value is chosen because, as we move across the image, it will sometimes | 
|  | 691 | // align with the jpeg block sizes and it will sometimes not.  This allows us | 
|  | 692 | // to test interestingly different code paths in the implementation. | 
|  | 693 | const int tileSize = 36; | 
| msarett | 91c22b2 | 2016-02-22 12:27:46 -0800 | [diff] [blame] | 694 | SkIRect subset; | 
|  | 695 | for (int x = 0; x < width; x += tileSize) { | 
|  | 696 | subset = SkIRect::MakeXYWH(x, 0, SkTMin(tileSize, width - x), height); | 
| Matt Sarett | a40d9c8 | 2017-05-19 15:21:05 -0400 | [diff] [blame] | 697 | options.fSubset = ⊂ | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 698 | if (SkCodec::kSuccess != codec->startScanlineDecode(decodeInfo, &options)) { | 
| msarett | 91c22b2 | 2016-02-22 12:27:46 -0800 | [diff] [blame] | 699 | return "Could not start scanline decoder."; | 
|  | 700 | } | 
|  | 701 |  | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 702 | codec->getScanlines(SkTAddOffset<void>(pixels.get(), x * bpp), height, rowBytes); | 
| msarett | 91c22b2 | 2016-02-22 12:27:46 -0800 | [diff] [blame] | 703 | } | 
|  | 704 |  | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 705 | draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType); | 
| msarett | 91c22b2 | 2016-02-22 12:27:46 -0800 | [diff] [blame] | 706 | break; | 
|  | 707 | } | 
| scroggo | b636b45 | 2015-07-22 07:16:20 -0700 | [diff] [blame] | 708 | case kSubset_Mode: { | 
|  | 709 | // Arbitrarily choose a divisor. | 
|  | 710 | int divisor = 2; | 
|  | 711 | // Total width/height of the image. | 
|  | 712 | const int W = codec->getInfo().width(); | 
|  | 713 | const int H = codec->getInfo().height(); | 
|  | 714 | if (divisor > W || divisor > H) { | 
|  | 715 | return Error::Nonfatal(SkStringPrintf("Cannot codec subset: divisor %d is too big " | 
|  | 716 | "for %s with dimensions (%d x %d)", divisor, | 
|  | 717 | fPath.c_str(), W, H)); | 
|  | 718 | } | 
|  | 719 | // subset dimensions | 
|  | 720 | // SkWebpCodec, the only one that supports subsets, requires even top/left boundaries. | 
|  | 721 | const int w = SkAlign2(W / divisor); | 
|  | 722 | const int h = SkAlign2(H / divisor); | 
|  | 723 | SkIRect subset; | 
| Matt Sarett | a40d9c8 | 2017-05-19 15:21:05 -0400 | [diff] [blame] | 724 | options.fSubset = ⊂ | 
| scroggo | b636b45 | 2015-07-22 07:16:20 -0700 | [diff] [blame] | 725 | SkBitmap subsetBm; | 
|  | 726 | // We will reuse pixel memory from bitmap. | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 727 | void* dst = pixels.get(); | 
| scroggo | b636b45 | 2015-07-22 07:16:20 -0700 | [diff] [blame] | 728 | // Keep track of left and top (for drawing subsetBm into canvas). We could use | 
|  | 729 | // fScale * x and fScale * y, but we want integers such that the next subset will start | 
|  | 730 | // where the last one ended. So we'll add decodeInfo.width() and height(). | 
|  | 731 | int left = 0; | 
|  | 732 | for (int x = 0; x < W; x += w) { | 
|  | 733 | int top = 0; | 
|  | 734 | for (int y = 0; y < H; y+= h) { | 
|  | 735 | // Do not make the subset go off the edge of the image. | 
|  | 736 | const int preScaleW = SkTMin(w, W - x); | 
|  | 737 | const int preScaleH = SkTMin(h, H - y); | 
|  | 738 | subset.setXYWH(x, y, preScaleW, preScaleH); | 
|  | 739 | // And scale | 
|  | 740 | // FIXME: Should we have a version of getScaledDimensions that takes a subset | 
|  | 741 | // into account? | 
| msarett | c7eb490 | 2016-04-25 07:04:58 -0700 | [diff] [blame] | 742 | const int scaledW = SkTMax(1, SkScalarRoundToInt(preScaleW * fScale)); | 
|  | 743 | const int scaledH = SkTMax(1, SkScalarRoundToInt(preScaleH * fScale)); | 
|  | 744 | decodeInfo = decodeInfo.makeWH(scaledW, scaledH); | 
|  | 745 | SkImageInfo subsetBitmapInfo = bitmapInfo.makeWH(scaledW, scaledH); | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 746 | size_t subsetRowBytes = subsetBitmapInfo.minRowBytes(); | 
|  | 747 | const SkCodec::Result result = codec->getPixels(decodeInfo, dst, subsetRowBytes, | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 748 | &options); | 
| scroggo | b636b45 | 2015-07-22 07:16:20 -0700 | [diff] [blame] | 749 | switch (result) { | 
|  | 750 | case SkCodec::kSuccess: | 
| Leon Scroggins III | 674a184 | 2017-07-06 12:26:09 -0400 | [diff] [blame] | 751 | case SkCodec::kErrorInInput: | 
| scroggo | b636b45 | 2015-07-22 07:16:20 -0700 | [diff] [blame] | 752 | case SkCodec::kIncompleteInput: | 
|  | 753 | break; | 
| scroggo | b636b45 | 2015-07-22 07:16:20 -0700 | [diff] [blame] | 754 | default: | 
|  | 755 | return SkStringPrintf("subset codec failed to decode (%d, %d, %d, %d) " | 
|  | 756 | "from %s with dimensions (%d x %d)\t error %d", | 
|  | 757 | x, y, decodeInfo.width(), decodeInfo.height(), | 
|  | 758 | fPath.c_str(), W, H, result); | 
|  | 759 | } | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 760 | draw_to_canvas(canvas, subsetBitmapInfo, dst, subsetRowBytes, fDstColorType, | 
|  | 761 | SkIntToScalar(left), SkIntToScalar(top)); | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 762 |  | 
| scroggo | b636b45 | 2015-07-22 07:16:20 -0700 | [diff] [blame] | 763 | // translate by the scaled height. | 
|  | 764 | top += decodeInfo.height(); | 
|  | 765 | } | 
|  | 766 | // translate by the scaled width. | 
|  | 767 | left += decodeInfo.width(); | 
|  | 768 | } | 
|  | 769 | return ""; | 
|  | 770 | } | 
| msarett | b714fb0 | 2016-01-22 14:46:42 -0800 | [diff] [blame] | 771 | default: | 
|  | 772 | SkASSERT(false); | 
|  | 773 | return "Invalid fMode"; | 
| scroggo | 9b77ddd | 2015-03-19 06:03:39 -0700 | [diff] [blame] | 774 | } | 
| scroggo | 9c59ebc | 2015-03-25 13:48:49 -0700 | [diff] [blame] | 775 | return ""; | 
| scroggo | 9b77ddd | 2015-03-19 06:03:39 -0700 | [diff] [blame] | 776 | } | 
|  | 777 |  | 
|  | 778 | SkISize CodecSrc::size() const { | 
| bungeman | 38d909e | 2016-08-02 14:40:46 -0700 | [diff] [blame] | 779 | sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); | 
| Mike Reed | ede7bac | 2017-07-23 15:30:02 -0400 | [diff] [blame] | 780 | std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded)); | 
| scroggo | 7fac5af | 2015-09-30 11:33:12 -0700 | [diff] [blame] | 781 | if (nullptr == codec) { | 
| Hal Canary | fafe135 | 2017-04-11 12:12:02 -0400 | [diff] [blame] | 782 | return {0, 0}; | 
| scroggo | 7fac5af | 2015-09-30 11:33:12 -0700 | [diff] [blame] | 783 | } | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 784 |  | 
|  | 785 | auto imageSize = codec->getScaledDimensions(fScale); | 
|  | 786 | if (fMode == kAnimated_Mode) { | 
| scroggo | 90e971a | 2016-10-25 06:11:01 -0700 | [diff] [blame] | 787 | // We'll draw one of each frame, so make it big enough to hold them all | 
|  | 788 | // in a grid. The grid will be roughly square, with "factor" frames per | 
|  | 789 | // row and up to "factor" rows. | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 790 | const size_t count = codec->getFrameInfo().size(); | 
| scroggo | 90e971a | 2016-10-25 06:11:01 -0700 | [diff] [blame] | 791 | const float root = sqrt((float) count); | 
|  | 792 | const int factor = sk_float_ceil2int(root); | 
|  | 793 | imageSize.fWidth  = imageSize.fWidth  * factor; | 
|  | 794 | imageSize.fHeight = imageSize.fHeight * sk_float_ceil2int((float) count / (float) factor); | 
| scroggo | 19b9153 | 2016-10-24 09:03:26 -0700 | [diff] [blame] | 795 | } | 
|  | 796 | return imageSize; | 
| scroggo | 9b77ddd | 2015-03-19 06:03:39 -0700 | [diff] [blame] | 797 | } | 
|  | 798 |  | 
|  | 799 | Name CodecSrc::name() const { | 
| msarett | 0a24297 | 2015-06-11 14:27:27 -0700 | [diff] [blame] | 800 | if (1.0f == fScale) { | 
| scroggo | 6e8c68e | 2016-10-24 13:48:49 -0700 | [diff] [blame] | 801 | Name name = SkOSPath::Basename(fPath.c_str()); | 
|  | 802 | if (fMode == kAnimated_Mode) { | 
|  | 803 | name.append("_animated"); | 
|  | 804 | } | 
|  | 805 | return name; | 
| msarett | 0a24297 | 2015-06-11 14:27:27 -0700 | [diff] [blame] | 806 | } | 
| scroggo | 6e8c68e | 2016-10-24 13:48:49 -0700 | [diff] [blame] | 807 | SkASSERT(fMode != kAnimated_Mode); | 
| msarett | a5783ae | 2015-09-08 15:35:32 -0700 | [diff] [blame] | 808 | return get_scaled_name(fPath, fScale); | 
| scroggo | 9b77ddd | 2015-03-19 06:03:39 -0700 | [diff] [blame] | 809 | } | 
|  | 810 |  | 
|  | 811 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 812 |  | 
| scroggo | f8dc9df | 2016-05-16 09:04:13 -0700 | [diff] [blame] | 813 | AndroidCodecSrc::AndroidCodecSrc(Path path, CodecSrc::DstColorType dstColorType, | 
| scroggo | c5560be | 2016-02-03 09:42:42 -0800 | [diff] [blame] | 814 | SkAlphaType dstAlphaType, int sampleSize) | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 815 | : fPath(path) | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 816 | , fDstColorType(dstColorType) | 
| scroggo | c5560be | 2016-02-03 09:42:42 -0800 | [diff] [blame] | 817 | , fDstAlphaType(dstAlphaType) | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 818 | , fSampleSize(sampleSize) | 
| scroggo | 3ac66e9 | 2016-02-08 15:09:48 -0800 | [diff] [blame] | 819 | , fRunSerially(serial_from_path_name(path)) | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 820 | {} | 
|  | 821 |  | 
|  | 822 | bool AndroidCodecSrc::veto(SinkFlags flags) const { | 
|  | 823 | // No need to test decoding to non-raster or indirect backend. | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 824 | return flags.type != SinkFlags::kRaster | 
|  | 825 | || flags.approach != SinkFlags::kDirect; | 
|  | 826 | } | 
|  | 827 |  | 
|  | 828 | Error AndroidCodecSrc::draw(SkCanvas* canvas) const { | 
| Matt Sarett | a40d9c8 | 2017-05-19 15:21:05 -0400 | [diff] [blame] | 829 | if (canvas->imageInfo().colorSpace() && | 
|  | 830 | kRGBA_F16_SkColorType != canvas->imageInfo().colorType()) { | 
|  | 831 | // SkAndroidCodec uses legacy premultiplication and blending.  Therefore, we only | 
|  | 832 | // run these tests on legacy canvases. | 
|  | 833 | // We allow an exception for F16, since Android uses F16. | 
|  | 834 | return Error::Nonfatal("Skip testing to color correct canvas."); | 
|  | 835 | } | 
|  | 836 |  | 
| bungeman | 38d909e | 2016-08-02 14:40:46 -0700 | [diff] [blame] | 837 | sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 838 | if (!encoded) { | 
|  | 839 | return SkStringPrintf("Couldn't read %s.", fPath.c_str()); | 
|  | 840 | } | 
| Mike Reed | ede7bac | 2017-07-23 15:30:02 -0400 | [diff] [blame] | 841 | std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(encoded)); | 
|  | 842 | if (nullptr == codec) { | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 843 | return SkStringPrintf("Couldn't create android codec for %s.", fPath.c_str()); | 
|  | 844 | } | 
|  | 845 |  | 
| scroggo | ba58489 | 2016-05-20 13:56:13 -0700 | [diff] [blame] | 846 | SkImageInfo decodeInfo = codec->getInfo(); | 
|  | 847 | if (!get_decode_info(&decodeInfo, canvas->imageInfo().colorType(), fDstColorType, | 
|  | 848 | fDstAlphaType)) { | 
| Matt Sarett | ea518f0 | 2017-02-03 11:58:59 -0800 | [diff] [blame] | 849 | return Error::Nonfatal("Skipping uninteresting test."); | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 850 | } | 
|  | 851 |  | 
|  | 852 | // Scale the image if it is desired. | 
|  | 853 | SkISize size = codec->getSampledDimensions(fSampleSize); | 
|  | 854 |  | 
|  | 855 | // Visually inspecting very small output images is not necessary.  We will | 
|  | 856 | // cover these cases in unit testing. | 
|  | 857 | if ((size.width() <= 10 || size.height() <= 10) && 1 != fSampleSize) { | 
|  | 858 | return Error::Nonfatal("Scaling very small images is uninteresting."); | 
|  | 859 | } | 
|  | 860 | decodeInfo = decodeInfo.makeWH(size.width(), size.height()); | 
|  | 861 |  | 
| Mike Reed | 7fcfb62 | 2018-02-09 13:26:46 -0500 | [diff] [blame] | 862 | int bpp = decodeInfo.bytesPerPixel(); | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 863 | size_t rowBytes = size.width() * bpp; | 
|  | 864 | SkAutoMalloc pixels(size.height() * rowBytes); | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 865 |  | 
|  | 866 | SkBitmap bitmap; | 
| msarett | 34e0ec4 | 2016-04-22 16:27:24 -0700 | [diff] [blame] | 867 | SkImageInfo bitmapInfo = decodeInfo; | 
| Matt Sarett | f485cf9 | 2017-05-26 08:58:03 -0400 | [diff] [blame] | 868 | set_bitmap_color_space(&bitmapInfo); | 
| msarett | 34e0ec4 | 2016-04-22 16:27:24 -0700 | [diff] [blame] | 869 | if (kRGBA_8888_SkColorType == decodeInfo.colorType() || | 
|  | 870 | kBGRA_8888_SkColorType == decodeInfo.colorType()) { | 
|  | 871 | bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); | 
|  | 872 | } | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 873 |  | 
|  | 874 | // Create options for the codec. | 
|  | 875 | SkAndroidCodec::AndroidOptions options; | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 876 | options.fSampleSize = fSampleSize; | 
|  | 877 |  | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 878 | switch (codec->getAndroidPixels(decodeInfo, pixels.get(), rowBytes, &options)) { | 
| scroggo | f8dc9df | 2016-05-16 09:04:13 -0700 | [diff] [blame] | 879 | case SkCodec::kSuccess: | 
| Leon Scroggins III | 674a184 | 2017-07-06 12:26:09 -0400 | [diff] [blame] | 880 | case SkCodec::kErrorInInput: | 
| scroggo | f8dc9df | 2016-05-16 09:04:13 -0700 | [diff] [blame] | 881 | case SkCodec::kIncompleteInput: | 
|  | 882 | break; | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 883 | default: | 
| scroggo | f8dc9df | 2016-05-16 09:04:13 -0700 | [diff] [blame] | 884 | return SkStringPrintf("Couldn't getPixels %s.", fPath.c_str()); | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 885 | } | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 886 | draw_to_canvas(canvas, bitmapInfo, pixels.get(), rowBytes, fDstColorType); | 
| scroggo | f8dc9df | 2016-05-16 09:04:13 -0700 | [diff] [blame] | 887 | return ""; | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 888 | } | 
|  | 889 |  | 
|  | 890 | SkISize AndroidCodecSrc::size() const { | 
| bungeman | 38d909e | 2016-08-02 14:40:46 -0700 | [diff] [blame] | 891 | sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); | 
| Mike Reed | ede7bac | 2017-07-23 15:30:02 -0400 | [diff] [blame] | 892 | std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::MakeFromData(encoded)); | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 893 | if (nullptr == codec) { | 
| Hal Canary | fafe135 | 2017-04-11 12:12:02 -0400 | [diff] [blame] | 894 | return {0, 0}; | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 895 | } | 
|  | 896 | return codec->getSampledDimensions(fSampleSize); | 
|  | 897 | } | 
|  | 898 |  | 
|  | 899 | Name AndroidCodecSrc::name() const { | 
|  | 900 | // We will replicate the names used by CodecSrc so that images can | 
|  | 901 | // be compared in Gold. | 
|  | 902 | if (1 == fSampleSize) { | 
|  | 903 | return SkOSPath::Basename(fPath.c_str()); | 
|  | 904 | } | 
| msarett | 4b0778e | 2015-11-13 09:59:11 -0800 | [diff] [blame] | 905 | return get_scaled_name(fPath, 1.0f / (float) fSampleSize); | 
| msarett | 3d9d7a7 | 2015-10-21 10:27:10 -0700 | [diff] [blame] | 906 | } | 
|  | 907 |  | 
|  | 908 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 909 |  | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 910 | ImageGenSrc::ImageGenSrc(Path path, Mode mode, SkAlphaType alphaType, bool isGpu) | 
|  | 911 | : fPath(path) | 
|  | 912 | , fMode(mode) | 
|  | 913 | , fDstAlphaType(alphaType) | 
|  | 914 | , fIsGpu(isGpu) | 
|  | 915 | , fRunSerially(serial_from_path_name(path)) | 
|  | 916 | {} | 
|  | 917 |  | 
|  | 918 | bool ImageGenSrc::veto(SinkFlags flags) const { | 
|  | 919 | if (fIsGpu) { | 
| Brian Salomon | bd7c551 | 2017-03-07 09:08:36 -0500 | [diff] [blame] | 920 | // MSAA runs tend to run out of memory and tests the same code paths as regular gpu configs. | 
|  | 921 | return flags.type != SinkFlags::kGPU || flags.approach != SinkFlags::kDirect || | 
|  | 922 | flags.multisampled == SinkFlags::kMultisampled; | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 923 | } | 
|  | 924 |  | 
|  | 925 | return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect; | 
|  | 926 | } | 
|  | 927 |  | 
|  | 928 | Error ImageGenSrc::draw(SkCanvas* canvas) const { | 
|  | 929 | if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) { | 
|  | 930 | return Error::Nonfatal("Uninteresting to test image generator to 565."); | 
|  | 931 | } | 
|  | 932 |  | 
| bungeman | 38d909e | 2016-08-02 14:40:46 -0700 | [diff] [blame] | 933 | sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 934 | if (!encoded) { | 
|  | 935 | return SkStringPrintf("Couldn't read %s.", fPath.c_str()); | 
|  | 936 | } | 
|  | 937 |  | 
| msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 938 | #if defined(SK_BUILD_FOR_WIN) | 
|  | 939 | // Initialize COM in order to test with WIC. | 
|  | 940 | SkAutoCoInitialize com; | 
|  | 941 | if (!com.succeeded()) { | 
|  | 942 | return "Could not initialize COM."; | 
|  | 943 | } | 
|  | 944 | #endif | 
|  | 945 |  | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 946 | std::unique_ptr<SkImageGenerator> gen(nullptr); | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 947 | switch (fMode) { | 
|  | 948 | case kCodec_Mode: | 
| Mike Reed | 185130c | 2017-02-15 15:14:16 -0500 | [diff] [blame] | 949 | gen = SkCodecImageGenerator::MakeFromEncodedCodec(encoded); | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 950 | if (!gen) { | 
|  | 951 | return "Could not create codec image generator."; | 
|  | 952 | } | 
|  | 953 | break; | 
| msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 954 | case kPlatform_Mode: { | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 955 | #if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) | 
| Leon Scroggins III | 0cbc10f | 2017-10-30 09:07:53 -0400 | [diff] [blame] | 956 | gen = SkImageGeneratorCG::MakeFromEncodedCG(encoded); | 
| msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 957 | #elif defined(SK_BUILD_FOR_WIN) | 
| bungeman | 38d909e | 2016-08-02 14:40:46 -0700 | [diff] [blame] | 958 | gen.reset(SkImageGeneratorWIC::NewFromEncodedWIC(encoded.get())); | 
| msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 959 | #endif | 
|  | 960 |  | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 961 | if (!gen) { | 
| msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 962 | return "Could not create platform image generator."; | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 963 | } | 
|  | 964 | break; | 
| msarett | fc0b6d1 | 2016-03-17 13:50:17 -0700 | [diff] [blame] | 965 | } | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 966 | default: | 
|  | 967 | SkASSERT(false); | 
|  | 968 | return "Invalid image generator mode"; | 
|  | 969 | } | 
|  | 970 |  | 
|  | 971 | // Test deferred decoding path on GPU | 
|  | 972 | if (fIsGpu) { | 
| Mike Reed | 185130c | 2017-02-15 15:14:16 -0500 | [diff] [blame] | 973 | sk_sp<SkImage> image(SkImage::MakeFromGenerator(std::move(gen), nullptr)); | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 974 | if (!image) { | 
|  | 975 | return "Could not create image from codec image generator."; | 
|  | 976 | } | 
|  | 977 | canvas->drawImage(image, 0, 0); | 
|  | 978 | return ""; | 
|  | 979 | } | 
| mtklein | 343a63d | 2016-03-22 11:46:53 -0700 | [diff] [blame] | 980 |  | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 981 | // Test various color and alpha types on CPU | 
|  | 982 | SkImageInfo decodeInfo = gen->getInfo().makeAlphaType(fDstAlphaType); | 
| mtklein | 343a63d | 2016-03-22 11:46:53 -0700 | [diff] [blame] | 983 |  | 
| Matt Sarett | a40d9c8 | 2017-05-19 15:21:05 -0400 | [diff] [blame] | 984 | SkImageGenerator::Options options; | 
|  | 985 | options.fBehavior = canvas->imageInfo().colorSpace() ? | 
|  | 986 | SkTransferFunctionBehavior::kRespect : SkTransferFunctionBehavior::kIgnore; | 
|  | 987 |  | 
| Mike Reed | 7fcfb62 | 2018-02-09 13:26:46 -0500 | [diff] [blame] | 988 | int bpp = decodeInfo.bytesPerPixel(); | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 989 | size_t rowBytes = decodeInfo.width() * bpp; | 
|  | 990 | SkAutoMalloc pixels(decodeInfo.height() * rowBytes); | 
| Matt Sarett | a40d9c8 | 2017-05-19 15:21:05 -0400 | [diff] [blame] | 991 | if (!gen->getPixels(decodeInfo, pixels.get(), rowBytes, &options)) { | 
| Matt Sarett | 05cb4c3 | 2017-03-02 12:07:46 -0500 | [diff] [blame] | 992 | SkString err = | 
|  | 993 | SkStringPrintf("Image generator could not getPixels() for %s\n", fPath.c_str()); | 
|  | 994 |  | 
|  | 995 | #if defined(SK_BUILD_FOR_WIN) | 
|  | 996 | if (kPlatform_Mode == fMode) { | 
|  | 997 | // Do not issue a fatal error for WIC flakiness. | 
|  | 998 | return Error::Nonfatal(err); | 
|  | 999 | } | 
|  | 1000 | #endif | 
|  | 1001 |  | 
|  | 1002 | return err; | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 1003 | } | 
|  | 1004 |  | 
| Matt Sarett | f485cf9 | 2017-05-26 08:58:03 -0400 | [diff] [blame] | 1005 | set_bitmap_color_space(&decodeInfo); | 
| Leon Scroggins | 571b30f | 2017-07-11 17:35:31 +0000 | [diff] [blame] | 1006 | draw_to_canvas(canvas, decodeInfo, pixels.get(), rowBytes, | 
| msarett | b1be46b | 2016-05-17 08:52:11 -0700 | [diff] [blame] | 1007 | CodecSrc::kGetFromCanvas_DstColorType); | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 1008 | return ""; | 
|  | 1009 | } | 
|  | 1010 |  | 
|  | 1011 | SkISize ImageGenSrc::size() const { | 
| bungeman | 38d909e | 2016-08-02 14:40:46 -0700 | [diff] [blame] | 1012 | sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); | 
| Mike Reed | ede7bac | 2017-07-23 15:30:02 -0400 | [diff] [blame] | 1013 | std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded)); | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 1014 | if (nullptr == codec) { | 
| Hal Canary | fafe135 | 2017-04-11 12:12:02 -0400 | [diff] [blame] | 1015 | return {0, 0}; | 
| msarett | 1897631 | 2016-03-09 14:20:58 -0800 | [diff] [blame] | 1016 | } | 
|  | 1017 | return codec->getInfo().dimensions(); | 
|  | 1018 | } | 
|  | 1019 |  | 
|  | 1020 | Name ImageGenSrc::name() const { | 
|  | 1021 | return SkOSPath::Basename(fPath.c_str()); | 
|  | 1022 | } | 
|  | 1023 |  | 
|  | 1024 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 1025 |  | 
| msarett | 9ce3a54 | 2016-07-15 13:54:38 -0700 | [diff] [blame] | 1026 | ColorCodecSrc::ColorCodecSrc(Path path, Mode mode, SkColorType colorType) | 
| msarett | 69deca8 | 2016-04-29 09:38:40 -0700 | [diff] [blame] | 1027 | : fPath(path) | 
|  | 1028 | , fMode(mode) | 
| msarett | 9ce3a54 | 2016-07-15 13:54:38 -0700 | [diff] [blame] | 1029 | , fColorType(colorType) | 
| msarett | 69deca8 | 2016-04-29 09:38:40 -0700 | [diff] [blame] | 1030 | {} | 
|  | 1031 |  | 
|  | 1032 | bool ColorCodecSrc::veto(SinkFlags flags) const { | 
|  | 1033 | // Test to direct raster backends (8888 and 565). | 
|  | 1034 | return flags.type != SinkFlags::kRaster || flags.approach != SinkFlags::kDirect; | 
|  | 1035 | } | 
|  | 1036 |  | 
| Matt Sarett | 6a0feba | 2017-06-09 10:45:44 -0400 | [diff] [blame] | 1037 | void clamp_if_necessary(const SkBitmap& bitmap, SkColorType dstCT) { | 
|  | 1038 | if (kRGBA_F16_SkColorType != bitmap.colorType() || kRGBA_F16_SkColorType == dstCT) { | 
|  | 1039 | // No need to clamp if the dst is F16.  We will clamp when we encode to PNG. | 
|  | 1040 | return; | 
|  | 1041 | } | 
|  | 1042 |  | 
| Mike Klein | 45c16fa | 2017-07-18 18:15:13 -0400 | [diff] [blame] | 1043 | SkJumper_MemoryCtx ptr = { bitmap.getAddr(0,0), bitmap.rowBytesAsPixels() }; | 
|  | 1044 |  | 
| Matt Sarett | 6a0feba | 2017-06-09 10:45:44 -0400 | [diff] [blame] | 1045 | SkRasterPipeline_<256> p; | 
|  | 1046 | p.append(SkRasterPipeline::load_f16, &ptr); | 
|  | 1047 | p.append(SkRasterPipeline::clamp_0); | 
|  | 1048 | if (kPremul_SkAlphaType == bitmap.alphaType()) { | 
|  | 1049 | p.append(SkRasterPipeline::clamp_a); | 
|  | 1050 | } else { | 
|  | 1051 | p.append(SkRasterPipeline::clamp_1); | 
|  | 1052 | } | 
|  | 1053 | p.append(SkRasterPipeline::store_f16, &ptr); | 
|  | 1054 |  | 
| Mike Klein | 45c16fa | 2017-07-18 18:15:13 -0400 | [diff] [blame] | 1055 | p.run(0,0, bitmap.width(), bitmap.height()); | 
| Matt Sarett | 6a0feba | 2017-06-09 10:45:44 -0400 | [diff] [blame] | 1056 | } | 
|  | 1057 |  | 
| msarett | 69deca8 | 2016-04-29 09:38:40 -0700 | [diff] [blame] | 1058 | Error ColorCodecSrc::draw(SkCanvas* canvas) const { | 
|  | 1059 | if (kRGB_565_SkColorType == canvas->imageInfo().colorType()) { | 
|  | 1060 | return Error::Nonfatal("No need to test color correction to 565 backend."); | 
|  | 1061 | } | 
|  | 1062 |  | 
| msarett | d1ec89b | 2016-08-03 12:59:27 -0700 | [diff] [blame] | 1063 | bool runInLegacyMode = kBaseline_Mode == fMode; | 
| msarett | d1ec89b | 2016-08-03 12:59:27 -0700 | [diff] [blame] | 1064 | if (runInLegacyMode && canvas->imageInfo().colorSpace()) { | 
|  | 1065 | return Error::Nonfatal("Skipping tests that are only interesting in legacy mode."); | 
|  | 1066 | } else if (!runInLegacyMode && !canvas->imageInfo().colorSpace()) { | 
|  | 1067 | return Error::Nonfatal("Skipping tests that are only interesting in srgb mode."); | 
| msarett | 9ce3a54 | 2016-07-15 13:54:38 -0700 | [diff] [blame] | 1068 | } | 
|  | 1069 |  | 
| bungeman | 38d909e | 2016-08-02 14:40:46 -0700 | [diff] [blame] | 1070 | sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); | 
| msarett | 69deca8 | 2016-04-29 09:38:40 -0700 | [diff] [blame] | 1071 | if (!encoded) { | 
|  | 1072 | return SkStringPrintf("Couldn't read %s.", fPath.c_str()); | 
|  | 1073 | } | 
|  | 1074 |  | 
| Mike Reed | ede7bac | 2017-07-23 15:30:02 -0400 | [diff] [blame] | 1075 | std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded)); | 
|  | 1076 | if (nullptr == codec) { | 
| msarett | 69deca8 | 2016-04-29 09:38:40 -0700 | [diff] [blame] | 1077 | return SkStringPrintf("Couldn't create codec for %s.", fPath.c_str()); | 
|  | 1078 | } | 
|  | 1079 |  | 
| msarett | 9876ac5 | 2016-06-01 14:47:18 -0700 | [diff] [blame] | 1080 | // Load the dst ICC profile.  This particular dst is fairly similar to Adobe RGB. | 
| Mike Reed | 0933bc9 | 2017-12-09 01:27:41 +0000 | [diff] [blame] | 1081 | sk_sp<SkData> dstData = GetResourceAsData("icc_profiles/HP_ZR30w.icc"); | 
| msarett | 9876ac5 | 2016-06-01 14:47:18 -0700 | [diff] [blame] | 1082 | if (!dstData) { | 
|  | 1083 | return "Cannot read monitor profile.  Is the resource path set correctly?"; | 
|  | 1084 | } | 
|  | 1085 |  | 
| msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 1086 | sk_sp<SkColorSpace> dstSpace = nullptr; | 
|  | 1087 | if (kDst_sRGB_Mode == fMode) { | 
| Matt Sarett | 77a7a1b | 2017-02-07 13:56:11 -0500 | [diff] [blame] | 1088 | dstSpace = SkColorSpace::MakeSRGB(); | 
| msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 1089 | } else if (kDst_HPZR30w_Mode == fMode) { | 
| Brian Osman | 526972e | 2016-10-24 09:24:02 -0400 | [diff] [blame] | 1090 | dstSpace = SkColorSpace::MakeICC(dstData->data(), dstData->size()); | 
| msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 1091 | } | 
|  | 1092 |  | 
|  | 1093 | SkImageInfo decodeInfo = codec->getInfo().makeColorType(fColorType).makeColorSpace(dstSpace); | 
| msarett | d1ec89b | 2016-08-03 12:59:27 -0700 | [diff] [blame] | 1094 | if (kUnpremul_SkAlphaType == decodeInfo.alphaType()) { | 
|  | 1095 | decodeInfo = decodeInfo.makeAlphaType(kPremul_SkAlphaType); | 
|  | 1096 | } | 
| msarett | 2ecc35f | 2016-09-08 11:55:16 -0700 | [diff] [blame] | 1097 | if (kRGBA_F16_SkColorType == fColorType) { | 
| Brian Osman | 36703d9 | 2017-12-12 14:09:31 -0500 | [diff] [blame] | 1098 | decodeInfo = decodeInfo.makeColorSpace(decodeInfo.colorSpace()->makeLinearGamma()); | 
| msarett | 2ecc35f | 2016-09-08 11:55:16 -0700 | [diff] [blame] | 1099 | } | 
| msarett | d1ec89b | 2016-08-03 12:59:27 -0700 | [diff] [blame] | 1100 |  | 
| msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 1101 | SkImageInfo bitmapInfo = decodeInfo; | 
| Matt Sarett | f485cf9 | 2017-05-26 08:58:03 -0400 | [diff] [blame] | 1102 | set_bitmap_color_space(&bitmapInfo); | 
| msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 1103 | if (kRGBA_8888_SkColorType == decodeInfo.colorType() || | 
|  | 1104 | kBGRA_8888_SkColorType == decodeInfo.colorType()) | 
|  | 1105 | { | 
|  | 1106 | bitmapInfo = bitmapInfo.makeColorType(kN32_SkColorType); | 
|  | 1107 | } | 
|  | 1108 |  | 
|  | 1109 | SkBitmap bitmap; | 
|  | 1110 | if (!bitmap.tryAllocPixels(bitmapInfo)) { | 
|  | 1111 | return SkStringPrintf("Image(%s) is too large (%d x %d)", fPath.c_str(), | 
|  | 1112 | bitmapInfo.width(), bitmapInfo.height()); | 
|  | 1113 | } | 
|  | 1114 |  | 
|  | 1115 | size_t rowBytes = bitmap.rowBytes(); | 
|  | 1116 | SkCodec::Result r = codec->getPixels(decodeInfo, bitmap.getPixels(), rowBytes); | 
| Leon Scroggins III | 674a184 | 2017-07-06 12:26:09 -0400 | [diff] [blame] | 1117 | switch (r) { | 
|  | 1118 | case SkCodec::kSuccess: | 
|  | 1119 | case SkCodec::kErrorInInput: | 
|  | 1120 | case SkCodec::kIncompleteInput: | 
|  | 1121 | break; | 
|  | 1122 | default: | 
|  | 1123 | return SkStringPrintf("Couldn't getPixels %s. Error code %d", fPath.c_str(), r); | 
| msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 1124 | } | 
|  | 1125 |  | 
| msarett | 69deca8 | 2016-04-29 09:38:40 -0700 | [diff] [blame] | 1126 | switch (fMode) { | 
|  | 1127 | case kBaseline_Mode: | 
| msarett | 39979d8 | 2016-07-28 17:11:18 -0700 | [diff] [blame] | 1128 | case kDst_sRGB_Mode: | 
| msarett | 50ce1f2 | 2016-07-29 06:23:33 -0700 | [diff] [blame] | 1129 | case kDst_HPZR30w_Mode: | 
| Matt Sarett | 6a0feba | 2017-06-09 10:45:44 -0400 | [diff] [blame] | 1130 | // We do not support drawing unclamped F16. | 
|  | 1131 | clamp_if_necessary(bitmap, canvas->imageInfo().colorType()); | 
| msarett | 39979d8 | 2016-07-28 17:11:18 -0700 | [diff] [blame] | 1132 | canvas->drawBitmap(bitmap, 0, 0); | 
|  | 1133 | break; | 
| msarett | 69deca8 | 2016-04-29 09:38:40 -0700 | [diff] [blame] | 1134 | default: | 
|  | 1135 | SkASSERT(false); | 
|  | 1136 | return "Invalid fMode"; | 
|  | 1137 | } | 
|  | 1138 | return ""; | 
|  | 1139 | } | 
|  | 1140 |  | 
|  | 1141 | SkISize ColorCodecSrc::size() const { | 
| bungeman | 38d909e | 2016-08-02 14:40:46 -0700 | [diff] [blame] | 1142 | sk_sp<SkData> encoded(SkData::MakeFromFileName(fPath.c_str())); | 
| Mike Reed | ede7bac | 2017-07-23 15:30:02 -0400 | [diff] [blame] | 1143 | std::unique_ptr<SkCodec> codec(SkCodec::MakeFromData(encoded)); | 
| msarett | 69deca8 | 2016-04-29 09:38:40 -0700 | [diff] [blame] | 1144 | if (nullptr == codec) { | 
| Hal Canary | fafe135 | 2017-04-11 12:12:02 -0400 | [diff] [blame] | 1145 | return {0, 0}; | 
| msarett | 69deca8 | 2016-04-29 09:38:40 -0700 | [diff] [blame] | 1146 | } | 
| Hal Canary | fafe135 | 2017-04-11 12:12:02 -0400 | [diff] [blame] | 1147 | return {codec->getInfo().width(), codec->getInfo().height()}; | 
| msarett | 69deca8 | 2016-04-29 09:38:40 -0700 | [diff] [blame] | 1148 | } | 
|  | 1149 |  | 
|  | 1150 | Name ColorCodecSrc::name() const { | 
|  | 1151 | return SkOSPath::Basename(fPath.c_str()); | 
|  | 1152 | } | 
|  | 1153 |  | 
|  | 1154 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 1155 |  | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1156 | static const SkRect kSKPViewport = {0, 0, 1000, 1000}; | 
| mtklein | f4ba321 | 2015-01-28 15:32:24 -0800 | [diff] [blame] | 1157 |  | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1158 | SKPSrc::SKPSrc(Path path) : fPath(path) { } | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 1159 |  | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1160 | static sk_sp<SkPicture> read_skp(const char* path, const SkDeserialProcs* procs = nullptr) { | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1161 | std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(path); | 
| mtklein | 75d98fd | 2015-01-18 07:05:01 -0800 | [diff] [blame] | 1162 | if (!stream) { | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1163 | return nullptr; | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 1164 | } | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1165 | sk_sp<SkPicture> pic(SkPicture::MakeFromStream(stream.get(), procs)); | 
| mtklein | 75d98fd | 2015-01-18 07:05:01 -0800 | [diff] [blame] | 1166 | if (!pic) { | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1167 | return nullptr; | 
| mtklein | 75d98fd | 2015-01-18 07:05:01 -0800 | [diff] [blame] | 1168 | } | 
| bungeman | f93d711 | 2016-09-16 06:24:20 -0700 | [diff] [blame] | 1169 | stream = nullptr;  // Might as well drop this when we're done with it. | 
| joshualitt | 7c3a2f8 | 2015-03-31 13:32:05 -0700 | [diff] [blame] | 1170 |  | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1171 | return pic; | 
|  | 1172 | } | 
|  | 1173 |  | 
|  | 1174 | Error SKPSrc::draw(SkCanvas* canvas) const { | 
|  | 1175 | sk_sp<SkPicture> pic = read_skp(fPath.c_str()); | 
|  | 1176 | if (!pic) { | 
|  | 1177 | return SkStringPrintf("Couldn't read %s.", fPath.c_str()); | 
|  | 1178 | } | 
|  | 1179 |  | 
| mtklein | f4ba321 | 2015-01-28 15:32:24 -0800 | [diff] [blame] | 1180 | canvas->clipRect(kSKPViewport); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 1181 | canvas->drawPicture(pic); | 
|  | 1182 | return ""; | 
|  | 1183 | } | 
|  | 1184 |  | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1185 | static SkRect get_cull_rect_for_skp(const char* path) { | 
|  | 1186 | std::unique_ptr<SkStream> stream = SkStream::MakeFromFile(path); | 
| mtklein | ffa901a | 2015-03-16 10:38:07 -0700 | [diff] [blame] | 1187 | if (!stream) { | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1188 | return SkRect::MakeEmpty(); | 
| mtklein | ffa901a | 2015-03-16 10:38:07 -0700 | [diff] [blame] | 1189 | } | 
|  | 1190 | SkPictInfo info; | 
| Mike Reed | e7a5832 | 2017-12-20 14:09:20 -0500 | [diff] [blame] | 1191 | if (!SkPicture_StreamIsSKP(stream.get(), &info)) { | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1192 | return SkRect::MakeEmpty(); | 
| mtklein | ffa901a | 2015-03-16 10:38:07 -0700 | [diff] [blame] | 1193 | } | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1194 |  | 
|  | 1195 | return info.fCullRect; | 
|  | 1196 | } | 
|  | 1197 |  | 
|  | 1198 | SkISize SKPSrc::size() const { | 
|  | 1199 | SkRect viewport = get_cull_rect_for_skp(fPath.c_str()); | 
|  | 1200 | if (!viewport.intersect(kSKPViewport)) { | 
| Hal Canary | fafe135 | 2017-04-11 12:12:02 -0400 | [diff] [blame] | 1201 | return {0, 0}; | 
| mtklein | ffa901a | 2015-03-16 10:38:07 -0700 | [diff] [blame] | 1202 | } | 
|  | 1203 | return viewport.roundOut().size(); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 1204 | } | 
|  | 1205 |  | 
|  | 1206 | Name SKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); } | 
|  | 1207 |  | 
|  | 1208 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1209 |  | 
| Robert Phillips | 7e6dafd | 2018-03-14 12:22:45 -0400 | [diff] [blame] | 1210 | static const int kDDLViewportSize = 2048; | 
|  | 1211 | static const SkRect kDDLSKPViewport = { 0, 0, kDDLViewportSize, kDDLViewportSize }; | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1212 |  | 
|  | 1213 | DDLSKPSrc::DDLSKPSrc(Path path) : fPath(path) { } | 
|  | 1214 |  | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1215 | SkISize DDLSKPSrc::size() const { | 
|  | 1216 | SkRect viewport = get_cull_rect_for_skp(fPath.c_str()); | 
|  | 1217 | if (!viewport.intersect(kDDLSKPViewport)) { | 
|  | 1218 | return {0, 0}; | 
|  | 1219 | } | 
|  | 1220 | return viewport.roundOut().size(); | 
|  | 1221 | } | 
|  | 1222 |  | 
|  | 1223 | Name DDLSKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); } | 
|  | 1224 |  | 
|  | 1225 | #if !SK_SUPPORT_GPU | 
|  | 1226 |  | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1227 | Error DDLSKPSrc::draw(SkCanvas* canvas) const { | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1228 | return SkStringPrintf("DDLs are GPU only\n"); | 
|  | 1229 | } | 
|  | 1230 |  | 
|  | 1231 | #else | 
|  | 1232 |  | 
|  | 1233 | class PromiseImageInfo { | 
|  | 1234 | public: | 
|  | 1235 | int              fIndex; | 
|  | 1236 | sk_sp<SkImage>   fImage; | 
|  | 1237 | SkBitmap         fBitmap; | 
|  | 1238 | GrBackendTexture fBackendTexture; | 
|  | 1239 | }; | 
|  | 1240 |  | 
|  | 1241 | static void promise_image_fulfill_proc(void* textureContext, GrBackendTexture* outTexture) { | 
|  | 1242 | const PromiseImageInfo* imgInfo = static_cast<const PromiseImageInfo*>(textureContext); | 
|  | 1243 |  | 
|  | 1244 | *outTexture = imgInfo->fBackendTexture; | 
|  | 1245 | } | 
|  | 1246 |  | 
|  | 1247 | static void promise_image_release_proc(void* textureContext) { | 
|  | 1248 | // Do nothing. We free all the backend textures at the end. | 
|  | 1249 | } | 
|  | 1250 |  | 
| Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 1251 | static void promise_image_done_proc(void* textureContext) { | 
|  | 1252 | // Do nothing. | 
|  | 1253 | } | 
|  | 1254 |  | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1255 | class PromiseImageCallbackContext { | 
|  | 1256 | public: | 
|  | 1257 | const SkTArray<PromiseImageInfo>* fImageInfo; | 
|  | 1258 | SkDeferredDisplayListRecorder*    fRecorder; | 
|  | 1259 | }; | 
|  | 1260 |  | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1261 | // This generates promise images to replace the indices in the compressed picture. This | 
|  | 1262 | // reconstitution is performed separately in each thread so we end of with multiple | 
|  | 1263 | // promise image referring to the same GrBackendTexture. | 
|  | 1264 | static sk_sp<SkImage> promise_image_creator(const void* rawData, size_t length, void* ctxIn) { | 
|  | 1265 | PromiseImageCallbackContext* ctx = static_cast<PromiseImageCallbackContext*>(ctxIn); | 
|  | 1266 | const SkTArray<PromiseImageInfo>* imageInfo = ctx->fImageInfo; | 
|  | 1267 | SkDeferredDisplayListRecorder* recorder = ctx->fRecorder; | 
|  | 1268 |  | 
|  | 1269 | SkASSERT(length == sizeof(int)); | 
|  | 1270 |  | 
|  | 1271 | const int* indexPtr = static_cast<const int*>(rawData); | 
|  | 1272 | SkASSERT(*indexPtr < imageInfo->count()); | 
|  | 1273 |  | 
|  | 1274 | const PromiseImageInfo& curImage = (*imageInfo)[*indexPtr]; | 
|  | 1275 | SkASSERT(curImage.fIndex == *indexPtr); | 
|  | 1276 |  | 
| Robert Phillips | 7f44196 | 2018-03-15 11:15:19 -0400 | [diff] [blame] | 1277 | GrBackendFormat backendFormat = curImage.fBackendTexture.format(); | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1278 |  | 
|  | 1279 | // DDL TODO: sort out mipmapping | 
|  | 1280 | sk_sp<SkImage> image = recorder->makePromiseTexture(backendFormat, | 
|  | 1281 | curImage.fBitmap.width(), | 
|  | 1282 | curImage.fBitmap.height(), | 
|  | 1283 | GrMipMapped::kNo, | 
|  | 1284 | GrSurfaceOrigin::kTopLeft_GrSurfaceOrigin, | 
|  | 1285 | curImage.fBitmap.colorType(), | 
|  | 1286 | curImage.fBitmap.alphaType(), | 
|  | 1287 | curImage.fBitmap.refColorSpace(), | 
|  | 1288 | promise_image_fulfill_proc, | 
|  | 1289 | promise_image_release_proc, | 
| Greg Daniel | 7278d68 | 2018-03-16 14:57:21 -0400 | [diff] [blame] | 1290 | promise_image_done_proc, | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1291 | (void*) &curImage); | 
|  | 1292 | SkASSERT(image); | 
|  | 1293 | return image; | 
|  | 1294 | }; | 
|  | 1295 |  | 
| Robert Phillips | 7e6dafd | 2018-03-14 12:22:45 -0400 | [diff] [blame] | 1296 | // DDL TODO: it would be great if we could draw the DDL directly into the destination SkSurface | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1297 | Error DDLSKPSrc::draw(SkCanvas* canvas) const { | 
|  | 1298 | GrContext* context = canvas->getGrContext(); | 
|  | 1299 | if (!context) { | 
|  | 1300 | return SkStringPrintf("DDLs are GPU only\n"); | 
|  | 1301 | } | 
|  | 1302 |  | 
| Robert Phillips | 7e6dafd | 2018-03-14 12:22:45 -0400 | [diff] [blame] | 1303 | if (1 == FLAGS_ddl) { | 
|  | 1304 | // If the number of x & y tiles is one just perform normal (non-DDL) rendering for | 
|  | 1305 | // comparison purposes | 
|  | 1306 | sk_sp<SkPicture> picture = read_skp(fPath.c_str()); | 
|  | 1307 | if (!picture) { | 
|  | 1308 | return SkStringPrintf("Couldn't read %s.", fPath.c_str()); | 
|  | 1309 | } | 
|  | 1310 |  | 
|  | 1311 | canvas->clipRect(kDDLSKPViewport); | 
|  | 1312 | canvas->drawPicture(std::move(picture)); | 
|  | 1313 | return ""; | 
|  | 1314 | } | 
|  | 1315 |  | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1316 | class TileData { | 
|  | 1317 | public: | 
|  | 1318 | // Note: we could just pass in surface characterization | 
|  | 1319 | TileData(sk_sp<SkSurface> surf, const SkIRect& clip) | 
|  | 1320 | : fSurface(std::move(surf)) | 
|  | 1321 | , fClip(clip) { | 
|  | 1322 | SkAssertResult(fSurface->characterize(&fCharacterization)); | 
|  | 1323 | } | 
|  | 1324 |  | 
|  | 1325 | // This method operates in parallel | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1326 | // In each thread we will reconvert the compressedPictureData into an SkPicture | 
|  | 1327 | // replacing each image-index with a promise image. | 
|  | 1328 | void preprocess(SkData* compressedPictureData, | 
|  | 1329 | const SkTArray<PromiseImageInfo>* imageInfo) { | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1330 | SkDeferredDisplayListRecorder recorder(fCharacterization); | 
|  | 1331 |  | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1332 | // DDL TODO: the DDLRecorder's GrContext isn't initialized until getCanvas is called. | 
|  | 1333 | // Maybe set it up in the ctor? | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1334 | SkCanvas* subCanvas = recorder.getCanvas(); | 
|  | 1335 |  | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1336 | sk_sp<SkPicture> reconstitutedPicture; | 
|  | 1337 |  | 
|  | 1338 | { | 
|  | 1339 | PromiseImageCallbackContext callbackCtx = { imageInfo, &recorder }; | 
|  | 1340 |  | 
|  | 1341 | SkDeserialProcs procs; | 
|  | 1342 | procs.fImageCtx = &callbackCtx; | 
|  | 1343 | procs.fImageProc = promise_image_creator; | 
|  | 1344 |  | 
|  | 1345 | reconstitutedPicture = SkPicture::MakeFromData(compressedPictureData, &procs); | 
|  | 1346 | if (!reconstitutedPicture) { | 
|  | 1347 | return; | 
|  | 1348 | } | 
|  | 1349 | } | 
|  | 1350 |  | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1351 | subCanvas->clipRect(SkRect::MakeWH(fClip.width(), fClip.height())); | 
|  | 1352 | subCanvas->translate(-fClip.fLeft, -fClip.fTop); | 
|  | 1353 |  | 
|  | 1354 | // Note: in this use case we only render a picture to the deferred canvas | 
|  | 1355 | // but, more generally, clients will use arbitrary draw calls. | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1356 | subCanvas->drawPicture(reconstitutedPicture); | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1357 |  | 
|  | 1358 | fDisplayList = recorder.detach(); | 
|  | 1359 | } | 
|  | 1360 |  | 
|  | 1361 | // This method operates serially | 
|  | 1362 | void draw() { | 
|  | 1363 | fSurface->draw(fDisplayList.get()); | 
|  | 1364 | } | 
|  | 1365 |  | 
|  | 1366 | // This method also operates serially | 
|  | 1367 | void compose(SkCanvas* dst) { | 
|  | 1368 | sk_sp<SkImage> img = fSurface->makeImageSnapshot(); | 
|  | 1369 | dst->save(); | 
|  | 1370 | dst->clipRect(SkRect::Make(fClip)); | 
|  | 1371 | dst->drawImage(std::move(img), fClip.fLeft, fClip.fTop); | 
|  | 1372 | dst->restore(); | 
|  | 1373 | } | 
|  | 1374 |  | 
|  | 1375 | private: | 
|  | 1376 | sk_sp<SkSurface> fSurface; | 
|  | 1377 | SkIRect          fClip;    // in the device space of the destination canvas | 
|  | 1378 | std::unique_ptr<SkDeferredDisplayList> fDisplayList; | 
|  | 1379 | SkSurfaceCharacterization              fCharacterization; | 
|  | 1380 | }; | 
|  | 1381 |  | 
|  | 1382 | SkTArray<TileData> tileData; | 
|  | 1383 | tileData.reserve(16); | 
|  | 1384 |  | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1385 | SkTArray<PromiseImageInfo> imageInfo; | 
|  | 1386 | sk_sp<SkData> compressedPictureData; | 
| Robert Phillips | 7e6dafd | 2018-03-14 12:22:45 -0400 | [diff] [blame] | 1387 |  | 
|  | 1388 | SkIRect viewport;  // this is our ultimate final drawing area/rect | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1389 |  | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1390 | // DDL TODO: should we also be deduping in the following preprocessing? | 
|  | 1391 |  | 
|  | 1392 | // Massage the input picture into something we can use with DDL | 
|  | 1393 | { | 
|  | 1394 | // In the first pass we read in an .skp file into an SkPicture recording all the images | 
|  | 1395 | // and getting a copy of their pixels in an uploadable form. | 
|  | 1396 | sk_sp<SkPicture> firstPassPicture; | 
|  | 1397 | { | 
|  | 1398 | SkDeserialProcs procs; | 
|  | 1399 |  | 
|  | 1400 | procs.fImageCtx = &imageInfo; | 
|  | 1401 | procs.fImageProc = [](const void* rawData, size_t length, void* ctx) -> sk_sp<SkImage> { | 
|  | 1402 | auto imageInfo = static_cast<SkTArray<PromiseImageInfo>*>(ctx); | 
|  | 1403 |  | 
|  | 1404 | sk_sp<SkData> data = SkData::MakeWithCopy(rawData, length); | 
|  | 1405 |  | 
|  | 1406 | PromiseImageInfo newImageInfo; | 
|  | 1407 | newImageInfo.fIndex = imageInfo->count(); | 
|  | 1408 | newImageInfo.fImage = SkImage::MakeFromEncoded(std::move(data)); | 
|  | 1409 | SkAssertResult(newImageInfo.fImage->asLegacyBitmap(&newImageInfo.fBitmap)); | 
|  | 1410 |  | 
|  | 1411 | imageInfo->push_back(newImageInfo); | 
|  | 1412 | return newImageInfo.fImage; | 
|  | 1413 | }; | 
|  | 1414 |  | 
|  | 1415 | firstPassPicture = read_skp(fPath.c_str(), &procs); | 
|  | 1416 | if (!firstPassPicture) { | 
|  | 1417 | return SkStringPrintf("Couldn't read %s.", fPath.c_str()); | 
|  | 1418 | } | 
|  | 1419 |  | 
| Robert Phillips | 7e6dafd | 2018-03-14 12:22:45 -0400 | [diff] [blame] | 1420 | SkRect pictureCullRect = firstPassPicture->cullRect(); | 
|  | 1421 | SkAssertResult(pictureCullRect.intersect(kDDLSKPViewport)); | 
|  | 1422 | viewport = pictureCullRect.roundOut(); | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1423 | } | 
|  | 1424 |  | 
|  | 1425 | // In the second pass we convert the SkPicture into SkData replacing all the SkImages | 
|  | 1426 | // with an index into the imageInfo we collected in the first pass. | 
|  | 1427 | { | 
|  | 1428 | SkSerialProcs procs; | 
|  | 1429 |  | 
|  | 1430 | procs.fImageCtx = &imageInfo; | 
|  | 1431 | procs.fImageProc = [](SkImage* image, void* ctx) -> sk_sp<SkData> { | 
|  | 1432 | auto imageInfo = static_cast<const SkTArray<PromiseImageInfo>*>(ctx); | 
|  | 1433 |  | 
|  | 1434 | int i; | 
|  | 1435 | for (i = 0; i < imageInfo->count(); ++i) { | 
|  | 1436 | if ((*imageInfo)[i].fImage.get() == image) { | 
|  | 1437 | break; | 
|  | 1438 | } | 
|  | 1439 | } | 
|  | 1440 |  | 
|  | 1441 | SkASSERT(i < imageInfo->count()); | 
|  | 1442 | return SkData::MakeWithCopy(&i, sizeof(i)); | 
|  | 1443 | }; | 
|  | 1444 |  | 
|  | 1445 | compressedPictureData = firstPassPicture->serialize(&procs); | 
|  | 1446 | if (!compressedPictureData) { | 
|  | 1447 | return SkStringPrintf("Couldn't re-serialize %s.", fPath.c_str()); | 
|  | 1448 | } | 
|  | 1449 | } | 
|  | 1450 |  | 
|  | 1451 | // In the third pass we go through all the images and upload them to the GPU and | 
|  | 1452 | // get rid of the SkImage from the first pass | 
|  | 1453 | { | 
|  | 1454 | GrGpu* gpu = context->contextPriv().getGpu(); | 
|  | 1455 | if (!gpu) { | 
|  | 1456 | return SkStringPrintf("Couldn't get GPU from GrContext\n"); | 
|  | 1457 | } | 
|  | 1458 |  | 
|  | 1459 | for (int i = 0; i < imageInfo.count(); ++i) { | 
|  | 1460 | // DDL TODO: how can we tell if we need mipmapping! | 
|  | 1461 | imageInfo[i].fBackendTexture = gpu->createTestingOnlyBackendTexture( | 
|  | 1462 | imageInfo[i].fBitmap.getPixels(), | 
|  | 1463 | imageInfo[i].fBitmap.width(), | 
|  | 1464 | imageInfo[i].fBitmap.height(), | 
|  | 1465 | imageInfo[i].fBitmap.colorType(), | 
|  | 1466 | false, GrMipMapped::kNo); | 
|  | 1467 | SkAssertResult(imageInfo[i].fBackendTexture.isValid()); | 
|  | 1468 | imageInfo[i].fImage = nullptr; // we don't need this anymore | 
|  | 1469 | } | 
|  | 1470 | } | 
|  | 1471 | } | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1472 |  | 
| Robert Phillips | 7e6dafd | 2018-03-14 12:22:45 -0400 | [diff] [blame] | 1473 | int xTileSize = viewport.width()/FLAGS_ddl; | 
|  | 1474 | int yTileSize = viewport.height()/FLAGS_ddl; | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1475 |  | 
|  | 1476 | // First, create the destination tiles | 
| Robert Phillips | 7e6dafd | 2018-03-14 12:22:45 -0400 | [diff] [blame] | 1477 | for (int y = 0, yOff = 0; y < FLAGS_ddl; ++y, yOff += yTileSize) { | 
|  | 1478 | int ySize = (y < FLAGS_ddl-1) ? yTileSize : viewport.height()-yOff; | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1479 |  | 
| Robert Phillips | 7e6dafd | 2018-03-14 12:22:45 -0400 | [diff] [blame] | 1480 | for (int x = 0, xOff = 0; x < FLAGS_ddl; ++x, xOff += xTileSize) { | 
|  | 1481 | int xSize = (x < FLAGS_ddl-1) ? xTileSize : viewport.width()-xOff; | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1482 |  | 
| Robert Phillips | 7e6dafd | 2018-03-14 12:22:45 -0400 | [diff] [blame] | 1483 | SkIRect clip = SkIRect::MakeXYWH(xOff, yOff, xSize, ySize); | 
|  | 1484 |  | 
|  | 1485 | SkASSERT(viewport.contains(clip)); | 
|  | 1486 |  | 
|  | 1487 | SkImageInfo tileII = SkImageInfo::MakeN32Premul(xSize, ySize); | 
|  | 1488 |  | 
|  | 1489 | tileData.push_back(TileData(canvas->makeSurface(tileII), clip)); | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1490 | } | 
|  | 1491 | } | 
|  | 1492 |  | 
|  | 1493 | // Second, run the cpu pre-processing in threads | 
|  | 1494 | SkTaskGroup().batch(tileData.count(), [&](int i) { | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1495 | tileData[i].preprocess(compressedPictureData.get(), &imageInfo); | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1496 | }); | 
|  | 1497 |  | 
|  | 1498 | // Third, synchronously render the display lists into the dest tiles | 
|  | 1499 | // TODO: it would be cool to not wait until all the tiles are drawn to begin | 
|  | 1500 | // drawing to the GPU | 
|  | 1501 | for (int i = 0; i < tileData.count(); ++i) { | 
|  | 1502 | tileData[i].draw(); | 
|  | 1503 | } | 
|  | 1504 |  | 
|  | 1505 | // Finally, compose the drawn tiles into the result | 
|  | 1506 | // Note: the separation between the tiles and the final composition better | 
|  | 1507 | // matches Chrome but costs us a copy | 
|  | 1508 | for (int i = 0; i < tileData.count(); ++i) { | 
|  | 1509 | tileData[i].compose(canvas); | 
|  | 1510 | } | 
|  | 1511 |  | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1512 | // All promise images need to be fulfulled before leaving this method since we are about to | 
|  | 1513 | // delete their backing GrBackendTextures | 
|  | 1514 | context->flush(); | 
|  | 1515 |  | 
|  | 1516 | // Clean up VRAM | 
|  | 1517 | { | 
|  | 1518 | GrGpu* gpu = context->contextPriv().getGpu(); | 
|  | 1519 | if (!gpu) { | 
|  | 1520 | return SkStringPrintf("Couldn't get GPU from GrContext\n"); | 
|  | 1521 | } | 
|  | 1522 |  | 
|  | 1523 | for (int i = 0; i < imageInfo.count(); ++i) { | 
|  | 1524 | gpu->deleteTestingOnlyBackendTexture(imageInfo[i].fBackendTexture); | 
|  | 1525 | } | 
|  | 1526 | } | 
|  | 1527 |  | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1528 | return ""; | 
|  | 1529 | } | 
|  | 1530 |  | 
| Robert Phillips | e4aae34 | 2018-03-14 10:26:57 -0400 | [diff] [blame] | 1531 | #endif | 
| Robert Phillips | ad8a43f | 2017-08-30 12:06:35 -0400 | [diff] [blame] | 1532 |  | 
| Florin Malita | fc043dc | 2017-12-31 11:08:42 -0500 | [diff] [blame] | 1533 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 1534 |  | 
| Florin Malita | 124d5af | 2017-12-31 17:02:26 -0500 | [diff] [blame] | 1535 | #if !defined(SK_BUILD_FOR_GOOGLE3) | 
| Florin Malita | 54f65c4 | 2018-01-16 17:04:30 -0500 | [diff] [blame] | 1536 | SkottieSrc::SkottieSrc(Path path) | 
| Florin Malita | fc043dc | 2017-12-31 11:08:42 -0500 | [diff] [blame] | 1537 | : fName(SkOSPath::Basename(path.c_str())) { | 
|  | 1538 |  | 
| Florin Malita | 54f65c4 | 2018-01-16 17:04:30 -0500 | [diff] [blame] | 1539 | fAnimation  = skottie::Animation::MakeFromFile(path.c_str()); | 
| Florin Malita | fc043dc | 2017-12-31 11:08:42 -0500 | [diff] [blame] | 1540 | if (!fAnimation) { | 
|  | 1541 | return; | 
|  | 1542 | } | 
|  | 1543 |  | 
|  | 1544 | // Fit kTileCount x kTileCount frames to a 1000x1000 film strip. | 
|  | 1545 | static constexpr SkScalar kTargetSize = 1000; | 
| Florin Malita | 3fae0f3 | 2018-03-15 21:52:54 -0400 | [diff] [blame^] | 1546 | fTileSize = SkSize::Make(kTargetSize / kTileCount, kTargetSize / kTileCount).toCeil(); | 
| Florin Malita | fc043dc | 2017-12-31 11:08:42 -0500 | [diff] [blame] | 1547 | } | 
|  | 1548 |  | 
| Florin Malita | 54f65c4 | 2018-01-16 17:04:30 -0500 | [diff] [blame] | 1549 | Error SkottieSrc::draw(SkCanvas* canvas) const { | 
| Florin Malita | fc043dc | 2017-12-31 11:08:42 -0500 | [diff] [blame] | 1550 | if (!fAnimation) { | 
|  | 1551 | return SkStringPrintf("Unable to parse file: %s", fName.c_str()); | 
|  | 1552 | } | 
|  | 1553 |  | 
|  | 1554 | canvas->drawColor(SK_ColorWHITE); | 
|  | 1555 |  | 
| Florin Malita | fc043dc | 2017-12-31 11:08:42 -0500 | [diff] [blame] | 1556 | const auto ip = fAnimation->inPoint() * 1000 / fAnimation->frameRate(), | 
|  | 1557 | op = fAnimation->outPoint() * 1000 / fAnimation->frameRate(), | 
|  | 1558 | fr = (op - ip) / (kTileCount * kTileCount - 1); | 
|  | 1559 |  | 
| Florin Malita | d3c1b84 | 2018-01-27 12:43:24 -0500 | [diff] [blame] | 1560 | // Shuffled order to exercise non-linear frame progression. | 
|  | 1561 | static constexpr int frames[] = { 4, 0, 3, 1, 2 }; | 
|  | 1562 | static_assert(SK_ARRAY_COUNT(frames) == kTileCount, ""); | 
|  | 1563 |  | 
| Florin Malita | fc043dc | 2017-12-31 11:08:42 -0500 | [diff] [blame] | 1564 | for (int i = 0; i < kTileCount; ++i) { | 
| Florin Malita | 3fae0f3 | 2018-03-15 21:52:54 -0400 | [diff] [blame^] | 1565 | const SkScalar y = frames[i] * fTileSize.height(); | 
| Florin Malita | fc043dc | 2017-12-31 11:08:42 -0500 | [diff] [blame] | 1566 |  | 
|  | 1567 | for (int j = 0; j < kTileCount; ++j) { | 
| Florin Malita | 3fae0f3 | 2018-03-15 21:52:54 -0400 | [diff] [blame^] | 1568 | const SkScalar x = frames[j] * fTileSize.width(); | 
| Florin Malita | fc043dc | 2017-12-31 11:08:42 -0500 | [diff] [blame] | 1569 | SkRect dest = SkRect::MakeXYWH(x, y, fTileSize.width(), fTileSize.height()); | 
|  | 1570 |  | 
| Florin Malita | d3c1b84 | 2018-01-27 12:43:24 -0500 | [diff] [blame] | 1571 | const auto t = fr * (frames[i] * kTileCount + frames[j]); | 
| Florin Malita | df2713c | 2018-01-09 15:51:21 -0500 | [diff] [blame] | 1572 | { | 
|  | 1573 | SkAutoCanvasRestore acr(canvas, true); | 
| Florin Malita | d3c1b84 | 2018-01-27 12:43:24 -0500 | [diff] [blame] | 1574 | canvas->clipRect(dest, true); | 
| Florin Malita | df2713c | 2018-01-09 15:51:21 -0500 | [diff] [blame] | 1575 | canvas->concat(SkMatrix::MakeRectToRect(SkRect::MakeSize(fAnimation->size()), | 
|  | 1576 | dest, | 
| Florin Malita | 3fae0f3 | 2018-03-15 21:52:54 -0400 | [diff] [blame^] | 1577 | SkMatrix::kCenter_ScaleToFit)); | 
| Florin Malita | df2713c | 2018-01-09 15:51:21 -0500 | [diff] [blame] | 1578 |  | 
|  | 1579 | fAnimation->animationTick(t); | 
|  | 1580 | fAnimation->render(canvas); | 
|  | 1581 | } | 
| Florin Malita | fc043dc | 2017-12-31 11:08:42 -0500 | [diff] [blame] | 1582 | } | 
|  | 1583 | } | 
|  | 1584 |  | 
|  | 1585 | return ""; | 
|  | 1586 | } | 
|  | 1587 |  | 
| Florin Malita | 54f65c4 | 2018-01-16 17:04:30 -0500 | [diff] [blame] | 1588 | SkISize SkottieSrc::size() const { | 
| Florin Malita | 3fae0f3 | 2018-03-15 21:52:54 -0400 | [diff] [blame^] | 1589 | return SkISize::Make(kTileCount * fTileSize.width(), | 
|  | 1590 | kTileCount * fTileSize.height()); | 
| Florin Malita | fc043dc | 2017-12-31 11:08:42 -0500 | [diff] [blame] | 1591 | } | 
|  | 1592 |  | 
| Florin Malita | 54f65c4 | 2018-01-16 17:04:30 -0500 | [diff] [blame] | 1593 | Name SkottieSrc::name() const { return fName; } | 
| Florin Malita | fc043dc | 2017-12-31 11:08:42 -0500 | [diff] [blame] | 1594 |  | 
| Florin Malita | 54f65c4 | 2018-01-16 17:04:30 -0500 | [diff] [blame] | 1595 | bool SkottieSrc::veto(SinkFlags flags) const { | 
| Florin Malita | fc043dc | 2017-12-31 11:08:42 -0500 | [diff] [blame] | 1596 | // No need to test to non-(raster||gpu||vector) or indirect backends. | 
|  | 1597 | bool type_ok = flags.type == SinkFlags::kRaster | 
|  | 1598 | || flags.type == SinkFlags::kGPU | 
|  | 1599 | || flags.type == SinkFlags::kVector; | 
|  | 1600 |  | 
|  | 1601 | return !type_ok || flags.approach != SinkFlags::kDirect; | 
|  | 1602 | } | 
| Florin Malita | 124d5af | 2017-12-31 17:02:26 -0500 | [diff] [blame] | 1603 | #endif | 
| Florin Malita | fc043dc | 2017-12-31 11:08:42 -0500 | [diff] [blame] | 1604 |  | 
|  | 1605 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
| fmalita | a2b9fdf | 2016-08-03 19:53:36 -0700 | [diff] [blame] | 1606 | #if defined(SK_XML) | 
| fmalita | bdf3e5c | 2016-09-17 07:26:26 -0700 | [diff] [blame] | 1607 | // Used when the image doesn't have an intrinsic size. | 
| Hal Canary | fafe135 | 2017-04-11 12:12:02 -0400 | [diff] [blame] | 1608 | static const SkSize kDefaultSVGSize = {1000, 1000}; | 
| fmalita | a2b9fdf | 2016-08-03 19:53:36 -0700 | [diff] [blame] | 1609 |  | 
| fmalita | bdf3e5c | 2016-09-17 07:26:26 -0700 | [diff] [blame] | 1610 | // Used to force-scale tiny fixed-size images. | 
| Hal Canary | fafe135 | 2017-04-11 12:12:02 -0400 | [diff] [blame] | 1611 | static const SkSize kMinimumSVGSize = {128, 128}; | 
| fmalita | a2b9fdf | 2016-08-03 19:53:36 -0700 | [diff] [blame] | 1612 |  | 
| fmalita | acd2f5c | 2016-11-08 07:13:45 -0800 | [diff] [blame] | 1613 | SVGSrc::SVGSrc(Path path) | 
|  | 1614 | : fName(SkOSPath::Basename(path.c_str())) | 
|  | 1615 | , fScale(1) { | 
| fmalita | bdf3e5c | 2016-09-17 07:26:26 -0700 | [diff] [blame] | 1616 |  | 
| fmalita | acd2f5c | 2016-11-08 07:13:45 -0800 | [diff] [blame] | 1617 | SkFILEStream stream(path.c_str()); | 
|  | 1618 | if (!stream.isValid()) { | 
|  | 1619 | return; | 
|  | 1620 | } | 
|  | 1621 | fDom = SkSVGDOM::MakeFromStream(stream); | 
|  | 1622 | if (!fDom) { | 
|  | 1623 | return; | 
|  | 1624 | } | 
|  | 1625 |  | 
|  | 1626 | const SkSize& sz = fDom->containerSize(); | 
|  | 1627 | if (sz.isEmpty()) { | 
|  | 1628 | // no intrinsic size | 
|  | 1629 | fDom->setContainerSize(kDefaultSVGSize); | 
|  | 1630 | } else { | 
|  | 1631 | fScale = SkTMax(1.f, SkTMax(kMinimumSVGSize.width()  / sz.width(), | 
|  | 1632 | kMinimumSVGSize.height() / sz.height())); | 
|  | 1633 | } | 
|  | 1634 | } | 
|  | 1635 |  | 
|  | 1636 | Error SVGSrc::draw(SkCanvas* canvas) const { | 
| fmalita | bdf3e5c | 2016-09-17 07:26:26 -0700 | [diff] [blame] | 1637 | if (!fDom) { | 
| fmalita | acd2f5c | 2016-11-08 07:13:45 -0800 | [diff] [blame] | 1638 | return SkStringPrintf("Unable to parse file: %s", fName.c_str()); | 
| fmalita | a2b9fdf | 2016-08-03 19:53:36 -0700 | [diff] [blame] | 1639 | } | 
|  | 1640 |  | 
| fmalita | acd2f5c | 2016-11-08 07:13:45 -0800 | [diff] [blame] | 1641 | SkAutoCanvasRestore acr(canvas, true); | 
|  | 1642 | canvas->scale(fScale, fScale); | 
|  | 1643 | fDom->render(canvas); | 
|  | 1644 |  | 
| fmalita | a2b9fdf | 2016-08-03 19:53:36 -0700 | [diff] [blame] | 1645 | return ""; | 
|  | 1646 | } | 
|  | 1647 |  | 
|  | 1648 | SkISize SVGSrc::size() const { | 
| fmalita | acd2f5c | 2016-11-08 07:13:45 -0800 | [diff] [blame] | 1649 | if (!fDom) { | 
| Hal Canary | fafe135 | 2017-04-11 12:12:02 -0400 | [diff] [blame] | 1650 | return {0, 0}; | 
| fmalita | bdf3e5c | 2016-09-17 07:26:26 -0700 | [diff] [blame] | 1651 | } | 
|  | 1652 |  | 
| Hal Canary | fafe135 | 2017-04-11 12:12:02 -0400 | [diff] [blame] | 1653 | return SkSize{fDom->containerSize().width() * fScale, fDom->containerSize().height() * fScale} | 
|  | 1654 | .toRound(); | 
| fmalita | a2b9fdf | 2016-08-03 19:53:36 -0700 | [diff] [blame] | 1655 | } | 
|  | 1656 |  | 
| fmalita | acd2f5c | 2016-11-08 07:13:45 -0800 | [diff] [blame] | 1657 | Name SVGSrc::name() const { return fName; } | 
| fmalita | a2b9fdf | 2016-08-03 19:53:36 -0700 | [diff] [blame] | 1658 |  | 
| fmalita | 179d885 | 2016-08-16 14:23:29 -0700 | [diff] [blame] | 1659 | bool SVGSrc::veto(SinkFlags flags) const { | 
| Florin Malita | 93323eb | 2017-06-16 15:31:17 -0400 | [diff] [blame] | 1660 | // No need to test to non-(raster||gpu||vector) or indirect backends. | 
| fmalita | 179d885 | 2016-08-16 14:23:29 -0700 | [diff] [blame] | 1661 | bool type_ok = flags.type == SinkFlags::kRaster | 
| Florin Malita | 93323eb | 2017-06-16 15:31:17 -0400 | [diff] [blame] | 1662 | || flags.type == SinkFlags::kGPU | 
|  | 1663 | || flags.type == SinkFlags::kVector; | 
| fmalita | 179d885 | 2016-08-16 14:23:29 -0700 | [diff] [blame] | 1664 |  | 
|  | 1665 | return !type_ok || flags.approach != SinkFlags::kDirect; | 
|  | 1666 | } | 
|  | 1667 |  | 
| fmalita | a2b9fdf | 2016-08-03 19:53:36 -0700 | [diff] [blame] | 1668 | #endif // defined(SK_XML) | 
|  | 1669 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 1670 |  | 
| halcanary | 45420a9 | 2016-06-02 12:41:14 -0700 | [diff] [blame] | 1671 | MSKPSrc::MSKPSrc(Path path) : fPath(path) { | 
| bungeman | f93d711 | 2016-09-16 06:24:20 -0700 | [diff] [blame] | 1672 | std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str()); | 
| Hal Canary | 45cde31 | 2017-04-03 16:06:42 -0400 | [diff] [blame] | 1673 | int count = SkMultiPictureDocumentReadPageCount(stream.get()); | 
|  | 1674 | if (count > 0) { | 
|  | 1675 | fPages.reset(count); | 
|  | 1676 | (void)SkMultiPictureDocumentReadPageSizes(stream.get(), &fPages[0], fPages.count()); | 
|  | 1677 | } | 
| halcanary | 45420a9 | 2016-06-02 12:41:14 -0700 | [diff] [blame] | 1678 | } | 
|  | 1679 |  | 
| Hal Canary | 45cde31 | 2017-04-03 16:06:42 -0400 | [diff] [blame] | 1680 | int MSKPSrc::pageCount() const { return fPages.count(); } | 
| halcanary | 45420a9 | 2016-06-02 12:41:14 -0700 | [diff] [blame] | 1681 |  | 
|  | 1682 | SkISize MSKPSrc::size() const { return this->size(0); } | 
| Hal Canary | 45cde31 | 2017-04-03 16:06:42 -0400 | [diff] [blame] | 1683 | SkISize MSKPSrc::size(int i) const { | 
| Hal Canary | fafe135 | 2017-04-11 12:12:02 -0400 | [diff] [blame] | 1684 | return i >= 0 && i < fPages.count() ? fPages[i].fSize.toCeil() : SkISize{0, 0}; | 
| Hal Canary | 45cde31 | 2017-04-03 16:06:42 -0400 | [diff] [blame] | 1685 | } | 
| halcanary | 45420a9 | 2016-06-02 12:41:14 -0700 | [diff] [blame] | 1686 |  | 
|  | 1687 | Error MSKPSrc::draw(SkCanvas* c) const { return this->draw(0, c); } | 
|  | 1688 | Error MSKPSrc::draw(int i, SkCanvas* canvas) const { | 
| Hal Canary | 45cde31 | 2017-04-03 16:06:42 -0400 | [diff] [blame] | 1689 | if (this->pageCount() == 0) { | 
| halcanary | 45420a9 | 2016-06-02 12:41:14 -0700 | [diff] [blame] | 1690 | return SkStringPrintf("Unable to parse MultiPictureDocument file: %s", fPath.c_str()); | 
|  | 1691 | } | 
| Hal Canary | 45cde31 | 2017-04-03 16:06:42 -0400 | [diff] [blame] | 1692 | if (i >= fPages.count() || i < 0) { | 
| halcanary | 45420a9 | 2016-06-02 12:41:14 -0700 | [diff] [blame] | 1693 | return SkStringPrintf("MultiPictureDocument page number out of range: %d", i); | 
|  | 1694 | } | 
| Hal Canary | 45cde31 | 2017-04-03 16:06:42 -0400 | [diff] [blame] | 1695 | SkPicture* page = fPages[i].fPicture.get(); | 
| halcanary | 45420a9 | 2016-06-02 12:41:14 -0700 | [diff] [blame] | 1696 | if (!page) { | 
| Hal Canary | 45cde31 | 2017-04-03 16:06:42 -0400 | [diff] [blame] | 1697 | std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(fPath.c_str()); | 
|  | 1698 | if (!stream) { | 
|  | 1699 | return SkStringPrintf("Unable to open file: %s", fPath.c_str()); | 
|  | 1700 | } | 
|  | 1701 | if (!SkMultiPictureDocumentRead(stream.get(), &fPages[0], fPages.count())) { | 
|  | 1702 | return SkStringPrintf("SkMultiPictureDocument reader failed on page %d: %s", i, | 
|  | 1703 | fPath.c_str()); | 
|  | 1704 | } | 
|  | 1705 | page = fPages[i].fPicture.get(); | 
| halcanary | 45420a9 | 2016-06-02 12:41:14 -0700 | [diff] [blame] | 1706 | } | 
|  | 1707 | canvas->drawPicture(page); | 
|  | 1708 | return ""; | 
|  | 1709 | } | 
|  | 1710 |  | 
|  | 1711 | Name MSKPSrc::name() const { return SkOSPath::Basename(fPath.c_str()); } | 
|  | 1712 |  | 
|  | 1713 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 1714 |  | 
| mtklein | ad66f9b | 2015-02-13 15:11:10 -0800 | [diff] [blame] | 1715 | Error NullSink::draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const { | 
| Mike Reed | 5df4934 | 2016-11-12 08:06:55 -0600 | [diff] [blame] | 1716 | return src.draw(SkMakeNullCanvas().get()); | 
| mtklein | ad66f9b | 2015-02-13 15:11:10 -0800 | [diff] [blame] | 1717 | } | 
|  | 1718 |  | 
|  | 1719 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 1720 |  | 
| Brian Osman | e5756ec | 2017-09-06 17:08:30 -0400 | [diff] [blame] | 1721 | static bool encode_png_base64(const SkBitmap& bitmap, SkString* dst) { | 
|  | 1722 | SkPixmap pm; | 
|  | 1723 | if (!bitmap.peekPixels(&pm)) { | 
|  | 1724 | dst->set("peekPixels failed"); | 
|  | 1725 | return false; | 
|  | 1726 | } | 
|  | 1727 |  | 
|  | 1728 | // We're going to embed this PNG in a data URI, so make it as small as possible | 
|  | 1729 | SkPngEncoder::Options options; | 
|  | 1730 | options.fFilterFlags = SkPngEncoder::FilterFlag::kAll; | 
|  | 1731 | options.fZLibLevel = 9; | 
|  | 1732 | options.fUnpremulBehavior = pm.colorSpace() ? SkTransferFunctionBehavior::kRespect | 
|  | 1733 | : SkTransferFunctionBehavior::kIgnore; | 
|  | 1734 |  | 
|  | 1735 | SkDynamicMemoryWStream wStream; | 
|  | 1736 | if (!SkPngEncoder::Encode(&wStream, pm, options)) { | 
|  | 1737 | dst->set("SkPngEncoder::Encode failed"); | 
|  | 1738 | return false; | 
|  | 1739 | } | 
|  | 1740 |  | 
|  | 1741 | sk_sp<SkData> pngData = wStream.detachAsData(); | 
|  | 1742 | size_t len = SkBase64::Encode(pngData->data(), pngData->size(), nullptr); | 
|  | 1743 |  | 
|  | 1744 | // The PNG can be almost arbitrarily large. We don't want to fill our logs with enormous URLs. | 
|  | 1745 | // Infra says these can be pretty big, as long as we're only outputting them on failure. | 
|  | 1746 | static const size_t kMaxBase64Length = 1024 * 1024; | 
|  | 1747 | if (len > kMaxBase64Length) { | 
|  | 1748 | dst->printf("Encoded image too large (%u bytes)", static_cast<uint32_t>(len)); | 
|  | 1749 | return false; | 
|  | 1750 | } | 
|  | 1751 |  | 
|  | 1752 | dst->resize(len); | 
|  | 1753 | SkBase64::Encode(pngData->data(), pngData->size(), dst->writable_str()); | 
|  | 1754 | return true; | 
|  | 1755 | } | 
|  | 1756 |  | 
|  | 1757 | static Error compare_bitmaps(const SkBitmap& reference, const SkBitmap& bitmap) { | 
|  | 1758 | // The dimensions are a property of the Src only, and so should be identical. | 
| Mike Reed | f0ffb89 | 2017-10-03 14:47:21 -0400 | [diff] [blame] | 1759 | SkASSERT(reference.computeByteSize() == bitmap.computeByteSize()); | 
|  | 1760 | if (reference.computeByteSize() != bitmap.computeByteSize()) { | 
| Brian Osman | e5756ec | 2017-09-06 17:08:30 -0400 | [diff] [blame] | 1761 | return "Dimensions don't match reference"; | 
|  | 1762 | } | 
|  | 1763 | // All SkBitmaps in DM are tight, so this comparison is easy. | 
| Mike Reed | f0ffb89 | 2017-10-03 14:47:21 -0400 | [diff] [blame] | 1764 | if (0 != memcmp(reference.getPixels(), bitmap.getPixels(), reference.computeByteSize())) { | 
| Brian Osman | e5756ec | 2017-09-06 17:08:30 -0400 | [diff] [blame] | 1765 | SkString encoded; | 
|  | 1766 | SkString errString("Pixels don't match reference"); | 
|  | 1767 | if (encode_png_base64(reference, &encoded)) { | 
|  | 1768 | errString.append("\nExpected: data:image/png;base64,"); | 
|  | 1769 | errString.append(encoded); | 
|  | 1770 | } else { | 
|  | 1771 | errString.append("\nExpected image failed to encode: "); | 
|  | 1772 | errString.append(encoded); | 
|  | 1773 | } | 
|  | 1774 | if (encode_png_base64(bitmap, &encoded)) { | 
|  | 1775 | errString.append("\nActual: data:image/png;base64,"); | 
|  | 1776 | errString.append(encoded); | 
|  | 1777 | } else { | 
|  | 1778 | errString.append("\nActual image failed to encode: "); | 
|  | 1779 | errString.append(encoded); | 
|  | 1780 | } | 
|  | 1781 | return errString; | 
|  | 1782 | } | 
|  | 1783 | return ""; | 
|  | 1784 | } | 
|  | 1785 |  | 
|  | 1786 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 1787 |  | 
| mtklein | b9eb4ac | 2015-02-02 18:26:03 -0800 | [diff] [blame] | 1788 | DEFINE_bool(gpuStats, false, "Append GPU stats to the log for each GPU task?"); | 
|  | 1789 |  | 
| bsalomon | 85b4b53 | 2016-04-05 11:06:27 -0700 | [diff] [blame] | 1790 | GPUSink::GPUSink(GrContextFactory::ContextType ct, | 
| csmartdalton | e812d49 | 2017-02-21 12:36:05 -0700 | [diff] [blame] | 1791 | GrContextFactory::ContextOverrides overrides, | 
| Brian Salomon | f865b05 | 2018-03-09 09:01:53 -0500 | [diff] [blame] | 1792 | SkCommandLineConfigGpu::SurfType surfType, | 
| mtklein | 82d2843 | 2015-01-15 12:46:02 -0800 | [diff] [blame] | 1793 | int samples, | 
| bsalomon | afcd7cd | 2015-08-31 12:39:41 -0700 | [diff] [blame] | 1794 | bool diText, | 
| brianosman | d93c120 | 2016-03-10 07:49:08 -0800 | [diff] [blame] | 1795 | SkColorType colorType, | 
| Brian Salomon | ce5ee60 | 2017-07-17 11:31:31 -0400 | [diff] [blame] | 1796 | SkAlphaType alphaType, | 
| brianosman | b109b8c | 2016-06-16 13:03:24 -0700 | [diff] [blame] | 1797 | sk_sp<SkColorSpace> colorSpace, | 
| Brian Osman | f21aa04 | 2017-08-21 16:48:46 -0400 | [diff] [blame] | 1798 | bool threaded, | 
|  | 1799 | const GrContextOptions& grCtxOptions) | 
| Brian Salomon | ce5ee60 | 2017-07-17 11:31:31 -0400 | [diff] [blame] | 1800 | : fContextType(ct) | 
|  | 1801 | , fContextOverrides(overrides) | 
| Brian Salomon | f865b05 | 2018-03-09 09:01:53 -0500 | [diff] [blame] | 1802 | , fSurfType(surfType) | 
| Brian Salomon | ce5ee60 | 2017-07-17 11:31:31 -0400 | [diff] [blame] | 1803 | , fSampleCount(samples) | 
|  | 1804 | , fUseDIText(diText) | 
|  | 1805 | , fColorType(colorType) | 
|  | 1806 | , fAlphaType(alphaType) | 
|  | 1807 | , fColorSpace(std::move(colorSpace)) | 
| Brian Osman | f21aa04 | 2017-08-21 16:48:46 -0400 | [diff] [blame] | 1808 | , fThreaded(threaded) | 
|  | 1809 | , fBaseContextOptions(grCtxOptions) {} | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 1810 |  | 
| Brian Salomon | 09d994e | 2016-12-21 11:14:46 -0500 | [diff] [blame] | 1811 | DEFINE_bool(drawOpClip, false, "Clip each GrDrawOp to its device bounds for testing."); | 
| bsalomon | 648c696 | 2015-10-23 09:06:59 -0700 | [diff] [blame] | 1812 |  | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 1813 | Error GPUSink::draw(const Src& src, SkBitmap* dst, SkWStream* dstStream, SkString* log) const { | 
|  | 1814 | return this->onDraw(src, dst, dstStream, log, fBaseContextOptions); | 
|  | 1815 | } | 
|  | 1816 |  | 
|  | 1817 | Error GPUSink::onDraw(const Src& src, SkBitmap* dst, SkWStream*, SkString* log, | 
|  | 1818 | const GrContextOptions& baseOptions) const { | 
|  | 1819 | GrContextOptions grOptions = baseOptions; | 
| kkinnunen | 64492c4 | 2015-12-08 01:24:40 -0800 | [diff] [blame] | 1820 |  | 
| kkinnunen | 5219fd9 | 2015-12-10 06:28:13 -0800 | [diff] [blame] | 1821 | src.modifyGrContextOptions(&grOptions); | 
|  | 1822 |  | 
|  | 1823 | GrContextFactory factory(grOptions); | 
| mtklein | f4ba321 | 2015-01-28 15:32:24 -0800 | [diff] [blame] | 1824 | const SkISize size = src.size(); | 
| Brian Salomon | ce5ee60 | 2017-07-17 11:31:31 -0400 | [diff] [blame] | 1825 | SkImageInfo info = | 
|  | 1826 | SkImageInfo::Make(size.width(), size.height(), fColorType, fAlphaType, fColorSpace); | 
| Brian Salomon | f865b05 | 2018-03-09 09:01:53 -0500 | [diff] [blame] | 1827 | sk_sp<SkSurface> surface; | 
| msarett | 13a036b | 2016-02-08 09:10:47 -0800 | [diff] [blame] | 1828 | #if SK_SUPPORT_GPU | 
| csmartdalton | e812d49 | 2017-02-21 12:36:05 -0700 | [diff] [blame] | 1829 | GrContext* context = factory.getContextInfo(fContextType, fContextOverrides).grContext(); | 
| bsalomon | 8b7451a | 2016-05-11 06:33:06 -0700 | [diff] [blame] | 1830 | const int maxDimension = context->caps()->maxTextureSize(); | 
| msarett | 13a036b | 2016-02-08 09:10:47 -0800 | [diff] [blame] | 1831 | if (maxDimension < SkTMax(size.width(), size.height())) { | 
|  | 1832 | return Error::Nonfatal("Src too large to create a texture.\n"); | 
|  | 1833 | } | 
| Brian Salomon | f865b05 | 2018-03-09 09:01:53 -0500 | [diff] [blame] | 1834 | uint32_t flags = fUseDIText ? SkSurfaceProps::kUseDeviceIndependentFonts_Flag : 0; | 
|  | 1835 | SkSurfaceProps props(flags, SkSurfaceProps::kLegacyFontHost_InitType); | 
|  | 1836 | GrBackendTexture backendTexture; | 
|  | 1837 | GrBackendRenderTarget backendRT; | 
|  | 1838 | switch (fSurfType) { | 
|  | 1839 | case SkCommandLineConfigGpu::SurfType::kDefault: | 
|  | 1840 | surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info, fSampleCount, | 
|  | 1841 | &props); | 
|  | 1842 | break; | 
|  | 1843 | case SkCommandLineConfigGpu::SurfType::kBackendTexture: | 
|  | 1844 | backendTexture = context->contextPriv().getGpu()->createTestingOnlyBackendTexture( | 
|  | 1845 | nullptr, info.width(), info.height(), info.colorType(), true, GrMipMapped::kNo); | 
|  | 1846 | surface = SkSurface::MakeFromBackendTexture(context, backendTexture, | 
|  | 1847 | kTopLeft_GrSurfaceOrigin, fSampleCount, | 
| Brian Salomon | 5370677 | 2018-03-19 14:18:08 -0400 | [diff] [blame] | 1848 | fColorType, info.refColorSpace(), &props); | 
| Brian Salomon | f865b05 | 2018-03-09 09:01:53 -0500 | [diff] [blame] | 1849 | break; | 
|  | 1850 | case SkCommandLineConfigGpu::SurfType::kBackendRenderTarget: | 
|  | 1851 | if (1 == fSampleCount) { | 
|  | 1852 | auto srgbEncoded = info.colorSpace() && info.colorSpace()->gammaCloseToSRGB() | 
|  | 1853 | ? GrSRGBEncoded::kYes | 
|  | 1854 | : GrSRGBEncoded::kNo; | 
|  | 1855 | auto colorType = SkColorTypeToGrColorType(info.colorType()); | 
|  | 1856 | backendRT = context->contextPriv().getGpu()->createTestingOnlyBackendRenderTarget( | 
|  | 1857 | info.width(), info.height(), colorType, srgbEncoded); | 
|  | 1858 | surface = SkSurface::MakeFromBackendRenderTarget(context, backendRT, | 
|  | 1859 | kBottomLeft_GrSurfaceOrigin, | 
|  | 1860 | info.refColorSpace(), &props); | 
|  | 1861 | } | 
|  | 1862 | break; | 
|  | 1863 | } | 
| msarett | 13a036b | 2016-02-08 09:10:47 -0800 | [diff] [blame] | 1864 | #endif | 
|  | 1865 |  | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 1866 | if (!surface) { | 
|  | 1867 | return "Could not create a surface."; | 
|  | 1868 | } | 
| joshualitt | 5f5a8d7 | 2015-02-25 14:09:45 -0800 | [diff] [blame] | 1869 | if (FLAGS_preAbandonGpuContext) { | 
| joshualitt | 5f5a8d7 | 2015-02-25 14:09:45 -0800 | [diff] [blame] | 1870 | factory.abandonContexts(); | 
|  | 1871 | } | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 1872 | SkCanvas* canvas = surface->getCanvas(); | 
|  | 1873 | Error err = src.draw(canvas); | 
|  | 1874 | if (!err.isEmpty()) { | 
|  | 1875 | return err; | 
|  | 1876 | } | 
|  | 1877 | canvas->flush(); | 
| mtklein | b9eb4ac | 2015-02-02 18:26:03 -0800 | [diff] [blame] | 1878 | if (FLAGS_gpuStats) { | 
| Robert Phillips | 0c4b7b1 | 2018-03-06 08:20:37 -0500 | [diff] [blame] | 1879 | #if SK_SUPPORT_GPU | 
|  | 1880 | canvas->getGrContext()->contextPriv().dumpCacheStats(log); | 
|  | 1881 | canvas->getGrContext()->contextPriv().dumpGpuStats(log); | 
|  | 1882 | #endif | 
| mtklein | b9eb4ac | 2015-02-02 18:26:03 -0800 | [diff] [blame] | 1883 | } | 
| Brian Salomon | ce5ee60 | 2017-07-17 11:31:31 -0400 | [diff] [blame] | 1884 | if (info.colorType() == kRGB_565_SkColorType || info.colorType() == kARGB_4444_SkColorType) { | 
|  | 1885 | // We don't currently support readbacks into these formats on the GPU backend. Convert to | 
|  | 1886 | // 32 bit. | 
|  | 1887 | info = SkImageInfo::Make(size.width(), size.height(), kRGBA_8888_SkColorType, | 
|  | 1888 | kPremul_SkAlphaType, fColorSpace); | 
|  | 1889 | } | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 1890 | dst->allocPixels(info); | 
| Mike Reed | 12e946b | 2017-04-17 10:53:29 -0400 | [diff] [blame] | 1891 | canvas->readPixels(*dst, 0, 0); | 
| mtklein | 55e88b2 | 2015-01-21 15:50:13 -0800 | [diff] [blame] | 1892 | if (FLAGS_abandonGpuContext) { | 
|  | 1893 | factory.abandonContexts(); | 
| bsalomon | 6e2aad4 | 2016-04-01 11:54:31 -0700 | [diff] [blame] | 1894 | } else if (FLAGS_releaseAndAbandonGpuContext) { | 
|  | 1895 | factory.releaseResourcesAndAbandonContexts(); | 
| mtklein | 55e88b2 | 2015-01-21 15:50:13 -0800 | [diff] [blame] | 1896 | } | 
| Brian Salomon | f865b05 | 2018-03-09 09:01:53 -0500 | [diff] [blame] | 1897 | #if SK_SUPPORT_GPU | 
|  | 1898 | if (!context->contextPriv().abandoned()) { | 
|  | 1899 | surface.reset(); | 
|  | 1900 | if (backendTexture.isValid()) { | 
| Brian Salomon | 26102cb | 2018-03-09 09:33:19 -0500 | [diff] [blame] | 1901 | context->contextPriv().getGpu()->deleteTestingOnlyBackendTexture(backendTexture); | 
| Brian Salomon | f865b05 | 2018-03-09 09:01:53 -0500 | [diff] [blame] | 1902 | } | 
|  | 1903 | if (backendRT.isValid()) { | 
|  | 1904 | context->contextPriv().getGpu()->deleteTestingOnlyBackendRenderTarget(backendRT); | 
|  | 1905 | } | 
|  | 1906 | } | 
|  | 1907 | #endif | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 1908 | return ""; | 
|  | 1909 | } | 
|  | 1910 |  | 
|  | 1911 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 1912 |  | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 1913 | GPUThreadTestingSink::GPUThreadTestingSink(GrContextFactory::ContextType ct, | 
|  | 1914 | GrContextFactory::ContextOverrides overrides, | 
| Brian Salomon | f865b05 | 2018-03-09 09:01:53 -0500 | [diff] [blame] | 1915 | SkCommandLineConfigGpu::SurfType surfType, | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 1916 | int samples, | 
|  | 1917 | bool diText, | 
|  | 1918 | SkColorType colorType, | 
|  | 1919 | SkAlphaType alphaType, | 
|  | 1920 | sk_sp<SkColorSpace> colorSpace, | 
|  | 1921 | bool threaded, | 
|  | 1922 | const GrContextOptions& grCtxOptions) | 
| Brian Salomon | f865b05 | 2018-03-09 09:01:53 -0500 | [diff] [blame] | 1923 | : INHERITED(ct, overrides, surfType, samples, diText, colorType, alphaType, | 
|  | 1924 | std::move(colorSpace), threaded, grCtxOptions) | 
| Chris Dalton | 040238b | 2017-12-18 14:22:34 -0700 | [diff] [blame] | 1925 | #if SK_SUPPORT_GPU | 
| Mike Klein | 022cfa2 | 2017-09-01 11:53:16 -0400 | [diff] [blame] | 1926 | , fExecutor(SkExecutor::MakeFIFOThreadPool(FLAGS_gpuThreads)) { | 
| Chris Dalton | 040238b | 2017-12-18 14:22:34 -0700 | [diff] [blame] | 1927 | #else | 
|  | 1928 | , fExecutor(nullptr) { | 
|  | 1929 | #endif | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 1930 | SkASSERT(fExecutor); | 
|  | 1931 | } | 
|  | 1932 |  | 
|  | 1933 | Error GPUThreadTestingSink::draw(const Src& src, SkBitmap* dst, SkWStream* wStream, | 
|  | 1934 | SkString* log) const { | 
|  | 1935 | // Draw twice, once with worker threads, and once without. Verify that we get the same result. | 
|  | 1936 | // Also, force us to only use the software path renderer, so we really stress-test the threaded | 
|  | 1937 | // version of that code. | 
|  | 1938 | GrContextOptions contextOptions = this->baseContextOptions(); | 
| Brian Osman | 195c05b | 2017-08-30 15:14:04 -0400 | [diff] [blame] | 1939 | contextOptions.fGpuPathRenderers = GpuPathRenderers::kNone; | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 1940 |  | 
|  | 1941 | contextOptions.fExecutor = fExecutor.get(); | 
|  | 1942 | Error err = this->onDraw(src, dst, wStream, log, contextOptions); | 
|  | 1943 | if (!err.isEmpty() || !dst) { | 
|  | 1944 | return err; | 
|  | 1945 | } | 
|  | 1946 |  | 
|  | 1947 | SkBitmap reference; | 
|  | 1948 | SkString refLog; | 
|  | 1949 | SkDynamicMemoryWStream refStream; | 
|  | 1950 | contextOptions.fExecutor = nullptr; | 
|  | 1951 | Error refErr = this->onDraw(src, &reference, &refStream, &refLog, contextOptions); | 
|  | 1952 | if (!refErr.isEmpty()) { | 
|  | 1953 | return refErr; | 
|  | 1954 | } | 
|  | 1955 |  | 
| Brian Osman | e5756ec | 2017-09-06 17:08:30 -0400 | [diff] [blame] | 1956 | return compare_bitmaps(reference, *dst); | 
| Brian Osman | f981066 | 2017-08-30 10:02:10 -0400 | [diff] [blame] | 1957 | } | 
|  | 1958 |  | 
|  | 1959 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 1960 |  | 
| halcanary | 47ef4d5 | 2015-03-03 09:13:09 -0800 | [diff] [blame] | 1961 | static Error draw_skdocument(const Src& src, SkDocument* doc, SkWStream* dst) { | 
| halcanary | 4ba051c | 2016-03-10 10:31:53 -0800 | [diff] [blame] | 1962 | if (src.size().isEmpty()) { | 
|  | 1963 | return "Source has empty dimensions"; | 
|  | 1964 | } | 
| halcanary | 47ef4d5 | 2015-03-03 09:13:09 -0800 | [diff] [blame] | 1965 | SkASSERT(doc); | 
| halcanary | 45420a9 | 2016-06-02 12:41:14 -0700 | [diff] [blame] | 1966 | int pageCount = src.pageCount(); | 
|  | 1967 | for (int i = 0; i < pageCount; ++i) { | 
|  | 1968 | int width = src.size(i).width(), height = src.size(i).height(); | 
| halcanary | 7e79818 | 2015-04-14 14:06:18 -0700 | [diff] [blame] | 1969 | SkCanvas* canvas = | 
|  | 1970 | doc->beginPage(SkIntToScalar(width), SkIntToScalar(height)); | 
|  | 1971 | if (!canvas) { | 
| halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 1972 | return "SkDocument::beginPage(w,h) returned nullptr"; | 
| halcanary | 7e79818 | 2015-04-14 14:06:18 -0700 | [diff] [blame] | 1973 | } | 
| halcanary | 45420a9 | 2016-06-02 12:41:14 -0700 | [diff] [blame] | 1974 | Error err = src.draw(i, canvas); | 
| halcanary | 7e79818 | 2015-04-14 14:06:18 -0700 | [diff] [blame] | 1975 | if (!err.isEmpty()) { | 
|  | 1976 | return err; | 
|  | 1977 | } | 
|  | 1978 | doc->endPage(); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 1979 | } | 
| reed | d14df7c | 2016-09-22 14:12:46 -0700 | [diff] [blame] | 1980 | doc->close(); | 
| halcanary | fd4a993 | 2015-01-28 11:45:58 -0800 | [diff] [blame] | 1981 | dst->flush(); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 1982 | return ""; | 
|  | 1983 | } | 
|  | 1984 |  | 
| halcanary | 47ef4d5 | 2015-03-03 09:13:09 -0800 | [diff] [blame] | 1985 | Error PDFSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { | 
| halcanary | 4b65666 | 2016-04-27 07:45:18 -0700 | [diff] [blame] | 1986 | SkDocument::PDFMetadata metadata; | 
|  | 1987 | metadata.fTitle = src.name(); | 
|  | 1988 | metadata.fSubject = "rendering correctness test"; | 
|  | 1989 | metadata.fCreator = "Skia/DM"; | 
| Mike Reed | a4daf19 | 2017-12-14 13:25:04 -0500 | [diff] [blame] | 1990 | metadata.fRasterDPI = fRasterDpi; | 
|  | 1991 | metadata.fPDFA = fPDFA; | 
|  | 1992 | sk_sp<SkDocument> doc = SkDocument::MakePDF(dst, metadata); | 
| halcanary | 47ef4d5 | 2015-03-03 09:13:09 -0800 | [diff] [blame] | 1993 | if (!doc) { | 
| halcanary | 4b65666 | 2016-04-27 07:45:18 -0700 | [diff] [blame] | 1994 | return "SkDocument::MakePDF() returned nullptr"; | 
| halcanary | 47ef4d5 | 2015-03-03 09:13:09 -0800 | [diff] [blame] | 1995 | } | 
|  | 1996 | return draw_skdocument(src, doc.get(), dst); | 
|  | 1997 | } | 
|  | 1998 |  | 
|  | 1999 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2000 |  | 
|  | 2001 | XPSSink::XPSSink() {} | 
|  | 2002 |  | 
| Hal Canary | abc88d2 | 2017-02-06 09:26:49 -0500 | [diff] [blame] | 2003 | #ifdef SK_BUILD_FOR_WIN | 
| Hal Canary | 5e221e7 | 2017-02-06 09:51:42 -0500 | [diff] [blame] | 2004 | static SkTScopedComPtr<IXpsOMObjectFactory> make_xps_factory() { | 
|  | 2005 | IXpsOMObjectFactory* factory; | 
|  | 2006 | HRN(CoCreateInstance(CLSID_XpsOMObjectFactory, | 
|  | 2007 | nullptr, | 
|  | 2008 | CLSCTX_INPROC_SERVER, | 
|  | 2009 | IID_PPV_ARGS(&factory))); | 
|  | 2010 | return SkTScopedComPtr<IXpsOMObjectFactory>(factory); | 
|  | 2011 | } | 
|  | 2012 |  | 
|  | 2013 | Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { | 
| Hal Canary | abc88d2 | 2017-02-06 09:26:49 -0500 | [diff] [blame] | 2014 | SkAutoCoInitialize com; | 
|  | 2015 | if (!com.succeeded()) { | 
|  | 2016 | return "Could not initialize COM."; | 
|  | 2017 | } | 
| Hal Canary | 5e221e7 | 2017-02-06 09:51:42 -0500 | [diff] [blame] | 2018 | SkTScopedComPtr<IXpsOMObjectFactory> factory = make_xps_factory(); | 
|  | 2019 | if (!factory) { | 
|  | 2020 | return "Failed to create XPS Factory."; | 
|  | 2021 | } | 
|  | 2022 | sk_sp<SkDocument> doc(SkDocument::MakeXPS(dst, factory.get())); | 
| halcanary | 47ef4d5 | 2015-03-03 09:13:09 -0800 | [diff] [blame] | 2023 | if (!doc) { | 
| halcanary | 4b65666 | 2016-04-27 07:45:18 -0700 | [diff] [blame] | 2024 | return "SkDocument::MakeXPS() returned nullptr"; | 
| halcanary | 47ef4d5 | 2015-03-03 09:13:09 -0800 | [diff] [blame] | 2025 | } | 
|  | 2026 | return draw_skdocument(src, doc.get(), dst); | 
|  | 2027 | } | 
| Hal Canary | 5e221e7 | 2017-02-06 09:51:42 -0500 | [diff] [blame] | 2028 | #else | 
|  | 2029 | Error XPSSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { | 
|  | 2030 | return "XPS not supported on this platform."; | 
|  | 2031 | } | 
|  | 2032 | #endif | 
| reed | 54dc487 | 2016-09-13 08:09:45 -0700 | [diff] [blame] | 2033 |  | 
|  | 2034 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2035 |  | 
|  | 2036 | PipeSink::PipeSink() {} | 
|  | 2037 |  | 
|  | 2038 | Error PipeSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { | 
|  | 2039 | return src.draw(SkPipeSerializer().beginWrite(SkRect::Make(src.size()), dst)); | 
|  | 2040 | } | 
|  | 2041 |  | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2042 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2043 |  | 
| mtklein | 9c3f17d | 2015-01-28 11:35:18 -0800 | [diff] [blame] | 2044 | SKPSink::SKPSink() {} | 
|  | 2045 |  | 
| mtklein | b9eb4ac | 2015-02-02 18:26:03 -0800 | [diff] [blame] | 2046 | Error SKPSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { | 
| mtklein | 9c3f17d | 2015-01-28 11:35:18 -0800 | [diff] [blame] | 2047 | SkSize size; | 
|  | 2048 | size = src.size(); | 
|  | 2049 | SkPictureRecorder recorder; | 
|  | 2050 | Error err = src.draw(recorder.beginRecording(size.width(), size.height())); | 
|  | 2051 | if (!err.isEmpty()) { | 
|  | 2052 | return err; | 
|  | 2053 | } | 
| reed | ca2622b | 2016-03-18 07:25:55 -0700 | [diff] [blame] | 2054 | recorder.finishRecordingAsPicture()->serialize(dst); | 
| mtklein | 9c3f17d | 2015-01-28 11:35:18 -0800 | [diff] [blame] | 2055 | return ""; | 
|  | 2056 | } | 
|  | 2057 |  | 
|  | 2058 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2059 |  | 
| Hal Canary | 85c7fe8 | 2016-10-25 10:33:27 -0400 | [diff] [blame] | 2060 | Error DebugSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { | 
|  | 2061 | SkDebugCanvas debugCanvas(src.size().width(), src.size().height()); | 
|  | 2062 | Error err = src.draw(&debugCanvas); | 
|  | 2063 | if (!err.isEmpty()) { | 
|  | 2064 | return err; | 
|  | 2065 | } | 
| Mike Reed | 5df4934 | 2016-11-12 08:06:55 -0600 | [diff] [blame] | 2066 | std::unique_ptr<SkCanvas> nullCanvas = SkMakeNullCanvas(); | 
| Hal Canary | 85c7fe8 | 2016-10-25 10:33:27 -0400 | [diff] [blame] | 2067 | UrlDataManager dataManager(SkString("data")); | 
|  | 2068 | Json::Value json = debugCanvas.toJSON( | 
|  | 2069 | dataManager, debugCanvas.getSize(), nullCanvas.get()); | 
|  | 2070 | std::string value = Json::StyledWriter().write(json); | 
|  | 2071 | return dst->write(value.c_str(), value.size()) ? "" : "SkWStream Error"; | 
|  | 2072 | } | 
|  | 2073 |  | 
|  | 2074 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2075 |  | 
| Bryce Thomas | 95a7b76 | 2018-03-02 13:54:21 -0800 | [diff] [blame] | 2076 | SVGSink::SVGSink(int pageIndex) : fPageIndex(pageIndex) {} | 
| mtklein | 8a4527e | 2015-01-31 20:00:58 -0800 | [diff] [blame] | 2077 |  | 
| mtklein | b9eb4ac | 2015-02-02 18:26:03 -0800 | [diff] [blame] | 2078 | Error SVGSink::draw(const Src& src, SkBitmap*, SkWStream* dst, SkString*) const { | 
| fmalita | 718df0a | 2016-07-15 10:33:29 -0700 | [diff] [blame] | 2079 | #if defined(SK_XML) | 
| Bryce Thomas | 95a7b76 | 2018-03-02 13:54:21 -0800 | [diff] [blame] | 2080 | if (src.pageCount() > 1) { | 
|  | 2081 | int pageCount = src.pageCount(); | 
|  | 2082 | if (fPageIndex > pageCount - 1) { | 
|  | 2083 | return Error(SkStringPrintf("Page index %d too high for document with only %d pages.", | 
|  | 2084 | fPageIndex, pageCount)); | 
|  | 2085 | } | 
|  | 2086 | } | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 2087 | std::unique_ptr<SkXMLWriter> xmlWriter(new SkXMLStreamWriter(dst)); | 
| Bryce Thomas | 95a7b76 | 2018-03-02 13:54:21 -0800 | [diff] [blame] | 2088 | return src.draw(fPageIndex, | 
|  | 2089 | SkSVGCanvas::Make(SkRect::MakeWH(SkIntToScalar(src.size().width()), | 
| Mike Reed | 5df4934 | 2016-11-12 08:06:55 -0600 | [diff] [blame] | 2090 | SkIntToScalar(src.size().height())), | 
| Bryce Thomas | 95a7b76 | 2018-03-02 13:54:21 -0800 | [diff] [blame] | 2091 | xmlWriter.get()) | 
|  | 2092 | .get()); | 
| fmalita | 718df0a | 2016-07-15 10:33:29 -0700 | [diff] [blame] | 2093 | #else | 
|  | 2094 | return Error("SVG sink is disabled."); | 
|  | 2095 | #endif // SK_XML | 
| mtklein | 8a4527e | 2015-01-31 20:00:58 -0800 | [diff] [blame] | 2096 | } | 
|  | 2097 |  | 
|  | 2098 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2099 |  | 
| brianosman | b109b8c | 2016-06-16 13:03:24 -0700 | [diff] [blame] | 2100 | RasterSink::RasterSink(SkColorType colorType, sk_sp<SkColorSpace> colorSpace) | 
| mtklein | 27c3fdd | 2016-02-26 14:43:21 -0800 | [diff] [blame] | 2101 | : fColorType(colorType) | 
| brianosman | b109b8c | 2016-06-16 13:03:24 -0700 | [diff] [blame] | 2102 | , fColorSpace(std::move(colorSpace)) {} | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2103 |  | 
| Yuqian Li | b8b6253 | 2018-02-23 14:13:36 +0800 | [diff] [blame] | 2104 | void RasterSink::allocPixels(const Src& src, SkBitmap* dst) const { | 
| mtklein | f4ba321 | 2015-01-28 15:32:24 -0800 | [diff] [blame] | 2105 | const SkISize size = src.size(); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2106 | // If there's an appropriate alpha type for this color type, use it, otherwise use premul. | 
|  | 2107 | SkAlphaType alphaType = kPremul_SkAlphaType; | 
|  | 2108 | (void)SkColorTypeValidateAlphaType(fColorType, alphaType, &alphaType); | 
|  | 2109 |  | 
| Mike Reed | 086a427 | 2017-07-18 10:53:11 -0400 | [diff] [blame] | 2110 | dst->allocPixelsFlags(SkImageInfo::Make(size.width(), size.height(), | 
|  | 2111 | fColorType, alphaType, fColorSpace), | 
|  | 2112 | SkBitmap::kZeroPixels_AllocFlag); | 
| Yuqian Li | b8b6253 | 2018-02-23 14:13:36 +0800 | [diff] [blame] | 2113 | } | 
|  | 2114 |  | 
|  | 2115 | Error RasterSink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const { | 
|  | 2116 | this->allocPixels(src, dst); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2117 | SkCanvas canvas(*dst); | 
|  | 2118 | return src.draw(&canvas); | 
|  | 2119 | } | 
|  | 2120 |  | 
|  | 2121 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2122 |  | 
| Yuqian Li | b8b6253 | 2018-02-23 14:13:36 +0800 | [diff] [blame] | 2123 | ThreadedSink::ThreadedSink(SkColorType colorType, sk_sp<SkColorSpace> colorSpace) | 
|  | 2124 | : RasterSink(colorType, colorSpace) | 
|  | 2125 | , fExecutor(SkExecutor::MakeFIFOThreadPool(FLAGS_backendThreads)) { | 
|  | 2126 | } | 
|  | 2127 |  | 
|  | 2128 | Error ThreadedSink::draw(const Src& src, SkBitmap* dst, SkWStream* stream, SkString* str) const { | 
|  | 2129 | this->allocPixels(src, dst); | 
|  | 2130 |  | 
|  | 2131 | std::unique_ptr<SkThreadedBMPDevice> device(new SkThreadedBMPDevice( | 
|  | 2132 | *dst, FLAGS_backendTiles, FLAGS_backendThreads, fExecutor.get())); | 
|  | 2133 | std::unique_ptr<SkCanvas> canvas(new SkCanvas(device.get())); | 
|  | 2134 | Error result = src.draw(canvas.get()); | 
|  | 2135 | canvas->flush(); | 
|  | 2136 | return result; | 
|  | 2137 |  | 
|  | 2138 | // ??? yuqian:  why does the following give me segmentation fault while the above one works? | 
|  | 2139 | //              The seg fault occurs right in the beginning of ThreadedSink::draw with invalid | 
|  | 2140 | //              memory address (it would crash without even calling this->allocPixels). | 
|  | 2141 |  | 
|  | 2142 | // SkThreadedBMPDevice device(*dst, tileCnt, FLAGS_cpuThreads, fExecutor.get()); | 
|  | 2143 | // SkCanvas canvas(&device); | 
|  | 2144 | // Error result = src.draw(&canvas); | 
|  | 2145 | // canvas.flush(); | 
|  | 2146 | // return result; | 
|  | 2147 | } | 
|  | 2148 |  | 
|  | 2149 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2150 |  | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2151 | // Handy for front-patching a Src.  Do whatever up-front work you need, then call draw_to_canvas(), | 
| mtklein | e44b508 | 2015-05-07 10:53:34 -0700 | [diff] [blame] | 2152 | // passing the Sink draw() arguments, a size, and a function draws into an SkCanvas. | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2153 | // Several examples below. | 
|  | 2154 |  | 
| mtklein | cbf8978 | 2016-02-19 14:27:14 -0800 | [diff] [blame] | 2155 | template <typename Fn> | 
| msarett | 62d3b10 | 2015-12-10 15:14:27 -0800 | [diff] [blame] | 2156 | static Error draw_to_canvas(Sink* sink, SkBitmap* bitmap, SkWStream* stream, SkString* log, | 
| mtklein | cbf8978 | 2016-02-19 14:27:14 -0800 | [diff] [blame] | 2157 | SkISize size, const Fn& draw) { | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2158 | class ProxySrc : public Src { | 
|  | 2159 | public: | 
| mtklein | cbf8978 | 2016-02-19 14:27:14 -0800 | [diff] [blame] | 2160 | ProxySrc(SkISize size, const Fn& draw) : fSize(size), fDraw(draw) {} | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2161 | Error   draw(SkCanvas* canvas) const override { return fDraw(canvas); } | 
| halcanary | b4a7f14 | 2016-03-30 08:31:27 -0700 | [diff] [blame] | 2162 | Name    name() const override { return "ProxySrc"; } | 
|  | 2163 | SkISize size() const override { return fSize; } | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2164 | private: | 
| mtklein | cbf8978 | 2016-02-19 14:27:14 -0800 | [diff] [blame] | 2165 | SkISize   fSize; | 
|  | 2166 | const Fn& fDraw; | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2167 | }; | 
| msarett | 62d3b10 | 2015-12-10 15:14:27 -0800 | [diff] [blame] | 2168 | return sink->draw(ProxySrc(size, draw), bitmap, stream, log); | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2169 | } | 
|  | 2170 |  | 
|  | 2171 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2172 |  | 
| mtklein | 4a34ecb | 2016-01-08 10:19:35 -0800 | [diff] [blame] | 2173 | DEFINE_bool(check, true, "If true, have most Via- modes fail if they affect the output."); | 
|  | 2174 |  | 
|  | 2175 | // Is *bitmap identical to what you get drawing src into sink? | 
|  | 2176 | static Error check_against_reference(const SkBitmap* bitmap, const Src& src, Sink* sink) { | 
|  | 2177 | // We can only check raster outputs. | 
|  | 2178 | // (Non-raster outputs like .pdf, .skp, .svg may differ but still draw identically.) | 
|  | 2179 | if (FLAGS_check && bitmap) { | 
|  | 2180 | SkBitmap reference; | 
|  | 2181 | SkString log; | 
| halcanary | b4a7f14 | 2016-03-30 08:31:27 -0700 | [diff] [blame] | 2182 | SkDynamicMemoryWStream wStream; | 
|  | 2183 | Error err = sink->draw(src, &reference, &wStream, &log); | 
| mtklein | 4a34ecb | 2016-01-08 10:19:35 -0800 | [diff] [blame] | 2184 | // If we can draw into this Sink via some pipeline, we should be able to draw directly. | 
|  | 2185 | SkASSERT(err.isEmpty()); | 
|  | 2186 | if (!err.isEmpty()) { | 
|  | 2187 | return err; | 
|  | 2188 | } | 
| Brian Osman | e5756ec | 2017-09-06 17:08:30 -0400 | [diff] [blame] | 2189 | return compare_bitmaps(reference, *bitmap); | 
| mtklein | 4a34ecb | 2016-01-08 10:19:35 -0800 | [diff] [blame] | 2190 | } | 
|  | 2191 | return ""; | 
|  | 2192 | } | 
|  | 2193 |  | 
|  | 2194 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2195 |  | 
| mtklein | d603b22 | 2015-02-17 11:13:33 -0800 | [diff] [blame] | 2196 | static SkISize auto_compute_translate(SkMatrix* matrix, int srcW, int srcH) { | 
|  | 2197 | SkRect bounds = SkRect::MakeIWH(srcW, srcH); | 
|  | 2198 | matrix->mapRect(&bounds); | 
|  | 2199 | matrix->postTranslate(-bounds.x(), -bounds.y()); | 
| Hal Canary | fafe135 | 2017-04-11 12:12:02 -0400 | [diff] [blame] | 2200 | return {SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height())}; | 
| mtklein | d603b22 | 2015-02-17 11:13:33 -0800 | [diff] [blame] | 2201 | } | 
|  | 2202 |  | 
| msarett | 62d3b10 | 2015-12-10 15:14:27 -0800 | [diff] [blame] | 2203 | ViaMatrix::ViaMatrix(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {} | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2204 |  | 
| mtklein | b9eb4ac | 2015-02-02 18:26:03 -0800 | [diff] [blame] | 2205 | Error ViaMatrix::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2206 | SkMatrix matrix = fMatrix; | 
|  | 2207 | SkISize size = auto_compute_translate(&matrix, src.size().width(), src.size().height()); | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 2208 | return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) { | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2209 | canvas->concat(matrix); | 
|  | 2210 | return src.draw(canvas); | 
|  | 2211 | }); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2212 | } | 
|  | 2213 |  | 
| mtklein | d603b22 | 2015-02-17 11:13:33 -0800 | [diff] [blame] | 2214 | // Undoes any flip or 90 degree rotate without changing the scale of the bitmap. | 
|  | 2215 | // This should be pixel-preserving. | 
| msarett | 62d3b10 | 2015-12-10 15:14:27 -0800 | [diff] [blame] | 2216 | ViaUpright::ViaUpright(SkMatrix matrix, Sink* sink) : Via(sink), fMatrix(matrix) {} | 
| mtklein | d603b22 | 2015-02-17 11:13:33 -0800 | [diff] [blame] | 2217 |  | 
|  | 2218 | Error ViaUpright::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { | 
|  | 2219 | Error err = fSink->draw(src, bitmap, stream, log); | 
|  | 2220 | if (!err.isEmpty()) { | 
|  | 2221 | return err; | 
|  | 2222 | } | 
|  | 2223 |  | 
|  | 2224 | SkMatrix inverse; | 
|  | 2225 | if (!fMatrix.rectStaysRect() || !fMatrix.invert(&inverse)) { | 
|  | 2226 | return "Cannot upright --matrix."; | 
|  | 2227 | } | 
|  | 2228 | SkMatrix upright = SkMatrix::I(); | 
|  | 2229 | upright.setScaleX(SkScalarSignAsScalar(inverse.getScaleX())); | 
|  | 2230 | upright.setScaleY(SkScalarSignAsScalar(inverse.getScaleY())); | 
|  | 2231 | upright.setSkewX(SkScalarSignAsScalar(inverse.getSkewX())); | 
|  | 2232 | upright.setSkewY(SkScalarSignAsScalar(inverse.getSkewY())); | 
|  | 2233 |  | 
|  | 2234 | SkBitmap uprighted; | 
|  | 2235 | SkISize size = auto_compute_translate(&upright, bitmap->width(), bitmap->height()); | 
|  | 2236 | uprighted.allocPixels(bitmap->info().makeWH(size.width(), size.height())); | 
|  | 2237 |  | 
|  | 2238 | SkCanvas canvas(uprighted); | 
|  | 2239 | canvas.concat(upright); | 
|  | 2240 | SkPaint paint; | 
| reed | 374772b | 2016-10-05 17:33:02 -0700 | [diff] [blame] | 2241 | paint.setBlendMode(SkBlendMode::kSrc); | 
| mtklein | d603b22 | 2015-02-17 11:13:33 -0800 | [diff] [blame] | 2242 | canvas.drawBitmap(*bitmap, 0, 0, &paint); | 
|  | 2243 |  | 
|  | 2244 | *bitmap = uprighted; | 
| mtklein | d603b22 | 2015-02-17 11:13:33 -0800 | [diff] [blame] | 2245 | return ""; | 
|  | 2246 | } | 
|  | 2247 |  | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2248 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2249 |  | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2250 | Error ViaSerialization::draw( | 
|  | 2251 | const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2252 | // Record our Src into a picture. | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2253 | auto size = src.size(); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2254 | SkPictureRecorder recorder; | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2255 | Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), | 
|  | 2256 | SkIntToScalar(size.height()))); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2257 | if (!err.isEmpty()) { | 
|  | 2258 | return err; | 
|  | 2259 | } | 
| reed | ca2622b | 2016-03-18 07:25:55 -0700 | [diff] [blame] | 2260 | sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture()); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2261 |  | 
|  | 2262 | // Serialize it and then deserialize it. | 
| reed | 39eaf5f | 2016-09-15 07:19:35 -0700 | [diff] [blame] | 2263 | sk_sp<SkPicture> deserialized(SkPicture::MakeFromData(pic->serialize().get())); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2264 |  | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 2265 | return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) { | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2266 | canvas->drawPicture(deserialized); | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 2267 | return check_against_reference(bitmap, src, fSink.get()); | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2268 | }); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2269 | } | 
|  | 2270 |  | 
|  | 2271 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2272 |  | 
| msarett | 62d3b10 | 2015-12-10 15:14:27 -0800 | [diff] [blame] | 2273 | ViaTiles::ViaTiles(int w, int h, SkBBHFactory* factory, Sink* sink) | 
|  | 2274 | : Via(sink) | 
| mtklein | 7882924 | 2015-05-06 07:54:07 -0700 | [diff] [blame] | 2275 | , fW(w) | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2276 | , fH(h) | 
| mtklein | 7882924 | 2015-05-06 07:54:07 -0700 | [diff] [blame] | 2277 | , fFactory(factory) {} | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2278 |  | 
| mtklein | b9eb4ac | 2015-02-02 18:26:03 -0800 | [diff] [blame] | 2279 | Error ViaTiles::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2280 | auto size = src.size(); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2281 | SkPictureRecorder recorder; | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2282 | Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), | 
|  | 2283 | SkIntToScalar(size.height()), | 
|  | 2284 | fFactory.get())); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2285 | if (!err.isEmpty()) { | 
|  | 2286 | return err; | 
|  | 2287 | } | 
| reed | ca2622b | 2016-03-18 07:25:55 -0700 | [diff] [blame] | 2288 | sk_sp<SkPicture> pic(recorder.finishRecordingAsPicture()); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2289 |  | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 2290 | return draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(), [&](SkCanvas* canvas) { | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2291 | const int xTiles = (size.width()  + fW - 1) / fW, | 
|  | 2292 | yTiles = (size.height() + fH - 1) / fH; | 
|  | 2293 | SkMultiPictureDraw mpd(xTiles*yTiles); | 
| reed | e8f3062 | 2016-03-23 18:59:25 -0700 | [diff] [blame] | 2294 | SkTArray<sk_sp<SkSurface>> surfaces; | 
|  | 2295 | //        surfaces.setReserve(xTiles*yTiles); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2296 |  | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2297 | SkImageInfo info = canvas->imageInfo().makeWH(fW, fH); | 
|  | 2298 | for (int j = 0; j < yTiles; j++) { | 
|  | 2299 | for (int i = 0; i < xTiles; i++) { | 
|  | 2300 | // This lets our ultimate Sink determine the best kind of surface. | 
|  | 2301 | // E.g., if it's a GpuSink, the surfaces and images are textures. | 
| reed | e8f3062 | 2016-03-23 18:59:25 -0700 | [diff] [blame] | 2302 | auto s = canvas->makeSurface(info); | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2303 | if (!s) { | 
| reed | e8f3062 | 2016-03-23 18:59:25 -0700 | [diff] [blame] | 2304 | s = SkSurface::MakeRaster(info);  // Some canvases can't create surfaces. | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2305 | } | 
| reed | e8f3062 | 2016-03-23 18:59:25 -0700 | [diff] [blame] | 2306 | surfaces.push_back(s); | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2307 | SkCanvas* c = s->getCanvas(); | 
|  | 2308 | c->translate(SkIntToScalar(-i * fW), | 
|  | 2309 | SkIntToScalar(-j * fH));  // Line up the canvas with this tile. | 
| reed | ca2622b | 2016-03-18 07:25:55 -0700 | [diff] [blame] | 2310 | mpd.add(c, pic.get()); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2311 | } | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2312 | } | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2313 | mpd.draw(); | 
|  | 2314 | for (int j = 0; j < yTiles; j++) { | 
|  | 2315 | for (int i = 0; i < xTiles; i++) { | 
| reed | 9ce9d67 | 2016-03-17 10:51:11 -0700 | [diff] [blame] | 2316 | sk_sp<SkImage> image(surfaces[i+xTiles*j]->makeImageSnapshot()); | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2317 | canvas->drawImage(image, SkIntToScalar(i*fW), SkIntToScalar(j*fH)); | 
|  | 2318 | } | 
|  | 2319 | } | 
| mtklein | a16e69e | 2015-05-05 11:38:45 -0700 | [diff] [blame] | 2320 | return ""; | 
|  | 2321 | }); | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2322 | } | 
|  | 2323 |  | 
| mtklein | b7e8d69 | 2015-04-07 08:30:32 -0700 | [diff] [blame] | 2324 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2325 |  | 
| mtklein | 4a34ecb | 2016-01-08 10:19:35 -0800 | [diff] [blame] | 2326 | Error ViaPicture::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { | 
|  | 2327 | auto size = src.size(); | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 2328 | return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { | 
| mtklein | 4a34ecb | 2016-01-08 10:19:35 -0800 | [diff] [blame] | 2329 | SkPictureRecorder recorder; | 
| reed | ca2622b | 2016-03-18 07:25:55 -0700 | [diff] [blame] | 2330 | sk_sp<SkPicture> pic; | 
| mtklein | 4a34ecb | 2016-01-08 10:19:35 -0800 | [diff] [blame] | 2331 | Error err = src.draw(recorder.beginRecording(SkIntToScalar(size.width()), | 
|  | 2332 | SkIntToScalar(size.height()))); | 
|  | 2333 | if (!err.isEmpty()) { | 
|  | 2334 | return err; | 
|  | 2335 | } | 
| reed | ca2622b | 2016-03-18 07:25:55 -0700 | [diff] [blame] | 2336 | pic = recorder.finishRecordingAsPicture(); | 
| mtklein | 4a34ecb | 2016-01-08 10:19:35 -0800 | [diff] [blame] | 2337 | canvas->drawPicture(pic); | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 2338 | return check_against_reference(bitmap, src, fSink.get()); | 
| mtklein | 4a34ecb | 2016-01-08 10:19:35 -0800 | [diff] [blame] | 2339 | }); | 
|  | 2340 | } | 
|  | 2341 |  | 
|  | 2342 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2343 |  | 
| reed | 54dc487 | 2016-09-13 08:09:45 -0700 | [diff] [blame] | 2344 | Error ViaPipe::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { | 
|  | 2345 | auto size = src.size(); | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 2346 | return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { | 
| reed | 54dc487 | 2016-09-13 08:09:45 -0700 | [diff] [blame] | 2347 | SkDynamicMemoryWStream tmpStream; | 
|  | 2348 | Error err = src.draw(SkPipeSerializer().beginWrite(SkRect::Make(size), &tmpStream)); | 
|  | 2349 | if (!err.isEmpty()) { | 
|  | 2350 | return err; | 
|  | 2351 | } | 
|  | 2352 | sk_sp<SkData> data = tmpStream.detachAsData(); | 
|  | 2353 | SkPipeDeserializer().playback(data->data(), data->size(), canvas); | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 2354 | return check_against_reference(bitmap, src, fSink.get()); | 
| reed | 54dc487 | 2016-09-13 08:09:45 -0700 | [diff] [blame] | 2355 | }); | 
|  | 2356 | } | 
|  | 2357 |  | 
|  | 2358 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2359 |  | 
| Mike Reed | bae888e | 2017-02-18 16:50:45 -0500 | [diff] [blame] | 2360 | #ifdef TEST_VIA_SVG | 
| Mike Reed | f67c459 | 2017-02-17 17:06:11 -0500 | [diff] [blame] | 2361 | #include "SkXMLWriter.h" | 
|  | 2362 | #include "SkSVGCanvas.h" | 
|  | 2363 | #include "SkSVGDOM.h" | 
|  | 2364 |  | 
|  | 2365 | Error ViaSVG::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { | 
|  | 2366 | auto size = src.size(); | 
|  | 2367 | return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { | 
|  | 2368 | SkDynamicMemoryWStream wstream; | 
|  | 2369 | SkXMLStreamWriter writer(&wstream); | 
|  | 2370 | Error err = src.draw(SkSVGCanvas::Make(SkRect::Make(size), &writer).get()); | 
|  | 2371 | if (!err.isEmpty()) { | 
|  | 2372 | return err; | 
|  | 2373 | } | 
|  | 2374 | std::unique_ptr<SkStream> rstream(wstream.detachAsStream()); | 
|  | 2375 | auto dom = SkSVGDOM::MakeFromStream(*rstream); | 
|  | 2376 | if (dom) { | 
|  | 2377 | dom->setContainerSize(SkSize::Make(size)); | 
|  | 2378 | dom->render(canvas); | 
|  | 2379 | } | 
|  | 2380 | return ""; | 
|  | 2381 | }); | 
|  | 2382 | } | 
| Mike Reed | bae888e | 2017-02-18 16:50:45 -0500 | [diff] [blame] | 2383 | #endif | 
| Mike Reed | f67c459 | 2017-02-17 17:06:11 -0500 | [diff] [blame] | 2384 |  | 
|  | 2385 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2386 |  | 
| mtklein | 9c5052f | 2016-08-06 12:51:51 -0700 | [diff] [blame] | 2387 | Error ViaLite::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { | 
|  | 2388 | auto size = src.size(); | 
| Derek Sollenberger | d7875f5 | 2017-03-01 15:33:23 -0500 | [diff] [blame] | 2389 | SkIRect bounds = {0,0, size.width(), size.height()}; | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 2390 | return draw_to_canvas(fSink.get(), bitmap, stream, log, size, [&](SkCanvas* canvas) -> Error { | 
| Derek Sollenberger | d7875f5 | 2017-03-01 15:33:23 -0500 | [diff] [blame] | 2391 | SkLiteDL dl; | 
| mtklein | 8bbbb69 | 2016-08-15 12:56:00 -0700 | [diff] [blame] | 2392 | SkLiteRecorder rec; | 
| Derek Sollenberger | d7875f5 | 2017-03-01 15:33:23 -0500 | [diff] [blame] | 2393 | rec.reset(&dl, bounds); | 
| mtklein | 8bbbb69 | 2016-08-15 12:56:00 -0700 | [diff] [blame] | 2394 |  | 
|  | 2395 | Error err = src.draw(&rec); | 
| mtklein | 9c5052f | 2016-08-06 12:51:51 -0700 | [diff] [blame] | 2396 | if (!err.isEmpty()) { | 
|  | 2397 | return err; | 
|  | 2398 | } | 
| Derek Sollenberger | d7875f5 | 2017-03-01 15:33:23 -0500 | [diff] [blame] | 2399 | dl.draw(canvas); | 
| Ben Wagner | 145dbcd | 2016-11-03 14:40:50 -0400 | [diff] [blame] | 2400 | return check_against_reference(bitmap, src, fSink.get()); | 
| mtklein | 9c5052f | 2016-08-06 12:51:51 -0700 | [diff] [blame] | 2401 | }); | 
|  | 2402 | } | 
|  | 2403 |  | 
| Mike Klein | 841101d | 2017-03-10 09:55:51 -0500 | [diff] [blame] | 2404 | /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ | 
|  | 2405 |  | 
| Mike Klein | 919cc45 | 2017-03-18 15:36:52 +0000 | [diff] [blame] | 2406 | ViaCSXform::ViaCSXform(Sink* sink, sk_sp<SkColorSpace> cs, bool colorSpin) | 
|  | 2407 | : Via(sink) | 
|  | 2408 | , fCS(std::move(cs)) | 
|  | 2409 | , fColorSpin(colorSpin) {} | 
| Mike Klein | 841101d | 2017-03-10 09:55:51 -0500 | [diff] [blame] | 2410 |  | 
|  | 2411 | Error ViaCSXform::draw(const Src& src, SkBitmap* bitmap, SkWStream* stream, SkString* log) const { | 
|  | 2412 | return draw_to_canvas(fSink.get(), bitmap, stream, log, src.size(), | 
|  | 2413 | [&](SkCanvas* canvas) -> Error { | 
| Brian Osman | 5b7e470 | 2017-10-31 16:41:29 -0400 | [diff] [blame] | 2414 | { | 
|  | 2415 | SkAutoCanvasRestore acr(canvas, true); | 
|  | 2416 | auto proxy = SkCreateColorSpaceXformCanvas(canvas, fCS); | 
|  | 2417 | Error err = src.draw(proxy.get()); | 
|  | 2418 | if (!err.isEmpty()) { | 
|  | 2419 | return err; | 
|  | 2420 | } | 
| Mike Klein | 919cc45 | 2017-03-18 15:36:52 +0000 | [diff] [blame] | 2421 | } | 
|  | 2422 |  | 
|  | 2423 | // Undo the color spin, so we can look at the pixels in Gold. | 
|  | 2424 | if (fColorSpin) { | 
|  | 2425 | SkBitmap pixels; | 
|  | 2426 | pixels.allocPixels(canvas->imageInfo()); | 
| Mike Reed | 12e946b | 2017-04-17 10:53:29 -0400 | [diff] [blame] | 2427 | canvas->readPixels(pixels, 0, 0); | 
| Mike Klein | 919cc45 | 2017-03-18 15:36:52 +0000 | [diff] [blame] | 2428 |  | 
| Brian Osman | 5b7e470 | 2017-10-31 16:41:29 -0400 | [diff] [blame] | 2429 | SkPaint rotateColors; | 
|  | 2430 | SkScalar matrix[20] = { 0, 0, 1, 0, 0,   // B -> R | 
|  | 2431 | 1, 0, 0, 0, 0,   // R -> G | 
|  | 2432 | 0, 1, 0, 0, 0,   // G -> B | 
|  | 2433 | 0, 0, 0, 1, 0 }; | 
|  | 2434 | rotateColors.setBlendMode(SkBlendMode::kSrc); | 
|  | 2435 | rotateColors.setColorFilter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix)); | 
|  | 2436 | canvas->drawBitmap(pixels, 0, 0, &rotateColors); | 
| Mike Klein | 919cc45 | 2017-03-18 15:36:52 +0000 | [diff] [blame] | 2437 | } | 
|  | 2438 |  | 
|  | 2439 | return ""; | 
| Mike Klein | 841101d | 2017-03-10 09:55:51 -0500 | [diff] [blame] | 2440 | }); | 
|  | 2441 | } | 
|  | 2442 |  | 
| mtklein | 748ca3b | 2015-01-15 10:56:12 -0800 | [diff] [blame] | 2443 | }  // namespace DM |