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