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