| /* | |
| * Copyright 2010 The Android Open Source Project | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #ifndef SkDevice_DEFINED | |
| #define SkDevice_DEFINED | |
| #include "include/core/SkBlender.h" // IWYU pragma: keep | |
| #include "include/core/SkCanvas.h" | |
| #include "include/core/SkClipOp.h" | |
| #include "include/core/SkColor.h" | |
| #include "include/core/SkImageInfo.h" | |
| #include "include/core/SkM44.h" | |
| #include "include/core/SkMatrix.h" | |
| #include "include/core/SkPoint.h" | |
| #include "include/core/SkRect.h" | |
| #include "include/core/SkRefCnt.h" | |
| #include "include/core/SkRegion.h" | |
| #include "include/core/SkSamplingOptions.h" | |
| #include "include/core/SkShader.h" | |
| #include "include/core/SkSize.h" | |
| #include "include/core/SkSpan.h" | |
| #include "include/core/SkSurfaceProps.h" | |
| #include "include/private/base/SkAssert.h" | |
| #include "include/private/base/SkNoncopyable.h" | |
| #include "include/private/base/SkTArray.h" | |
| #include "src/core/SkMatrixPriv.h" | |
| #include "src/shaders/SkShaderBase.h" | |
| #include <cstdint> | |
| #include <utility> | |
| struct SkArc; | |
| class SkColorSpace; | |
| class SkMesh; | |
| struct SkDrawShadowRec; | |
| class SkImageFilter; | |
| class SkRasterHandleAllocator; | |
| class SkSpecialImage; | |
| class GrRecordingContext; | |
| class SkData; | |
| class SkDrawable; | |
| class SkImage; | |
| class SkPaint; | |
| class SkPath; | |
| class SkPixmap; | |
| class SkRRect; | |
| class SkRecorder; | |
| class SkSurface; | |
| class SkVertices; | |
| enum SkColorType : int; | |
| enum class SkBlendMode; | |
| enum class SkScalerContextFlags : uint32_t; | |
| struct SkRSXform; | |
| namespace sktext { | |
| class GlyphRunList; | |
| } | |
| namespace skif { | |
| class Backend; | |
| class Mapping; | |
| } | |
| namespace skgpu::ganesh { | |
| class Device; | |
| } | |
| namespace skgpu::graphite { | |
| class Device; | |
| class Recorder; | |
| } | |
| namespace sktext::gpu { | |
| class SubRunControl; | |
| class Slug; | |
| } | |
| struct SkStrikeDeviceInfo { | |
| const SkSurfaceProps fSurfaceProps; | |
| const SkScalerContextFlags fScalerContextFlags; | |
| // This is a pointer so this can be compiled without SK_GPU_SUPPORT. | |
| const sktext::gpu::SubRunControl* const fSubRunControl; | |
| }; | |
| /** | |
| * SkDevice is the internal API and implementation that SkCanvas will use to perform rendering and | |
| * implement the saveLayer abstraction. A device wraps some pixel allocation (for non-document based | |
| * devices) or wraps some other container that stores rendering operations. The drawing operations | |
| * perform equivalently to their corresponding functions in SkCanvas except that the canvas is | |
| * responsible for all SkImageFilters. An image filter is applied by automatically creating a layer, | |
| * drawing the filter-less paint into the layer, and then evaluating the filter on the layer's | |
| * image. | |
| * | |
| * Each layer in an SkCanvas stack is represented by an SkDevice instance that was created by the | |
| * parent SkDevice (up to the canvas's base device). In most cases these devices will be pixel | |
| * aligned with one another but may differ in size based on the known extent of the active clip. In | |
| * complex image filtering scenarios, they may not be axis aligned, although the effective pixel | |
| * size should remain approximately equal across all devices in a canvas. | |
| * | |
| * While SkCanvas manages a single stack of layers and canvas transforms, SkDevice does not have a | |
| * stack of transforms. Instead, it has a single active transform that is modified as needed by | |
| * SkCanvas. However, SkDevices are the means by which SkCanvas manages the clip stack because each | |
| * layer's clip stack starts anew (although the layer's results are then clipped by its parent's | |
| * stack when it is restored). | |
| */ | |
| class SkDevice : public SkRefCnt { | |
| public: | |
| SkDevice(const SkImageInfo&, const SkSurfaceProps&); | |
| // -- Surface properties and metadata | |
| /** | |
| * Return ImageInfo for this device. If the canvas is not backed by pixels | |
| * (cpu or gpu), then the info's ColorType will be kUnknown_SkColorType. | |
| */ | |
| const SkImageInfo& imageInfo() const { return fInfo; } | |
| int width() const { return this->imageInfo().width(); } | |
| int height() const { return this->imageInfo().height(); } | |
| bool isOpaque() const { return this->imageInfo().isOpaque(); } | |
| // NOTE: Image dimensions as a rect, *not* the current restricted clip bounds. | |
| SkIRect bounds() const { return SkIRect::MakeWH(this->width(), this->height()); } | |
| SkISize size() const { return this->imageInfo().dimensions(); } | |
| /** | |
| * Return SurfaceProps for this device. | |
| */ | |
| const SkSurfaceProps& surfaceProps() const { | |
| return fSurfaceProps; | |
| } | |
| SkScalerContextFlags scalerContextFlags() const; | |
| virtual SkStrikeDeviceInfo strikeDeviceInfo() const { | |
| return {fSurfaceProps, this->scalerContextFlags(), nullptr}; | |
| } | |
| // -- Direct pixel manipulation | |
| /** | |
| * Write the pixels in 'src' into this Device at the specified x,y offset. The caller is | |
| * responsible for "pre-clipping" the src. | |
| */ | |
| bool writePixels(const SkPixmap& src, int x, int y) { return this->onWritePixels(src, x, y); } | |
| /** | |
| * Read pixels from this Device at the specified x,y offset into dst. The caller is | |
| * responsible for "pre-clipping" the dst | |
| */ | |
| bool readPixels(const SkPixmap& dst, int x, int y) { return this->onReadPixels(dst, x, y); } | |
| /** | |
| * Try to get write-access to the pixels behind the device. If successful, this returns true | |
| * and fills-out the pixmap parameter. On success it also bumps the genID of the underlying | |
| * bitmap. | |
| * | |
| * On failure, returns false and ignores the pixmap parameter. | |
| */ | |
| bool accessPixels(SkPixmap* pmap); | |
| /** | |
| * Try to get read-only-access to the pixels behind the device. If successful, this returns | |
| * true and fills-out the pixmap parameter. | |
| * | |
| * On failure, returns false and ignores the pixmap parameter. | |
| */ | |
| bool peekPixels(SkPixmap*); | |
| // -- Device's transform (both current transform affecting draws, and its fixed global mapping) | |
| /** | |
| * Returns the transformation that maps from the local space to the device's coordinate space. | |
| */ | |
| const SkM44& localToDevice44() const { return fLocalToDevice; } | |
| const SkMatrix& localToDevice() const { return fLocalToDevice33; } | |
| /** | |
| * Return the device's coordinate space transform: this maps from the device's coordinate space | |
| * into the global canvas' space (or root device space). This includes the translation | |
| * necessary to account for the device's origin. | |
| */ | |
| const SkM44& deviceToGlobal() const { return fDeviceToGlobal; } | |
| /** | |
| * Return the inverse of getDeviceToGlobal(), mapping from the global canvas' space (or root | |
| * device space) into this device's coordinate space. | |
| */ | |
| const SkM44& globalToDevice() const { return fGlobalToDevice; } | |
| /** | |
| * DEPRECATED: This asserts that 'getDeviceToGlobal' is a translation matrix with integer | |
| * components. In the future some SkDevices will have more complex device-to-global transforms, | |
| * so getDeviceToGlobal() or getRelativeTransform() should be used instead. | |
| */ | |
| SkIPoint getOrigin() const; | |
| /** | |
| * Returns true when this device's pixel grid is axis aligned with the global coordinate space, | |
| * and any relative translation between the two spaces is in integer pixel units. | |
| */ | |
| bool isPixelAlignedToGlobal() const; | |
| /** | |
| * Get the transformation from this device's coordinate system to the provided device space. | |
| * This transform can be used to draw this device into the provided device, such that once | |
| * that device is drawn to the root device, the net effect will be that this device's contents | |
| * have been transformed by the global CTM. | |
| */ | |
| SkM44 getRelativeTransform(const SkDevice&) const; | |
| void setLocalToDevice(const SkM44& localToDevice) { | |
| fLocalToDevice = localToDevice; | |
| fLocalToDevice33 = fLocalToDevice.asM33(); | |
| fLocalToDeviceDirty = true; | |
| } | |
| void setGlobalCTM(const SkM44& ctm); | |
| // -- Device's clip bounds and stack manipulation | |
| /** | |
| * Return the bounds of the device in the coordinate space of the root canvas. The root device | |
| * will have its top-left at 0,0, but other devices such as those associated with saveLayer may | |
| * have a non-zero origin. | |
| */ | |
| void getGlobalBounds(SkIRect* bounds) const { | |
| SkASSERT(bounds); | |
| *bounds = SkMatrixPriv::MapRect(fDeviceToGlobal, SkRect::Make(this->bounds())).roundOut(); | |
| } | |
| SkIRect getGlobalBounds() const { | |
| SkIRect bounds; | |
| this->getGlobalBounds(&bounds); | |
| return bounds; | |
| } | |
| /** | |
| * Returns the bounding box of the current clip, in this device's coordinate space. No pixels | |
| * outside of these bounds will be touched by draws unless the clip is further modified (at | |
| * which point this will return the updated bounds). | |
| */ | |
| virtual SkIRect devClipBounds() const = 0; | |
| virtual void pushClipStack() = 0; | |
| virtual void popClipStack() = 0; | |
| virtual void clipRect(const SkRect& rect, SkClipOp op, bool aa) = 0; | |
| virtual void clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) = 0; | |
| virtual void clipPath(const SkPath& path, SkClipOp op, bool aa) = 0; | |
| virtual void clipRegion(const SkRegion& region, SkClipOp op) = 0; | |
| void clipShader(sk_sp<SkShader> sh, SkClipOp op) { | |
| sh = as_SB(sh)->makeWithCTM(this->localToDevice()); | |
| if (op == SkClipOp::kDifference) { | |
| sh = as_SB(sh)->makeInvertAlpha(); | |
| } | |
| this->onClipShader(std::move(sh)); | |
| } | |
| virtual void replaceClip(const SkIRect& rect) = 0; | |
| virtual bool isClipAntiAliased() const = 0; | |
| virtual bool isClipEmpty() const = 0; | |
| virtual bool isClipRect() const = 0; | |
| virtual bool isClipWideOpen() const = 0; | |
| virtual void android_utils_clipAsRgn(SkRegion*) const = 0; | |
| virtual bool android_utils_clipWithStencil() { return false; } | |
| // -- Device reflection | |
| // TEMPORARY: Whether or not SkCanvas should use an layer and image filters to simulate | |
| // mask filters and then draw the filtered mask using drawCoverageMask. Unlike regular | |
| // layers, the color type passed to SkDevice::createDevice() will always be an alpha-only | |
| // color type. Eventually this will be the only way that mask filters are handled (barring | |
| // dedicated fast-paths for blurs on [r]rects and text). | |
| virtual bool useDrawCoverageMaskForMaskFilters() const { return false; } | |
| // SkCanvas uses NoPixelsDevice when createDevice fails; but then it needs to be able to | |
| // inspect a layer's device to know if calling drawDevice() later is allowed. | |
| virtual bool isNoPixelsDevice() const { return false; } | |
| virtual void* getRasterHandle() const { return nullptr; } | |
| virtual GrRecordingContext* recordingContext() const { return nullptr; } | |
| virtual skgpu::graphite::Recorder* recorder() const { return nullptr; } | |
| virtual SkRecorder* baseRecorder() const { return nullptr; } | |
| virtual skgpu::ganesh::Device* asGaneshDevice() { return nullptr; } | |
| virtual skgpu::graphite::Device* asGraphiteDevice() { return nullptr; } | |
| // Marking an SkDevice immutable declares the intent that rendering to the device is | |
| // complete, allowing it to be sampled as an image without requiring a copy. Drawing | |
| // operations may not function and may assert if invoked after setImmutable() is called. | |
| virtual void setImmutable() {} | |
| virtual sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&); | |
| struct CreateInfo { | |
| CreateInfo(const SkImageInfo& info, | |
| SkPixelGeometry geo, | |
| SkRasterHandleAllocator* allocator) | |
| : fInfo(info) | |
| , fPixelGeometry(geo) | |
| , fAllocator(allocator) | |
| {} | |
| const SkImageInfo fInfo; | |
| const SkPixelGeometry fPixelGeometry; | |
| SkRasterHandleAllocator* fAllocator = nullptr; | |
| }; | |
| /** | |
| * Create a new device based on CreateInfo. If the paint is not null, then it represents a | |
| * preview of how the new device will be composed with its creator device (this). | |
| * | |
| * The subclass may be handed this device in drawDevice(), so it must always return a device | |
| * that it knows how to draw, and that it knows how to identify if it is not of the same | |
| * subclass (since drawDevice is passed a SkDevice*). If the subclass cannot fulfill that | |
| * contract (e.g. PDF cannot support some settings on the paint) it should return NULL, and the | |
| * caller may then decide to explicitly create a bitmapdevice, knowing that later it could not | |
| * call drawDevice with it (but it could call drawSprite or drawBitmap). | |
| */ | |
| virtual sk_sp<SkDevice> createDevice(const CreateInfo&, const SkPaint*) { return nullptr; } | |
| // -- Drawing routines (called after saveLayers and imagefilter operations are applied) | |
| // Ensure that non-RSXForm runs are passed to onDrawGlyphRunList. | |
| void drawGlyphRunList(SkCanvas*, | |
| const sktext::GlyphRunList& glyphRunList, | |
| const SkPaint& paint); | |
| // Slug handling routines. | |
| virtual sk_sp<sktext::gpu::Slug> convertGlyphRunListToSlug( | |
| const sktext::GlyphRunList& glyphRunList, const SkPaint& paint); | |
| virtual void drawSlug(SkCanvas*, const sktext::gpu::Slug* slug, const SkPaint& paint); | |
| virtual void drawPaint(const SkPaint& paint) = 0; | |
| virtual void drawPoints(SkCanvas::PointMode, SkSpan<const SkPoint>, const SkPaint&) = 0; | |
| virtual void drawRect(const SkRect& r, | |
| const SkPaint& paint) = 0; | |
| virtual void drawRegion(const SkRegion& r, | |
| const SkPaint& paint); | |
| virtual void drawOval(const SkRect& oval, | |
| const SkPaint& paint) = 0; | |
| /** By the time this is called we know that abs(sweepAngle) is in the range [0, 360). */ | |
| virtual void drawArc(const SkArc& arc, const SkPaint& paint); | |
| virtual void drawRRect(const SkRRect& rr, | |
| const SkPaint& paint) = 0; | |
| // Default impl calls drawPath() | |
| virtual void drawDRRect(const SkRRect& outer, | |
| const SkRRect& inner, const SkPaint&); | |
| /** | |
| * If pathIsMutable, then the implementation is allowed to cast path to a | |
| * non-const pointer and modify it in place (as an optimization). Canvas | |
| * may do this to implement helpers such as drawOval, by placing a temp | |
| * path on the stack to hold the representation of the oval. | |
| */ | |
| virtual void drawPath(const SkPath& path, | |
| const SkPaint& paint) = 0; | |
| virtual void drawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, | |
| const SkSamplingOptions&, const SkPaint&, | |
| SkCanvas::SrcRectConstraint) = 0; | |
| // Return true if canvas calls to drawImage or drawImageRect should try to | |
| // be drawn in a tiled way. | |
| virtual bool shouldDrawAsTiledImageRect() const { return false; } | |
| virtual bool drawAsTiledImageRect(SkCanvas*, | |
| const SkImage*, | |
| const SkRect* src, | |
| const SkRect& dst, | |
| const SkSamplingOptions&, | |
| const SkPaint&, | |
| SkCanvas::SrcRectConstraint) { return false; } | |
| virtual void drawImageLattice(const SkImage*, const SkCanvas::Lattice&, | |
| const SkRect& dst, SkFilterMode, const SkPaint&); | |
| /** | |
| * If skipColorXform is true, then the implementation should assume that the provided | |
| * vertex colors are already in the destination color space. | |
| */ | |
| virtual void drawVertices(const SkVertices*, | |
| sk_sp<SkBlender>, | |
| const SkPaint&, | |
| bool skipColorXform = false) = 0; | |
| virtual void drawMesh(const SkMesh& mesh, sk_sp<SkBlender>, const SkPaint&) = 0; | |
| virtual void drawShadow(SkCanvas*, const SkPath&, const SkDrawShadowRec&); | |
| // default implementation calls drawVertices | |
| virtual void drawPatch(const SkPoint cubics[12], const SkColor colors[4], | |
| const SkPoint texCoords[4], sk_sp<SkBlender>, const SkPaint& paint); | |
| // default implementation calls drawVertices | |
| virtual void drawAtlas(SkSpan<const SkRSXform>, SkSpan<const SkRect>, SkSpan<const SkColor>, | |
| sk_sp<SkBlender>, const SkPaint&); | |
| virtual void drawAnnotation(const SkRect&, const char[], SkData*) {} | |
| // Default impl always calls drawRect() with a solid-color paint, setting it to anti-aliased | |
| // only when all edge flags are set. If there's a clip region, it draws that using drawPath, | |
| // or uses clipPath(). | |
| virtual void drawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], | |
| SkCanvas::QuadAAFlags aaFlags, const SkColor4f& color, | |
| SkBlendMode mode); | |
| // Default impl uses drawImageRect per entry, being anti-aliased only when an entry's edge flags | |
| // are all set. If there's a clip region, it will be applied using clipPath(). | |
| virtual void drawEdgeAAImageSet(const SkCanvas::ImageSetEntry[], int count, | |
| const SkPoint dstClips[], const SkMatrix preViewMatrices[], | |
| const SkSamplingOptions&, const SkPaint&, | |
| SkCanvas::SrcRectConstraint); | |
| virtual void drawDrawable(SkCanvas*, SkDrawable*, const SkMatrix*); | |
| // -- "Special" drawing and image routines | |
| // Snap the 'subset' contents from this device, possibly as a read-only view. If 'forceCopy' | |
| // is true then the returned image's pixels must not be affected by subsequent draws into the | |
| // device. When 'forceCopy' is false, the image can be a view into the device's pixels | |
| // (avoiding a copy for performance, at the expense of safety). Default returns null. | |
| virtual sk_sp<SkSpecialImage> snapSpecial(const SkIRect& subset, bool forceCopy = false); | |
| // Can return null if unable to perform scaling as part of the copy, even if snapSpecial() w/o | |
| // scaling would succeed. | |
| virtual sk_sp<SkSpecialImage> snapSpecialScaled(const SkIRect& subset, const SkISize& dstDims); | |
| // Get a view of the entire device's current contents as an image. | |
| sk_sp<SkSpecialImage> snapSpecial(); | |
| /** | |
| * The SkDevice passed will be an SkDevice which was returned by a call to | |
| * createDevice on this device with kNeverTile_TileExpectation. | |
| * | |
| * The default implementation calls snapSpecial() and drawSpecial() with the relative transform | |
| * from the input device to this device. The provided SkPaint cannot have a mask filter or | |
| * image filter, and any shader is ignored. | |
| */ | |
| virtual void drawDevice(SkDevice*, const SkSamplingOptions&, const SkPaint&); | |
| /** | |
| * Draw the special image's subset to this device, subject to the given matrix transform instead | |
| * of the device's current local to device matrix. | |
| * | |
| * If 'constraint' is kFast, the rendered geometry of the image still reflects the extent of | |
| * the SkSpecialImage's subset, but it's assumed that the pixel data beyond the subset is valid | |
| * (e.g. SkSpecialImage::makeSubset() was called to crop a larger image). | |
| */ | |
| virtual void drawSpecial(SkSpecialImage*, const SkMatrix& localToDevice, | |
| const SkSamplingOptions&, const SkPaint&, | |
| SkCanvas::SrcRectConstraint constraint = | |
| SkCanvas::kStrict_SrcRectConstraint); | |
| /** | |
| * Draw the special image's subset to this device, treating its alpha channel as coverage for | |
| * the draw and ignoring any RGB channels that might be present. This will be drawn using the | |
| * provided matrix transform instead of the device's current local to device matrix. | |
| * | |
| * Coverage values beyond the image's subset are treated as 0 (i.e. kDecal tiling). Color values | |
| * before coverage are determined as normal by the SkPaint, ignoring style, path effects, | |
| * mask filters and image filters. The local coords of any SkShader on the paint should be | |
| * relative to the SkDevice's current matrix (i.e. 'maskToDevice' determines how the coverage | |
| * mask aligns with device-space, but otherwise shading proceeds like other draws). | |
| */ | |
| virtual void drawCoverageMask(const SkSpecialImage*, const SkMatrix& maskToDevice, | |
| const SkSamplingOptions&, const SkPaint&); | |
| /** | |
| * Draw rrect with an optimized path for analytic blurs, if provided by the device. | |
| */ | |
| virtual bool drawBlurredRRect(const SkRRect&, const SkPaint&, float deviceSigma) { | |
| return false; | |
| } | |
| /** | |
| * Evaluate 'filter' and draw the final output into this device using 'paint'. The 'mapping' | |
| * defines the parameter-to-layer space transform used to evaluate the image filter on 'src', | |
| * and the layer-to-device space transform that is used to draw the result into this device. | |
| * Since 'mapping' fully specifies the transform, this draw function ignores the current | |
| * local-to-device matrix (i.e. just like drawSpecial and drawDevice). | |
| * | |
| * The final paint must not have an image filter or mask filter set on it; a shader is ignored. | |
| * The provided color type will be used for any intermediate surfaces that need to be created as | |
| * part of filter evaluation. It does not have to be src's color type or this Device's type. | |
| */ | |
| void drawFilteredImage(const skif::Mapping& mapping, SkSpecialImage* src, SkColorType ct, | |
| const SkImageFilter*, const SkSamplingOptions&, const SkPaint&); | |
| protected: | |
| // Configure the device's coordinate spaces, specifying both how its device image maps back to | |
| // the global space (via 'deviceToGlobal') and the initial CTM of the device (via | |
| // 'localToDevice', i.e. what geometry drawn into this device will be transformed with). | |
| // | |
| // (bufferOriginX, bufferOriginY) defines where the (0,0) pixel the device's backing buffer | |
| // is anchored in the device space. The final device-to-global matrix stored by the SkDevice | |
| // will include a pre-translation by T(deviceOriginX, deviceOriginY), and the final | |
| // local-to-device matrix will have a post-translation of T(-deviceOriginX, -deviceOriginY). | |
| void setDeviceCoordinateSystem(const SkM44& deviceToGlobal, | |
| const SkM44& globalToDevice, | |
| const SkM44& localToDevice, | |
| int bufferOriginX, | |
| int bufferOriginY); | |
| // Convenience to configure the device to be axis-aligned with the root canvas, but with a | |
| // unique origin. | |
| void setOrigin(const SkM44& globalCTM, int x, int y) { | |
| this->setDeviceCoordinateSystem(SkM44(), SkM44(), globalCTM, x, y); | |
| } | |
| // Returns whether or not localToDevice() has changed since the last call to this function. | |
| bool checkLocalToDeviceDirty() { | |
| bool wasDirty = fLocalToDeviceDirty; | |
| fLocalToDeviceDirty = false; | |
| return wasDirty; | |
| } | |
| private: | |
| friend class SkCanvas; // for setOrigin/setDeviceCoordinateSystem | |
| friend class DeviceTestingAccess; | |
| // Defaults to a CPU image filtering backend. | |
| virtual sk_sp<skif::Backend> createImageFilteringBackend(const SkSurfaceProps& surfaceProps, | |
| SkColorType colorType) const; | |
| // Implementations can assume that the device from (x,y) to (w,h) will fit within dst. | |
| virtual bool onReadPixels(const SkPixmap&, int x, int y) { return false; } | |
| // Implementations can assume that the src image placed at 'x,y' will fit within the device. | |
| virtual bool onWritePixels(const SkPixmap&, int x, int y) { return false; } | |
| virtual bool onAccessPixels(SkPixmap*) { return false; } | |
| virtual bool onPeekPixels(SkPixmap*) { return false; } | |
| virtual void onClipShader(sk_sp<SkShader>) = 0; | |
| // Only called with glyphRunLists that do not contain RSXForm. | |
| virtual void onDrawGlyphRunList(SkCanvas*, | |
| const sktext::GlyphRunList&, | |
| const SkPaint& paint) = 0; | |
| void simplifyGlyphRunRSXFormAndRedraw(SkCanvas*, | |
| const sktext::GlyphRunList&, | |
| const SkPaint& paint); | |
| const SkImageInfo fInfo; | |
| const SkSurfaceProps fSurfaceProps; | |
| SkM44 fLocalToDevice; | |
| // fDeviceToGlobal and fGlobalToDevice are inverses of each other; there are never that many | |
| // SkDevices, so pay the memory cost to avoid recalculating the inverse. | |
| SkM44 fDeviceToGlobal; | |
| SkM44 fGlobalToDevice; | |
| // fLocalToDevice but as a 3x3. | |
| SkMatrix fLocalToDevice33; | |
| // fLocalToDevice is the device CTM, not the global CTM. | |
| // It maps from local space to the device's coordinate space. | |
| // fDeviceToGlobal * fLocalToDevice will match the canvas' CTM. | |
| // | |
| // setGlobalCTM and setLocalToDevice are intentionally not virtual for performance reasons. | |
| // However, track a dirty bit for subclasses that want to defer local-to-device dependent | |
| // calculations until needed for a clip or draw. | |
| bool fLocalToDeviceDirty = true; | |
| }; | |
| class SkNoPixelsDevice : public SkDevice { | |
| public: | |
| SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props); | |
| SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props, | |
| sk_sp<SkColorSpace> colorSpace); | |
| // Returns false if the device could not be reset; this should only be called on a root device. | |
| bool resetForNextPicture(const SkIRect& bounds); | |
| // SkNoPixelsDevice tracks the clip conservatively in order to respond to some queries as | |
| // accurately as possible while emphasizing performance | |
| void pushClipStack() override; | |
| void popClipStack() override; | |
| void clipRect(const SkRect& rect, SkClipOp op, bool aa) override; | |
| void clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) override; | |
| void clipPath(const SkPath& path, SkClipOp op, bool aa) override; | |
| void clipRegion(const SkRegion& globalRgn, SkClipOp op) override; | |
| void replaceClip(const SkIRect& rect) override; | |
| bool isClipAntiAliased() const override { return this->clip().fIsAA; } | |
| bool isClipEmpty() const override { return this->devClipBounds().isEmpty(); } | |
| bool isClipRect() const override { return this->clip().fIsRect && !this->isClipEmpty(); } | |
| bool isClipWideOpen() const override { | |
| return this->clip().fIsRect && | |
| this->devClipBounds() == this->bounds(); | |
| } | |
| void android_utils_clipAsRgn(SkRegion* rgn) const override { | |
| rgn->setRect(this->devClipBounds()); | |
| } | |
| SkIRect devClipBounds() const override { return this->clip().fClipBounds; } | |
| protected: | |
| void drawPaint(const SkPaint& paint) override {} | |
| void drawPoints(SkCanvas::PointMode, SkSpan<const SkPoint>, const SkPaint&) override {} | |
| void drawImageRect(const SkImage*, const SkRect*, const SkRect&, | |
| const SkSamplingOptions&, const SkPaint&, | |
| SkCanvas::SrcRectConstraint) override {} | |
| void drawRect(const SkRect&, const SkPaint&) override {} | |
| void drawOval(const SkRect&, const SkPaint&) override {} | |
| void drawRRect(const SkRRect&, const SkPaint&) override {} | |
| void drawPath(const SkPath&, const SkPaint&) override {} | |
| void drawDevice(SkDevice*, const SkSamplingOptions&, const SkPaint&) override {} | |
| void drawVertices(const SkVertices*, sk_sp<SkBlender>, const SkPaint&, bool) override {} | |
| void drawMesh(const SkMesh&, sk_sp<SkBlender>, const SkPaint&) override {} | |
| void drawSlug(SkCanvas*, const sktext::gpu::Slug*, const SkPaint&) override {} | |
| void onDrawGlyphRunList(SkCanvas*, const sktext::GlyphRunList&, const SkPaint&) override {} | |
| bool isNoPixelsDevice() const override { return true; } | |
| private: | |
| struct ClipState { | |
| SkIRect fClipBounds; | |
| int fDeferredSaveCount; | |
| bool fIsAA; | |
| bool fIsRect; | |
| ClipState(const SkIRect& bounds, bool isAA, bool isRect) | |
| : fClipBounds(bounds) | |
| , fDeferredSaveCount(0) | |
| , fIsAA(isAA) | |
| , fIsRect(isRect) {} | |
| void op(SkClipOp op, const SkM44& transform, const SkRect& bounds, | |
| bool isAA, bool fillsBounds); | |
| }; | |
| void onClipShader(sk_sp<SkShader> shader) override; | |
| const ClipState& clip() const { return fClipStack.back(); } | |
| ClipState& writableClip(); | |
| skia_private::STArray<4, ClipState> fClipStack; | |
| }; | |
| class SkAutoDeviceTransformRestore : SkNoncopyable { | |
| public: | |
| SkAutoDeviceTransformRestore(SkDevice* device, const SkM44& localToDevice) | |
| : fDevice(device) | |
| , fPrevLocalToDevice(device->localToDevice()) | |
| { | |
| fDevice->setLocalToDevice(localToDevice); | |
| } | |
| ~SkAutoDeviceTransformRestore() { | |
| fDevice->setLocalToDevice(fPrevLocalToDevice); | |
| } | |
| private: | |
| SkDevice* fDevice; | |
| const SkM44 fPrevLocalToDevice; | |
| }; | |
| #endif |