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