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