• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2010 The Android Open Source Project
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 SkDevice_DEFINED
9 #define SkDevice_DEFINED
10 
11 #include "include/core/SkCanvas.h"
12 #include "include/core/SkColor.h"
13 #include "include/core/SkRefCnt.h"
14 #include "include/core/SkRegion.h"
15 #include "include/core/SkShader.h"
16 #include "include/core/SkSurfaceProps.h"
17 #include "include/private/SkNoncopyable.h"
18 #include "src/core/SkMatrixPriv.h"
19 #include "src/core/SkMatrixProvider.h"
20 #include "src/core/SkRasterClip.h"
21 #include "src/shaders/SkShaderBase.h"
22 
23 class SkBitmap;
24 struct SkDrawShadowRec;
25 class SkGlyphRun;
26 class SkGlyphRunList;
27 class SkImageFilter;
28 class SkImageFilterCache;
29 struct SkIRect;
30 class SkMarkerStack;
31 class SkRasterHandleAllocator;
32 class SkSpecialImage;
33 
34 namespace skif { class Mapping; }
35 namespace skgpu { class BaseDevice; }
36 
37 class SkBaseDevice : public SkRefCnt, public SkMatrixProvider {
38 public:
39     SkBaseDevice(const SkImageInfo&, const SkSurfaceProps&);
40 
41     /**
42      *  Return ImageInfo for this device. If the canvas is not backed by pixels
43      *  (cpu or gpu), then the info's ColorType will be kUnknown_SkColorType.
44      */
imageInfo()45     const SkImageInfo& imageInfo() const { return fInfo; }
46 
47     /**
48      *  Return SurfaceProps for this device.
49      */
surfaceProps()50     const SkSurfaceProps& surfaceProps() const {
51         return fSurfaceProps;
52     }
53 
bounds()54     SkIRect bounds() const { return SkIRect::MakeWH(this->width(), this->height()); }
55 
56     /**
57      *  Return the bounds of the device in the coordinate space of the root
58      *  canvas. The root device will have its top-left at 0,0, but other devices
59      *  such as those associated with saveLayer may have a non-zero origin.
60      */
getGlobalBounds(SkIRect * bounds)61     void getGlobalBounds(SkIRect* bounds) const {
62         SkASSERT(bounds);
63         *bounds = SkMatrixPriv::MapRect(fDeviceToGlobal, SkRect::Make(this->bounds())).roundOut();
64     }
65 
getGlobalBounds()66     SkIRect getGlobalBounds() const {
67         SkIRect bounds;
68         this->getGlobalBounds(&bounds);
69         return bounds;
70     }
71 
72     /**
73      *  Returns the bounding box of the current clip, in this device's
74      *  coordinate space. No pixels outside of these bounds will be touched by
75      *  draws unless the clip is further modified (at which point this will
76      *  return the updated bounds).
77      */
devClipBounds()78     SkIRect devClipBounds() const { return this->onDevClipBounds(); }
79 
width()80     int width() const {
81         return this->imageInfo().width();
82     }
83 
height()84     int height() const {
85         return this->imageInfo().height();
86     }
87 
isOpaque()88     bool isOpaque() const {
89         return this->imageInfo().isOpaque();
90     }
91 
92     bool writePixels(const SkPixmap&, int x, int y);
93 
94     /**
95      *  Try to get write-access to the pixels behind the device. If successful, this returns true
96      *  and fills-out the pixmap parameter. On success it also bumps the genID of the underlying
97      *  bitmap.
98      *
99      *  On failure, returns false and ignores the pixmap parameter.
100      */
101     bool accessPixels(SkPixmap* pmap);
102 
103     /**
104      *  Try to get read-only-access to the pixels behind the device. If successful, this returns
105      *  true and fills-out the pixmap parameter.
106      *
107      *  On failure, returns false and ignores the pixmap parameter.
108      */
109     bool peekPixels(SkPixmap*);
110 
111     /**
112      *  Return the device's coordinate space transform: this maps from the device's coordinate space
113      *  into the global canvas' space (or root device space). This includes the translation
114      *  necessary to account for the device's origin.
115      */
deviceToGlobal()116     const SkM44& deviceToGlobal() const { return fDeviceToGlobal; }
117     /**
118      *  Return the inverse of getDeviceToGlobal(), mapping from the global canvas' space (or root
119      *  device space) into this device's coordinate space.
120      */
globalToDevice()121     const SkM44& globalToDevice() const { return fGlobalToDevice; }
122     /**
123      *  DEPRECATED: This asserts that 'getDeviceToGlobal' is a translation matrix with integer
124      *  components. In the future some SkDevices will have more complex device-to-global transforms,
125      *  so getDeviceToGlobal() or getRelativeTransform() should be used instead.
126      */
127     SkIPoint getOrigin() const;
128     /**
129      * Returns true when this device's pixel grid is axis aligned with the global coordinate space,
130      * and any relative translation between the two spaces is in integer pixel units.
131      */
132     bool isPixelAlignedToGlobal() const;
133     /**
134      * Get the transformation from this device's coordinate system to the provided device space.
135      * This transform can be used to draw this device into the provided device, such that once
136      * that device is drawn to the root device, the net effect will be that this device's contents
137      * have been transformed by the global CTM.
138      */
139     SkMatrix getRelativeTransform(const SkBaseDevice&) const;
140 
getRasterHandle()141     virtual void* getRasterHandle() const { return nullptr; }
142 
markerStack()143     SkMarkerStack* markerStack() const { return fMarkerStack; }
setMarkerStack(SkMarkerStack * ms)144     void setMarkerStack(SkMarkerStack* ms) { fMarkerStack = ms; }
145 
146     // SkMatrixProvider interface:
147     bool getLocalToMarker(uint32_t, SkM44* localToMarker) const override;
localToDeviceHitsPixelCenters()148     bool localToDeviceHitsPixelCenters() const override { return true; }
149 
asMatrixProvider()150     const SkMatrixProvider& asMatrixProvider() const { return *this; }
151 
save()152     void save() { this->onSave(); }
restore(const SkM44 & ctm)153     void restore(const SkM44& ctm) {
154         this->onRestore();
155         this->setGlobalCTM(ctm);
156     }
restoreLocal(const SkM44 & localToDevice)157     void restoreLocal(const SkM44& localToDevice) {
158         this->onRestore();
159         this->setLocalToDevice(localToDevice);
160     }
clipRect(const SkRect & rect,SkClipOp op,bool aa)161     void clipRect(const SkRect& rect, SkClipOp op, bool aa) {
162         this->onClipRect(rect, op, aa);
163     }
clipRRect(const SkRRect & rrect,SkClipOp op,bool aa)164     void clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) {
165         this->onClipRRect(rrect, op, aa);
166     }
clipPath(const SkPath & path,SkClipOp op,bool aa)167     void clipPath(const SkPath& path, SkClipOp op, bool aa) {
168         this->onClipPath(path, op, aa);
169     }
clipShader(sk_sp<SkShader> sh,SkClipOp op)170     void clipShader(sk_sp<SkShader> sh, SkClipOp op) {
171         sh = as_SB(sh)->makeWithCTM(this->localToDevice());
172         if (op == SkClipOp::kDifference) {
173             sh = as_SB(sh)->makeInvertAlpha();
174         }
175         this->onClipShader(std::move(sh));
176     }
clipRegion(const SkRegion & region,SkClipOp op)177     void clipRegion(const SkRegion& region, SkClipOp op) {
178         this->onClipRegion(region, op);
179     }
replaceClip(const SkIRect & rect)180     void replaceClip(const SkIRect& rect) {
181         this->onReplaceClip(rect);
182     }
183 
clipIsWideOpen()184     bool clipIsWideOpen() const {
185         return this->onClipIsWideOpen();
186     }
187 
setLocalToDevice(const SkM44 & localToDevice)188     void setLocalToDevice(const SkM44& localToDevice) {
189         fLocalToDevice = localToDevice;
190         fLocalToDevice33 = fLocalToDevice.asM33();
191     }
192     void setGlobalCTM(const SkM44& ctm);
validateDevBounds(const SkIRect &)193     virtual void validateDevBounds(const SkIRect&) {}
194 
android_utils_clipWithStencil()195     virtual bool android_utils_clipWithStencil() { return false; }
196 
asGpuDevice()197     virtual skgpu::BaseDevice* asGpuDevice() { return nullptr; }
198 
199     // Ensure that non-RSXForm runs are passed to onDrawGlyphRunList.
200     void drawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint);
201 
202 protected:
203     enum TileUsage {
204         kPossible_TileUsage,    //!< the created device may be drawn tiled
205         kNever_TileUsage,       //!< the created device will never be drawn tiled
206     };
207 
208     struct TextFlags {
209         uint32_t    fFlags;     // SkPaint::getFlags()
210     };
211 
onSave()212     virtual void onSave() {}
onRestore()213     virtual void onRestore() {}
onClipRect(const SkRect & rect,SkClipOp,bool aa)214     virtual void onClipRect(const SkRect& rect, SkClipOp, bool aa) {}
onClipRRect(const SkRRect & rrect,SkClipOp,bool aa)215     virtual void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) {}
onClipPath(const SkPath & path,SkClipOp,bool aa)216     virtual void onClipPath(const SkPath& path, SkClipOp, bool aa) {}
onClipShader(sk_sp<SkShader>)217     virtual void onClipShader(sk_sp<SkShader>) {}
onClipRegion(const SkRegion & deviceRgn,SkClipOp)218     virtual void onClipRegion(const SkRegion& deviceRgn, SkClipOp) {}
onReplaceClip(const SkIRect & rect)219     virtual void onReplaceClip(const SkIRect& rect) {}
220     virtual bool onClipIsAA() const = 0;
221     virtual bool onClipIsWideOpen() const = 0;
222     virtual void onAsRgnClip(SkRegion*) const = 0;
223     enum class ClipType {
224         kEmpty,
225         kRect,
226         kComplex
227     };
228     virtual ClipType onGetClipType() const = 0;
229 
230     // This should strive to be as tight as possible, ideally not just mapping
231     // the global clip bounds by fToGlobal^-1.
232     virtual SkIRect onDevClipBounds() const = 0;
233 
234     /** These are called inside the per-device-layer loop for each draw call.
235      When these are called, we have already applied any saveLayer operations,
236      and are handling any looping from the paint.
237      */
238     virtual void drawPaint(const SkPaint& paint) = 0;
239     virtual void drawPoints(SkCanvas::PointMode mode, size_t count,
240                             const SkPoint[], const SkPaint& paint) = 0;
241     virtual void drawRect(const SkRect& r,
242                           const SkPaint& paint) = 0;
243     virtual void drawRegion(const SkRegion& r,
244                             const SkPaint& paint);
245     virtual void drawOval(const SkRect& oval,
246                           const SkPaint& paint) = 0;
247     /** By the time this is called we know that abs(sweepAngle) is in the range [0, 360). */
248     virtual void drawArc(const SkRect& oval, SkScalar startAngle,
249                          SkScalar sweepAngle, bool useCenter, const SkPaint& paint);
250     virtual void drawRRect(const SkRRect& rr,
251                            const SkPaint& paint) = 0;
252 
253     // Default impl calls drawPath()
254     virtual void drawDRRect(const SkRRect& outer,
255                             const SkRRect& inner, const SkPaint&);
256 
257     /**
258      *  If pathIsMutable, then the implementation is allowed to cast path to a
259      *  non-const pointer and modify it in place (as an optimization). Canvas
260      *  may do this to implement helpers such as drawOval, by placing a temp
261      *  path on the stack to hold the representation of the oval.
262      */
263     virtual void drawPath(const SkPath& path,
264                           const SkPaint& paint,
265                           bool pathIsMutable = false) = 0;
266 
267     virtual void drawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
268                                const SkSamplingOptions&, const SkPaint&,
269                                SkCanvas::SrcRectConstraint) = 0;
270     virtual void drawImageLattice(const SkImage*, const SkCanvas::Lattice&,
271                                   const SkRect& dst, SkFilterMode, const SkPaint&);
272 
273     virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) = 0;
274     virtual void drawShadow(const SkPath&, const SkDrawShadowRec&);
275 
276     // default implementation calls drawVertices
277     virtual void drawPatch(const SkPoint cubics[12], const SkColor colors[4],
278                            const SkPoint texCoords[4], SkBlendMode, const SkPaint& paint);
279 
280     // default implementation calls drawVertices
281     virtual void drawAtlas(const SkRSXform[], const SkRect[], const SkColor[], int count,
282                            SkBlendMode, const SkPaint&);
283 
drawAnnotation(const SkRect &,const char[],SkData *)284     virtual void drawAnnotation(const SkRect&, const char[], SkData*) {}
285 
286     // Default impl always calls drawRect() with a solid-color paint, setting it to anti-aliased
287     // only when all edge flags are set. If there's a clip region, it draws that using drawPath,
288     // or uses clipPath().
289     virtual void drawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
290                                 SkCanvas::QuadAAFlags aaFlags, const SkColor4f& color,
291                                 SkBlendMode mode);
292     // Default impl uses drawImageRect per entry, being anti-aliased only when an entry's edge flags
293     // are all set. If there's a clip region, it will be applied using clipPath().
294     virtual void drawEdgeAAImageSet(const SkCanvas::ImageSetEntry[], int count,
295                                     const SkPoint dstClips[], const SkMatrix preViewMatrices[],
296                                     const SkSamplingOptions&, const SkPaint&,
297                                     SkCanvas::SrcRectConstraint);
298 
299     virtual void drawDrawable(SkDrawable*, const SkMatrix*, SkCanvas*);
300 
301     // Only called with glyphRunLists that do not contain RSXForm.
302     virtual void onDrawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint) = 0;
303 
304     /**
305      * The SkDevice passed will be an SkDevice which was returned by a call to
306      * onCreateDevice on this device with kNeverTile_TileExpectation.
307      *
308      * The default implementation calls snapSpecial() and drawSpecial() with the relative transform
309      * from the input device to this device. The provided SkPaint cannot have a mask filter or
310      * image filter, and any shader is ignored.
311      */
312     virtual void drawDevice(SkBaseDevice*, const SkSamplingOptions&, const SkPaint&);
313 
314     /**
315      * Draw the special image's subset to this device, subject to the given matrix transform instead
316      * of the device's current local to device matrix.
317      */
318     virtual void drawSpecial(SkSpecialImage*, const SkMatrix& localToDevice,
319                              const SkSamplingOptions&, const SkPaint&);
320 
321     /**
322      * Evaluate 'filter' and draw the final output into this device using 'paint'. The 'mapping'
323      * defines the parameter-to-layer space transform used to evaluate the image filter on 'src',
324      * and the layer-to-device space transform that is used to draw the result into this device.
325      * Since 'mapping' fully specifies the transform, this draw function ignores the current
326      * local-to-device matrix (i.e. just like drawSpecial and drawDevice).
327      *
328      * The final paint must not have an image filter or mask filter set on it; a shader is ignored.
329      */
330     virtual void drawFilteredImage(const skif::Mapping& mapping, SkSpecialImage* src,
331                                    const SkImageFilter*, const SkSamplingOptions&, const SkPaint&);
332 
333     virtual sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&);
334     virtual sk_sp<SkSpecialImage> makeSpecial(const SkImage*);
335 
336     // Get a view of the entire device's current contents as an image.
337     sk_sp<SkSpecialImage> snapSpecial();
338     // Snap the 'subset' contents from this device, possibly as a read-only view. If 'forceCopy'
339     // is true then the returned image's pixels must not be affected by subsequent draws into the
340     // device. When 'forceCopy' is false, the image can be a view into the device's pixels
341     // (avoiding a copy for performance, at the expense of safety). Default returns null.
342     virtual sk_sp<SkSpecialImage> snapSpecial(const SkIRect& subset, bool forceCopy = false);
343 
setImmutable()344     virtual void setImmutable() {}
345 
346     bool readPixels(const SkPixmap&, int x, int y);
347 
348     virtual sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&);
onPeekPixels(SkPixmap *)349     virtual bool onPeekPixels(SkPixmap*) { return false; }
350 
351     /**
352      *  The caller is responsible for "pre-clipping" the dst. The impl can assume that the dst
353      *  image at the specified x,y offset will fit within the device's bounds.
354      *
355      *  This is explicitly asserted in readPixels(), the public way to call this.
356      */
357     virtual bool onReadPixels(const SkPixmap&, int x, int y);
358 
359     /**
360      *  The caller is responsible for "pre-clipping" the src. The impl can assume that the src
361      *  image at the specified x,y offset will fit within the device's bounds.
362      *
363      *  This is explicitly asserted in writePixelsDirect(), the public way to call this.
364      */
365     virtual bool onWritePixels(const SkPixmap&, int x, int y);
366 
onAccessPixels(SkPixmap *)367     virtual bool onAccessPixels(SkPixmap*) { return false; }
368 
369     struct CreateInfo {
CreateInfoCreateInfo370         CreateInfo(const SkImageInfo& info,
371                    SkPixelGeometry geo,
372                    TileUsage tileUsage,
373                    bool trackCoverage,
374                    SkRasterHandleAllocator* allocator)
375             : fInfo(info)
376             , fTileUsage(tileUsage)
377             , fPixelGeometry(geo)
378             , fTrackCoverage(trackCoverage)
379             , fAllocator(allocator)
380         {}
381 
382         const SkImageInfo       fInfo;
383         const TileUsage         fTileUsage;
384         const SkPixelGeometry   fPixelGeometry;
385         const bool              fTrackCoverage = false;
386         SkRasterHandleAllocator* fAllocator = nullptr;
387     };
388 
389     /**
390      *  Create a new device based on CreateInfo. If the paint is not null, then it represents a
391      *  preview of how the new device will be composed with its creator device (this).
392      *
393      *  The subclass may be handed this device in drawDevice(), so it must always return
394      *  a device that it knows how to draw, and that it knows how to identify if it is not of the
395      *  same subclass (since drawDevice is passed a SkBaseDevice*). If the subclass cannot fulfill
396      *  that contract (e.g. PDF cannot support some settings on the paint) it should return NULL,
397      *  and the caller may then decide to explicitly create a bitmapdevice, knowing that later
398      *  it could not call drawDevice with it (but it could call drawSprite or drawBitmap).
399      */
onCreateDevice(const CreateInfo &,const SkPaint *)400     virtual SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) {
401         return nullptr;
402     }
403 
404     // SkCanvas uses NoPixelsDevice when onCreateDevice fails; but then it needs to be able to
405     // inspect a layer's device to know if calling drawDevice() later is allowed.
isNoPixelsDevice()406     virtual bool isNoPixelsDevice() const { return false; }
407 
408 private:
409     friend class SkAndroidFrameworkUtils;
410     friend class SkCanvas;
411     friend class SkDraw;
412     friend class SkSurface_Raster;
413     friend class DeviceTestingAccess;
414 
415     void simplifyGlyphRunRSXFormAndRedraw(const SkGlyphRunList& glyphRunList, const SkPaint& paint);
416 
417     // used to change the backend's pixels (and possibly config/rowbytes)
418     // but cannot change the width/height, so there should be no change to
419     // any clip information.
420     // TODO: move to SkBitmapDevice
replaceBitmapBackendForRasterSurface(const SkBitmap &)421     virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) {}
422 
forceConservativeRasterClip()423     virtual bool forceConservativeRasterClip() const { return false; }
424 
425     // Configure the device's coordinate spaces, specifying both how its device image maps back to
426     // the global space (via 'deviceToGlobal') and the initial CTM of the device (via
427     // 'localToDevice', i.e. what geometry drawn into this device will be transformed with).
428     //
429     // (bufferOriginX, bufferOriginY) defines where the (0,0) pixel the device's backing buffer
430     // is anchored in the device space. The final device-to-global matrix stored by the SkDevice
431     // will include a pre-translation by T(deviceOriginX, deviceOriginY), and the final
432     // local-to-device matrix will have a post-translation of T(-deviceOriginX, -deviceOriginY).
433     //
434     // Returns false if the final device coordinate space is invalid, in which case the canvas
435     // should discard the device
436     bool SK_WARN_UNUSED_RESULT setDeviceCoordinateSystem(const SkM44& deviceToGlobal,
437                                                          const SkM44& localToDevice,
438                                                          int bufferOriginX, int bufferOriginY);
439     // Convenience to configure the device to be axis-aligned with the root canvas, but with a
440     // unique origin.
setOrigin(const SkM44 & globalCTM,int x,int y)441     void setOrigin(const SkM44& globalCTM, int x, int y) {
442         SkAssertResult(this->setDeviceCoordinateSystem(SkM44(), globalCTM, x, y));
443     }
444 
getImageFilterCache()445     virtual SkImageFilterCache* getImageFilterCache() { return nullptr; }
446 
447     friend class SkNoPixelsDevice;
448     friend class SkBitmapDevice;
privateResize(int w,int h)449     void privateResize(int w, int h) {
450         *const_cast<SkImageInfo*>(&fInfo) = fInfo.makeWH(w, h);
451     }
452 
453     SkMarkerStack* fMarkerStack = nullptr;  // does not own this, set in setMarkerStack()
454 
455     const SkImageInfo    fInfo;
456     const SkSurfaceProps fSurfaceProps;
457     // fDeviceToGlobal and fGlobalToDevice are inverses of each other; there are never that many
458     // SkDevices, so pay the memory cost to avoid recalculating the inverse.
459     SkM44 fDeviceToGlobal;
460     SkM44 fGlobalToDevice;
461 
462     // fLocalToDevice (inherited from SkMatrixProvider) is the device CTM, not the global CTM
463     // It maps from local space to the device's coordinate space.
464     // fDeviceToGlobal * fLocalToDevice will match the canvas' CTM.
465 
466     using INHERITED = SkRefCnt;
467 };
468 
469 class SkNoPixelsDevice : public SkBaseDevice {
470 public:
471     SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props,
472                      sk_sp<SkColorSpace> colorSpace = nullptr)
473             : SkBaseDevice(SkImageInfo::Make(bounds.size(), kUnknown_SkColorType,
474                                              kUnknown_SkAlphaType, std::move(colorSpace)),
475                            props) {
476         // this fails if we enable this assert: DiscardableImageMapTest.GetDiscardableImagesInRectMaxImage
477         //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
478 
479         this->setOrigin(SkM44(), bounds.left(), bounds.top());
480         this->resetClipStack();
481     }
482 
resetForNextPicture(const SkIRect & bounds)483     void resetForNextPicture(const SkIRect& bounds) {
484         //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0);
485         this->privateResize(bounds.width(), bounds.height());
486         this->setOrigin(SkM44(), bounds.left(), bounds.top());
487         this->resetClipStack();
488     }
489 
490 protected:
491     // SkNoPixelsDevice tracks the clip conservatively in order to respond to some queries as
492     // accurately as possible while emphasizing performance
493     void onSave() override;
494     void onRestore() override;
495     void onClipRect(const SkRect& rect, SkClipOp op, bool aa) override;
496     void onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) override;
497     void onClipPath(const SkPath& path, SkClipOp op, bool aa) override;
498     void onClipRegion(const SkRegion& globalRgn, SkClipOp op) override;
499     void onClipShader(sk_sp<SkShader> shader) override;
500     void onReplaceClip(const SkIRect& rect) override;
onClipIsAA()501     bool onClipIsAA() const override { return this->clip().fIsAA; }
onClipIsWideOpen()502     bool onClipIsWideOpen() const override {
503         return this->clip().fIsRect &&
504                this->onDevClipBounds() == this->bounds();
505     }
onAsRgnClip(SkRegion * rgn)506     void onAsRgnClip(SkRegion* rgn) const override {
507         rgn->setRect(this->onDevClipBounds());
508     }
509     ClipType onGetClipType() const override;
onDevClipBounds()510     SkIRect onDevClipBounds() const override { return this->clip().fClipBounds; }
511 
drawPaint(const SkPaint & paint)512     void drawPaint(const SkPaint& paint) override {}
drawPoints(SkCanvas::PointMode,size_t,const SkPoint[],const SkPaint &)513     void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
drawImageRect(const SkImage *,const SkRect *,const SkRect &,const SkSamplingOptions &,const SkPaint &,SkCanvas::SrcRectConstraint)514     void drawImageRect(const SkImage*, const SkRect*, const SkRect&,
515                        const SkSamplingOptions&, const SkPaint&,
516                        SkCanvas::SrcRectConstraint) override {}
drawRect(const SkRect &,const SkPaint &)517     void drawRect(const SkRect&, const SkPaint&) override {}
drawOval(const SkRect &,const SkPaint &)518     void drawOval(const SkRect&, const SkPaint&) override {}
drawRRect(const SkRRect &,const SkPaint &)519     void drawRRect(const SkRRect&, const SkPaint&) override {}
drawPath(const SkPath &,const SkPaint &,bool)520     void drawPath(const SkPath&, const SkPaint&, bool) override {}
drawDevice(SkBaseDevice *,const SkSamplingOptions &,const SkPaint &)521     void drawDevice(SkBaseDevice*, const SkSamplingOptions&, const SkPaint&) override {}
drawVertices(const SkVertices *,SkBlendMode,const SkPaint &)522     void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {}
523 
drawFilteredImage(const skif::Mapping &,SkSpecialImage * src,const SkImageFilter *,const SkSamplingOptions &,const SkPaint &)524     void drawFilteredImage(const skif::Mapping&, SkSpecialImage* src, const SkImageFilter*,
525                            const SkSamplingOptions&, const SkPaint&) override {}
526 
onDrawGlyphRunList(const SkGlyphRunList & glyphRunList,const SkPaint & paint)527     void onDrawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint) override {}
528 
529 
isNoPixelsDevice()530     bool isNoPixelsDevice() const override { return true; }
531 
532 private:
533     struct ClipState {
534         SkIRect fClipBounds;
535         int fDeferredSaveCount;
536         bool fIsAA;
537         bool fIsRect;
538 
ClipStateClipState539         ClipState(const SkIRect& bounds, bool isAA, bool isRect)
540                 : fClipBounds(bounds)
541                 , fDeferredSaveCount(0)
542                 , fIsAA(isAA)
543                 , fIsRect(isRect) {}
544 
545         void op(SkClipOp op, const SkM44& transform, const SkRect& bounds,
546                 bool isAA, bool fillsBounds);
547     };
548 
clip()549     const ClipState& clip() const { return fClipStack.back(); }
550     ClipState& writableClip();
551 
resetClipStack()552     void resetClipStack() {
553         fClipStack.reset();
554         fClipStack.emplace_back(this->bounds(), /*isAA=*/false, /*isRect=*/true);
555     }
556 
557     SkSTArray<4, ClipState> fClipStack;
558 
559     using INHERITED = SkBaseDevice;
560 };
561 
562 class SkAutoDeviceTransformRestore : SkNoncopyable {
563 public:
SkAutoDeviceTransformRestore(SkBaseDevice * device,const SkMatrix & localToDevice)564     SkAutoDeviceTransformRestore(SkBaseDevice* device, const SkMatrix& localToDevice)
565         : fDevice(device)
566         , fPrevLocalToDevice(device->localToDevice())
567     {
568         fDevice->setLocalToDevice(SkM44(localToDevice));
569     }
~SkAutoDeviceTransformRestore()570     ~SkAutoDeviceTransformRestore() {
571         fDevice->setLocalToDevice(fPrevLocalToDevice);
572     }
573 
574 private:
575     SkBaseDevice* fDevice;
576     const SkM44   fPrevLocalToDevice;
577 };
578 
579 #endif
580