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" // IWYU pragma: keep 12 #include "include/core/SkCanvas.h" 13 #include "include/core/SkClipOp.h" 14 #include "include/core/SkColor.h" 15 #include "include/core/SkImageInfo.h" 16 #include "include/core/SkM44.h" 17 #include "include/core/SkMatrix.h" 18 #include "include/core/SkPoint.h" 19 #include "include/core/SkRect.h" 20 #include "include/core/SkRefCnt.h" 21 #include "include/core/SkRegion.h" 22 #include "include/core/SkSamplingOptions.h" 23 #include "include/core/SkShader.h" 24 #include "include/core/SkSize.h" 25 #include "include/core/SkSurfaceProps.h" 26 #include "include/private/base/SkAssert.h" 27 #include "include/private/base/SkNoncopyable.h" 28 #include "include/private/base/SkTArray.h" 29 #include "src/core/SkMatrixPriv.h" 30 #include "src/shaders/SkShaderBase.h" 31 32 #include <cstddef> 33 #include <cstdint> 34 #include <utility> 35 36 struct SkArc; 37 class SkBitmap; 38 class SkColorSpace; 39 class SkMesh; 40 struct SkDrawShadowRec; 41 class SkImageFilter; 42 class SkRasterHandleAllocator; 43 class SkSpecialImage; 44 class GrRecordingContext; 45 class SkData; 46 class SkDrawable; 47 class SkImage; 48 class SkPaint; 49 class SkPath; 50 class SkPixmap; 51 class SkRRect; 52 class SkSurface; 53 class SkVertices; 54 enum SkColorType : int; 55 enum class SkBlendMode; 56 enum class SkScalerContextFlags : uint32_t; 57 struct SkRSXform; 58 59 namespace sktext { 60 class GlyphRunList; 61 } 62 63 namespace skif { 64 class Backend; 65 class Mapping; 66 } 67 namespace skgpu::ganesh { 68 class Device; 69 } 70 namespace skgpu::graphite { 71 class Device; 72 class Recorder; 73 } 74 namespace sktext::gpu { 75 class SubRunControl; 76 class Slug; 77 } 78 79 struct SkStrikeDeviceInfo { 80 const SkSurfaceProps fSurfaceProps; 81 const SkScalerContextFlags fScalerContextFlags; 82 // This is a pointer so this can be compiled without SK_GPU_SUPPORT. 83 const sktext::gpu::SubRunControl* const fSubRunControl; 84 }; 85 86 /** 87 * SkDevice is the internal API and implementation that SkCanvas will use to perform rendering and 88 * implement the saveLayer abstraction. A device wraps some pixel allocation (for non-document based 89 * devices) or wraps some other container that stores rendering operations. The drawing operations 90 * perform equivalently to their corresponding functions in SkCanvas except that the canvas is 91 * responsible for all SkImageFilters. An image filter is applied by automatically creating a layer, 92 * drawing the filter-less paint into the layer, and then evaluating the filter on the layer's 93 * image. 94 * 95 * Each layer in an SkCanvas stack is represented by an SkDevice instance that was created by the 96 * parent SkDevice (up to the canvas's base device). In most cases these devices will be pixel 97 * aligned with one another but may differ in size based on the known extent of the active clip. In 98 * complex image filtering scenarios, they may not be axis aligned, although the effective pixel 99 * size should remain approximately equal across all devices in a canvas. 100 * 101 * While SkCanvas manages a single stack of layers and canvas transforms, SkDevice does not have a 102 * stack of transforms. Instead, it has a single active transform that is modified as needed by 103 * SkCanvas. However, SkDevices are the means by which SkCanvas manages the clip stack because each 104 * layer's clip stack starts anew (although the layer's results are then clipped by its parent's 105 * stack when it is restored). 106 */ 107 class SkDevice : public SkRefCnt { 108 public: 109 SkDevice(const SkImageInfo&, const SkSurfaceProps&); 110 111 // -- Surface properties and metadata 112 113 /** 114 * Return ImageInfo for this device. If the canvas is not backed by pixels 115 * (cpu or gpu), then the info's ColorType will be kUnknown_SkColorType. 116 */ imageInfo()117 const SkImageInfo& imageInfo() const { return fInfo; } 118 width()119 int width() const { return this->imageInfo().width(); } height()120 int height() const { return this->imageInfo().height(); } 121 isOpaque()122 bool isOpaque() const { return this->imageInfo().isOpaque(); } 123 124 // NOTE: Image dimensions as a rect, *not* the current restricted clip bounds. bounds()125 SkIRect bounds() const { return SkIRect::MakeWH(this->width(), this->height()); } size()126 SkISize size() const { return this->imageInfo().dimensions(); } 127 128 /** 129 * Return SurfaceProps for this device. 130 */ surfaceProps()131 const SkSurfaceProps& surfaceProps() const { 132 return fSurfaceProps; 133 } 134 135 SkScalerContextFlags scalerContextFlags() const; 136 strikeDeviceInfo()137 virtual SkStrikeDeviceInfo strikeDeviceInfo() const { 138 return {fSurfaceProps, this->scalerContextFlags(), nullptr}; 139 } 140 141 // -- Direct pixel manipulation 142 143 /** 144 * Write the pixels in 'src' into this Device at the specified x,y offset. The caller is 145 * responsible for "pre-clipping" the src. 146 */ writePixels(const SkPixmap & src,int x,int y)147 bool writePixels(const SkPixmap& src, int x, int y) { return this->onWritePixels(src, x, y); } 148 149 /** 150 * Read pixels from this Device at the specified x,y offset into dst. The caller is 151 * responsible for "pre-clipping" the dst 152 */ readPixels(const SkPixmap & dst,int x,int y)153 bool readPixels(const SkPixmap& dst, int x, int y) { return this->onReadPixels(dst, x, y); } 154 155 /** 156 * Try to get write-access to the pixels behind the device. If successful, this returns true 157 * and fills-out the pixmap parameter. On success it also bumps the genID of the underlying 158 * bitmap. 159 * 160 * On failure, returns false and ignores the pixmap parameter. 161 */ 162 bool accessPixels(SkPixmap* pmap); 163 164 /** 165 * Try to get read-only-access to the pixels behind the device. If successful, this returns 166 * true and fills-out the pixmap parameter. 167 * 168 * On failure, returns false and ignores the pixmap parameter. 169 */ 170 bool peekPixels(SkPixmap*); 171 172 173 // -- Device's transform (both current transform affecting draws, and its fixed global mapping) 174 175 /** 176 * Returns the transformation that maps from the local space to the device's coordinate space. 177 */ localToDevice44()178 const SkM44& localToDevice44() const { return fLocalToDevice; } localToDevice()179 const SkMatrix& localToDevice() const { return fLocalToDevice33; } 180 181 /** 182 * Return the device's coordinate space transform: this maps from the device's coordinate space 183 * into the global canvas' space (or root device space). This includes the translation 184 * necessary to account for the device's origin. 185 */ deviceToGlobal()186 const SkM44& deviceToGlobal() const { return fDeviceToGlobal; } 187 /** 188 * Return the inverse of getDeviceToGlobal(), mapping from the global canvas' space (or root 189 * device space) into this device's coordinate space. 190 */ globalToDevice()191 const SkM44& globalToDevice() const { return fGlobalToDevice; } 192 /** 193 * DEPRECATED: This asserts that 'getDeviceToGlobal' is a translation matrix with integer 194 * components. In the future some SkDevices will have more complex device-to-global transforms, 195 * so getDeviceToGlobal() or getRelativeTransform() should be used instead. 196 */ 197 SkIPoint getOrigin() const; 198 /** 199 * Returns true when this device's pixel grid is axis aligned with the global coordinate space, 200 * and any relative translation between the two spaces is in integer pixel units. 201 */ 202 bool isPixelAlignedToGlobal() const; 203 /** 204 * Get the transformation from this device's coordinate system to the provided device space. 205 * This transform can be used to draw this device into the provided device, such that once 206 * that device is drawn to the root device, the net effect will be that this device's contents 207 * have been transformed by the global CTM. 208 */ 209 SkMatrix getRelativeTransform(const SkDevice&) const; 210 setLocalToDevice(const SkM44 & localToDevice)211 void setLocalToDevice(const SkM44& localToDevice) { 212 fLocalToDevice = localToDevice; 213 fLocalToDevice33 = fLocalToDevice.asM33(); 214 fLocalToDeviceDirty = true; 215 } 216 void setGlobalCTM(const SkM44& ctm); 217 218 // -- Device's clip bounds and stack manipulation 219 220 /** 221 * Return the bounds of the device in the coordinate space of the root canvas. The root device 222 * will have its top-left at 0,0, but other devices such as those associated with saveLayer may 223 * have a non-zero origin. 224 */ getGlobalBounds(SkIRect * bounds)225 void getGlobalBounds(SkIRect* bounds) const { 226 SkASSERT(bounds); 227 *bounds = SkMatrixPriv::MapRect(fDeviceToGlobal, SkRect::Make(this->bounds())).roundOut(); 228 } 229 getGlobalBounds()230 SkIRect getGlobalBounds() const { 231 SkIRect bounds; 232 this->getGlobalBounds(&bounds); 233 return bounds; 234 } 235 236 /** 237 * Returns the bounding box of the current clip, in this device's coordinate space. No pixels 238 * outside of these bounds will be touched by draws unless the clip is further modified (at 239 * which point this will return the updated bounds). 240 */ 241 virtual SkIRect devClipBounds() const = 0; 242 243 virtual void pushClipStack() = 0; 244 virtual void popClipStack() = 0; 245 246 virtual void clipRect(const SkRect& rect, SkClipOp op, bool aa) = 0; 247 virtual void clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) = 0; 248 virtual void clipPath(const SkPath& path, SkClipOp op, bool aa) = 0; 249 virtual void clipRegion(const SkRegion& region, SkClipOp op) = 0; 250 clipShader(sk_sp<SkShader> sh,SkClipOp op)251 void clipShader(sk_sp<SkShader> sh, SkClipOp op) { 252 sh = as_SB(sh)->makeWithCTM(this->localToDevice()); 253 if (op == SkClipOp::kDifference) { 254 sh = as_SB(sh)->makeInvertAlpha(); 255 } 256 this->onClipShader(std::move(sh)); 257 } 258 259 virtual void replaceClip(const SkIRect& rect) = 0; 260 261 virtual bool isClipAntiAliased() const = 0; 262 virtual bool isClipEmpty() const = 0; 263 virtual bool isClipRect() const = 0; 264 virtual bool isClipWideOpen() const = 0; 265 266 virtual void android_utils_clipAsRgn(SkRegion*) const = 0; android_utils_clipWithStencil()267 virtual bool android_utils_clipWithStencil() { return false; } 268 269 // -- Device reflection 270 271 // TEMPORARY: Whether or not SkCanvas should use an layer and image filters to simulate 272 // mask filters and then draw the filtered mask using drawCoverageMask. Unlike regular 273 // layers, the color type passed to SkDevice::createDevice() will always be an alpha-only 274 // color type. Eventually this will be the only way that mask filters are handled (barring 275 // dedicated fast-paths for blurs on [r]rects and text). useDrawCoverageMaskForMaskFilters()276 virtual bool useDrawCoverageMaskForMaskFilters() const { return false; } 277 278 // SkCanvas uses NoPixelsDevice when createDevice fails; but then it needs to be able to 279 // inspect a layer's device to know if calling drawDevice() later is allowed. isNoPixelsDevice()280 virtual bool isNoPixelsDevice() const { return false; } 281 getRasterHandle()282 virtual void* getRasterHandle() const { return nullptr; } 283 recordingContext()284 virtual GrRecordingContext* recordingContext() const { return nullptr; } recorder()285 virtual skgpu::graphite::Recorder* recorder() const { return nullptr; } 286 asGaneshDevice()287 virtual skgpu::ganesh::Device* asGaneshDevice() { return nullptr; } asGraphiteDevice()288 virtual skgpu::graphite::Device* asGraphiteDevice() { return nullptr; } 289 290 // Marking an SkDevice immutable declares the intent that rendering to the device is 291 // complete, allowing it to be sampled as an image without requiring a copy. Drawing 292 // operations may not function and may assert if invoked after setImmutable() is called. setImmutable()293 virtual void setImmutable() {} 294 295 virtual sk_sp<SkSurface> makeSurface(const SkImageInfo&, const SkSurfaceProps&); 296 297 struct CreateInfo { CreateInfoCreateInfo298 CreateInfo(const SkImageInfo& info, 299 SkPixelGeometry geo, 300 SkRasterHandleAllocator* allocator) 301 : fInfo(info) 302 , fPixelGeometry(geo) 303 , fAllocator(allocator) 304 {} 305 306 const SkImageInfo fInfo; 307 const SkPixelGeometry fPixelGeometry; 308 SkRasterHandleAllocator* fAllocator = nullptr; 309 }; 310 311 /** 312 * Create a new device based on CreateInfo. If the paint is not null, then it represents a 313 * preview of how the new device will be composed with its creator device (this). 314 * 315 * The subclass may be handed this device in drawDevice(), so it must always return a device 316 * that it knows how to draw, and that it knows how to identify if it is not of the same 317 * subclass (since drawDevice is passed a SkDevice*). If the subclass cannot fulfill that 318 * contract (e.g. PDF cannot support some settings on the paint) it should return NULL, and the 319 * caller may then decide to explicitly create a bitmapdevice, knowing that later it could not 320 * call drawDevice with it (but it could call drawSprite or drawBitmap). 321 */ createDevice(const CreateInfo &,const SkPaint *)322 virtual sk_sp<SkDevice> createDevice(const CreateInfo&, const SkPaint*) { return nullptr; } 323 324 // -- Drawing routines (called after saveLayers and imagefilter operations are applied) 325 326 // Ensure that non-RSXForm runs are passed to onDrawGlyphRunList. 327 void drawGlyphRunList(SkCanvas*, 328 const sktext::GlyphRunList& glyphRunList, 329 const SkPaint& paint); 330 // Slug handling routines. 331 virtual sk_sp<sktext::gpu::Slug> convertGlyphRunListToSlug( 332 const sktext::GlyphRunList& glyphRunList, const SkPaint& paint); 333 virtual void drawSlug(SkCanvas*, const sktext::gpu::Slug* slug, const SkPaint& paint); 334 335 virtual void drawPaint(const SkPaint& paint) = 0; 336 virtual void drawPoints(SkCanvas::PointMode mode, size_t count, 337 const SkPoint[], const SkPaint& paint) = 0; 338 virtual void drawRect(const SkRect& r, 339 const SkPaint& paint) = 0; 340 virtual void drawRegion(const SkRegion& r, 341 const SkPaint& paint); 342 virtual void drawOval(const SkRect& oval, 343 const SkPaint& paint) = 0; 344 /** By the time this is called we know that abs(sweepAngle) is in the range [0, 360). */ 345 virtual void drawArc(const SkArc& arc, const SkPaint& paint); 346 virtual void drawRRect(const SkRRect& rr, 347 const SkPaint& paint) = 0; 348 349 // Default impl calls drawPath() 350 virtual void drawDRRect(const SkRRect& outer, 351 const SkRRect& inner, const SkPaint&); 352 353 /** 354 * If pathIsMutable, then the implementation is allowed to cast path to a 355 * non-const pointer and modify it in place (as an optimization). Canvas 356 * may do this to implement helpers such as drawOval, by placing a temp 357 * path on the stack to hold the representation of the oval. 358 */ 359 virtual void drawPath(const SkPath& path, 360 const SkPaint& paint, 361 bool pathIsMutable = false) = 0; 362 363 virtual void drawImageRect(const SkImage*, const SkRect* src, const SkRect& dst, 364 const SkSamplingOptions&, const SkPaint&, 365 SkCanvas::SrcRectConstraint) = 0; 366 // Return true if canvas calls to drawImage or drawImageRect should try to 367 // be drawn in a tiled way. shouldDrawAsTiledImageRect()368 virtual bool shouldDrawAsTiledImageRect() const { return false; } drawAsTiledImageRect(SkCanvas *,const SkImage *,const SkRect * src,const SkRect & dst,const SkSamplingOptions &,const SkPaint &,SkCanvas::SrcRectConstraint)369 virtual bool drawAsTiledImageRect(SkCanvas*, 370 const SkImage*, 371 const SkRect* src, 372 const SkRect& dst, 373 const SkSamplingOptions&, 374 const SkPaint&, 375 SkCanvas::SrcRectConstraint) { return false; } 376 377 virtual void drawImageLattice(const SkImage*, const SkCanvas::Lattice&, 378 const SkRect& dst, SkFilterMode, const SkPaint&); 379 380 /** 381 * If skipColorXform is true, then the implementation should assume that the provided 382 * vertex colors are already in the destination color space. 383 */ 384 virtual void drawVertices(const SkVertices*, 385 sk_sp<SkBlender>, 386 const SkPaint&, 387 bool skipColorXform = false) = 0; 388 virtual void drawMesh(const SkMesh& mesh, sk_sp<SkBlender>, const SkPaint&) = 0; 389 virtual void drawShadow(const SkPath&, const SkDrawShadowRec&); 390 391 // default implementation calls drawVertices 392 virtual void drawPatch(const SkPoint cubics[12], const SkColor colors[4], 393 const SkPoint texCoords[4], sk_sp<SkBlender>, const SkPaint& paint); 394 395 // default implementation calls drawVertices 396 virtual void drawAtlas(const SkRSXform[], const SkRect[], const SkColor[], int count, 397 sk_sp<SkBlender>, const SkPaint&); 398 drawAnnotation(const SkRect &,const char[],SkData *)399 virtual void drawAnnotation(const SkRect&, const char[], SkData*) {} 400 401 // Default impl always calls drawRect() with a solid-color paint, setting it to anti-aliased 402 // only when all edge flags are set. If there's a clip region, it draws that using drawPath, 403 // or uses clipPath(). 404 virtual void drawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], 405 SkCanvas::QuadAAFlags aaFlags, const SkColor4f& color, 406 SkBlendMode mode); 407 // Default impl uses drawImageRect per entry, being anti-aliased only when an entry's edge flags 408 // are all set. If there's a clip region, it will be applied using clipPath(). 409 virtual void drawEdgeAAImageSet(const SkCanvas::ImageSetEntry[], int count, 410 const SkPoint dstClips[], const SkMatrix preViewMatrices[], 411 const SkSamplingOptions&, const SkPaint&, 412 SkCanvas::SrcRectConstraint); 413 414 virtual void drawDrawable(SkCanvas*, SkDrawable*, const SkMatrix*); 415 416 // -- "Special" drawing and image routines 417 418 // Snap the 'subset' contents from this device, possibly as a read-only view. If 'forceCopy' 419 // is true then the returned image's pixels must not be affected by subsequent draws into the 420 // device. When 'forceCopy' is false, the image can be a view into the device's pixels 421 // (avoiding a copy for performance, at the expense of safety). Default returns null. 422 virtual sk_sp<SkSpecialImage> snapSpecial(const SkIRect& subset, bool forceCopy = false); 423 // Can return null if unable to perform scaling as part of the copy, even if snapSpecial() w/o 424 // scaling would succeed. 425 virtual sk_sp<SkSpecialImage> snapSpecialScaled(const SkIRect& subset, const SkISize& dstDims); 426 // Get a view of the entire device's current contents as an image. 427 sk_sp<SkSpecialImage> snapSpecial(); 428 429 /** 430 * The SkDevice passed will be an SkDevice which was returned by a call to 431 * createDevice on this device with kNeverTile_TileExpectation. 432 * 433 * The default implementation calls snapSpecial() and drawSpecial() with the relative transform 434 * from the input device to this device. The provided SkPaint cannot have a mask filter or 435 * image filter, and any shader is ignored. 436 */ 437 virtual void drawDevice(SkDevice*, const SkSamplingOptions&, const SkPaint&); 438 439 /** 440 * Draw the special image's subset to this device, subject to the given matrix transform instead 441 * of the device's current local to device matrix. 442 * 443 * If 'constraint' is kFast, the rendered geometry of the image still reflects the extent of 444 * the SkSpecialImage's subset, but it's assumed that the pixel data beyond the subset is valid 445 * (e.g. SkSpecialImage::makeSubset() was called to crop a larger image). 446 */ 447 virtual void drawSpecial(SkSpecialImage*, const SkMatrix& localToDevice, 448 const SkSamplingOptions&, const SkPaint&, 449 SkCanvas::SrcRectConstraint constraint = 450 SkCanvas::kStrict_SrcRectConstraint); 451 452 /** 453 * Draw the special image's subset to this device, treating its alpha channel as coverage for 454 * the draw and ignoring any RGB channels that might be present. This will be drawn using the 455 * provided matrix transform instead of the device's current local to device matrix. 456 * 457 * Coverage values beyond the image's subset are treated as 0 (i.e. kDecal tiling). Color values 458 * before coverage are determined as normal by the SkPaint, ignoring style, path effects, 459 * mask filters and image filters. The local coords of any SkShader on the paint should be 460 * relative to the SkDevice's current matrix (i.e. 'maskToDevice' determines how the coverage 461 * mask aligns with device-space, but otherwise shading proceeds like other draws). 462 */ 463 virtual void drawCoverageMask(const SkSpecialImage*, const SkMatrix& maskToDevice, 464 const SkSamplingOptions&, const SkPaint&); 465 466 /** 467 * Draw rrect with an optimized path for analytic blurs, if provided by the device. 468 */ drawBlurredRRect(const SkRRect &,const SkPaint &,float deviceSigma)469 virtual bool drawBlurredRRect(const SkRRect&, const SkPaint&, float deviceSigma) { 470 return false; 471 } 472 473 /** 474 * Evaluate 'filter' and draw the final output into this device using 'paint'. The 'mapping' 475 * defines the parameter-to-layer space transform used to evaluate the image filter on 'src', 476 * and the layer-to-device space transform that is used to draw the result into this device. 477 * Since 'mapping' fully specifies the transform, this draw function ignores the current 478 * local-to-device matrix (i.e. just like drawSpecial and drawDevice). 479 * 480 * The final paint must not have an image filter or mask filter set on it; a shader is ignored. 481 * The provided color type will be used for any intermediate surfaces that need to be created as 482 * part of filter evaluation. It does not have to be src's color type or this Device's type. 483 */ 484 void drawFilteredImage(const skif::Mapping& mapping, SkSpecialImage* src, SkColorType ct, 485 const SkImageFilter*, const SkSamplingOptions&, const SkPaint&); 486 487 protected: 488 // DEPRECATED: Can be deleted once SkCanvas::onDrawImage() uses skif::FilterResult so don't 489 // bother re-arranging. 490 virtual sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&); 491 virtual sk_sp<SkSpecialImage> makeSpecial(const SkImage*); 492 493 // Configure the device's coordinate spaces, specifying both how its device image maps back to 494 // the global space (via 'deviceToGlobal') and the initial CTM of the device (via 495 // 'localToDevice', i.e. what geometry drawn into this device will be transformed with). 496 // 497 // (bufferOriginX, bufferOriginY) defines where the (0,0) pixel the device's backing buffer 498 // is anchored in the device space. The final device-to-global matrix stored by the SkDevice 499 // will include a pre-translation by T(deviceOriginX, deviceOriginY), and the final 500 // local-to-device matrix will have a post-translation of T(-deviceOriginX, -deviceOriginY). 501 void setDeviceCoordinateSystem(const SkM44& deviceToGlobal, 502 const SkM44& globalToDevice, 503 const SkM44& localToDevice, 504 int bufferOriginX, 505 int bufferOriginY); 506 // Convenience to configure the device to be axis-aligned with the root canvas, but with a 507 // unique origin. setOrigin(const SkM44 & globalCTM,int x,int y)508 void setOrigin(const SkM44& globalCTM, int x, int y) { 509 this->setDeviceCoordinateSystem(SkM44(), SkM44(), globalCTM, x, y); 510 } 511 512 // Returns whether or not localToDevice() has changed since the last call to this function. checkLocalToDeviceDirty()513 bool checkLocalToDeviceDirty() { 514 bool wasDirty = fLocalToDeviceDirty; 515 fLocalToDeviceDirty = false; 516 return wasDirty; 517 } 518 519 private: 520 friend class SkCanvas; // for setOrigin/setDeviceCoordinateSystem 521 friend class DeviceTestingAccess; 522 523 // Defaults to a CPU image filtering backend. 524 virtual sk_sp<skif::Backend> createImageFilteringBackend(const SkSurfaceProps& surfaceProps, 525 SkColorType colorType) const; 526 527 // Implementations can assume that the device from (x,y) to (w,h) will fit within dst. onReadPixels(const SkPixmap &,int x,int y)528 virtual bool onReadPixels(const SkPixmap&, int x, int y) { return false; } 529 530 // Implementations can assume that the src image placed at 'x,y' will fit within the device. onWritePixels(const SkPixmap &,int x,int y)531 virtual bool onWritePixels(const SkPixmap&, int x, int y) { return false; } 532 onAccessPixels(SkPixmap *)533 virtual bool onAccessPixels(SkPixmap*) { return false; } 534 onPeekPixels(SkPixmap *)535 virtual bool onPeekPixels(SkPixmap*) { return false; } 536 537 virtual void onClipShader(sk_sp<SkShader>) = 0; 538 539 // Only called with glyphRunLists that do not contain RSXForm. 540 virtual void onDrawGlyphRunList(SkCanvas*, 541 const sktext::GlyphRunList&, 542 const SkPaint& paint) = 0; 543 544 void simplifyGlyphRunRSXFormAndRedraw(SkCanvas*, 545 const sktext::GlyphRunList&, 546 const SkPaint& paint); 547 548 const SkImageInfo fInfo; 549 const SkSurfaceProps fSurfaceProps; 550 SkM44 fLocalToDevice; 551 // fDeviceToGlobal and fGlobalToDevice are inverses of each other; there are never that many 552 // SkDevices, so pay the memory cost to avoid recalculating the inverse. 553 SkM44 fDeviceToGlobal; 554 SkM44 fGlobalToDevice; 555 556 // fLocalToDevice but as a 3x3. 557 SkMatrix fLocalToDevice33; 558 559 // fLocalToDevice is the device CTM, not the global CTM. 560 // It maps from local space to the device's coordinate space. 561 // fDeviceToGlobal * fLocalToDevice will match the canvas' CTM. 562 // 563 // setGlobalCTM and setLocalToDevice are intentionally not virtual for performance reasons. 564 // However, track a dirty bit for subclasses that want to defer local-to-device dependent 565 // calculations until needed for a clip or draw. 566 bool fLocalToDeviceDirty = true; 567 }; 568 569 class SkNoPixelsDevice : public SkDevice { 570 public: 571 SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props); 572 SkNoPixelsDevice(const SkIRect& bounds, const SkSurfaceProps& props, 573 sk_sp<SkColorSpace> colorSpace); 574 575 // Returns false if the device could not be reset; this should only be called on a root device. 576 bool resetForNextPicture(const SkIRect& bounds); 577 578 // SkNoPixelsDevice tracks the clip conservatively in order to respond to some queries as 579 // accurately as possible while emphasizing performance 580 void pushClipStack() override; 581 void popClipStack() override; 582 void clipRect(const SkRect& rect, SkClipOp op, bool aa) override; 583 void clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) override; 584 void clipPath(const SkPath& path, SkClipOp op, bool aa) override; 585 void clipRegion(const SkRegion& globalRgn, SkClipOp op) override; 586 void replaceClip(const SkIRect& rect) override; isClipAntiAliased()587 bool isClipAntiAliased() const override { return this->clip().fIsAA; } isClipEmpty()588 bool isClipEmpty() const override { return this->devClipBounds().isEmpty(); } isClipRect()589 bool isClipRect() const override { return this->clip().fIsRect && !this->isClipEmpty(); } isClipWideOpen()590 bool isClipWideOpen() const override { 591 return this->clip().fIsRect && 592 this->devClipBounds() == this->bounds(); 593 } android_utils_clipAsRgn(SkRegion * rgn)594 void android_utils_clipAsRgn(SkRegion* rgn) const override { 595 rgn->setRect(this->devClipBounds()); 596 } devClipBounds()597 SkIRect devClipBounds() const override { return this->clip().fClipBounds; } 598 599 protected: 600 drawPaint(const SkPaint & paint)601 void drawPaint(const SkPaint& paint) override {} drawPoints(SkCanvas::PointMode,size_t,const SkPoint[],const SkPaint &)602 void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&) override {} drawImageRect(const SkImage *,const SkRect *,const SkRect &,const SkSamplingOptions &,const SkPaint &,SkCanvas::SrcRectConstraint)603 void drawImageRect(const SkImage*, const SkRect*, const SkRect&, 604 const SkSamplingOptions&, const SkPaint&, 605 SkCanvas::SrcRectConstraint) override {} drawRect(const SkRect &,const SkPaint &)606 void drawRect(const SkRect&, const SkPaint&) override {} drawOval(const SkRect &,const SkPaint &)607 void drawOval(const SkRect&, const SkPaint&) override {} drawRRect(const SkRRect &,const SkPaint &)608 void drawRRect(const SkRRect&, const SkPaint&) override {} drawPath(const SkPath &,const SkPaint &,bool)609 void drawPath(const SkPath&, const SkPaint&, bool) override {} drawDevice(SkDevice *,const SkSamplingOptions &,const SkPaint &)610 void drawDevice(SkDevice*, const SkSamplingOptions&, const SkPaint&) override {} drawVertices(const SkVertices *,sk_sp<SkBlender>,const SkPaint &,bool)611 void drawVertices(const SkVertices*, sk_sp<SkBlender>, const SkPaint&, bool) override {} drawMesh(const SkMesh &,sk_sp<SkBlender>,const SkPaint &)612 void drawMesh(const SkMesh&, sk_sp<SkBlender>, const SkPaint&) override {} 613 drawSlug(SkCanvas *,const sktext::gpu::Slug *,const SkPaint &)614 void drawSlug(SkCanvas*, const sktext::gpu::Slug*, const SkPaint&) override {} onDrawGlyphRunList(SkCanvas *,const sktext::GlyphRunList &,const SkPaint &)615 void onDrawGlyphRunList(SkCanvas*, const sktext::GlyphRunList&, const SkPaint&) override {} 616 isNoPixelsDevice()617 bool isNoPixelsDevice() const override { return true; } 618 619 private: 620 struct ClipState { 621 SkIRect fClipBounds; 622 int fDeferredSaveCount; 623 bool fIsAA; 624 bool fIsRect; 625 ClipStateClipState626 ClipState(const SkIRect& bounds, bool isAA, bool isRect) 627 : fClipBounds(bounds) 628 , fDeferredSaveCount(0) 629 , fIsAA(isAA) 630 , fIsRect(isRect) {} 631 632 void op(SkClipOp op, const SkM44& transform, const SkRect& bounds, 633 bool isAA, bool fillsBounds); 634 }; 635 636 void onClipShader(sk_sp<SkShader> shader) override; 637 clip()638 const ClipState& clip() const { return fClipStack.back(); } 639 ClipState& writableClip(); 640 641 skia_private::STArray<4, ClipState> fClipStack; 642 }; 643 644 class SkAutoDeviceTransformRestore : SkNoncopyable { 645 public: SkAutoDeviceTransformRestore(SkDevice * device,const SkMatrix & localToDevice)646 SkAutoDeviceTransformRestore(SkDevice* device, const SkMatrix& localToDevice) 647 : fDevice(device) 648 , fPrevLocalToDevice(device->localToDevice()) 649 { 650 fDevice->setLocalToDevice(SkM44(localToDevice)); 651 } ~SkAutoDeviceTransformRestore()652 ~SkAutoDeviceTransformRestore() { 653 fDevice->setLocalToDevice(fPrevLocalToDevice); 654 } 655 656 private: 657 SkDevice* fDevice; 658 const SkM44 fPrevLocalToDevice; 659 }; 660 661 #endif 662