xref: /aosp_15_r20/external/skia/src/core/SkDevice.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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"  // IWYU pragma: keep
12 #include "include/core/SkCanvas.h"
13 #include "include/core/SkClipOp.h"
14 #include "include/core/SkColor.h"
15 #include "include/core/SkImageInfo.h"
16 #include "include/core/SkM44.h"
17 #include "include/core/SkMatrix.h"
18 #include "include/core/SkPoint.h"
19 #include "include/core/SkRect.h"
20 #include "include/core/SkRefCnt.h"
21 #include "include/core/SkRegion.h"
22 #include "include/core/SkSamplingOptions.h"
23 #include "include/core/SkShader.h"
24 #include "include/core/SkSize.h"
25 #include "include/core/SkSurfaceProps.h"
26 #include "include/private/base/SkAssert.h"
27 #include "include/private/base/SkNoncopyable.h"
28 #include "include/private/base/SkTArray.h"
29 #include "src/core/SkMatrixPriv.h"
30 #include "src/shaders/SkShaderBase.h"
31 
32 #include <cstddef>
33 #include <cstdint>
34 #include <utility>
35 
36 struct SkArc;
37 class SkBitmap;
38 class SkColorSpace;
39 class SkMesh;
40 struct SkDrawShadowRec;
41 class SkImageFilter;
42 class SkRasterHandleAllocator;
43 class SkSpecialImage;
44 class GrRecordingContext;
45 class SkData;
46 class SkDrawable;
47 class SkImage;
48 class SkPaint;
49 class SkPath;
50 class SkPixmap;
51 class SkRRect;
52 class SkSurface;
53 class SkVertices;
54 enum SkColorType : int;
55 enum class SkBlendMode;
56 enum class SkScalerContextFlags : uint32_t;
57 struct SkRSXform;
58 
59 namespace sktext {
60 class GlyphRunList;
61 }
62 
63 namespace skif {
64 class Backend;
65 class Mapping;
66 }
67 namespace skgpu::ganesh {
68 class Device;
69 }
70 namespace skgpu::graphite {
71 class Device;
72 class Recorder;
73 }
74 namespace sktext::gpu {
75 class SubRunControl;
76 class Slug;
77 }
78 
79 struct SkStrikeDeviceInfo {
80     const SkSurfaceProps fSurfaceProps;
81     const SkScalerContextFlags fScalerContextFlags;
82     // This is a pointer so this can be compiled without SK_GPU_SUPPORT.
83     const sktext::gpu::SubRunControl* const fSubRunControl;
84 };
85 
86 /**
87  * SkDevice is the internal API and implementation that SkCanvas will use to perform rendering and
88  * implement the saveLayer abstraction. A device wraps some pixel allocation (for non-document based
89  * devices) or wraps some other container that stores rendering operations. The drawing operations
90  * perform equivalently to their corresponding functions in SkCanvas except that the canvas is
91  * responsible for all SkImageFilters. An image filter is applied by automatically creating a layer,
92  * drawing the filter-less paint into the layer, and then evaluating the filter on the layer's
93  * image.
94  *
95  * Each layer in an SkCanvas stack is represented by an SkDevice instance that was created by the
96  * parent SkDevice (up to the canvas's base device). In most cases these devices will be pixel
97  * aligned with one another but may differ in size based on the known extent of the active clip. In
98  * complex image filtering scenarios, they may not be axis aligned, although the effective pixel
99  * size should remain approximately equal across all devices in a canvas.
100  *
101  * While SkCanvas manages a single stack of layers and canvas transforms, SkDevice does not have a
102  * stack of transforms. Instead, it has a single active transform that is modified as needed by
103  * SkCanvas. However, SkDevices are the means by which SkCanvas manages the clip stack because each
104  * layer's clip stack starts anew (although the layer's results are then clipped by its parent's
105  * stack when it is restored).
106  */
107 class SkDevice : public SkRefCnt {
108 public:
109     SkDevice(const SkImageInfo&, const SkSurfaceProps&);
110 
111     // -- Surface properties and metadata
112 
113     /**
114      *  Return ImageInfo for this device. If the canvas is not backed by pixels
115      *  (cpu or gpu), then the info's ColorType will be kUnknown_SkColorType.
116      */
imageInfo()117     const SkImageInfo& imageInfo() const { return fInfo; }
118 
width()119     int width() const { return this->imageInfo().width(); }
height()120     int height() const { return this->imageInfo().height(); }
121 
isOpaque()122     bool isOpaque() const { return this->imageInfo().isOpaque(); }
123 
124     // NOTE: Image dimensions as a rect, *not* the current restricted clip bounds.
bounds()125     SkIRect bounds() const { return SkIRect::MakeWH(this->width(), this->height()); }
size()126     SkISize size() const { return this->imageInfo().dimensions(); }
127 
128     /**
129      *  Return SurfaceProps for this device.
130      */
surfaceProps()131     const SkSurfaceProps& surfaceProps() const {
132         return fSurfaceProps;
133     }
134 
135     SkScalerContextFlags scalerContextFlags() const;
136 
strikeDeviceInfo()137     virtual SkStrikeDeviceInfo strikeDeviceInfo() const {
138         return {fSurfaceProps, this->scalerContextFlags(), nullptr};
139     }
140 
141     // -- Direct pixel manipulation
142 
143     /**
144      *  Write the pixels in 'src' into this Device at the specified x,y offset. The caller is
145      *  responsible for "pre-clipping" the src.
146      */
writePixels(const SkPixmap & src,int x,int y)147     bool writePixels(const SkPixmap& src, int x, int y) { return this->onWritePixels(src, x, y); }
148 
149     /**
150      *  Read pixels from this Device at the specified x,y offset into dst. The caller is
151      *  responsible for "pre-clipping" the dst
152      */
readPixels(const SkPixmap & dst,int x,int y)153     bool readPixels(const SkPixmap& dst, int x, int y) { return this->onReadPixels(dst, x, y); }
154 
155     /**
156      *  Try to get write-access to the pixels behind the device. If successful, this returns true
157      *  and fills-out the pixmap parameter. On success it also bumps the genID of the underlying
158      *  bitmap.
159      *
160      *  On failure, returns false and ignores the pixmap parameter.
161      */
162     bool accessPixels(SkPixmap* pmap);
163 
164     /**
165      *  Try to get read-only-access to the pixels behind the device. If successful, this returns
166      *  true and fills-out the pixmap parameter.
167      *
168      *  On failure, returns false and ignores the pixmap parameter.
169      */
170     bool peekPixels(SkPixmap*);
171 
172 
173     // -- Device's transform (both current transform affecting draws, and its fixed global mapping)
174 
175     /**
176      *  Returns the transformation that maps from the local space to the device's coordinate space.
177      */
localToDevice44()178     const SkM44& localToDevice44() const { return fLocalToDevice; }
localToDevice()179     const SkMatrix& localToDevice() const { return fLocalToDevice33; }
180 
181     /**
182      *  Return the device's coordinate space transform: this maps from the device's coordinate space
183      *  into the global canvas' space (or root device space). This includes the translation
184      *  necessary to account for the device's origin.
185      */
deviceToGlobal()186     const SkM44& deviceToGlobal() const { return fDeviceToGlobal; }
187     /**
188      *  Return the inverse of getDeviceToGlobal(), mapping from the global canvas' space (or root
189      *  device space) into this device's coordinate space.
190      */
globalToDevice()191     const SkM44& globalToDevice() const { return fGlobalToDevice; }
192     /**
193      *  DEPRECATED: This asserts that 'getDeviceToGlobal' is a translation matrix with integer
194      *  components. In the future some SkDevices will have more complex device-to-global transforms,
195      *  so getDeviceToGlobal() or getRelativeTransform() should be used instead.
196      */
197     SkIPoint getOrigin() const;
198     /**
199      * Returns true when this device's pixel grid is axis aligned with the global coordinate space,
200      * and any relative translation between the two spaces is in integer pixel units.
201      */
202     bool isPixelAlignedToGlobal() const;
203     /**
204      * Get the transformation from this device's coordinate system to the provided device space.
205      * This transform can be used to draw this device into the provided device, such that once
206      * that device is drawn to the root device, the net effect will be that this device's contents
207      * have been transformed by the global CTM.
208      */
209     SkMatrix getRelativeTransform(const SkDevice&) const;
210 
setLocalToDevice(const SkM44 & localToDevice)211     void setLocalToDevice(const SkM44& localToDevice) {
212         fLocalToDevice = localToDevice;
213         fLocalToDevice33 = fLocalToDevice.asM33();
214         fLocalToDeviceDirty = true;
215     }
216     void setGlobalCTM(const SkM44& ctm);
217 
218     // -- Device's clip bounds and stack manipulation
219 
220     /**
221      *  Return the bounds of the device in the coordinate space of the root canvas. The root device
222      *  will have its top-left at 0,0, but other devices such as those associated with saveLayer may
223      *  have a non-zero origin.
224      */
getGlobalBounds(SkIRect * bounds)225     void getGlobalBounds(SkIRect* bounds) const {
226         SkASSERT(bounds);
227         *bounds = SkMatrixPriv::MapRect(fDeviceToGlobal, SkRect::Make(this->bounds())).roundOut();
228     }
229 
getGlobalBounds()230     SkIRect getGlobalBounds() const {
231         SkIRect bounds;
232         this->getGlobalBounds(&bounds);
233         return bounds;
234     }
235 
236     /**
237      *  Returns the bounding box of the current clip, in this device's coordinate space. No pixels
238      *  outside of these bounds will be touched by draws unless the clip is further modified (at
239      *  which point this will return the updated bounds).
240      */
241     virtual SkIRect devClipBounds() const = 0;
242 
243     virtual void pushClipStack() = 0;
244     virtual void popClipStack() = 0;
245 
246     virtual void clipRect(const SkRect& rect, SkClipOp op, bool aa) = 0;
247     virtual void clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) = 0;
248     virtual void clipPath(const SkPath& path, SkClipOp op, bool aa) = 0;
249     virtual void clipRegion(const SkRegion& region, SkClipOp op) = 0;
250 
clipShader(sk_sp<SkShader> sh,SkClipOp op)251     void clipShader(sk_sp<SkShader> sh, SkClipOp op) {
252         sh = as_SB(sh)->makeWithCTM(this->localToDevice());
253         if (op == SkClipOp::kDifference) {
254             sh = as_SB(sh)->makeInvertAlpha();
255         }
256         this->onClipShader(std::move(sh));
257     }
258 
259     virtual void replaceClip(const SkIRect& rect) = 0;
260 
261     virtual bool isClipAntiAliased() const = 0;
262     virtual bool isClipEmpty() const = 0;
263     virtual bool isClipRect() const = 0;
264     virtual bool isClipWideOpen() const = 0;
265 
266     virtual void android_utils_clipAsRgn(SkRegion*) const = 0;
android_utils_clipWithStencil()267     virtual bool android_utils_clipWithStencil() { return false; }
268 
269     // -- Device reflection
270 
271     // TEMPORARY: Whether or not SkCanvas should use an layer and image filters to simulate
272     // mask filters and then draw the filtered mask using drawCoverageMask. Unlike regular
273     // layers, the color type passed to SkDevice::createDevice() will always be an alpha-only
274     // color type. Eventually this will be the only way that mask filters are handled (barring
275     // dedicated fast-paths for blurs on [r]rects and text).
useDrawCoverageMaskForMaskFilters()276     virtual bool useDrawCoverageMaskForMaskFilters() const { return false; }
277 
278     // SkCanvas uses NoPixelsDevice when createDevice fails; but then it needs to be able to
279     // inspect a layer's device to know if calling drawDevice() later is allowed.
isNoPixelsDevice()280     virtual bool isNoPixelsDevice() const { return false; }
281 
getRasterHandle()282     virtual void* getRasterHandle() const { return nullptr; }
283 
recordingContext()284     virtual GrRecordingContext* recordingContext() const { return nullptr; }
recorder()285     virtual skgpu::graphite::Recorder* recorder() const { return nullptr; }
286 
asGaneshDevice()287     virtual skgpu::ganesh::Device* asGaneshDevice() { return nullptr; }
asGraphiteDevice()288     virtual skgpu::graphite::Device* asGraphiteDevice() { return nullptr; }
289 
290     // Marking an SkDevice immutable declares the intent that rendering to the device is
291     // complete, allowing it to be sampled as an image without requiring a copy. Drawing
292     // operations may not function and may assert if invoked after setImmutable() is called.
setImmutable()293     virtual void setImmutable() {}
294 
295     virtual sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&);
296 
297     struct CreateInfo {
CreateInfoCreateInfo298         CreateInfo(const SkImageInfo& info,
299                    SkPixelGeometry geo,
300                    SkRasterHandleAllocator* allocator)
301             : fInfo(info)
302             , fPixelGeometry(geo)
303             , fAllocator(allocator)
304         {}
305 
306         const SkImageInfo        fInfo;
307         const SkPixelGeometry    fPixelGeometry;
308         SkRasterHandleAllocator* fAllocator = nullptr;
309     };
310 
311     /**
312      *  Create a new device based on CreateInfo. If the paint is not null, then it represents a
313      *  preview of how the new device will be composed with its creator device (this).
314      *
315      *  The subclass may be handed this device in drawDevice(), so it must always return a device
316      *  that it knows how to draw, and that it knows how to identify if it is not of the same
317      *  subclass (since drawDevice is passed a SkDevice*). If the subclass cannot fulfill that
318      *  contract (e.g. PDF cannot support some settings on the paint) it should return NULL, and the
319      *  caller may then decide to explicitly create a bitmapdevice, knowing that later it could not
320      *  call drawDevice with it (but it could call drawSprite or drawBitmap).
321      */
createDevice(const CreateInfo &,const SkPaint *)322     virtual sk_sp<SkDevice> createDevice(const CreateInfo&, const SkPaint*) { return nullptr; }
323 
324     // -- Drawing routines (called after saveLayers and imagefilter operations are applied)
325 
326     // Ensure that non-RSXForm runs are passed to onDrawGlyphRunList.
327     void drawGlyphRunList(SkCanvas*,
328                           const sktext::GlyphRunList& glyphRunList,
329                           const SkPaint& paint);
330     // Slug handling routines.
331     virtual sk_sp<sktext::gpu::Slug> convertGlyphRunListToSlug(
332             const sktext::GlyphRunList& glyphRunList, const SkPaint& paint);
333     virtual void drawSlug(SkCanvas*, const sktext::gpu::Slug* slug, const SkPaint& paint);
334 
335     virtual void drawPaint(const SkPaint& paint) = 0;
336     virtual void drawPoints(SkCanvas::PointMode mode, size_t count,
337                             const SkPoint[], const SkPaint& paint) = 0;
338     virtual void drawRect(const SkRect& r,
339                           const SkPaint& paint) = 0;
340     virtual void drawRegion(const SkRegion& r,
341                             const SkPaint& paint);
342     virtual void drawOval(const SkRect& oval,
343                           const SkPaint& paint) = 0;
344     /** By the time this is called we know that abs(sweepAngle) is in the range [0, 360). */
345     virtual void drawArc(const SkArc& arc, const SkPaint& paint);
346     virtual void drawRRect(const SkRRect& rr,
347                            const SkPaint& paint) = 0;
348 
349     // Default impl calls drawPath()
350     virtual void drawDRRect(const SkRRect& outer,
351                             const SkRRect& inner, const SkPaint&);
352 
353     /**
354      *  If pathIsMutable, then the implementation is allowed to cast path to a
355      *  non-const pointer and modify it in place (as an optimization). Canvas
356      *  may do this to implement helpers such as drawOval, by placing a temp
357      *  path on the stack to hold the representation of the oval.
358      */
359     virtual void drawPath(const SkPath& path,
360                           const SkPaint& paint,
361                           bool pathIsMutable = false) = 0;
362 
363     virtual void drawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
364                                const SkSamplingOptions&, const SkPaint&,
365                                SkCanvas::SrcRectConstraint) = 0;
366     // Return true if canvas calls to drawImage or drawImageRect should try to
367     // be drawn in a tiled way.
shouldDrawAsTiledImageRect()368     virtual bool shouldDrawAsTiledImageRect() const { return false; }
drawAsTiledImageRect(SkCanvas *,const SkImage *,const SkRect * src,const SkRect & dst,const SkSamplingOptions &,const SkPaint &,SkCanvas::SrcRectConstraint)369     virtual bool drawAsTiledImageRect(SkCanvas*,
370                                       const SkImage*,
371                                       const SkRect* src,
372                                       const SkRect& dst,
373                                       const SkSamplingOptions&,
374                                       const SkPaint&,
375                                       SkCanvas::SrcRectConstraint) { return false; }
376 
377     virtual void drawImageLattice(const SkImage*, const SkCanvas::Lattice&,
378                                   const SkRect& dst, SkFilterMode, const SkPaint&);
379 
380     /**
381      * If skipColorXform is true, then the implementation should assume that the provided
382      * vertex colors are already in the destination color space.
383      */
384     virtual void drawVertices(const SkVertices*,
385                               sk_sp<SkBlender>,
386                               const SkPaint&,
387                               bool skipColorXform = false) = 0;
388     virtual void drawMesh(const SkMesh& mesh, sk_sp<SkBlender>, const SkPaint&) = 0;
389     virtual void drawShadow(const SkPath&, const SkDrawShadowRec&);
390 
391     // default implementation calls drawVertices
392     virtual void drawPatch(const SkPoint cubics[12], const SkColor colors[4],
393                            const SkPoint texCoords[4], sk_sp<SkBlender>, const SkPaint& paint);
394 
395     // default implementation calls drawVertices
396     virtual void drawAtlas(const SkRSXform[], const SkRect[], const SkColor[], int count,
397                            sk_sp<SkBlender>, const SkPaint&);
398 
drawAnnotation(const SkRect &,const char[],SkData *)399     virtual void drawAnnotation(const SkRect&, const char[], SkData*) {}
400 
401     // Default impl always calls drawRect() with a solid-color paint, setting it to anti-aliased
402     // only when all edge flags are set. If there's a clip region, it draws that using drawPath,
403     // or uses clipPath().
404     virtual void drawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4],
405                                 SkCanvas::QuadAAFlags aaFlags, const SkColor4f& color,
406                                 SkBlendMode mode);
407     // Default impl uses drawImageRect per entry, being anti-aliased only when an entry's edge flags
408     // are all set. If there's a clip region, it will be applied using clipPath().
409     virtual void drawEdgeAAImageSet(const SkCanvas::ImageSetEntry[], int count,
410                                     const SkPoint dstClips[], const SkMatrix preViewMatrices[],
411                                     const SkSamplingOptions&, const SkPaint&,
412                                     SkCanvas::SrcRectConstraint);
413 
414     virtual void drawDrawable(SkCanvas*, SkDrawable*, const SkMatrix*);
415 
416     // -- "Special" drawing and image routines
417 
418     // Snap the 'subset' contents from this device, possibly as a read-only view. If 'forceCopy'
419     // is true then the returned image's pixels must not be affected by subsequent draws into the
420     // device. When 'forceCopy' is false, the image can be a view into the device's pixels
421     // (avoiding a copy for performance, at the expense of safety). Default returns null.
422     virtual sk_sp<SkSpecialImage> snapSpecial(const SkIRect& subset, bool forceCopy = false);
423     // Can return null if unable to perform scaling as part of the copy, even if snapSpecial() w/o
424     // scaling would succeed.
425     virtual sk_sp<SkSpecialImage> snapSpecialScaled(const SkIRect& subset, const SkISize& dstDims);
426     // Get a view of the entire device's current contents as an image.
427     sk_sp<SkSpecialImage> snapSpecial();
428 
429     /**
430      * The SkDevice passed will be an SkDevice which was returned by a call to
431      * createDevice on this device with kNeverTile_TileExpectation.
432      *
433      * The default implementation calls snapSpecial() and drawSpecial() with the relative transform
434      * from the input device to this device. The provided SkPaint cannot have a mask filter or
435      * image filter, and any shader is ignored.
436      */
437     virtual void drawDevice(SkDevice*, const SkSamplingOptions&, const SkPaint&);
438 
439     /**
440      * Draw the special image's subset to this device, subject to the given matrix transform instead
441      * of the device's current local to device matrix.
442      *
443      * If 'constraint' is kFast, the rendered geometry of the image still reflects the extent of
444      * the SkSpecialImage's subset, but it's assumed that the pixel data beyond the subset is valid
445      * (e.g. SkSpecialImage::makeSubset() was called to crop a larger image).
446      */
447     virtual void drawSpecial(SkSpecialImage*, const SkMatrix& localToDevice,
448                              const SkSamplingOptions&, const SkPaint&,
449                              SkCanvas::SrcRectConstraint constraint =
450                                     SkCanvas::kStrict_SrcRectConstraint);
451 
452     /**
453      * Draw the special image's subset to this device, treating its alpha channel as coverage for
454      * the draw and ignoring any RGB channels that might be present. This will be drawn using the
455      * provided matrix transform instead of the device's current local to device matrix.
456      *
457      * Coverage values beyond the image's subset are treated as 0 (i.e. kDecal tiling). Color values
458      * before coverage are determined as normal by the SkPaint, ignoring style, path effects,
459      * mask filters and image filters. The local coords of any SkShader on the paint should be
460      * relative to the SkDevice's current matrix (i.e. 'maskToDevice' determines how the coverage
461      * mask aligns with device-space, but otherwise shading proceeds like other draws).
462     */
463     virtual void drawCoverageMask(const SkSpecialImage*, const SkMatrix& maskToDevice,
464                                   const SkSamplingOptions&, const SkPaint&);
465 
466     /**
467      * Draw rrect with an optimized path for analytic blurs, if provided by the device.
468      */
drawBlurredRRect(const SkRRect &,const SkPaint &,float deviceSigma)469     virtual bool drawBlurredRRect(const SkRRect&, const SkPaint&, float deviceSigma) {
470         return false;
471     }
472 
473     /**
474      * Evaluate 'filter' and draw the final output into this device using 'paint'. The 'mapping'
475      * defines the parameter-to-layer space transform used to evaluate the image filter on 'src',
476      * and the layer-to-device space transform that is used to draw the result into this device.
477      * Since 'mapping' fully specifies the transform, this draw function ignores the current
478      * local-to-device matrix (i.e. just like drawSpecial and drawDevice).
479      *
480      * The final paint must not have an image filter or mask filter set on it; a shader is ignored.
481      * The provided color type will be used for any intermediate surfaces that need to be created as
482      * part of filter evaluation. It does not have to be src's color type or this Device's type.
483      */
484     void drawFilteredImage(const skif::Mapping& mapping, SkSpecialImage* src, SkColorType ct,
485                            const SkImageFilter*, const SkSamplingOptions&, const SkPaint&);
486 
487 protected:
488     // DEPRECATED: Can be deleted once SkCanvas::onDrawImage() uses skif::FilterResult so don't
489     // bother re-arranging.
490     virtual sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&);
491     virtual sk_sp<SkSpecialImage> makeSpecial(const SkImage*);
492 
493     // Configure the device's coordinate spaces, specifying both how its device image maps back to
494     // the global space (via 'deviceToGlobal') and the initial CTM of the device (via
495     // 'localToDevice', i.e. what geometry drawn into this device will be transformed with).
496     //
497     // (bufferOriginX, bufferOriginY) defines where the (0,0) pixel the device's backing buffer
498     // is anchored in the device space. The final device-to-global matrix stored by the SkDevice
499     // will include a pre-translation by T(deviceOriginX, deviceOriginY), and the final
500     // local-to-device matrix will have a post-translation of T(-deviceOriginX, -deviceOriginY).
501     void setDeviceCoordinateSystem(const SkM44& deviceToGlobal,
502                                    const SkM44& globalToDevice,
503                                    const SkM44& localToDevice,
504                                    int bufferOriginX,
505                                    int bufferOriginY);
506     // Convenience to configure the device to be axis-aligned with the root canvas, but with a
507     // unique origin.
setOrigin(const SkM44 & globalCTM,int x,int y)508     void setOrigin(const SkM44& globalCTM, int x, int y) {
509         this->setDeviceCoordinateSystem(SkM44(), SkM44(), globalCTM, x, y);
510     }
511 
512     // Returns whether or not localToDevice() has changed since the last call to this function.
checkLocalToDeviceDirty()513     bool checkLocalToDeviceDirty() {
514         bool wasDirty = fLocalToDeviceDirty;
515         fLocalToDeviceDirty = false;
516         return wasDirty;
517     }
518 
519 private:
520     friend class SkCanvas; // for setOrigin/setDeviceCoordinateSystem
521     friend class DeviceTestingAccess;
522 
523     // Defaults to a CPU image filtering backend.
524     virtual sk_sp<skif::Backend> createImageFilteringBackend(const SkSurfaceProps& surfaceProps,
525                                                              SkColorType colorType) const;
526 
527     // Implementations can assume that the device from (x,y) to (w,h) will fit within dst.
onReadPixels(const SkPixmap &,int x,int y)528     virtual bool onReadPixels(const SkPixmap&, int x, int y) { return false; }
529 
530     // Implementations can assume that the src image placed at 'x,y' will fit within the device.
onWritePixels(const SkPixmap &,int x,int y)531     virtual bool onWritePixels(const SkPixmap&, int x, int y) { return false; }
532 
onAccessPixels(SkPixmap *)533     virtual bool onAccessPixels(SkPixmap*) { return false; }
534 
onPeekPixels(SkPixmap *)535     virtual bool onPeekPixels(SkPixmap*) { return false; }
536 
537     virtual void onClipShader(sk_sp<SkShader>) = 0;
538 
539     // Only called with glyphRunLists that do not contain RSXForm.
540     virtual void onDrawGlyphRunList(SkCanvas*,
541                                     const sktext::GlyphRunList&,
542                                     const SkPaint& paint) = 0;
543 
544     void simplifyGlyphRunRSXFormAndRedraw(SkCanvas*,
545                                           const sktext::GlyphRunList&,
546                                           const SkPaint& paint);
547 
548     const SkImageInfo    fInfo;
549     const SkSurfaceProps fSurfaceProps;
550     SkM44 fLocalToDevice;
551     // fDeviceToGlobal and fGlobalToDevice are inverses of each other; there are never that many
552     // SkDevices, so pay the memory cost to avoid recalculating the inverse.
553     SkM44 fDeviceToGlobal;
554     SkM44 fGlobalToDevice;
555 
556     // fLocalToDevice but as a 3x3.
557     SkMatrix fLocalToDevice33;
558 
559     // fLocalToDevice is the device CTM, not the global CTM.
560     // It maps from local space to the device's coordinate space.
561     // fDeviceToGlobal * fLocalToDevice will match the canvas' CTM.
562     //
563     // setGlobalCTM and setLocalToDevice are intentionally not virtual for performance reasons.
564     // However, track a dirty bit for subclasses that want to defer local-to-device dependent
565     // calculations until needed for a clip or draw.
566     bool fLocalToDeviceDirty = true;
567 };
568 
569 class SkNoPixelsDevice : public SkDevice {
570 public:
571     SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props);
572     SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props,
573                      sk_sp<SkColorSpace> colorSpace);
574 
575     // Returns false if the device could not be reset; this should only be called on a root device.
576     bool resetForNextPicture(const SkIRect& bounds);
577 
578     // SkNoPixelsDevice tracks the clip conservatively in order to respond to some queries as
579     // accurately as possible while emphasizing performance
580     void pushClipStack() override;
581     void popClipStack() override;
582     void clipRect(const SkRect& rect, SkClipOp op, bool aa) override;
583     void clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) override;
584     void clipPath(const SkPath& path, SkClipOp op, bool aa) override;
585     void clipRegion(const SkRegion& globalRgn, SkClipOp op) override;
586     void replaceClip(const SkIRect& rect) override;
isClipAntiAliased()587     bool isClipAntiAliased() const override { return this->clip().fIsAA; }
isClipEmpty()588     bool isClipEmpty() const override { return this->devClipBounds().isEmpty(); }
isClipRect()589     bool isClipRect() const override { return this->clip().fIsRect && !this->isClipEmpty(); }
isClipWideOpen()590     bool isClipWideOpen() const override {
591         return this->clip().fIsRect &&
592                this->devClipBounds() == this->bounds();
593     }
android_utils_clipAsRgn(SkRegion * rgn)594     void android_utils_clipAsRgn(SkRegion* rgn) const override {
595         rgn->setRect(this->devClipBounds());
596     }
devClipBounds()597     SkIRect devClipBounds() const override { return this->clip().fClipBounds; }
598 
599 protected:
600 
drawPaint(const SkPaint & paint)601     void drawPaint(const SkPaint& paint) override {}
drawPoints(SkCanvas::PointMode,size_t,const SkPoint[],const SkPaint &)602     void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {}
drawImageRect(const SkImage *,const SkRect *,const SkRect &,const SkSamplingOptions &,const SkPaint &,SkCanvas::SrcRectConstraint)603     void drawImageRect(const SkImage*, const SkRect*, const SkRect&,
604                        const SkSamplingOptions&, const SkPaint&,
605                        SkCanvas::SrcRectConstraint) override {}
drawRect(const SkRect &,const SkPaint &)606     void drawRect(const SkRect&, const SkPaint&) override {}
drawOval(const SkRect &,const SkPaint &)607     void drawOval(const SkRect&, const SkPaint&) override {}
drawRRect(const SkRRect &,const SkPaint &)608     void drawRRect(const SkRRect&, const SkPaint&) override {}
drawPath(const SkPath &,const SkPaint &,bool)609     void drawPath(const SkPath&, const SkPaint&, bool) override {}
drawDevice(SkDevice *,const SkSamplingOptions &,const SkPaint &)610     void drawDevice(SkDevice*, const SkSamplingOptions&, const SkPaint&) override {}
drawVertices(const SkVertices *,sk_sp<SkBlender>,const SkPaint &,bool)611     void drawVertices(const SkVertices*, sk_sp<SkBlender>, const SkPaint&, bool) override {}
drawMesh(const SkMesh &,sk_sp<SkBlender>,const SkPaint &)612     void drawMesh(const SkMesh&, sk_sp<SkBlender>, const SkPaint&) override {}
613 
drawSlug(SkCanvas *,const sktext::gpu::Slug *,const SkPaint &)614     void drawSlug(SkCanvas*, const sktext::gpu::Slug*, const SkPaint&) override {}
onDrawGlyphRunList(SkCanvas *,const sktext::GlyphRunList &,const SkPaint &)615     void onDrawGlyphRunList(SkCanvas*, const sktext::GlyphRunList&, const SkPaint&) override {}
616 
isNoPixelsDevice()617     bool isNoPixelsDevice() const override { return true; }
618 
619 private:
620     struct ClipState {
621         SkIRect fClipBounds;
622         int fDeferredSaveCount;
623         bool fIsAA;
624         bool fIsRect;
625 
ClipStateClipState626         ClipState(const SkIRect& bounds, bool isAA, bool isRect)
627                 : fClipBounds(bounds)
628                 , fDeferredSaveCount(0)
629                 , fIsAA(isAA)
630                 , fIsRect(isRect) {}
631 
632         void op(SkClipOp op, const SkM44& transform, const SkRect& bounds,
633                 bool isAA, bool fillsBounds);
634     };
635 
636     void onClipShader(sk_sp<SkShader> shader) override;
637 
clip()638     const ClipState& clip() const { return fClipStack.back(); }
639     ClipState& writableClip();
640 
641     skia_private::STArray<4, ClipState> fClipStack;
642 };
643 
644 class SkAutoDeviceTransformRestore : SkNoncopyable {
645 public:
SkAutoDeviceTransformRestore(SkDevice * device,const SkMatrix & localToDevice)646     SkAutoDeviceTransformRestore(SkDevice* device, const SkMatrix& localToDevice)
647         : fDevice(device)
648         , fPrevLocalToDevice(device->localToDevice())
649     {
650         fDevice->setLocalToDevice(SkM44(localToDevice));
651     }
~SkAutoDeviceTransformRestore()652     ~SkAutoDeviceTransformRestore() {
653         fDevice->setLocalToDevice(fPrevLocalToDevice);
654     }
655 
656 private:
657     SkDevice* fDevice;
658     const SkM44   fPrevLocalToDevice;
659 };
660 
661 #endif
662