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 | |
21 | class SkBitmap; |
22 | struct SkDrawShadowRec; |
23 | class SkGlyphRun; |
24 | class SkGlyphRunList; |
25 | class SkImageFilterCache; |
26 | struct SkIRect; |
27 | class SkMarkerStack; |
28 | class SkMatrix; |
29 | class SkRasterHandleAllocator; |
30 | class SkSpecialImage; |
31 | |
32 | class SkBaseDevice : public SkRefCnt, public SkMatrixProvider { |
33 | public: |
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 | |
193 | protected: |
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 | |
381 | private: |
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 | |
452 | class SkNoPixelsDevice : public SkBaseDevice { |
453 | public: |
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 | |
471 | protected: |
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 | |
505 | private: |
506 | typedef SkBaseDevice INHERITED; |
507 | }; |
508 | |
509 | class SkAutoDeviceTransformRestore : SkNoncopyable { |
510 | public: |
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 | |
521 | private: |
522 | SkBaseDevice* fDevice; |
523 | const SkM44 fPrevLocalToDevice; |
524 | }; |
525 | |
526 | #endif |
527 | |