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