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 8 #ifndef DMSrcSink_DEFINED 9 #define DMSrcSink_DEFINED 10 11 #include "gm/gm.h" 12 #include "include/android/SkBitmapRegionDecoder.h" 13 #include "include/core/SkBBHFactory.h" 14 #include "include/core/SkBitmap.h" 15 #include "include/core/SkCanvas.h" 16 #include "include/core/SkData.h" 17 #include "include/core/SkPicture.h" 18 #include "src/core/SkBBoxHierarchy.h" 19 #include "src/utils/SkMultiPictureDocument.h" 20 #include "tools/flags/CommonFlagsConfig.h" 21 #include "tools/gpu/MemoryCache.h" 22 23 //#define TEST_VIA_SVG 24 25 namespace DM { 26 27 // This is just convenience. It lets you use either return "foo" or return SkStringPrintf(...). 28 struct ImplicitString : public SkString { 29 template <typename T> ImplicitStringImplicitString30 ImplicitString(const T& s) : SkString(s) {} ImplicitStringImplicitString31 ImplicitString() : SkString("") {} 32 }; 33 typedef ImplicitString Name; 34 typedef ImplicitString Path; 35 36 class Error { 37 public: Error(const SkString & s)38 Error(const SkString& s) : fMsg(s), fFatal(!this->isEmpty()) {} Error(const char * s)39 Error(const char* s) : fMsg(s), fFatal(!this->isEmpty()) {} 40 41 Error(const Error&) = default; 42 Error& operator=(const Error&) = default; 43 Nonfatal(const SkString & s)44 static Error Nonfatal(const SkString& s) { return Nonfatal(s.c_str()); } Nonfatal(const char * s)45 static Error Nonfatal(const char* s) { 46 Error e(s); 47 e.fFatal = false; 48 return e; 49 } 50 c_str()51 const char* c_str() const { return fMsg.c_str(); } isEmpty()52 bool isEmpty() const { return fMsg.isEmpty(); } isFatal()53 bool isFatal() const { return fFatal; } 54 55 private: 56 SkString fMsg; 57 bool fFatal; 58 }; 59 60 struct SinkFlags { 61 enum Type { kNull, kGPU, kVector, kRaster } type; 62 enum Approach { kDirect, kIndirect } approach; 63 enum Multisampled { kNotMultisampled, kMultisampled } multisampled; 64 SinkFlags(Type t, Approach a, Multisampled ms = kNotMultisampled) typeSinkFlags65 : type(t), approach(a), multisampled(ms) {} 66 }; 67 68 struct Src { ~SrcSrc69 virtual ~Src() {} 70 virtual Error SK_WARN_UNUSED_RESULT draw(SkCanvas*) const = 0; 71 virtual SkISize size() const = 0; 72 virtual Name name() const = 0; modifyGrContextOptionsSrc73 virtual void modifyGrContextOptions(GrContextOptions* options) const {} vetoSrc74 virtual bool veto(SinkFlags) const { return false; } 75 pageCountSrc76 virtual int pageCount() const { return 1; } drawSrc77 virtual Error SK_WARN_UNUSED_RESULT draw(int, SkCanvas* canvas) const { 78 return this->draw(canvas); 79 } sizeSrc80 virtual SkISize size(int) const { return this->size(); } 81 // Force Tasks using this Src to run on the main thread? serialSrc82 virtual bool serial() const { return false; } 83 }; 84 85 struct Sink { ~SinkSink86 virtual ~Sink() {} 87 // You may write to either the bitmap or stream. If you write to log, we'll print that out. 88 virtual Error SK_WARN_UNUSED_RESULT draw(const Src&, SkBitmap*, SkWStream*, SkString* log) 89 const = 0; 90 91 // Force Tasks using this Sink to run on the main thread? serialSink92 virtual bool serial() const { return false; } 93 94 // File extension for the content draw() outputs, e.g. "png", "pdf". 95 virtual const char* fileExtension() const = 0; 96 97 virtual SinkFlags flags() const = 0; 98 }; 99 100 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 101 102 class GMSrc : public Src { 103 public: 104 explicit GMSrc(skiagm::GMFactory); 105 106 Error draw(SkCanvas*) const override; 107 SkISize size() const override; 108 Name name() const override; 109 void modifyGrContextOptions(GrContextOptions* options) const override; 110 111 private: 112 skiagm::GMFactory fFactory; 113 }; 114 115 class CodecSrc : public Src { 116 public: 117 enum Mode { 118 kCodec_Mode, 119 // We choose to test only one mode with zero initialized memory. 120 // This will exercise all of the interesting cases in SkSwizzler 121 // without doubling the size of our test suite. 122 kCodecZeroInit_Mode, 123 kScanline_Mode, 124 kStripe_Mode, // Tests the skipping of scanlines 125 kCroppedScanline_Mode, // Tests (jpeg) cropped scanline optimization 126 kSubset_Mode, // For codecs that support subsets directly. 127 kAnimated_Mode, // For codecs that support animation. 128 }; 129 enum DstColorType { 130 kGetFromCanvas_DstColorType, 131 kGrayscale_Always_DstColorType, 132 kNonNative8888_Always_DstColorType, 133 }; 134 CodecSrc(Path, Mode, DstColorType, SkAlphaType, float); 135 136 Error draw(SkCanvas*) const override; 137 SkISize size() const override; 138 Name name() const override; veto(SinkFlags)139 bool veto(SinkFlags) const override; 140 bool serial() const override { return fRunSerially; } 141 private: 142 Path fPath; 143 Mode fMode; 144 DstColorType fDstColorType; 145 SkAlphaType fDstAlphaType; 146 float fScale; 147 bool fRunSerially; 148 }; 149 150 class AndroidCodecSrc : public Src { 151 public: 152 AndroidCodecSrc(Path, CodecSrc::DstColorType, SkAlphaType, int sampleSize); 153 154 Error draw(SkCanvas*) const override; 155 SkISize size() const override; 156 Name name() const override; veto(SinkFlags)157 bool veto(SinkFlags) const override; 158 bool serial() const override { return fRunSerially; } 159 private: 160 Path fPath; 161 CodecSrc::DstColorType fDstColorType; 162 SkAlphaType fDstAlphaType; 163 int fSampleSize; 164 bool fRunSerially; 165 }; 166 167 // Allows for testing of various implementations of Android's BitmapRegionDecoder 168 class BRDSrc : public Src { 169 public: 170 enum Mode { 171 // Decode the entire image as one region. 172 kFullImage_Mode, 173 // Splits the image into multiple regions using a divisor and decodes the regions 174 // separately. Also, this test adds a border of a few pixels to each of the regions 175 // that it is decoding. This tests the behavior when a client asks for a region that 176 // does not fully fit in the image. 177 kDivisor_Mode, 178 }; 179 180 BRDSrc(Path, Mode, CodecSrc::DstColorType, uint32_t); 181 182 Error draw(SkCanvas*) const override; 183 SkISize size() const override; 184 Name name() const override; 185 bool veto(SinkFlags) const override; 186 private: 187 Path fPath; 188 Mode fMode; 189 CodecSrc::DstColorType fDstColorType; 190 uint32_t fSampleSize; 191 }; 192 193 class ImageGenSrc : public Src { 194 public: 195 enum Mode { 196 kCodec_Mode, // Use CodecImageGenerator 197 kPlatform_Mode, // Uses CG or WIC 198 }; 199 ImageGenSrc(Path, Mode, SkAlphaType, bool); 200 201 Error draw(SkCanvas*) const override; 202 SkISize size() const override; 203 Name name() const override; veto(SinkFlags)204 bool veto(SinkFlags) const override; 205 bool serial() const override { return fRunSerially; } 206 private: 207 Path fPath; 208 Mode fMode; 209 SkAlphaType fDstAlphaType; 210 bool fIsGpu; 211 bool fRunSerially; 212 }; 213 214 class ColorCodecSrc : public Src { 215 public: 216 ColorCodecSrc(Path, bool decode_to_dst); 217 218 Error draw(SkCanvas*) const override; 219 SkISize size() const override; 220 Name name() const override; 221 bool veto(SinkFlags) const override; 222 private: 223 Path fPath; 224 bool fDecodeToDst; 225 }; 226 227 class SKPSrc : public Src { 228 public: 229 explicit SKPSrc(Path path); 230 231 Error draw(SkCanvas*) const override; 232 SkISize size() const override; 233 Name name() const override; 234 private: 235 Path fPath; 236 }; 237 238 // This class extracts all the paths from an SKP and then removes unwanted paths according to the 239 // provided l/r trail. It then just draws the remaining paths. (Non-path draws are thrown out.) It 240 // is useful for finding a reduced repo case for path drawing bugs. 241 class BisectSrc : public SKPSrc { 242 public: 243 explicit BisectSrc(Path path, const char* trail); 244 245 Error draw(SkCanvas*) const override; 246 247 private: 248 SkString fTrail; 249 250 typedef SKPSrc INHERITED; 251 }; 252 253 254 #if defined(SK_ENABLE_SKOTTIE) 255 class SkottieSrc final : public Src { 256 public: 257 explicit SkottieSrc(Path path); 258 259 Error draw(SkCanvas*) const override; 260 SkISize size() const override; 261 Name name() const override; 262 bool veto(SinkFlags) const override; 263 264 private: 265 // Generates a kTileCount x kTileCount filmstrip with evenly distributed frames. 266 static constexpr int kTileCount = 5; 267 268 // Fit kTileCount x kTileCount frames to a 1000x1000 film strip. 269 static constexpr SkScalar kTargetSize = 1000; 270 static constexpr SkScalar kTileSize = kTargetSize / kTileCount; 271 272 Path fPath; 273 }; 274 #endif 275 276 #if defined(SK_XML) 277 } // namespace DM 278 279 class SkSVGDOM; 280 281 namespace DM { 282 283 class SVGSrc : public Src { 284 public: 285 explicit SVGSrc(Path path); 286 287 Error draw(SkCanvas*) const override; 288 SkISize size() const override; 289 Name name() const override; 290 bool veto(SinkFlags) const override; 291 292 private: 293 Name fName; 294 sk_sp<SkSVGDOM> fDom; 295 SkScalar fScale; 296 297 typedef Src INHERITED; 298 }; 299 #endif // SK_XML 300 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 301 302 class MSKPSrc : public Src { 303 public: 304 explicit MSKPSrc(Path path); 305 306 int pageCount() const override; 307 Error draw(SkCanvas* c) const override; 308 Error draw(int, SkCanvas*) const override; 309 SkISize size() const override; 310 SkISize size(int) const override; 311 Name name() const override; 312 313 private: 314 Path fPath; 315 mutable SkTArray<SkDocumentPage> fPages; 316 }; 317 318 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 319 320 class NullSink : public Sink { 321 public: NullSink()322 NullSink() {} 323 324 Error draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const override; fileExtension()325 const char* fileExtension() const override { return ""; } flags()326 SinkFlags flags() const override { return SinkFlags{ SinkFlags::kNull, SinkFlags::kDirect }; } 327 }; 328 329 class GPUSink : public Sink { 330 public: 331 GPUSink(sk_gpu_test::GrContextFactory::ContextType, 332 sk_gpu_test::GrContextFactory::ContextOverrides, 333 SkCommandLineConfigGpu::SurfType surfType, int samples, bool diText, 334 SkColorType colorType, SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace, 335 bool threaded, const GrContextOptions& grCtxOptions); 336 337 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 338 Error onDraw(const Src&, SkBitmap*, SkWStream*, SkString*, 339 const GrContextOptions& baseOptions) const; 340 contextType()341 sk_gpu_test::GrContextFactory::ContextType contextType() const { return fContextType; } contextOverrides()342 const sk_gpu_test::GrContextFactory::ContextOverrides& contextOverrides() { 343 return fContextOverrides; 344 } surfType()345 SkCommandLineConfigGpu::SurfType surfType() const { return fSurfType; } useDIText()346 bool useDIText() const { return fUseDIText; } serial()347 bool serial() const override { return !fThreaded; } fileExtension()348 const char* fileExtension() const override { return "png"; } flags()349 SinkFlags flags() const override { 350 SinkFlags::Multisampled ms = fSampleCount > 1 ? SinkFlags::kMultisampled 351 : SinkFlags::kNotMultisampled; 352 return SinkFlags{ SinkFlags::kGPU, SinkFlags::kDirect, ms }; 353 } baseContextOptions()354 const GrContextOptions& baseContextOptions() const { return fBaseContextOptions; } 355 356 private: 357 sk_gpu_test::GrContextFactory::ContextType fContextType; 358 sk_gpu_test::GrContextFactory::ContextOverrides fContextOverrides; 359 SkCommandLineConfigGpu::SurfType fSurfType; 360 int fSampleCount; 361 bool fUseDIText; 362 SkColorType fColorType; 363 SkAlphaType fAlphaType; 364 sk_sp<SkColorSpace> fColorSpace; 365 bool fThreaded; 366 GrContextOptions fBaseContextOptions; 367 sk_gpu_test::MemoryCache fMemoryCache; 368 }; 369 370 class GPUThreadTestingSink : public GPUSink { 371 public: 372 GPUThreadTestingSink(sk_gpu_test::GrContextFactory::ContextType, 373 sk_gpu_test::GrContextFactory::ContextOverrides, 374 SkCommandLineConfigGpu::SurfType surfType, int samples, bool diText, 375 SkColorType colorType, SkAlphaType alphaType, 376 sk_sp<SkColorSpace> colorSpace, bool threaded, 377 const GrContextOptions& grCtxOptions); 378 379 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 380 fileExtension()381 const char* fileExtension() const override { 382 // Suppress writing out results from this config - we just want to do our matching test 383 return nullptr; 384 } 385 386 private: 387 std::unique_ptr<SkExecutor> fExecutor; 388 389 typedef GPUSink INHERITED; 390 }; 391 392 class GPUPersistentCacheTestingSink : public GPUSink { 393 public: 394 GPUPersistentCacheTestingSink(sk_gpu_test::GrContextFactory::ContextType, 395 sk_gpu_test::GrContextFactory::ContextOverrides, 396 SkCommandLineConfigGpu::SurfType surfType, int samples, 397 bool diText, SkColorType colorType, SkAlphaType alphaType, 398 sk_sp<SkColorSpace> colorSpace, bool threaded, 399 const GrContextOptions& grCtxOptions, 400 int cacheType); 401 402 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 403 fileExtension()404 const char* fileExtension() const override { 405 // Suppress writing out results from this config - we just want to do our matching test 406 return nullptr; 407 } 408 409 private: 410 int fCacheType; 411 412 typedef GPUSink INHERITED; 413 }; 414 415 class PDFSink : public Sink { 416 public: PDFSink(bool pdfa,SkScalar rasterDpi)417 PDFSink(bool pdfa, SkScalar rasterDpi) : fPDFA(pdfa), fRasterDpi(rasterDpi) {} 418 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; fileExtension()419 const char* fileExtension() const override { return "pdf"; } flags()420 SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; } 421 bool fPDFA; 422 SkScalar fRasterDpi; 423 }; 424 425 class XPSSink : public Sink { 426 public: 427 XPSSink(); 428 429 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; fileExtension()430 const char* fileExtension() const override { return "xps"; } flags()431 SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; } 432 }; 433 434 class RasterSink : public Sink { 435 public: 436 explicit RasterSink(SkColorType, sk_sp<SkColorSpace> = nullptr); 437 438 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; fileExtension()439 const char* fileExtension() const override { return "png"; } flags()440 SinkFlags flags() const override { return SinkFlags{ SinkFlags::kRaster, SinkFlags::kDirect }; } 441 442 private: 443 SkColorType fColorType; 444 sk_sp<SkColorSpace> fColorSpace; 445 }; 446 447 class ThreadedSink : public RasterSink { 448 public: 449 explicit ThreadedSink(SkColorType, sk_sp<SkColorSpace> = nullptr); 450 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 451 }; 452 453 class SKPSink : public Sink { 454 public: 455 SKPSink(); 456 457 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; fileExtension()458 const char* fileExtension() const override { return "skp"; } flags()459 SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; } 460 }; 461 462 class DebugSink : public Sink { 463 public: 464 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; fileExtension()465 const char* fileExtension() const override { return "json"; } flags()466 SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; } 467 }; 468 469 class SVGSink : public Sink { 470 public: 471 SVGSink(int pageIndex = 0); 472 473 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; fileExtension()474 const char* fileExtension() const override { return "svg"; } flags()475 SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; } 476 477 private: 478 int fPageIndex; 479 }; 480 481 482 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 483 484 class Via : public Sink { 485 public: Via(Sink * sink)486 explicit Via(Sink* sink) : fSink(sink) {} fileExtension()487 const char* fileExtension() const override { return fSink->fileExtension(); } serial()488 bool serial() const override { return fSink->serial(); } flags()489 SinkFlags flags() const override { 490 SinkFlags flags = fSink->flags(); 491 flags.approach = SinkFlags::kIndirect; 492 return flags; 493 } 494 protected: 495 std::unique_ptr<Sink> fSink; 496 }; 497 498 class ViaMatrix : public Via { 499 public: 500 ViaMatrix(SkMatrix, Sink*); 501 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 502 private: 503 const SkMatrix fMatrix; 504 }; 505 506 class ViaUpright : public Via { 507 public: 508 ViaUpright(SkMatrix, Sink*); 509 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 510 private: 511 const SkMatrix fMatrix; 512 }; 513 514 class ViaSerialization : public Via { 515 public: ViaSerialization(Sink * sink)516 explicit ViaSerialization(Sink* sink) : Via(sink) {} 517 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 518 }; 519 520 class ViaPicture : public Via { 521 public: ViaPicture(Sink * sink)522 explicit ViaPicture(Sink* sink) : Via(sink) {} 523 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 524 }; 525 526 class ViaTiles : public Via { 527 public: 528 ViaTiles(int w, int h, SkBBHFactory*, Sink*); 529 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 530 private: 531 const int fW, fH; 532 std::unique_ptr<SkBBHFactory> fFactory; 533 }; 534 535 class ViaDDL : public Via { 536 public: 537 ViaDDL(int numReplays, int numDivisions, Sink* sink); 538 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 539 private: 540 const int fNumReplays; 541 const int fNumDivisions; 542 }; 543 544 class ViaSVG : public Via { 545 public: ViaSVG(Sink * sink)546 explicit ViaSVG(Sink* sink) : Via(sink) {} 547 Error draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override; 548 }; 549 550 } // namespace DM 551 552 #endif//DMSrcSink_DEFINED 553