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