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