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