• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/core/SkBBHFactory.h"
13 #include "include/core/SkBitmap.h"
14 #include "include/core/SkCanvas.h"
15 #include "include/core/SkData.h"
16 #include "include/core/SkPicture.h"
17 #include "src/utils/SkMultiPictureDocument.h"
18 #include "tools/flags/CommonFlagsConfig.h"
19 #include "tools/gpu/MemoryCache.h"
20 
21 #include <functional>
22 
23 //#define TEST_VIA_SVG
24 
25 namespace skiagm {
26 namespace verifiers {
27 class VerifierList;
28 }  // namespace verifiers
29 }  // namespace skiagm
30 
31 namespace DM {
32 
33 // This is just convenience.  It lets you use either return "foo" or return SkStringPrintf(...).
34 struct ImplicitString : public SkString {
35     template <typename T>
ImplicitStringImplicitString36     ImplicitString(const T& s) : SkString(s) {}
ImplicitStringImplicitString37     ImplicitString() : SkString("") {}
38 };
39 typedef ImplicitString Name;
40 typedef ImplicitString Path;
41 
42 class Result {
43 public:
44     enum class Status : int { Ok, Fatal, Skip };
Result(Status status,const SkString & s)45     Result(Status status, const SkString& s) : fMsg(s), fStatus(status) {}
Result(Status status,const char * s)46     Result(Status status, const char* s) : fMsg(s), fStatus(status) {}
Result(Status status,const char * s,Args...args)47     template <typename... Args> Result (Status status, const char* s, Args... args)
48         : fMsg(SkStringPrintf(s, args...)), fStatus(status) {}
49 
50     Result(const Result&)            = default;
51     Result& operator=(const Result&) = default;
52 
Ok()53     static Result Ok() { return Result(Status::Ok, nullptr); }
54 
Fatal(const SkString & s)55     static Result Fatal(const SkString& s) { return Result(Status::Fatal, s); }
Fatal(const char * s)56     static Result Fatal(const char* s) { return Result(Status::Fatal, s); }
Fatal(const char * s,Args...args)57     template <typename... Args> static Result Fatal(const char* s, Args... args) {
58         return Result(Status::Fatal, s, args...);
59     }
60 
Skip(const SkString & s)61     static Result Skip(const SkString& s) { return Result(Status::Skip, s); }
Skip(const char * s)62     static Result Skip(const char* s) { return Result(Status::Skip, s); }
Skip(const char * s,Args...args)63     template <typename... Args> static Result Skip(const char* s, Args... args) {
64         return Result(Status::Skip, s, args...);
65     }
66 
isOk()67     bool isOk() { return fStatus == Status::Ok; }
isFatal()68     bool isFatal() { return fStatus == Status::Fatal; }
isSkip()69     bool isSkip() { return fStatus == Status::Skip; }
70 
c_str()71     const char* c_str() const { return fMsg.c_str(); }
status()72     Status status() const { return fStatus; }
73 
74 private:
75     SkString fMsg;
76     Status   fStatus;
77 };
78 
79 struct SinkFlags {
80     enum Type { kNull, kGPU, kVector, kRaster } type;
81     enum Approach { kDirect, kIndirect } approach;
82     enum Multisampled { kNotMultisampled, kMultisampled } multisampled;
83     SinkFlags(Type t, Approach a, Multisampled ms = kNotMultisampled)
typeSinkFlags84             : type(t), approach(a), multisampled(ms) {}
85 };
86 
87 struct Src {
~SrcSrc88     virtual ~Src() {}
89     virtual Result SK_WARN_UNUSED_RESULT draw(GrDirectContext*, SkCanvas*) const = 0;
90     virtual SkISize size() const = 0;
91     virtual Name name() const = 0;
modifyGrContextOptionsSrc92     virtual void modifyGrContextOptions(GrContextOptions* options) const {}
vetoSrc93     virtual bool veto(SinkFlags) const { return false; }
94 
pageCountSrc95     virtual int pageCount() const { return 1; }
drawSrc96     virtual Result SK_WARN_UNUSED_RESULT draw(int, GrDirectContext* context,
97                                               SkCanvas* canvas) const {
98         return this->draw(context, canvas);
99     }
sizeSrc100     virtual SkISize size(int) const { return this->size(); }
101     // Force Tasks using this Src to run on the main thread?
serialSrc102     virtual bool serial() const { return false; }
103 
104     /** Return a list of verifiers for the src, or null if no verifiers should be run .*/
getVerifiersSrc105     virtual std::unique_ptr<skiagm::verifiers::VerifierList> getVerifiers() const {
106         return nullptr;
107     }
108 };
109 
110 struct Sink {
~SinkSink111     virtual ~Sink() {}
112     // You may write to either the bitmap or stream.  If you write to log, we'll print that out.
113     virtual Result SK_WARN_UNUSED_RESULT draw(const Src&, SkBitmap*, SkWStream*, SkString* log)
114         const = 0;
115 
116     // Force Tasks using this Sink to run on the main thread?
serialSink117     virtual bool serial() const { return false; }
118 
119     // File extension for the content draw() outputs, e.g. "png", "pdf".
120     virtual const char* fileExtension() const  = 0;
121 
122     virtual SinkFlags flags() const = 0;
123 
124     /** Returns the color type and space used by the sink. */
colorInfoSink125     virtual SkColorInfo colorInfo() const { return SkColorInfo(); }
126 };
127 
128 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
129 
130 class GMSrc : public Src {
131 public:
132     explicit GMSrc(skiagm::GMFactory);
133 
134     Result draw(GrDirectContext*, SkCanvas*) const override;
135     SkISize size() const override;
136     Name name() const override;
137     void modifyGrContextOptions(GrContextOptions* options) const override;
138 
139     std::unique_ptr<skiagm::verifiers::VerifierList> getVerifiers() const override;
140 
141 private:
142     skiagm::GMFactory fFactory;
143 };
144 
145 class CodecSrc : public Src {
146 public:
147     enum Mode {
148         kCodec_Mode,
149         // We choose to test only one mode with zero initialized memory.
150         // This will exercise all of the interesting cases in SkSwizzler
151         // without doubling the size of our test suite.
152         kCodecZeroInit_Mode,
153         kScanline_Mode,
154         kStripe_Mode, // Tests the skipping of scanlines
155         kCroppedScanline_Mode, // Tests (jpeg) cropped scanline optimization
156         kSubset_Mode, // For codecs that support subsets directly.
157         kAnimated_Mode, // For codecs that support animation.
158     };
159     enum DstColorType {
160         kGetFromCanvas_DstColorType,
161         kGrayscale_Always_DstColorType,
162         kNonNative8888_Always_DstColorType,
163     };
164     CodecSrc(Path, Mode, DstColorType, SkAlphaType, float);
165 
166     Result draw(GrDirectContext*, SkCanvas*) const override;
167     SkISize size() const override;
168     Name name() const override;
veto(SinkFlags)169     bool veto(SinkFlags) const override;
170     bool serial() const override { return fRunSerially; }
171 private:
172     Path                    fPath;
173     Mode                    fMode;
174     DstColorType            fDstColorType;
175     SkAlphaType             fDstAlphaType;
176     float                   fScale;
177     bool                    fRunSerially;
178 };
179 
180 class AndroidCodecSrc : public Src {
181 public:
182     AndroidCodecSrc(Path, CodecSrc::DstColorType, SkAlphaType, int sampleSize);
183 
184     Result draw(GrDirectContext*, SkCanvas*) const override;
185     SkISize size() const override;
186     Name name() const override;
veto(SinkFlags)187     bool veto(SinkFlags) const override;
188     bool serial() const override { return fRunSerially; }
189 private:
190     Path                    fPath;
191     CodecSrc::DstColorType  fDstColorType;
192     SkAlphaType             fDstAlphaType;
193     int                     fSampleSize;
194     bool                    fRunSerially;
195 };
196 
197 #ifdef SK_ENABLE_ANDROID_UTILS
198 // Allows for testing of various implementations of Android's BitmapRegionDecoder
199 class BRDSrc : public Src {
200 public:
201     enum Mode {
202         // Decode the entire image as one region.
203         kFullImage_Mode,
204         // Splits the image into multiple regions using a divisor and decodes the regions
205         // separately.  Also, this test adds a border of a few pixels to each of the regions
206         // that it is decoding.  This tests the behavior when a client asks for a region that
207         // does not fully fit in the image.
208         kDivisor_Mode,
209     };
210 
211     BRDSrc(Path, Mode, CodecSrc::DstColorType, uint32_t);
212 
213     Result draw(GrDirectContext*, SkCanvas*) const override;
214     SkISize size() const override;
215     Name name() const override;
216     bool veto(SinkFlags) const override;
217 private:
218     Path                                     fPath;
219     Mode                                     fMode;
220     CodecSrc::DstColorType                   fDstColorType;
221     uint32_t                                 fSampleSize;
222 };
223 #endif
224 
225 class ImageGenSrc : public Src {
226 public:
227     enum Mode {
228         kCodec_Mode,    // Use CodecImageGenerator
229         kPlatform_Mode, // Uses CG or WIC
230     };
231     ImageGenSrc(Path, Mode, SkAlphaType, bool);
232 
233     Result draw(GrDirectContext*, SkCanvas*) const override;
234     SkISize size() const override;
235     Name name() const override;
veto(SinkFlags)236     bool veto(SinkFlags) const override;
237     bool serial() const override { return fRunSerially; }
238 private:
239     Path        fPath;
240     Mode        fMode;
241     SkAlphaType fDstAlphaType;
242     bool        fIsGpu;
243     bool        fRunSerially;
244 };
245 
246 class ColorCodecSrc : public Src {
247 public:
248     ColorCodecSrc(Path, bool decode_to_dst);
249 
250     Result draw(GrDirectContext*, SkCanvas*) const override;
251     SkISize size() const override;
252     Name name() const override;
253     bool veto(SinkFlags) const override;
254 private:
255     Path fPath;
256     bool fDecodeToDst;
257 };
258 
259 class SKPSrc : public Src {
260 public:
261     explicit SKPSrc(Path path);
262 
263     Result draw(GrDirectContext*, SkCanvas*) const override;
264     SkISize size() const override;
265     Name name() const override;
266 private:
267     Path fPath;
268 };
269 
270 // This class extracts all the paths from an SKP and then removes unwanted paths according to the
271 // provided l/r trail. It then just draws the remaining paths. (Non-path draws are thrown out.) It
272 // is useful for finding a reduced repo case for path drawing bugs.
273 class BisectSrc : public SKPSrc {
274 public:
275     explicit BisectSrc(Path path, const char* trail);
276 
277     Result draw(GrDirectContext*, SkCanvas*) const override;
278 
279 private:
280     SkString fTrail;
281 
282     using INHERITED = SKPSrc;
283 };
284 
285 #if defined(SK_ENABLE_SKOTTIE)
286 class SkottieSrc final : public Src {
287 public:
288     explicit SkottieSrc(Path path);
289 
290     Result draw(GrDirectContext*, SkCanvas*) const override;
291     SkISize size() const override;
292     Name name() const override;
293     bool veto(SinkFlags) const override;
294 
295 private:
296     // Generates a kTileCount x kTileCount filmstrip with evenly distributed frames.
297     static constexpr int      kTileCount = 5;
298 
299     // Fit kTileCount x kTileCount frames to a 1000x1000 film strip.
300     static constexpr SkScalar kTargetSize = 1000;
301     static constexpr SkScalar kTileSize = kTargetSize / kTileCount;
302 
303     Path                      fPath;
304 };
305 #endif
306 
307 #if defined(SK_ENABLE_SKRIVE)
308 class SkRiveSrc final : public Src {
309 public:
310     explicit SkRiveSrc(Path path);
311 
312     Result draw(GrDirectContext*, SkCanvas*) const override;
313     SkISize size() const override;
314     Name name() const override;
315     bool veto(SinkFlags) const override;
316 
317 private:
318     // Generates a kTileCount x kTileCount filmstrip with evenly distributed frames.
319     static constexpr int      kTileCount  = 5;
320 
321     // Fit kTileCount x kTileCount frames to a 1000x1000 film strip.
322     static constexpr SkScalar kTargetSize = 1000;
323     static constexpr SkScalar kTileSize   = kTargetSize / kTileCount;
324 
325     const Path fPath;
326 };
327 #endif
328 
329 #if defined(SK_XML)
330 } // namespace DM
331 
332 class SkSVGDOM;
333 
334 namespace DM {
335 
336 class SVGSrc : public Src {
337 public:
338     explicit SVGSrc(Path path);
339 
340     Result draw(GrDirectContext*, SkCanvas*) const override;
341     SkISize size() const override;
342     Name name() const override;
343     bool veto(SinkFlags) const override;
344 
345 private:
346     Name            fName;
347     sk_sp<SkSVGDOM> fDom;
348     SkScalar        fScale;
349 
350     using INHERITED = Src;
351 };
352 #endif // SK_XML
353 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
354 
355 class MSKPSrc : public Src {
356 public:
357     explicit MSKPSrc(Path path);
358 
359     int pageCount() const override;
360     Result draw(GrDirectContext*, SkCanvas* c) const override;
361     Result draw(int, GrDirectContext*, SkCanvas*) const override;
362     SkISize size() const override;
363     SkISize size(int) const override;
364     Name name() const override;
365 
366 private:
367     Path fPath;
368     mutable SkTArray<SkDocumentPage> fPages;
369 };
370 
371 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
372 
373 class NullSink : public Sink {
374 public:
NullSink()375     NullSink() {}
376 
377     Result draw(const Src& src, SkBitmap*, SkWStream*, SkString*) const override;
fileExtension()378     const char* fileExtension() const override { return ""; }
flags()379     SinkFlags flags() const override { return SinkFlags{ SinkFlags::kNull, SinkFlags::kDirect }; }
380 };
381 
382 class GPUSink : public Sink {
383 public:
384     GPUSink(const SkCommandLineConfigGpu*, const GrContextOptions&);
385 
386     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
387     Result onDraw(const Src&, SkBitmap*, SkWStream*, SkString*,
388                   const GrContextOptions& baseOptions,
389                   std::function<void(GrDirectContext*)> initContext = nullptr) const;
390 
contextType()391     sk_gpu_test::GrContextFactory::ContextType contextType() const { return fContextType; }
contextOverrides()392     const sk_gpu_test::GrContextFactory::ContextOverrides& contextOverrides() const {
393         return fContextOverrides;
394     }
surfType()395     SkCommandLineConfigGpu::SurfType surfType() const { return fSurfType; }
serial()396     bool serial() const override { return true; }
fileExtension()397     const char* fileExtension() const override { return "png"; }
flags()398     SinkFlags flags() const override {
399         SinkFlags::Multisampled ms = fSampleCount > 1 ? SinkFlags::kMultisampled
400                                                       : SinkFlags::kNotMultisampled;
401         return SinkFlags{ SinkFlags::kGPU, SinkFlags::kDirect, ms };
402     }
baseContextOptions()403     const GrContextOptions& baseContextOptions() const { return fBaseContextOptions; }
colorInfo()404     SkColorInfo colorInfo() const override {
405         return SkColorInfo(fColorType, fAlphaType, fColorSpace);
406     }
407 
408 protected:
409     sk_sp<SkSurface> createDstSurface(GrDirectContext*, SkISize size) const;
410     bool readBack(SkSurface*, SkBitmap* dst) const;
411 
412 private:
413     sk_gpu_test::GrContextFactory::ContextType        fContextType;
414     sk_gpu_test::GrContextFactory::ContextOverrides   fContextOverrides;
415     SkCommandLineConfigGpu::SurfType                  fSurfType;
416     int                                               fSampleCount;
417     uint32_t                                          fSurfaceFlags;
418     SkColorType                                       fColorType;
419     SkAlphaType                                       fAlphaType;
420     sk_sp<SkColorSpace>                               fColorSpace;
421     GrContextOptions                                  fBaseContextOptions;
422     sk_gpu_test::MemoryCache                          fMemoryCache;
423 };
424 
425 class GPUThreadTestingSink : public GPUSink {
426 public:
427     GPUThreadTestingSink(const SkCommandLineConfigGpu*, const GrContextOptions&);
428 
429     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
430 
fileExtension()431     const char* fileExtension() const override {
432         // Suppress writing out results from this config - we just want to do our matching test
433         return nullptr;
434     }
435 
436 private:
437     std::unique_ptr<SkExecutor> fExecutor;
438 
439     using INHERITED = GPUSink;
440 };
441 
442 class GPUPersistentCacheTestingSink : public GPUSink {
443 public:
444     GPUPersistentCacheTestingSink(const SkCommandLineConfigGpu*, const GrContextOptions&);
445 
446     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
447 
fileExtension()448     const char* fileExtension() const override {
449         // Suppress writing out results from this config - we just want to do our matching test
450         return nullptr;
451     }
452 
453 private:
454     int fCacheType;
455 
456     using INHERITED = GPUSink;
457 };
458 
459 class GPUPrecompileTestingSink : public GPUSink {
460 public:
461     GPUPrecompileTestingSink(const SkCommandLineConfigGpu*, const GrContextOptions&);
462 
463     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
464 
fileExtension()465     const char* fileExtension() const override {
466         // Suppress writing out results from this config - we just want to do our matching test
467         return nullptr;
468     }
469 
470 private:
471     using INHERITED = GPUSink;
472 };
473 
474 // This sink attempts to emulate Chrome's OOP-R behavior. It:
475 //    doesn't use promise images
476 //    uses only a single thread for both DDL creation & drawing
477 class GPUOOPRSink : public GPUSink {
478 public:
479     GPUOOPRSink(const SkCommandLineConfigGpu*, const GrContextOptions&);
480 
481     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
482 
483 private:
484     Result ooprDraw(const Src&, sk_sp<SkSurface> dstSurface, GrDirectContext*) const;
485 
486     using INHERITED = GPUSink;
487 };
488 
489 // This sink attempts to better simulate the Chrome DDL use-case. It:
490 //    creates the DDLs on separate recording threads
491 //    performs all the GPU work on a separate GPU thread
492 // In the future this should be expanded to:
493 //    upload on a utility thread w/ access to a shared context
494 //    compile the programs on the utility thread
495 //    perform fine grained scheduling of gpu tasks based on their image and program prerequisites
496 //    create a single "compositing" DDL that is replayed last
497 class GPUDDLSink : public GPUSink {
498 public:
499     GPUDDLSink(const SkCommandLineConfigGpu*, const GrContextOptions&);
500 
501     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
502 
503 private:
504     Result ddlDraw(const Src&,
505                    sk_sp<SkSurface> dstSurface,
506                    SkTaskGroup* recordingTaskGroup,
507                    SkTaskGroup* gpuTaskGroup,
508                    sk_gpu_test::TestContext* gpuTestCtx,
509                    GrDirectContext* gpuThreadCtx) const;
510 
511     std::unique_ptr<SkExecutor> fRecordingExecutor;
512     std::unique_ptr<SkExecutor> fGPUExecutor;
513 
514     using INHERITED = GPUSink;
515 };
516 
517 class PDFSink : public Sink {
518 public:
PDFSink(bool pdfa,SkScalar rasterDpi)519     PDFSink(bool pdfa, SkScalar rasterDpi) : fPDFA(pdfa), fRasterDpi(rasterDpi) {}
520     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
fileExtension()521     const char* fileExtension() const override { return "pdf"; }
flags()522     SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; }
523     bool fPDFA;
524     SkScalar fRasterDpi;
525 };
526 
527 class XPSSink : public Sink {
528 public:
529     XPSSink();
530 
531     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
fileExtension()532     const char* fileExtension() const override { return "xps"; }
flags()533     SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; }
534 };
535 
536 class RasterSink : public Sink {
537 public:
538     explicit RasterSink(SkColorType, sk_sp<SkColorSpace> = nullptr);
539 
540     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
fileExtension()541     const char* fileExtension() const override { return "png"; }
flags()542     SinkFlags flags() const override { return SinkFlags{ SinkFlags::kRaster, SinkFlags::kDirect }; }
543 
544 private:
545     SkColorType         fColorType;
546     sk_sp<SkColorSpace> fColorSpace;
547 };
548 
549 class ThreadedSink : public RasterSink {
550 public:
551     explicit ThreadedSink(SkColorType, sk_sp<SkColorSpace> = nullptr);
552     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
553 };
554 
555 class SKPSink : public Sink {
556 public:
557     SKPSink();
558 
559     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
fileExtension()560     const char* fileExtension() const override { return "skp"; }
flags()561     SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; }
562 };
563 
564 class DebugSink : public Sink {
565 public:
566     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
fileExtension()567     const char* fileExtension() const override { return "json"; }
flags()568     SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; }
569 };
570 
571 class SVGSink : public Sink {
572 public:
573     SVGSink(int pageIndex = 0);
574 
575     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
fileExtension()576     const char* fileExtension() const override { return "svg"; }
flags()577     SinkFlags flags() const override { return SinkFlags{ SinkFlags::kVector, SinkFlags::kDirect }; }
578 
579 private:
580     int fPageIndex;
581 };
582 
583 
584 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
585 
586 class Via : public Sink {
587 public:
Via(Sink * sink)588     explicit Via(Sink* sink) : fSink(sink) {}
fileExtension()589     const char* fileExtension() const override { return fSink->fileExtension(); }
serial()590     bool               serial() const override { return fSink->serial(); }
flags()591     SinkFlags flags() const override {
592         SinkFlags flags = fSink->flags();
593         flags.approach = SinkFlags::kIndirect;
594         return flags;
595     }
596 protected:
597     std::unique_ptr<Sink> fSink;
598 };
599 
600 class ViaMatrix : public Via {
601 public:
602     ViaMatrix(SkMatrix, Sink*);
603     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
604 private:
605     const SkMatrix fMatrix;
606 };
607 
608 class ViaUpright : public Via {
609 public:
610     ViaUpright(SkMatrix, Sink*);
611     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
612 private:
613     const SkMatrix fMatrix;
614 };
615 
616 class ViaSerialization : public Via {
617 public:
ViaSerialization(Sink * sink)618     explicit ViaSerialization(Sink* sink) : Via(sink) {}
619     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
620 };
621 
622 class ViaPicture : public Via {
623 public:
ViaPicture(Sink * sink)624     explicit ViaPicture(Sink* sink) : Via(sink) {}
625     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
626 };
627 
628 class ViaSVG : public Via {
629 public:
ViaSVG(Sink * sink)630     explicit ViaSVG(Sink* sink) : Via(sink) {}
631     Result draw(const Src&, SkBitmap*, SkWStream*, SkString*) const override;
632 };
633 
634 }  // namespace DM
635 
636 #endif//DMSrcSink_DEFINED
637