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