tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SkDevice.h (29443B)


      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/SkSpan.h"
     26 #include "include/core/SkSurfaceProps.h"
     27 #include "include/private/base/SkAssert.h"
     28 #include "include/private/base/SkNoncopyable.h"
     29 #include "include/private/base/SkTArray.h"
     30 #include "src/core/SkMatrixPriv.h"
     31 #include "src/shaders/SkShaderBase.h"
     32 
     33 #include <cstdint>
     34 #include <utility>
     35 
     36 struct SkArc;
     37 class SkColorSpace;
     38 class SkMesh;
     39 struct SkDrawShadowRec;
     40 class SkImageFilter;
     41 class SkRasterHandleAllocator;
     42 class SkSpecialImage;
     43 class GrRecordingContext;
     44 class SkData;
     45 class SkDrawable;
     46 class SkImage;
     47 class SkPaint;
     48 class SkPath;
     49 class SkPixmap;
     50 class SkRRect;
     51 class SkRecorder;
     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     */
    117    const SkImageInfo& imageInfo() const { return fInfo; }
    118 
    119    int width() const { return this->imageInfo().width(); }
    120    int height() const { return this->imageInfo().height(); }
    121 
    122    bool isOpaque() const { return this->imageInfo().isOpaque(); }
    123 
    124    // NOTE: Image dimensions as a rect, *not* the current restricted clip bounds.
    125    SkIRect bounds() const { return SkIRect::MakeWH(this->width(), this->height()); }
    126    SkISize size() const { return this->imageInfo().dimensions(); }
    127 
    128    /**
    129     *  Return SurfaceProps for this device.
    130     */
    131    const SkSurfaceProps& surfaceProps() const {
    132        return fSurfaceProps;
    133    }
    134 
    135    SkScalerContextFlags scalerContextFlags() const;
    136 
    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     */
    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     */
    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     */
    178    const SkM44& localToDevice44() const { return fLocalToDevice; }
    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     */
    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     */
    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    SkM44 getRelativeTransform(const SkDevice&) const;
    210 
    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     */
    225    void getGlobalBounds(SkIRect* bounds) const {
    226        SkASSERT(bounds);
    227        *bounds = SkMatrixPriv::MapRect(fDeviceToGlobal, SkRect::Make(this->bounds())).roundOut();
    228    }
    229 
    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 
    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;
    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).
    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.
    280    virtual bool isNoPixelsDevice() const { return false; }
    281 
    282    virtual void* getRasterHandle() const { return nullptr; }
    283 
    284    virtual GrRecordingContext* recordingContext() const { return nullptr; }
    285    virtual skgpu::graphite::Recorder* recorder() const { return nullptr; }
    286    virtual SkRecorder* baseRecorder() const { return nullptr; }
    287 
    288    virtual skgpu::ganesh::Device* asGaneshDevice() { return nullptr; }
    289    virtual skgpu::graphite::Device* asGraphiteDevice() { return nullptr; }
    290 
    291    // Marking an SkDevice immutable declares the intent that rendering to the device is
    292    // complete, allowing it to be sampled as an image without requiring a copy. Drawing
    293    // operations may not function and may assert if invoked after setImmutable() is called.
    294    virtual void setImmutable() {}
    295 
    296    virtual sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&);
    297 
    298    struct CreateInfo {
    299        CreateInfo(const SkImageInfo& info,
    300                   SkPixelGeometry geo,
    301                   SkRasterHandleAllocator* allocator)
    302            : fInfo(info)
    303            , fPixelGeometry(geo)
    304            , fAllocator(allocator)
    305        {}
    306 
    307        const SkImageInfo        fInfo;
    308        const SkPixelGeometry    fPixelGeometry;
    309        SkRasterHandleAllocator* fAllocator = nullptr;
    310    };
    311 
    312    /**
    313     *  Create a new device based on CreateInfo. If the paint is not null, then it represents a
    314     *  preview of how the new device will be composed with its creator device (this).
    315     *
    316     *  The subclass may be handed this device in drawDevice(), so it must always return a device
    317     *  that it knows how to draw, and that it knows how to identify if it is not of the same
    318     *  subclass (since drawDevice is passed a SkDevice*). If the subclass cannot fulfill that
    319     *  contract (e.g. PDF cannot support some settings on the paint) it should return NULL, and the
    320     *  caller may then decide to explicitly create a bitmapdevice, knowing that later it could not
    321     *  call drawDevice with it (but it could call drawSprite or drawBitmap).
    322     */
    323    virtual sk_sp<SkDevice> createDevice(const CreateInfo&, const SkPaint*) { return nullptr; }
    324 
    325    // -- Drawing routines (called after saveLayers and imagefilter operations are applied)
    326 
    327    // Ensure that non-RSXForm runs are passed to onDrawGlyphRunList.
    328    void drawGlyphRunList(SkCanvas*,
    329                          const sktext::GlyphRunList& glyphRunList,
    330                          const SkPaint& paint);
    331    // Slug handling routines.
    332    virtual sk_sp<sktext::gpu::Slug> convertGlyphRunListToSlug(
    333            const sktext::GlyphRunList& glyphRunList, const SkPaint& paint);
    334    virtual void drawSlug(SkCanvas*, const sktext::gpu::Slug* slug, const SkPaint& paint);
    335 
    336    virtual void drawPaint(const SkPaint& paint) = 0;
    337    virtual void drawPoints(SkCanvas::PointMode, SkSpan<const SkPoint>, const SkPaint&) = 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) = 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.
    368    virtual bool shouldDrawAsTiledImageRect() const { return false; }
    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(SkCanvas*, 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(SkSpan<const SkRSXform>, SkSpan<const SkRect>, SkSpan<const SkColor>,
    397                           sk_sp<SkBlender>, const SkPaint&);
    398 
    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     */
    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    // Configure the device's coordinate spaces, specifying both how its device image maps back to
    489    // the global space (via 'deviceToGlobal') and the initial CTM of the device (via
    490    // 'localToDevice', i.e. what geometry drawn into this device will be transformed with).
    491    //
    492    // (bufferOriginX, bufferOriginY) defines where the (0,0) pixel the device's backing buffer
    493    // is anchored in the device space. The final device-to-global matrix stored by the SkDevice
    494    // will include a pre-translation by T(deviceOriginX, deviceOriginY), and the final
    495    // local-to-device matrix will have a post-translation of T(-deviceOriginX, -deviceOriginY).
    496    void setDeviceCoordinateSystem(const SkM44& deviceToGlobal,
    497                                   const SkM44& globalToDevice,
    498                                   const SkM44& localToDevice,
    499                                   int bufferOriginX,
    500                                   int bufferOriginY);
    501    // Convenience to configure the device to be axis-aligned with the root canvas, but with a
    502    // unique origin.
    503    void setOrigin(const SkM44& globalCTM, int x, int y) {
    504        this->setDeviceCoordinateSystem(SkM44(), SkM44(), globalCTM, x, y);
    505    }
    506 
    507    // Returns whether or not localToDevice() has changed since the last call to this function.
    508    bool checkLocalToDeviceDirty() {
    509        bool wasDirty = fLocalToDeviceDirty;
    510        fLocalToDeviceDirty = false;
    511        return wasDirty;
    512    }
    513 
    514 private:
    515    friend class SkCanvas; // for setOrigin/setDeviceCoordinateSystem
    516    friend class DeviceTestingAccess;
    517 
    518    // Defaults to a CPU image filtering backend.
    519    virtual sk_sp<skif::Backend> createImageFilteringBackend(const SkSurfaceProps& surfaceProps,
    520                                                             SkColorType colorType) const;
    521 
    522    // Implementations can assume that the device from (x,y) to (w,h) will fit within dst.
    523    virtual bool onReadPixels(const SkPixmap&, int x, int y) { return false; }
    524 
    525    // Implementations can assume that the src image placed at 'x,y' will fit within the device.
    526    virtual bool onWritePixels(const SkPixmap&, int x, int y) { return false; }
    527 
    528    virtual bool onAccessPixels(SkPixmap*) { return false; }
    529 
    530    virtual bool onPeekPixels(SkPixmap*) { return false; }
    531 
    532    virtual void onClipShader(sk_sp<SkShader>) = 0;
    533 
    534    // Only called with glyphRunLists that do not contain RSXForm.
    535    virtual void onDrawGlyphRunList(SkCanvas*,
    536                                    const sktext::GlyphRunList&,
    537                                    const SkPaint& paint) = 0;
    538 
    539    void simplifyGlyphRunRSXFormAndRedraw(SkCanvas*,
    540                                          const sktext::GlyphRunList&,
    541                                          const SkPaint& paint);
    542 
    543    const SkImageInfo    fInfo;
    544    const SkSurfaceProps fSurfaceProps;
    545    SkM44 fLocalToDevice;
    546    // fDeviceToGlobal and fGlobalToDevice are inverses of each other; there are never that many
    547    // SkDevices, so pay the memory cost to avoid recalculating the inverse.
    548    SkM44 fDeviceToGlobal;
    549    SkM44 fGlobalToDevice;
    550 
    551    // fLocalToDevice but as a 3x3.
    552    SkMatrix fLocalToDevice33;
    553 
    554    // fLocalToDevice is the device CTM, not the global CTM.
    555    // It maps from local space to the device's coordinate space.
    556    // fDeviceToGlobal * fLocalToDevice will match the canvas' CTM.
    557    //
    558    // setGlobalCTM and setLocalToDevice are intentionally not virtual for performance reasons.
    559    // However, track a dirty bit for subclasses that want to defer local-to-device dependent
    560    // calculations until needed for a clip or draw.
    561    bool fLocalToDeviceDirty = true;
    562 };
    563 
    564 class SkNoPixelsDevice : public SkDevice {
    565 public:
    566    SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props);
    567    SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props,
    568                     sk_sp<SkColorSpace> colorSpace);
    569 
    570    // Returns false if the device could not be reset; this should only be called on a root device.
    571    bool resetForNextPicture(const SkIRect& bounds);
    572 
    573    // SkNoPixelsDevice tracks the clip conservatively in order to respond to some queries as
    574    // accurately as possible while emphasizing performance
    575    void pushClipStack() override;
    576    void popClipStack() override;
    577    void clipRect(const SkRect& rect, SkClipOp op, bool aa) override;
    578    void clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) override;
    579    void clipPath(const SkPath& path, SkClipOp op, bool aa) override;
    580    void clipRegion(const SkRegion& globalRgn, SkClipOp op) override;
    581    void replaceClip(const SkIRect& rect) override;
    582    bool isClipAntiAliased() const override { return this->clip().fIsAA; }
    583    bool isClipEmpty() const override { return this->devClipBounds().isEmpty(); }
    584    bool isClipRect() const override { return this->clip().fIsRect && !this->isClipEmpty(); }
    585    bool isClipWideOpen() const override {
    586        return this->clip().fIsRect &&
    587               this->devClipBounds() == this->bounds();
    588    }
    589    void android_utils_clipAsRgn(SkRegion* rgn) const override {
    590        rgn->setRect(this->devClipBounds());
    591    }
    592    SkIRect devClipBounds() const override { return this->clip().fClipBounds; }
    593 
    594 protected:
    595 
    596    void drawPaint(const SkPaint& paint) override {}
    597    void drawPoints(SkCanvas::PointMode, SkSpan<const SkPoint>, const SkPaint&) override {}
    598    void drawImageRect(const SkImage*, const SkRect*, const SkRect&,
    599                       const SkSamplingOptions&, const SkPaint&,
    600                       SkCanvas::SrcRectConstraint) override {}
    601    void drawRect(const SkRect&, const SkPaint&) override {}
    602    void drawOval(const SkRect&, const SkPaint&) override {}
    603    void drawRRect(const SkRRect&, const SkPaint&) override {}
    604    void drawPath(const SkPath&, const SkPaint&, bool) override {}
    605    void drawDevice(SkDevice*, const SkSamplingOptions&, const SkPaint&) override {}
    606    void drawVertices(const SkVertices*, sk_sp<SkBlender>, const SkPaint&, bool) override {}
    607    void drawMesh(const SkMesh&, sk_sp<SkBlender>, const SkPaint&) override {}
    608 
    609    void drawSlug(SkCanvas*, const sktext::gpu::Slug*, const SkPaint&) override {}
    610    void onDrawGlyphRunList(SkCanvas*, const sktext::GlyphRunList&, const SkPaint&) override {}
    611 
    612    bool isNoPixelsDevice() const override { return true; }
    613 
    614 private:
    615    struct ClipState {
    616        SkIRect fClipBounds;
    617        int fDeferredSaveCount;
    618        bool fIsAA;
    619        bool fIsRect;
    620 
    621        ClipState(const SkIRect& bounds, bool isAA, bool isRect)
    622                : fClipBounds(bounds)
    623                , fDeferredSaveCount(0)
    624                , fIsAA(isAA)
    625                , fIsRect(isRect) {}
    626 
    627        void op(SkClipOp op, const SkM44& transform, const SkRect& bounds,
    628                bool isAA, bool fillsBounds);
    629    };
    630 
    631    void onClipShader(sk_sp<SkShader> shader) override;
    632 
    633    const ClipState& clip() const { return fClipStack.back(); }
    634    ClipState& writableClip();
    635 
    636    skia_private::STArray<4, ClipState> fClipStack;
    637 };
    638 
    639 class SkAutoDeviceTransformRestore : SkNoncopyable {
    640 public:
    641    SkAutoDeviceTransformRestore(SkDevice* device, const SkM44& localToDevice)
    642        : fDevice(device)
    643        , fPrevLocalToDevice(device->localToDevice())
    644    {
    645        fDevice->setLocalToDevice(localToDevice);
    646    }
    647    ~SkAutoDeviceTransformRestore() {
    648        fDevice->setLocalToDevice(fPrevLocalToDevice);
    649    }
    650 
    651 private:
    652    SkDevice* fDevice;
    653    const SkM44   fPrevLocalToDevice;
    654 };
    655 
    656 #endif