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/SkBlurTypes.h" 12 #include "include/core/SkCanvas.h" 13 #include "include/core/SkColor.h" 14 #include "include/core/SkRefCnt.h" 15 #include "include/core/SkRegion.h" 16 #include "include/core/SkShader.h" 17 #include "include/core/SkSurfaceProps.h" 18 #include "include/private/SkNoncopyable.h" 19 #include "src/core/SkMatrixPriv.h" 20 #include "src/core/SkMatrixProvider.h" 21 #include "src/core/SkRasterClip.h" 22 #include "src/shaders/SkShaderBase.h" 23 24 class SkBitmap; 25 struct SkDrawShadowRec; 26 class SkGlyphRun; 27 class SkGlyphRunList; 28 class SkImageFilter; 29 class SkImageFilterCache; 30 struct SkIRect; 31 class SkMarkerStack; 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 markerStack()144 SkMarkerStack* markerStack() const { return fMarkerStack; } setMarkerStack(SkMarkerStack * ms)145 void setMarkerStack(SkMarkerStack* ms) { fMarkerStack = ms; } 146 147 // SkMatrixProvider interface: 148 bool getLocalToMarker(uint32_t, SkM44* localToMarker) const override; localToDeviceHitsPixelCenters()149 bool localToDeviceHitsPixelCenters() const override { return true; } 150 asMatrixProvider()151 const SkMatrixProvider& asMatrixProvider() const { return *this; } 152 save()153 void save() { this->onSave(); } restore(const SkM44 & ctm)154 void restore(const SkM44& ctm) { 155 this->onRestore(); 156 this->setGlobalCTM(ctm); 157 } restoreLocal(const SkM44 & localToDevice)158 void restoreLocal(const SkM44& localToDevice) { 159 this->onRestore(); 160 this->setLocalToDevice(localToDevice); 161 } clipRect(const SkRect & rect,SkClipOp op,bool aa)162 void clipRect(const SkRect& rect, SkClipOp op, bool aa) { 163 this->onClipRect(rect, op, aa); 164 } clipRRect(const SkRRect & rrect,SkClipOp op,bool aa)165 void clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) { 166 this->onClipRRect(rrect, op, aa); 167 } clipPath(const SkPath & path,SkClipOp op,bool aa)168 void clipPath(const SkPath& path, SkClipOp op, bool aa) { 169 this->onClipPath(path, op, aa); 170 } clipShader(sk_sp<SkShader> sh,SkClipOp op)171 void clipShader(sk_sp<SkShader> sh, SkClipOp op) { 172 sh = as_SB(sh)->makeWithCTM(this->localToDevice()); 173 if (op == SkClipOp::kDifference) { 174 sh = as_SB(sh)->makeInvertAlpha(); 175 } 176 this->onClipShader(std::move(sh)); 177 } clipRegion(const SkRegion & region,SkClipOp op)178 void clipRegion(const SkRegion& region, SkClipOp op) { 179 this->onClipRegion(region, op); 180 } replaceClip(const SkIRect & rect)181 void replaceClip(const SkIRect& rect) { 182 this->onReplaceClip(rect); 183 } 184 clipIsWideOpen()185 bool clipIsWideOpen() const { 186 return this->onClipIsWideOpen(); 187 } 188 setLocalToDevice(const SkM44 & localToDevice)189 void setLocalToDevice(const SkM44& localToDevice) { 190 fLocalToDevice = localToDevice; 191 fLocalToDevice33 = fLocalToDevice.asM33(); 192 } 193 void setGlobalCTM(const SkM44& ctm); validateDevBounds(const SkIRect &)194 virtual void validateDevBounds(const SkIRect&) {} 195 android_utils_clipWithStencil()196 virtual bool android_utils_clipWithStencil() { return false; } 197 asGpuDevice()198 virtual skgpu::BaseDevice* asGpuDevice() { return nullptr; } 199 200 // Ensure that non-RSXForm runs are passed to onDrawGlyphRunList. 201 void drawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint); 202 203 protected: 204 enum TileUsage { 205 kPossible_TileUsage, //!< the created device may be drawn tiled 206 kNever_TileUsage, //!< the created device will never be drawn tiled 207 }; 208 209 struct TextFlags { 210 uint32_t fFlags; // SkPaint::getFlags() 211 }; 212 onSave()213 virtual void onSave() {} onRestore()214 virtual void onRestore() {} onClipRect(const SkRect & rect,SkClipOp,bool aa)215 virtual void onClipRect(const SkRect& rect, SkClipOp, bool aa) {} onClipRRect(const SkRRect & rrect,SkClipOp,bool aa)216 virtual void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) {} onClipPath(const SkPath & path,SkClipOp,bool aa)217 virtual void onClipPath(const SkPath& path, SkClipOp, bool aa) {} onClipShader(sk_sp<SkShader>)218 virtual void onClipShader(sk_sp<SkShader>) {} onClipRegion(const SkRegion & deviceRgn,SkClipOp)219 virtual void onClipRegion(const SkRegion& deviceRgn, SkClipOp) {} onReplaceClip(const SkIRect & rect)220 virtual void onReplaceClip(const SkIRect& rect) {} 221 virtual bool onClipIsAA() const = 0; 222 virtual bool onClipIsWideOpen() const = 0; 223 virtual void onAsRgnClip(SkRegion*) const = 0; 224 enum class ClipType { 225 kEmpty, 226 kRect, 227 kComplex 228 }; 229 virtual ClipType onGetClipType() const = 0; 230 231 // This should strive to be as tight as possible, ideally not just mapping 232 // the global clip bounds by fToGlobal^-1. 233 virtual SkIRect onDevClipBounds() const = 0; 234 235 /** These are called inside the per-device-layer loop for each draw call. 236 When these are called, we have already applied any saveLayer operations, 237 and are handling any looping from the paint. 238 */ 239 virtual void drawPaint(const SkPaint& paint) = 0; 240 virtual void drawPoints(SkCanvas::PointMode mode, size_t count, 241 const SkPoint[], const SkPaint& paint) = 0; 242 virtual void drawRect(const SkRect& r, 243 const SkPaint& paint) = 0; 244 virtual void drawRegion(const SkRegion& r, 245 const SkPaint& paint); 246 virtual void drawOval(const SkRect& oval, 247 const SkPaint& paint) = 0; 248 /** By the time this is called we know that abs(sweepAngle) is in the range [0, 360). */ 249 virtual void drawArc(const SkRect& oval, SkScalar startAngle, 250 SkScalar sweepAngle, bool useCenter, const SkPaint& paint); 251 virtual void drawRRect(const SkRRect& rr, 252 const SkPaint& paint) = 0; 253 254 // Default impl calls drawPath() 255 virtual void drawDRRect(const SkRRect& outer, 256 const SkRRect& inner, const SkPaint&); 257 258 /** 259 * If pathIsMutable, then the implementation is allowed to cast path to a 260 * non-const pointer and modify it in place (as an optimization). Canvas 261 * may do this to implement helpers such as drawOval, by placing a temp 262 * path on the stack to hold the representation of the oval. 263 */ 264 virtual void drawPath(const SkPath& path, 265 const SkPaint& paint, 266 bool pathIsMutable = false) = 0; 267 268 virtual void drawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, 269 const SkSamplingOptions&, const SkPaint&, 270 SkCanvas::SrcRectConstraint) = 0; 271 virtual void drawImageLattice(const SkImage*, const SkCanvas::Lattice&, 272 const SkRect& dst, SkFilterMode, const SkPaint&); 273 274 virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) = 0; 275 virtual void drawShadow(const SkPath&, const SkDrawShadowRec&); 276 277 // default implementation calls drawVertices 278 virtual void drawPatch(const SkPoint cubics[12], const SkColor colors[4], 279 const SkPoint texCoords[4], SkBlendMode, const SkPaint& paint); 280 281 // default implementation calls drawVertices 282 virtual void drawAtlas(const SkRSXform[], const SkRect[], const SkColor[], int count, 283 SkBlendMode, const SkPaint&); 284 drawAnnotation(const SkRect &,const char[],SkData *)285 virtual void drawAnnotation(const SkRect&, const char[], SkData*) {} 286 287 // Default impl always calls drawRect() with a solid-color paint, setting it to anti-aliased 288 // only when all edge flags are set. If there's a clip region, it draws that using drawPath, 289 // or uses clipPath(). 290 virtual void drawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], 291 SkCanvas::QuadAAFlags aaFlags, const SkColor4f& color, 292 SkBlendMode mode); 293 // Default impl uses drawImageRect per entry, being anti-aliased only when an entry's edge flags 294 // are all set. If there's a clip region, it will be applied using clipPath(). 295 virtual void drawEdgeAAImageSet(const SkCanvas::ImageSetEntry[], int count, 296 const SkPoint dstClips[], const SkMatrix preViewMatrices[], 297 const SkSamplingOptions&, const SkPaint&, 298 SkCanvas::SrcRectConstraint); 299 300 virtual void drawDrawable(SkDrawable*, const SkMatrix*, SkCanvas*); 301 302 // Only called with glyphRunLists that do not contain RSXForm. 303 virtual void onDrawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint) = 0; 304 305 /** 306 * The SkDevice passed will be an SkDevice which was returned by a call to 307 * onCreateDevice on this device with kNeverTile_TileExpectation. 308 * 309 * The default implementation calls snapSpecial() and drawSpecial() with the relative transform 310 * from the input device to this device. The provided SkPaint cannot have a mask filter or 311 * image filter, and any shader is ignored. 312 */ 313 virtual void drawDevice(SkBaseDevice*, const SkSamplingOptions&, const SkPaint&); 314 315 /** 316 * Draw the special image's subset to this device, subject to the given matrix transform instead 317 * of the device's current local to device matrix. 318 */ 319 virtual void drawSpecial(SkSpecialImage*, const SkMatrix& localToDevice, 320 const SkSamplingOptions&, const SkPaint&); 321 322 /** 323 * Evaluate 'filter' and draw the final output into this device using 'paint'. The 'mapping' 324 * defines the parameter-to-layer space transform used to evaluate the image filter on 'src', 325 * and the layer-to-device space transform that is used to draw the result into this device. 326 * Since 'mapping' fully specifies the transform, this draw function ignores the current 327 * local-to-device matrix (i.e. just like drawSpecial and drawDevice). 328 * 329 * The final paint must not have an image filter or mask filter set on it; a shader is ignored. 330 */ 331 virtual void drawFilteredImage(const skif::Mapping& mapping, SkSpecialImage* src, 332 const SkImageFilter*, const SkSamplingOptions&, const SkPaint&); 333 334 virtual bool drawBlurImage(const SkImage* image, const SkBlurArg& blurArg) = 0; 335 336 virtual sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&); 337 virtual sk_sp<SkSpecialImage> makeSpecial(const SkImage*); 338 339 // Get a view of the entire device's current contents as an image. 340 sk_sp<SkSpecialImage> snapSpecial(); 341 // Snap the 'subset' contents from this device, possibly as a read-only view. If 'forceCopy' 342 // is true then the returned image's pixels must not be affected by subsequent draws into the 343 // device. When 'forceCopy' is false, the image can be a view into the device's pixels 344 // (avoiding a copy for performance, at the expense of safety). Default returns null. 345 virtual sk_sp<SkSpecialImage> snapSpecial(const SkIRect& subset, bool forceCopy = false); 346 setImmutable()347 virtual void setImmutable() {} 348 349 bool readPixels(const SkPixmap&, int x, int y); 350 351 virtual sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&); onPeekPixels(SkPixmap *)352 virtual bool onPeekPixels(SkPixmap*) { return false; } 353 354 /** 355 * The caller is responsible for "pre-clipping" the dst. The impl can assume that the dst 356 * image at the specified x,y offset will fit within the device's bounds. 357 * 358 * This is explicitly asserted in readPixels(), the public way to call this. 359 */ 360 virtual bool onReadPixels(const SkPixmap&, int x, int y); 361 362 /** 363 * The caller is responsible for "pre-clipping" the src. The impl can assume that the src 364 * image at the specified x,y offset will fit within the device's bounds. 365 * 366 * This is explicitly asserted in writePixelsDirect(), the public way to call this. 367 */ 368 virtual bool onWritePixels(const SkPixmap&, int x, int y); 369 onAccessPixels(SkPixmap *)370 virtual bool onAccessPixels(SkPixmap*) { return false; } 371 372 struct CreateInfo { CreateInfoCreateInfo373 CreateInfo(const SkImageInfo& info, 374 SkPixelGeometry geo, 375 TileUsage tileUsage, 376 bool trackCoverage, 377 SkRasterHandleAllocator* allocator) 378 : fInfo(info) 379 , fTileUsage(tileUsage) 380 , fPixelGeometry(geo) 381 , fTrackCoverage(trackCoverage) 382 , fAllocator(allocator) 383 {} 384 385 const SkImageInfo fInfo; 386 const TileUsage fTileUsage; 387 const SkPixelGeometry fPixelGeometry; 388 const bool fTrackCoverage = false; 389 SkRasterHandleAllocator* fAllocator = nullptr; 390 }; 391 392 /** 393 * Create a new device based on CreateInfo. If the paint is not null, then it represents a 394 * preview of how the new device will be composed with its creator device (this). 395 * 396 * The subclass may be handed this device in drawDevice(), so it must always return 397 * a device that it knows how to draw, and that it knows how to identify if it is not of the 398 * same subclass (since drawDevice is passed a SkBaseDevice*). If the subclass cannot fulfill 399 * that contract (e.g. PDF cannot support some settings on the paint) it should return NULL, 400 * and the caller may then decide to explicitly create a bitmapdevice, knowing that later 401 * it could not call drawDevice with it (but it could call drawSprite or drawBitmap). 402 */ onCreateDevice(const CreateInfo &,const SkPaint *)403 virtual SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) { 404 return nullptr; 405 } 406 407 // SkCanvas uses NoPixelsDevice when onCreateDevice fails; but then it needs to be able to 408 // inspect a layer's device to know if calling drawDevice() later is allowed. isNoPixelsDevice()409 virtual bool isNoPixelsDevice() const { return false; } 410 #ifdef SK_ENABLE_STENCIL_CULLING_OHOS 411 // stencil Culling API clearStencil(const SkIRect & rect,uint32_t stencilVal)412 virtual void clearStencil(const SkIRect& rect, uint32_t stencilVal) {}; 413 virtual void drawPathWithStencil(const SkPath& path, 414 const SkPaint& paint, 415 uint32_t stencilRef, 416 bool pathIsMutable = false) {}; drawImageRectWithStencil(const SkImage *,const SkRect * src,const SkRect & dst,const SkSamplingOptions &,const SkPaint &,SkCanvas::SrcRectConstraint,uint32_t stencilRef)417 virtual void drawImageRectWithStencil(const SkImage*, 418 const SkRect* src, 419 const SkRect& dst, 420 const SkSamplingOptions&, 421 const SkPaint&, 422 SkCanvas::SrcRectConstraint, 423 uint32_t stencilRef) {}; 424 #endif 425 private: 426 friend class SkAndroidFrameworkUtils; 427 friend class SkCanvas; 428 friend class SkDraw; 429 friend class SkSurface_Raster; 430 friend class DeviceTestingAccess; 431 432 void simplifyGlyphRunRSXFormAndRedraw(const SkGlyphRunList& glyphRunList, const SkPaint& paint); 433 434 // used to change the backend's pixels (and possibly config/rowbytes) 435 // but cannot change the width/height, so there should be no change to 436 // any clip information. 437 // TODO: move to SkBitmapDevice replaceBitmapBackendForRasterSurface(const SkBitmap &)438 virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) {} 439 forceConservativeRasterClip()440 virtual bool forceConservativeRasterClip() const { return false; } 441 442 // Configure the device's coordinate spaces, specifying both how its device image maps back to 443 // the global space (via 'deviceToGlobal') and the initial CTM of the device (via 444 // 'localToDevice', i.e. what geometry drawn into this device will be transformed with). 445 // 446 // (bufferOriginX, bufferOriginY) defines where the (0,0) pixel the device's backing buffer 447 // is anchored in the device space. The final device-to-global matrix stored by the SkDevice 448 // will include a pre-translation by T(deviceOriginX, deviceOriginY), and the final 449 // local-to-device matrix will have a post-translation of T(-deviceOriginX, -deviceOriginY). 450 // 451 // Returns false if the final device coordinate space is invalid, in which case the canvas 452 // should discard the device 453 bool SK_WARN_UNUSED_RESULT setDeviceCoordinateSystem(const SkM44& deviceToGlobal, 454 const SkM44& localToDevice, 455 int bufferOriginX, int bufferOriginY); 456 // Convenience to configure the device to be axis-aligned with the root canvas, but with a 457 // unique origin. setOrigin(const SkM44 & globalCTM,int x,int y)458 void setOrigin(const SkM44& globalCTM, int x, int y) { 459 SkAssertResult(this->setDeviceCoordinateSystem(SkM44(), globalCTM, x, y)); 460 } 461 getImageFilterCache()462 virtual SkImageFilterCache* getImageFilterCache() { return nullptr; } 463 464 friend class SkNoPixelsDevice; 465 friend class SkBitmapDevice; privateResize(int w,int h)466 void privateResize(int w, int h) { 467 *const_cast<SkImageInfo*>(&fInfo) = fInfo.makeWH(w, h); 468 } 469 470 SkMarkerStack* fMarkerStack = nullptr; // does not own this, set in setMarkerStack() 471 472 const SkImageInfo fInfo; 473 const SkSurfaceProps fSurfaceProps; 474 // fDeviceToGlobal and fGlobalToDevice are inverses of each other; there are never that many 475 // SkDevices, so pay the memory cost to avoid recalculating the inverse. 476 SkM44 fDeviceToGlobal; 477 SkM44 fGlobalToDevice; 478 479 // fLocalToDevice (inherited from SkMatrixProvider) is the device CTM, not the global CTM 480 // It maps from local space to the device's coordinate space. 481 // fDeviceToGlobal * fLocalToDevice will match the canvas' CTM. 482 483 using INHERITED = SkRefCnt; 484 }; 485 486 class SkNoPixelsDevice : public SkBaseDevice { 487 public: 488 SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props, 489 sk_sp<SkColorSpace> colorSpace = nullptr) 490 : SkBaseDevice(SkImageInfo::Make(bounds.size(), kUnknown_SkColorType, 491 kUnknown_SkAlphaType, std::move(colorSpace)), 492 props) { 493 // this fails if we enable this assert: DiscardableImageMapTest.GetDiscardableImagesInRectMaxImage 494 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0); 495 496 this->setOrigin(SkM44(), bounds.left(), bounds.top()); 497 this->resetClipStack(); 498 } 499 resetForNextPicture(const SkIRect & bounds)500 void resetForNextPicture(const SkIRect& bounds) { 501 //SkASSERT(bounds.width() >= 0 && bounds.height() >= 0); 502 this->privateResize(bounds.width(), bounds.height()); 503 this->setOrigin(SkM44(), bounds.left(), bounds.top()); 504 this->resetClipStack(); 505 } 506 507 protected: 508 // SkNoPixelsDevice tracks the clip conservatively in order to respond to some queries as 509 // accurately as possible while emphasizing performance 510 void onSave() override; 511 void onRestore() override; 512 void onClipRect(const SkRect& rect, SkClipOp op, bool aa) override; 513 void onClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) override; 514 void onClipPath(const SkPath& path, SkClipOp op, bool aa) override; 515 void onClipRegion(const SkRegion& globalRgn, SkClipOp op) override; 516 void onClipShader(sk_sp<SkShader> shader) override; 517 void onReplaceClip(const SkIRect& rect) override; onClipIsAA()518 bool onClipIsAA() const override { return this->clip().fIsAA; } onClipIsWideOpen()519 bool onClipIsWideOpen() const override { 520 return this->clip().fIsRect && 521 this->onDevClipBounds() == this->bounds(); 522 } onAsRgnClip(SkRegion * rgn)523 void onAsRgnClip(SkRegion* rgn) const override { 524 rgn->setRect(this->onDevClipBounds()); 525 } 526 ClipType onGetClipType() const override; onDevClipBounds()527 SkIRect onDevClipBounds() const override { return this->clip().fClipBounds; } 528 drawPaint(const SkPaint & paint)529 void drawPaint(const SkPaint& paint) override {} drawPoints(SkCanvas::PointMode,size_t,const SkPoint[],const SkPaint &)530 void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {} drawImageRect(const SkImage *,const SkRect *,const SkRect &,const SkSamplingOptions &,const SkPaint &,SkCanvas::SrcRectConstraint)531 void drawImageRect(const SkImage*, const SkRect*, const SkRect&, 532 const SkSamplingOptions&, const SkPaint&, 533 SkCanvas::SrcRectConstraint) override {} drawRect(const SkRect &,const SkPaint &)534 void drawRect(const SkRect&, const SkPaint&) override {} drawOval(const SkRect &,const SkPaint &)535 void drawOval(const SkRect&, const SkPaint&) override {} drawRRect(const SkRRect &,const SkPaint &)536 void drawRRect(const SkRRect&, const SkPaint&) override {} drawPath(const SkPath &,const SkPaint &,bool)537 void drawPath(const SkPath&, const SkPaint&, bool) override {} drawDevice(SkBaseDevice *,const SkSamplingOptions &,const SkPaint &)538 void drawDevice(SkBaseDevice*, const SkSamplingOptions&, const SkPaint&) override {} drawVertices(const SkVertices *,SkBlendMode,const SkPaint &)539 void drawVertices(const SkVertices*, SkBlendMode, const SkPaint&) override {} 540 drawFilteredImage(const skif::Mapping &,SkSpecialImage * src,const SkImageFilter *,const SkSamplingOptions &,const SkPaint &)541 void drawFilteredImage(const skif::Mapping&, SkSpecialImage* src, const SkImageFilter*, 542 const SkSamplingOptions&, const SkPaint&) override {} 543 drawBlurImage(const SkImage * image,const SkBlurArg & blurArg)544 bool drawBlurImage(const SkImage* image, const SkBlurArg& blurArg) override { return false; } 545 onDrawGlyphRunList(const SkGlyphRunList & glyphRunList,const SkPaint & paint)546 void onDrawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint) override {} 547 548 isNoPixelsDevice()549 bool isNoPixelsDevice() const override { return true; } 550 551 private: 552 struct ClipState { 553 SkIRect fClipBounds; 554 int fDeferredSaveCount; 555 bool fIsAA; 556 bool fIsRect; 557 ClipStateClipState558 ClipState(const SkIRect& bounds, bool isAA, bool isRect) 559 : fClipBounds(bounds) 560 , fDeferredSaveCount(0) 561 , fIsAA(isAA) 562 , fIsRect(isRect) {} 563 564 void op(SkClipOp op, const SkM44& transform, const SkRect& bounds, 565 bool isAA, bool fillsBounds); 566 }; 567 clip()568 const ClipState& clip() const { return fClipStack.back(); } 569 ClipState& writableClip(); 570 resetClipStack()571 void resetClipStack() { 572 fClipStack.reset(); 573 fClipStack.emplace_back(this->bounds(), /*isAA=*/false, /*isRect=*/true); 574 } 575 576 SkSTArray<4, ClipState> fClipStack; 577 578 using INHERITED = SkBaseDevice; 579 }; 580 581 class SkAutoDeviceTransformRestore : SkNoncopyable { 582 public: SkAutoDeviceTransformRestore(SkBaseDevice * device,const SkMatrix & localToDevice)583 SkAutoDeviceTransformRestore(SkBaseDevice* device, const SkMatrix& localToDevice) 584 : fDevice(device) 585 , fPrevLocalToDevice(device->localToDevice()) 586 { 587 fDevice->setLocalToDevice(SkM44(localToDevice)); 588 } ~SkAutoDeviceTransformRestore()589 ~SkAutoDeviceTransformRestore() { 590 fDevice->setLocalToDevice(fPrevLocalToDevice); 591 } 592 593 private: 594 SkBaseDevice* fDevice; 595 const SkM44 fPrevLocalToDevice; 596 }; 597 598 #endif 599